From 698569f8428ca088f764d704034a1330517b98c0 Mon Sep 17 00:00:00 2001 From: tpearson Date: Sun, 26 Jun 2011 00:41:16 +0000 Subject: Finish rebranding of Krita as Chalk git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1238363 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- Doxyfile.temp | 2 +- README | 2 +- README.APPS | 2 +- README.PACKAGERS | 22 +- chalk/AUTHORS | 20 + chalk/ChangeLog | 1 + chalk/HACKING | 93 + chalk/IMAGE_LIBRARIES | 259 + chalk/Makefile.am | 47 + chalk/README | 13 + chalk/TODO | 181 + chalk/UIcomments | 59 + chalk/chalk.desktop | 95 + chalk/chalk.rc | 199 + chalk/chalk_part_init.cc | 23 + chalk/chalk_readonly.rc | 35 + chalk/chalkcolor/Makefile.am | 45 + chalk/chalkcolor/README | 4 + chalk/chalkcolor/TODO | 11 + chalk/chalkcolor/chalk_colorspace.desktop | 38 + chalk/chalkcolor/colorspaces/Makefile.am | 20 + .../chalkcolor/colorspaces/kis_alpha_colorspace.cc | 296 + .../chalkcolor/colorspaces/kis_alpha_colorspace.h | 93 + chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc | 571 + chalk/chalkcolor/colorspaces/kis_lab_colorspace.h | 153 + chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc | 624 + chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h | 112 + chalk/chalkcolor/kis_abstract_colorspace.cc | 762 + chalk/chalkcolor/kis_abstract_colorspace.h | 312 + chalk/chalkcolor/kis_basic_histogram_producers.cc | 484 + chalk/chalkcolor/kis_basic_histogram_producers.h | 197 + chalk/chalkcolor/kis_channelinfo.h | 115 + chalk/chalkcolor/kis_color.cc | 185 + chalk/chalkcolor/kis_color.h | 90 + chalk/chalkcolor/kis_color_conversions.cc | 427 + chalk/chalkcolor/kis_color_conversions.h | 49 + chalk/chalkcolor/kis_colorspace.cc | 39 + chalk/chalkcolor/kis_colorspace.h | 450 + .../chalkcolor/kis_colorspace_factory_registry.cc | 222 + chalk/chalkcolor/kis_colorspace_factory_registry.h | 121 + chalk/chalkcolor/kis_colorspace_iface.cc | 39 + chalk/chalkcolor/kis_colorspace_iface.h | 43 + chalk/chalkcolor/kis_composite_op.cc | 138 + chalk/chalkcolor/kis_composite_op.h | 103 + chalk/chalkcolor/kis_f16half_base_colorspace.cc | 125 + chalk/chalkcolor/kis_f16half_base_colorspace.h | 107 + chalk/chalkcolor/kis_f32_base_colorspace.cc | 125 + chalk/chalkcolor/kis_f32_base_colorspace.h | 83 + chalk/chalkcolor/kis_histogram_producer.cc | 67 + chalk/chalkcolor/kis_histogram_producer.h | 129 + chalk/chalkcolor/kis_profile.cc | 208 + chalk/chalkcolor/kis_profile.h | 98 + chalk/chalkcolor/kis_u16_base_colorspace.cc | 148 + chalk/chalkcolor/kis_u16_base_colorspace.h | 80 + chalk/chalkcolor/kis_u8_base_colorspace.cc | 118 + chalk/chalkcolor/kis_u8_base_colorspace.h | 77 + chalk/chalkcolor/tests/Makefile.am | 16 + .../tests/kis_color_conversions_tester.cpp | 227 + .../tests/kis_color_conversions_tester.h | 44 + chalk/chalkpart.desktop | 91 + chalk/colorspaces/Makefile.am | 15 + chalk/colorspaces/README | 11 + chalk/colorspaces/cmyk_u16/Makefile.am | 30 + .../cmyk_u16/chalk_cmyk_u16_plugin.desktop | 85 + chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.cc | 61 + chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.h | 38 + .../cmyk_u16/kis_cmyk_u16_colorspace.cc | 714 + .../colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h | 123 + chalk/colorspaces/cmyk_u8/Makefile.am | 20 + chalk/colorspaces/cmyk_u8/chalkcmykplugin.desktop | 99 + chalk/colorspaces/cmyk_u8/cmyk_plugin.cc | 66 + chalk/colorspaces/cmyk_u8/cmyk_plugin.h | 38 + chalk/colorspaces/cmyk_u8/cmykplugin.rc | 7 + chalk/colorspaces/cmyk_u8/composite.h | 76 + chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc | 710 + chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.h | 126 + chalk/colorspaces/cmyk_u8/templates/.directory | 5 + chalk/colorspaces/cmyk_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_cmyk_empty.png | Bin 0 -> 432 bytes .../templates/crsc-action-template_cmyk_empty.svgz | Bin 0 -> 1655 bytes .../cmyk_u8/templates/white_2000x800.desktop | 100 + .../cmyk_u8/templates/white_2000x800.kra | Bin 0 -> 17590 bytes chalk/colorspaces/gray_u16/Makefile.am | 29 + .../gray_u16/chalk_gray_u16_plugin.desktop | 83 + chalk/colorspaces/gray_u16/gray_u16_plugin.cc | 63 + chalk/colorspaces/gray_u16/gray_u16_plugin.h | 38 + .../gray_u16/kis_gray_u16_colorspace.cc | 658 + .../colorspaces/gray_u16/kis_gray_u16_colorspace.h | 118 + chalk/colorspaces/gray_u8/Makefile.am | 31 + chalk/colorspaces/gray_u8/chalkgrayplugin.desktop | 97 + chalk/colorspaces/gray_u8/gray_plugin.cc | 77 + chalk/colorspaces/gray_u8/gray_plugin.h | 37 + chalk/colorspaces/gray_u8/grayplugin.rc | 7 + chalk/colorspaces/gray_u8/kis_gray_colorspace.cc | 997 + chalk/colorspaces/gray_u8/kis_gray_colorspace.h | 114 + chalk/colorspaces/gray_u8/templates/.directory | 48 + chalk/colorspaces/gray_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_gray_empty.png | Bin 0 -> 1368 bytes .../templates/crsc-action-template_gray_empty.svgz | Bin 0 -> 1725 bytes .../gray_u8/templates/white_640x480.desktop | 99 + .../gray_u8/templates/white_640x480.kra | Bin 0 -> 2824 bytes chalk/colorspaces/gray_u8/tests/Makefile.am | 17 + .../kis_strategy_colorspace_grayscale_tester.cpp | 155 + .../kis_strategy_colorspace_grayscale_tester.h | 34 + chalk/colorspaces/lms_f32/Makefile.am | 28 + .../lms_f32/chalk_lms_f32_plugin.desktop | 77 + .../colorspaces/lms_f32/kis_lms_f32_colorspace.cc | 385 + chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.h | 157 + chalk/colorspaces/lms_f32/lms_f32_plugin.cc | 64 + chalk/colorspaces/lms_f32/lms_f32_plugin.h | 40 + chalk/colorspaces/lms_f32/lms_f32_plugin.rc | 9 + chalk/colorspaces/rgb_f16half/Makefile.am | 35 + .../rgb_f16half/chalk_rgb_f16half_plugin.desktop | 76 + .../rgb_f16half/kis_rgb_f16half_colorspace.cc | 952 + .../rgb_f16half/kis_rgb_f16half_colorspace.h | 144 + .../colorspaces/rgb_f16half/rgb_f16half_plugin.cc | 63 + chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.h | 39 + .../colorspaces/rgb_f16half/rgb_f16half_plugin.rc | 9 + chalk/colorspaces/rgb_f16half/tests/Makefile.am | 19 + .../tests/kis_rgb_f16half_colorspace_tester.cc | 545 + .../tests/kis_rgb_f16half_colorspace_tester.h | 47 + chalk/colorspaces/rgb_f32/Makefile.am | 34 + .../rgb_f32/chalk_rgb_f32_plugin.desktop | 77 + .../colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc | 949 + chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h | 165 + chalk/colorspaces/rgb_f32/rgb_f32_plugin.cc | 63 + chalk/colorspaces/rgb_f32/rgb_f32_plugin.h | 39 + chalk/colorspaces/rgb_f32/rgb_f32_plugin.rc | 9 + chalk/colorspaces/rgb_f32/tests/Makefile.am | 17 + .../kis_strategy_colorspace_rgb_f32_tester.cc | 541 + .../tests/kis_strategy_colorspace_rgb_f32_tester.h | 47 + chalk/colorspaces/rgb_u16/Makefile.am | 32 + .../rgb_u16/chalk_rgb_u16_plugin.desktop | 80 + .../colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc | 869 + chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h | 128 + chalk/colorspaces/rgb_u16/rgb_u16_plugin.cc | 61 + chalk/colorspaces/rgb_u16/rgb_u16_plugin.h | 37 + chalk/colorspaces/rgb_u16/tests/Makefile.am | 17 + .../kis_strategy_colorspace_rgb_u16_tester.cc | 524 + .../tests/kis_strategy_colorspace_rgb_u16_tester.h | 46 + chalk/colorspaces/rgb_u8/Makefile.am | 33 + chalk/colorspaces/rgb_u8/chalkrgbplugin.desktop | 99 + chalk/colorspaces/rgb_u8/composite.h | 868 + chalk/colorspaces/rgb_u8/kis_rgb_colorspace.cc | 1501 + chalk/colorspaces/rgb_u8/kis_rgb_colorspace.h | 116 + chalk/colorspaces/rgb_u8/rgb_plugin.cc | 74 + chalk/colorspaces/rgb_u8/rgb_plugin.h | 38 + chalk/colorspaces/rgb_u8/rgbplugin.rc | 9 + chalk/colorspaces/rgb_u8/templates/.directory | 6 + chalk/colorspaces/rgb_u8/templates/Makefile.am | 8 + .../templates/cr48-action-template_rgb_empty.png | Bin 0 -> 2364 bytes .../templates/crsc-action-template_rgb_empty.svgz | Bin 0 -> 1818 bytes .../rgb_u8/templates/transparent_1024x768.desktop | 91 + .../rgb_u8/templates/transparent_1024x768.kra | Bin 0 -> 7141 bytes .../rgb_u8/templates/transparent_1280x1024.desktop | 92 + .../rgb_u8/templates/transparent_1280x1024.kra | Bin 0 -> 9806 bytes .../rgb_u8/templates/transparent_1600x1200.desktop | 97 + .../rgb_u8/templates/transparent_1600x1200.kra | Bin 0 -> 13147 bytes .../rgb_u8/templates/transparent_640x480.desktop | 92 + .../rgb_u8/templates/transparent_640x480.kra | Bin 0 -> 4947 bytes .../rgb_u8/templates/white_1024x768.desktop | 102 + .../rgb_u8/templates/white_1024x768.kra | Bin 0 -> 5323 bytes .../rgb_u8/templates/white_1280x1024.desktop | 95 + .../rgb_u8/templates/white_1280x1024.kra | Bin 0 -> 7988 bytes .../rgb_u8/templates/white_1600x1200.desktop | 95 + .../rgb_u8/templates/white_1600x1200.kra | Bin 0 -> 11442 bytes .../rgb_u8/templates/white_640x480.desktop | 102 + .../colorspaces/rgb_u8/templates/white_640x480.kra | Bin 0 -> 3164 bytes chalk/colorspaces/rgb_u8/tests/Makefile.am | 17 + .../tests/kis_strategy_colorspace_rgb_tester.cpp | 197 + .../tests/kis_strategy_colorspace_rgb_tester.h | 34 + chalk/colorspaces/wet/Makefile.am | 28 + chalk/colorspaces/wet/chalkwetplugin.desktop | 86 + chalk/colorspaces/wet/kis_texture_filter.cc | 43 + chalk/colorspaces/wet/kis_texture_filter.h | 38 + chalk/colorspaces/wet/kis_texture_painter.cc | 92 + chalk/colorspaces/wet/kis_texture_painter.h | 40 + chalk/colorspaces/wet/kis_wet_colorspace.cc | 514 + chalk/colorspaces/wet/kis_wet_colorspace.h | 219 + chalk/colorspaces/wet/kis_wet_palette_widget.cc | 245 + chalk/colorspaces/wet/kis_wet_palette_widget.h | 68 + .../wet/kis_wetness_visualisation_filter.cc | 77 + .../wet/kis_wetness_visualisation_filter.h | 51 + chalk/colorspaces/wet/kis_wetop.cc | 230 + chalk/colorspaces/wet/kis_wetop.h | 73 + chalk/colorspaces/wet/todo | 24 + chalk/colorspaces/wet/wdgpressure.ui | 60 + chalk/colorspaces/wet/wet_plugin.cc | 128 + chalk/colorspaces/wet/wet_plugin.h | 46 + chalk/colorspaces/wet/wetdreams/Makefile | 6 + chalk/colorspaces/wet/wetdreams/wetmain.c | 517 + chalk/colorspaces/wet/wetdreams/wetpaint.c | 101 + chalk/colorspaces/wet/wetdreams/wetpaint.h | 4 + chalk/colorspaces/wet/wetdreams/wetphysics.c | 334 + chalk/colorspaces/wet/wetdreams/wetphysics.h | 9 + chalk/colorspaces/wet/wetdreams/wetpix.c | 332 + chalk/colorspaces/wet/wetdreams/wetpix.h | 87 + chalk/colorspaces/wet/wetdreams/wettexture.c | 84 + chalk/colorspaces/wet/wetdreams/wettexture.h | 9 + chalk/colorspaces/wet/wetphysicsfilter.cc | 424 + chalk/colorspaces/wet/wetphysicsfilter.h | 87 + chalk/colorspaces/wet/wetplugin.rc | 8 + chalk/colorspaces/wetsticky/Makefile.am | 25 + chalk/colorspaces/wetsticky/README | 42 + chalk/colorspaces/wetsticky/TODO | 7 + chalk/colorspaces/wetsticky/brushop/Makefile.am | 28 + chalk/colorspaces/wetsticky/brushop/README | 2 + .../wetsticky/brushop/chalkwsbrushpaintop.desktop | 73 + .../colorspaces/wetsticky/brushop/kis_wsbrushop.cc | 117 + .../colorspaces/wetsticky/brushop/kis_wsbrushop.h | 56 + .../wetsticky/brushop/wetpaintbrush.png | Bin 0 -> 1329 bytes .../wetsticky/brushop/wsbrushpaintop_plugin.cc | 56 + .../wetsticky/brushop/wsbrushpaintop_plugin.h | 44 + chalk/colorspaces/wetsticky/chalkwsplugin.desktop | 46 + .../wetsticky/kis_wet_sticky_colorspace.cc | 605 + .../wetsticky/kis_wet_sticky_colorspace.h | 148 + .../colorspaces/wetsticky/kis_ws_engine_filter.cc | 180 + chalk/colorspaces/wetsticky/kis_ws_engine_filter.h | 77 + chalk/colorspaces/wetsticky/wet_sticky_plugin.cc | 60 + chalk/colorspaces/wetsticky/wet_sticky_plugin.h | 42 + chalk/colorspaces/wetsticky/ws/GNU | 0 .../wetsticky/ws/GNU Public Licence.txt | 341 + chalk/colorspaces/wetsticky/ws/README | 4 + chalk/colorspaces/wetsticky/ws/TODO | 24 + chalk/colorspaces/wetsticky/ws/after.jpg | Bin 0 -> 29607 bytes chalk/colorspaces/wetsticky/ws/anim.c | 154 + chalk/colorspaces/wetsticky/ws/before.jpg | Bin 0 -> 15496 bytes chalk/colorspaces/wetsticky/ws/canvas.c | 514 + chalk/colorspaces/wetsticky/ws/canvas.h | 70 + chalk/colorspaces/wetsticky/ws/cmap.c | 681 + chalk/colorspaces/wetsticky/ws/constants.h | 69 + chalk/colorspaces/wetsticky/ws/engine.c | 802 + chalk/colorspaces/wetsticky/ws/engine.h | 33 + chalk/colorspaces/wetsticky/ws/engine3.c | 617 + chalk/colorspaces/wetsticky/ws/load_ppm.c | 244 + chalk/colorspaces/wetsticky/ws/main.c | 105 + chalk/colorspaces/wetsticky/ws/makefile | 55 + chalk/colorspaces/wetsticky/ws/mona.pgm | Bin 0 -> 86269 bytes chalk/colorspaces/wetsticky/ws/ogl_interface.c | 302 + chalk/colorspaces/wetsticky/ws/test2.jpg | Bin 0 -> 13051 bytes chalk/colorspaces/wetsticky/ws/test3.jpg | Bin 0 -> 21238 bytes chalk/colorspaces/wetsticky/ws/types.h | 72 + chalk/colorspaces/wetsticky/ws/win_interface.h | 28 + chalk/colorspaces/wetsticky/ws/x_interface.c | 795 + chalk/colorspaces/wetsticky/wstool.ui | 262 + chalk/colorspaces/ycbcr_u16/Makefile.am | 27 + .../ycbcr_u16/chalk_ycbcr_u16_plugin.desktop | 71 + .../ycbcr_u16/kis_ycbcr_u16_colorspace.cc | 338 + .../ycbcr_u16/kis_ycbcr_u16_colorspace.h | 144 + chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc | 60 + chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h | 38 + chalk/colorspaces/ycbcr_u8/Makefile.am | 29 + .../ycbcr_u8/chalk_ycbcr_u8_plugin.desktop | 71 + .../ycbcr_u8/kis_ycbcr_u8_colorspace.cc | 344 + .../colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h | 144 + chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc | 62 + chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h | 38 + chalk/configure.in.bot | 19 + chalk/configure.in.in | 113 + chalk/core/Makefile.am | 59 + chalk/core/createdcop.py | 171 + chalk/core/kis_adjustment_layer.cc | 252 + chalk/core/kis_adjustment_layer.h | 106 + chalk/core/kis_alpha_mask.cc | 132 + chalk/core/kis_alpha_mask.h | 106 + chalk/core/kis_autobrush_resource.cc | 106 + chalk/core/kis_autobrush_resource.h | 71 + chalk/core/kis_autogradient_resource.cc | 221 + chalk/core/kis_autogradient_resource.h | 88 + chalk/core/kis_background.cc | 155 + chalk/core/kis_background.h | 49 + chalk/core/kis_basic_math_toolbox.cpp | 137 + chalk/core/kis_basic_math_toolbox.h | 44 + chalk/core/kis_boundary.cc | 83 + chalk/core/kis_boundary.h | 57 + chalk/core/kis_brush.cc | 1333 + chalk/core/kis_brush.h | 192 + chalk/core/kis_change_profile_visitor.h | 109 + chalk/core/kis_colorspace_convert_visitor.h | 101 + chalk/core/kis_command.cc | 43 + chalk/core/kis_command.h | 55 + chalk/core/kis_convolution_painter.cc | 426 + chalk/core/kis_convolution_painter.h | 95 + chalk/core/kis_crop_visitor.h | 109 + chalk/core/kis_datamanager.h | 217 + chalk/core/kis_exif_info.cc | 66 + chalk/core/kis_exif_info.h | 58 + chalk/core/kis_exif_value.cc | 678 + chalk/core/kis_exif_value.h | 270 + chalk/core/kis_fill_painter.cc | 407 + chalk/core/kis_fill_painter.h | 207 + chalk/core/kis_filter.cc | 133 + chalk/core/kis_filter.h | 201 + chalk/core/kis_filter_config_widget.cc | 31 + chalk/core/kis_filter_config_widget.h | 50 + chalk/core/kis_filter_configuration.cc | 185 + chalk/core/kis_filter_configuration.h | 105 + chalk/core/kis_filter_registry.cc | 82 + chalk/core/kis_filter_registry.h | 53 + chalk/core/kis_filter_strategy.cc | 192 + chalk/core/kis_filter_strategy.h | 150 + chalk/core/kis_gradient.cc | 639 + chalk/core/kis_gradient.h | 265 + chalk/core/kis_gradient_painter.cc | 723 + chalk/core/kis_gradient_painter.h | 84 + chalk/core/kis_group_layer.cc | 428 + chalk/core/kis_group_layer.h | 141 + chalk/core/kis_histogram.cc | 215 + chalk/core/kis_histogram.h | 150 + chalk/core/kis_image.cc | 1702 + chalk/core/kis_image.h | 461 + chalk/core/kis_image_iface.cc | 97 + chalk/core/kis_image_iface.h | 65 + chalk/core/kis_imagepipe_brush.cc | 456 + chalk/core/kis_imagepipe_brush.h | 169 + chalk/core/kis_iterator.cc | 142 + chalk/core/kis_iterator.h | 173 + chalk/core/kis_iteratorpixeltrait.h | 131 + chalk/core/kis_iterators_pixel.cc | 59 + chalk/core/kis_iterators_pixel.h | 154 + chalk/core/kis_layer.cc | 611 + chalk/core/kis_layer.h | 257 + chalk/core/kis_layer_visitor.h | 43 + chalk/core/kis_math_toolbox.cpp | 166 + chalk/core/kis_math_toolbox.h | 124 + chalk/core/kis_merge_visitor.h | 358 + chalk/core/kis_meta_registry.cc | 68 + chalk/core/kis_meta_registry.h | 49 + chalk/core/kis_nameserver.cc | 49 + chalk/core/kis_nameserver.h | 40 + chalk/core/kis_paint_device.cc | 1285 + chalk/core/kis_paint_device.h | 597 + chalk/core/kis_paint_device_action.h | 43 + chalk/core/kis_paint_device_iface.cc | 74 + chalk/core/kis_paint_device_iface.h | 85 + chalk/core/kis_paint_layer.cc | 509 + chalk/core/kis_paint_layer.h | 157 + chalk/core/kis_painter.cc | 928 + chalk/core/kis_painter.h | 432 + chalk/core/kis_paintop.cc | 113 + chalk/core/kis_paintop.h | 141 + chalk/core/kis_paintop_registry.cc | 139 + chalk/core/kis_paintop_registry.h | 84 + chalk/core/kis_palette.cc | 306 + chalk/core/kis_palette.h | 113 + chalk/core/kis_part_layer_iface.h | 36 + chalk/core/kis_pattern.cc | 335 + chalk/core/kis_pattern.h | 80 + chalk/core/kis_perspective_grid.cpp | 100 + chalk/core/kis_perspective_grid.h | 107 + chalk/core/kis_perspective_math.cpp | 546 + chalk/core/kis_perspective_math.h | 70 + chalk/core/kis_perspectivetransform_worker.cpp | 121 + chalk/core/kis_perspectivetransform_worker.h | 52 + chalk/core/kis_point.h | 48 + chalk/core/kis_random_accessor.cpp | 58 + chalk/core/kis_random_accessor.h | 95 + chalk/core/kis_random_sub_accessor.cpp | 84 + chalk/core/kis_random_sub_accessor.h | 45 + chalk/core/kis_rect.cc | 28 + chalk/core/kis_rect.h | 50 + chalk/core/kis_resource.cc | 62 + chalk/core/kis_resource.h | 84 + chalk/core/kis_rotate_visitor.cc | 406 + chalk/core/kis_rotate_visitor.h | 80 + chalk/core/kis_scale_visitor.cc | 279 + chalk/core/kis_scale_visitor.h | 204 + chalk/core/kis_selected_transaction.cc | 73 + chalk/core/kis_selected_transaction.h | 50 + chalk/core/kis_selection.cc | 582 + chalk/core/kis_selection.h | 160 + chalk/core/kis_shear_visitor.h | 95 + chalk/core/kis_strategy_move.cc | 148 + chalk/core/kis_strategy_move.h | 59 + chalk/core/kis_substrate.h | 78 + chalk/core/kis_thread.h | 57 + chalk/core/kis_thread_pool.cc | 192 + chalk/core/kis_thread_pool.h | 70 + chalk/core/kis_transaction.cc | 94 + chalk/core/kis_transaction.h | 46 + chalk/core/kis_transform_visitor.h | 137 + chalk/core/kis_transform_worker.cc | 676 + chalk/core/kis_transform_worker.h | 79 + chalk/core/kis_types.h | 90 + chalk/core/kis_vec.cc | 67 + chalk/core/kis_vec.h | 405 + chalk/core/tests/Makefile.am | 30 + .../core/tests/kis_filter_configuration_tester.cc | 67 + chalk/core/tests/kis_filter_configuration_tester.h | 34 + chalk/core/tests/kis_image_tester.cpp | 88 + chalk/core/tests/kis_image_tester.h | 32 + chalk/core/tests/kis_integer_maths_tester.cpp | 93 + chalk/core/tests/kis_integer_maths_tester.h | 34 + chalk/core/tiles/Makefile.am | 23 + chalk/core/tiles/kis_memento.cc | 154 + chalk/core/tiles/kis_memento.h | 147 + chalk/core/tiles/kis_tile.cc | 152 + chalk/core/tiles/kis_tile.h | 87 + chalk/core/tiles/kis_tile_global.h | 23 + chalk/core/tiles/kis_tiled_random_accessor.cc | 115 + chalk/core/tiles/kis_tiled_random_accessor.h | 66 + chalk/core/tiles/kis_tileddatamanager.cc | 1044 + chalk/core/tiles/kis_tileddatamanager.h | 233 + chalk/core/tiles/kis_tiledhlineiterator.cc | 213 + chalk/core/tiles/kis_tilediterator.cc | 131 + chalk/core/tiles/kis_tilediterator.h | 213 + chalk/core/tiles/kis_tiledrectiterator.cc | 242 + chalk/core/tiles/kis_tiledvlineiterator.cc | 154 + chalk/core/tiles/kis_tilemanager.cc | 578 + chalk/core/tiles/kis_tilemanager.h | 139 + chalk/core/tiles/tests/Makefile.am | 15 + chalk/core/tiles/tests/kis_tiled_data_tester.cpp | 74 + chalk/core/tiles/tests/kis_tiled_data_tester.h | 32 + chalk/data/Makefile.am | 7 + chalk/data/README | 13 + chalk/data/brushes/10x10square.gbr | Bin 0 -> 143 bytes chalk/data/brushes/10x10squareBlur.gbr | Bin 0 -> 148 bytes chalk/data/brushes/11circle.gbr | Bin 0 -> 161 bytes chalk/data/brushes/11fcircle.gbr | Bin 0 -> 159 bytes chalk/data/brushes/13circle.gbr | Bin 0 -> 209 bytes chalk/data/brushes/13fcircle.gbr | Bin 0 -> 207 bytes chalk/data/brushes/15circle.gbr | Bin 0 -> 265 bytes chalk/data/brushes/15fcircle.gbr | Bin 0 -> 263 bytes chalk/data/brushes/17circle.gbr | Bin 0 -> 329 bytes chalk/data/brushes/17fcircle.gbr | Bin 0 -> 327 bytes chalk/data/brushes/19circle.gbr | Bin 0 -> 401 bytes chalk/data/brushes/19fcircle.gbr | Bin 0 -> 399 bytes chalk/data/brushes/1circle.gbr | Bin 0 -> 41 bytes chalk/data/brushes/20x20square.gbr | Bin 0 -> 443 bytes chalk/data/brushes/20x20squareBlur.gbr | Bin 0 -> 448 bytes chalk/data/brushes/3circle.gbr | Bin 0 -> 49 bytes chalk/data/brushes/3fcircle.gbr | Bin 0 -> 47 bytes chalk/data/brushes/5circle.gbr | Bin 0 -> 65 bytes chalk/data/brushes/5fcircle.gbr | Bin 0 -> 63 bytes chalk/data/brushes/5x5square.gbr | Bin 0 -> 66 bytes chalk/data/brushes/5x5squareBlur.gbr | Bin 0 -> 71 bytes chalk/data/brushes/7circle.gbr | Bin 0 -> 89 bytes chalk/data/brushes/7fcircle.gbr | Bin 0 -> 87 bytes chalk/data/brushes/9circle.gbr | Bin 0 -> 121 bytes chalk/data/brushes/9fcircle.gbr | Bin 0 -> 119 bytes chalk/data/brushes/BRUSHES.README | 19 + chalk/data/brushes/COPYING | 340 + chalk/data/brushes/DStar11.gbr | Bin 0 -> 168 bytes chalk/data/brushes/DStar17.gbr | Bin 0 -> 336 bytes chalk/data/brushes/DStar25.gbr | Bin 0 -> 672 bytes chalk/data/brushes/Makefile.am | 69 + chalk/data/brushes/SketchBrush-16.gih | Bin 0 -> 1618 bytes chalk/data/brushes/SketchBrush-32.gih | Bin 0 -> 5458 bytes chalk/data/brushes/SketchBrush-64.gih | Bin 0 -> 20818 bytes chalk/data/brushes/callig1.gbr | Bin 0 -> 147 bytes chalk/data/brushes/callig2.gbr | Bin 0 -> 447 bytes chalk/data/brushes/callig3.gbr | Bin 0 -> 272 bytes chalk/data/brushes/callig4.gbr | Bin 0 -> 72 bytes chalk/data/brushes/confetti.gbr | Bin 0 -> 793 bytes chalk/data/brushes/confetti.gih | Bin 0 -> 8076 bytes chalk/data/brushes/cursor.gbr | Bin 0 -> 899 bytes chalk/data/brushes/cursor_big_lb.gbr | Bin 0 -> 2858 bytes chalk/data/brushes/cursor_big_lw.gbr | Bin 0 -> 2858 bytes chalk/data/brushes/cursor_big_rb.gbr | Bin 0 -> 2858 bytes chalk/data/brushes/cursor_big_rw.gbr | Bin 0 -> 2858 bytes chalk/data/brushes/cursor_lw.gbr | Bin 0 -> 1802 bytes chalk/data/brushes/cursor_resize_diag_1.gbr | Bin 0 -> 1072 bytes chalk/data/brushes/cursor_resize_diag_2.gbr | Bin 0 -> 1072 bytes chalk/data/brushes/cursor_resize_hor.gbr | Bin 0 -> 958 bytes chalk/data/brushes/cursor_resize_vert.gbr | Bin 0 -> 959 bytes chalk/data/brushes/cursor_rw.gbr | Bin 0 -> 1802 bytes chalk/data/brushes/cursor_small_lb.gbr | Bin 0 -> 1004 bytes chalk/data/brushes/cursor_small_lw.gbr | Bin 0 -> 1004 bytes chalk/data/brushes/cursor_small_rb.gbr | Bin 0 -> 1004 bytes chalk/data/brushes/cursor_small_rw.gbr | Bin 0 -> 1004 bytes chalk/data/brushes/cursor_tiny_lw.gbr | Bin 0 -> 523 bytes chalk/data/brushes/cursor_tiny_rw.gbr | Bin 0 -> 523 bytes chalk/data/brushes/cursor_up.gbr | Bin 0 -> 1606 bytes chalk/data/brushes/dunes.gbr | Bin 0 -> 1100 bytes chalk/data/brushes/feltpen.gih | Bin 0 -> 118795 bytes chalk/data/brushes/galaxy.gbr | Bin 0 -> 2636 bytes chalk/data/brushes/galaxy_big.gbr | Bin 0 -> 10037 bytes chalk/data/brushes/galaxy_small.gbr | Bin 0 -> 749 bytes chalk/data/brushes/hsparks.gih | Bin 0 -> 127644 bytes chalk/data/brushes/pepper.gbr | Bin 0 -> 11991 bytes chalk/data/brushes/pixel.gbr | Bin 0 -> 48 bytes chalk/data/brushes/vine.gih | Bin 0 -> 116027 bytes chalk/data/chalk_filter.desktop | 47 + chalk/data/chalk_paintop.desktop | 41 + chalk/data/chalk_plugin.desktop | 42 + chalk/data/chalk_tool.desktop | 46 + chalk/data/gradients/Abstract_1.ggr | 9 + chalk/data/gradients/Abstract_2.ggr | 9 + chalk/data/gradients/Abstract_3.ggr | 9 + chalk/data/gradients/Aneurism.ggr | 11 + chalk/data/gradients/Blinds.ggr | 12 + chalk/data/gradients/Blue_Green.ggr | 5 + chalk/data/gradients/Browns.ggr | 14 + chalk/data/gradients/Brushed_Aluminium.ggr | 27 + chalk/data/gradients/Burning_Paper.ggr | 9 + chalk/data/gradients/Burning_Transparency.ggr | 9 + chalk/data/gradients/CD.ggr | 21 + chalk/data/gradients/CD_Half.ggr | 12 + chalk/data/gradients/Caribbean_Blues.ggr | 6 + chalk/data/gradients/Coffee.ggr | 4 + chalk/data/gradients/Cold_Steel.ggr | 5 + chalk/data/gradients/Cold_Steel_2.ggr | 6 + chalk/data/gradients/Crown_molding.ggr | 9 + chalk/data/gradients/Dark_1.ggr | 6 + chalk/data/gradients/Deep_Sea.ggr | 5 + chalk/data/gradients/Default.ggr | 4 + chalk/data/gradients/Flare_Glow_Angular_1.ggr | 49 + chalk/data/gradients/Flare_Glow_Radial_1.ggr | 7 + chalk/data/gradients/Flare_Glow_Radial_2.ggr | 8 + chalk/data/gradients/Flare_Glow_Radial_3.ggr | 8 + chalk/data/gradients/Flare_Glow_Radial_4.ggr | 6 + chalk/data/gradients/Flare_Radial_101.ggr | 10 + chalk/data/gradients/Flare_Radial_102.ggr | 9 + chalk/data/gradients/Flare_Radial_103.ggr | 4 + chalk/data/gradients/Flare_Rays_Radial_1.ggr | 5 + chalk/data/gradients/Flare_Rays_Radial_2.ggr | 5 + chalk/data/gradients/Flare_Rays_Size_1.ggr | 19 + chalk/data/gradients/Flare_Sizefac_101.ggr | 4 + chalk/data/gradients/Four_bars.ggr | 11 + chalk/data/gradients/French_flag.ggr | 6 + chalk/data/gradients/French_flag_smooth.ggr | 5 + .../gradients/Full_saturation_spectrum_CCW.ggr | 4 + .../data/gradients/Full_saturation_spectrum_CW.ggr | 4 + chalk/data/gradients/German_flag.ggr | 6 + chalk/data/gradients/German_flag_smooth.ggr | 5 + chalk/data/gradients/Golden.ggr | 17 + chalk/data/gradients/Greens.ggr | 12 + chalk/data/gradients/Horizon_1.ggr | 8 + chalk/data/gradients/Horizon_2.ggr | 8 + chalk/data/gradients/Incandescent.ggr | 7 + chalk/data/gradients/Land_1.ggr | 8 + chalk/data/gradients/Land_and_Sea.ggr | 8 + chalk/data/gradients/Makefile.am | 4 + chalk/data/gradients/Metallic_Something.ggr | 11 + chalk/data/gradients/Mexican_flag.ggr | 6 + chalk/data/gradients/Mexican_flag_smooth.ggr | 5 + chalk/data/gradients/Nauseating_Headache.ggr | 28 + chalk/data/gradients/Neon_Cyan.ggr | 7 + chalk/data/gradients/Neon_Green.ggr | 7 + chalk/data/gradients/Neon_Yellow.ggr | 7 + chalk/data/gradients/Pastel_Rainbow.ggr | 4 + chalk/data/gradients/Pastels.ggr | 17 + chalk/data/gradients/Purples.ggr | 10 + chalk/data/gradients/Radial_Eyeball_Blue.ggr | 8 + chalk/data/gradients/Radial_Eyeball_Brown.ggr | 8 + chalk/data/gradients/Radial_Eyeball_Green.ggr | 8 + chalk/data/gradients/Radial_Glow_1.ggr | 8 + chalk/data/gradients/Radial_Rainbow_Hoop.ggr | 6 + chalk/data/gradients/Romanian_flag.ggr | 6 + chalk/data/gradients/Romanian_flag_smooth.ggr | 5 + chalk/data/gradients/Rounded_edge.ggr | 10 + chalk/data/gradients/Shadows_1.ggr | 8 + chalk/data/gradients/Shadows_2.ggr | 8 + chalk/data/gradients/Shadows_3.ggr | 9 + chalk/data/gradients/Skyline.ggr | 8 + chalk/data/gradients/Skyline_polluted.ggr | 8 + chalk/data/gradients/Square_Wood_Frame.ggr | 9 + chalk/data/gradients/Sunrise.ggr | 9 + chalk/data/gradients/Three_bars_sin.ggr | 9 + chalk/data/gradients/Tropical_Colors.ggr | 12 + chalk/data/gradients/Tube_Red.ggr | 10 + chalk/data/gradients/Wood_1.ggr | 6 + chalk/data/gradients/Wood_2.ggr | 12 + chalk/data/gradients/Yellow_Contrast.ggr | 10 + chalk/data/gradients/Yellow_Orange.ggr | 5 + chalk/data/images/Azay-Le-Rideau.jpg | Bin 0 -> 82588 bytes chalk/data/images/Makefile.am | 6 + chalk/data/images/WeyDesc.png | Bin 0 -> 1061530 bytes chalk/data/images/evenings.jpg | Bin 0 -> 53510 bytes chalk/data/images/hakonepa.jpg | Bin 0 -> 58724 bytes chalk/data/images/hiro_awate.jpg | Bin 0 -> 54283 bytes chalk/data/images/paintbrush.png | Bin 0 -> 13186 bytes chalk/data/images/previewfilter.png | Bin 0 -> 5988 bytes chalk/data/palettes/40_Colors.gpl | 43 + chalk/data/palettes/Anchor.gpl | 448 + chalk/data/palettes/Bears.gpl | 259 + chalk/data/palettes/Bgold.gpl | 259 + chalk/data/palettes/Blues.gpl | 261 + chalk/data/palettes/Borders.gpl | 259 + chalk/data/palettes/Browns_And_Yellows.gpl | 25 + chalk/data/palettes/Caramel.gpl | 259 + chalk/data/palettes/Cascade.gpl | 259 + chalk/data/palettes/China.gpl | 259 + chalk/data/palettes/Coldfire.gpl | 259 + chalk/data/palettes/Cool_Colors.gpl | 11 + chalk/data/palettes/Cranes.gpl | 259 + chalk/data/palettes/DMC.gpl | 458 + chalk/data/palettes/Dark_pastels.gpl | 259 + chalk/data/palettes/Default.gpl | 26 + chalk/data/palettes/Ega.gpl | 244 + chalk/data/palettes/Firecode.gpl | 259 + chalk/data/palettes/Gold.gpl | 259 + chalk/data/palettes/GrayViolet.gpl | 259 + chalk/data/palettes/Grayblue.gpl | 259 + chalk/data/palettes/Grays.gpl | 34 + chalk/data/palettes/Greens.gpl | 259 + chalk/data/palettes/Hilite.gpl | 259 + chalk/data/palettes/Khaki.gpl | 258 + chalk/data/palettes/Lights.gpl | 28 + chalk/data/palettes/Madeira.gpl | 372 + chalk/data/palettes/Makefile.am | 50 + chalk/data/palettes/Muted.gpl | 81 + chalk/data/palettes/Named_Colors.gpl | 452 + chalk/data/palettes/News3.gpl | 259 + chalk/data/palettes/Op2.gpl | 259 + chalk/data/palettes/Paintjet.gpl | 22 + chalk/data/palettes/Pantone_Coated_Approx.gpl | 949 + chalk/data/palettes/Pastels.gpl | 21 + chalk/data/palettes/Plasma.gpl | 260 + chalk/data/palettes/Reds.gpl | 259 + chalk/data/palettes/Reds_And_Purples.gpl | 33 + chalk/data/palettes/Royal.gpl | 259 + chalk/data/palettes/Topographic.gpl | 265 + chalk/data/palettes/Visibone.gpl | 346 + chalk/data/palettes/Visibone_2.gpl | 266 + chalk/data/palettes/Volcano.gpl | 259 + chalk/data/palettes/Warm_Colors.gpl | 10 + chalk/data/palettes/Web.gpl | 220 + chalk/data/palettes/new_kde.gpl | 48 + chalk/data/patterns/3dgreen.pat | Bin 0 -> 6108 bytes chalk/data/patterns/Craters.pat | Bin 0 -> 39707 bytes chalk/data/patterns/Makefile.am | 5 + chalk/data/patterns/Moonfoot.pat | Bin 0 -> 14442 bytes chalk/data/patterns/Stripes1px.pat | Bin 0 -> 9253 bytes chalk/data/patterns/Stripes2px.pat | Bin 0 -> 9248 bytes chalk/data/patterns/amethyst.pat | Bin 0 -> 12321 bytes chalk/data/patterns/bark.pat | Bin 0 -> 22173 bytes chalk/data/patterns/blue.pat | Bin 0 -> 6108 bytes chalk/data/patterns/bluegrid.pat | Bin 0 -> 1909 bytes chalk/data/patterns/bluesquares.pat | Bin 0 -> 48037 bytes chalk/data/patterns/blueweb.pat | Bin 0 -> 12321 bytes chalk/data/patterns/brick.pat | Bin 0 -> 27674 bytes chalk/data/patterns/burlap.pat | Bin 0 -> 27676 bytes chalk/data/patterns/burlwood.pat | Bin 0 -> 27681 bytes chalk/data/patterns/choc_swirl.pat | Bin 0 -> 7538 bytes chalk/data/patterns/corkboard.pat | Bin 0 -> 10097 bytes chalk/data/patterns/cracked.pat | Bin 0 -> 62238 bytes chalk/data/patterns/crinklepaper.pat | Bin 0 -> 49191 bytes chalk/data/patterns/electric.pat | Bin 0 -> 9638 bytes chalk/data/patterns/fibers.pat | Bin 0 -> 7531 bytes chalk/data/patterns/granite1.pat | Bin 0 -> 10035 bytes chalk/data/patterns/ground1.pat | Bin 0 -> 30034 bytes chalk/data/patterns/ice.pat | Bin 0 -> 43228 bytes chalk/data/patterns/java.pat | Bin 0 -> 12315 bytes chalk/data/patterns/leather.pat | Bin 0 -> 12320 bytes chalk/data/patterns/leaves.pat | Bin 0 -> 7537 bytes chalk/data/patterns/leopard.pat | Bin 0 -> 11921 bytes chalk/data/patterns/lightning.pat | Bin 0 -> 40707 bytes chalk/data/patterns/marble1.pat | Bin 0 -> 16418 bytes chalk/data/patterns/marble2.pat | Bin 0 -> 16418 bytes chalk/data/patterns/marble3.pat | Bin 0 -> 12322 bytes chalk/data/patterns/nops.pat | Bin 0 -> 49177 bytes chalk/data/patterns/paper.pat | Bin 0 -> 10030 bytes chalk/data/patterns/parque1.pat | Bin 0 -> 12322 bytes chalk/data/patterns/parque2.pat | Bin 0 -> 12322 bytes chalk/data/patterns/parque3.pat | Bin 0 -> 12322 bytes chalk/data/patterns/pastel.pat | Bin 0 -> 12325 bytes chalk/data/patterns/pine.pat | Bin 0 -> 10781 bytes chalk/data/patterns/pink_marble.pat | Bin 0 -> 49188 bytes chalk/data/patterns/pool.pat | Bin 0 -> 6111 bytes chalk/data/patterns/qube1.pat | Bin 0 -> 5331 bytes chalk/data/patterns/rain.pat | Bin 0 -> 35021 bytes chalk/data/patterns/recessed.pat | Bin 0 -> 6433 bytes chalk/data/patterns/redcube.pat | Bin 0 -> 12320 bytes chalk/data/patterns/rock.pat | Bin 0 -> 30510 bytes chalk/data/patterns/sky.pat | Bin 0 -> 11002 bytes chalk/data/patterns/slate.pat | Bin 0 -> 16414 bytes chalk/data/patterns/sm_squares.pat | Bin 0 -> 7538 bytes chalk/data/patterns/starfield.pat | Bin 0 -> 49163 bytes chalk/data/patterns/stone33.pat | Bin 0 -> 73034 bytes chalk/data/patterns/terra.pat | Bin 0 -> 12318 bytes chalk/data/patterns/walnut.pat | Bin 0 -> 49183 bytes chalk/data/patterns/warning.pat | Bin 0 -> 1233 bytes chalk/data/patterns/wood1.pat | Bin 0 -> 27690 bytes chalk/data/patterns/wood2.pat | Bin 0 -> 30030 bytes chalk/data/patterns/wood3.pat | Bin 0 -> 7532 bytes chalk/data/patterns/wood4.pat | Bin 0 -> 7532 bytes chalk/data/patterns/wood5.pat | Bin 0 -> 27677 bytes chalk/data/profiles/Adobe.icm | Bin 0 -> 2036 bytes chalk/data/profiles/Apple.icm | Bin 0 -> 2036 bytes chalk/data/profiles/CIE.icm | Bin 0 -> 2036 bytes chalk/data/profiles/CMY.icm | Bin 0 -> 101936 bytes chalk/data/profiles/ColorMatch.icm | Bin 0 -> 2044 bytes chalk/data/profiles/Makefile.am | 4 + chalk/data/profiles/NTSC.icm | Bin 0 -> 2044 bytes chalk/data/profiles/PAL.icm | Bin 0 -> 2040 bytes chalk/data/profiles/README | 5 + chalk/data/profiles/SMPTE-C.icm | Bin 0 -> 2052 bytes chalk/data/profiles/WideGamut.icm | Bin 0 -> 2044 bytes chalk/data/profiles/cmyk.icm | Bin 0 -> 725407 bytes chalk/data/profiles/fogra27l.icm | Bin 0 -> 225823 bytes chalk/data/profiles/lcmslabi.icm | Bin 0 -> 154326 bytes chalk/data/profiles/lcmsxyzi.icm | Bin 0 -> 154323 bytes chalk/data/profiles/monoscnr.icm | Bin 0 -> 410 bytes chalk/data/profiles/sRGB.icm | Bin 0 -> 2032 bytes chalk/data/profiles/srgb_color_space_profile.icm | Bin 0 -> 3144 bytes chalk/data/profiles/srgbspac.icm | Bin 0 -> 28202 bytes chalk/data/profiles/tifflab8spac.icm | Bin 0 -> 200182 bytes chalk/data/profiles/ycc601.icm | Bin 0 -> 101940 bytes chalk/data/profiles/ycc709.icm | Bin 0 -> 101940 bytes chalk/data/templates/.directory | 56 + chalk/design.h | 27 + chalk/doc/DESIGN.obsolete | 179 + chalk/doc/Developing Chalk Plugins.odt | Bin 0 -> 50195 bytes chalk/doc/autoextending paintdevices | 54 + chalk/doc/background_paper.txt | 84 + chalk/doc/brush.txt | 36 + chalk/doc/chalk-features | 215 + chalk/doc/chalk.kpr | Bin 0 -> 2857392 bytes chalk/doc/chalk.pdf | Bin 0 -> 2701147 bytes chalk/doc/chalk.xmi | 56432 +++++++++++++++++++ chalk/doc/channels_masks_selections | 12 + chalk/doc/colordiff | 68 + chalk/doc/colorspaces.xmi | 41965 ++++++++++++++ chalk/doc/colorstrategyAPI | 58 + chalk/doc/controller.xmi | 39776 +++++++++++++ chalk/doc/coordinates.txt | 9 + chalk/doc/dirty.txt | 53 + chalk/doc/doc-outline | 187 + chalk/doc/histograms.xmi | 4145 ++ chalk/doc/hooks | 33 + chalk/doc/howtofilters.txt | 30 + chalk/doc/impexp.txt | 41 + chalk/doc/large_files | 36 + chalk/doc/layersupdatesignals.flw | Bin 0 -> 10783 bytes chalk/doc/manual/chalk.kwd | Bin 0 -> 2505238 bytes chalk/doc/oasis | 5 + chalk/doc/paint_device.txt | 98 + chalk/doc/palettedesign.txt | 34 + chalk/doc/plugins.txt | 32 + chalk/doc/profiles.txt | 125 + chalk/doc/resolution.txt | 40 + chalk/doc/scripts/dcop.py | 14 + chalk/doc/sdk | 10 + chalk/doc/selections | 127 + chalk/doc/the preview widget | 81 + chalk/doc/transform_undo.txt | 38 + chalk/dtd/Makefile.am | 4 + chalk/dtd/chalk.dtd | 93 + chalk/extracti18n.pl | 90 + chalk/main.cc | 43 + chalk/pics/Makefile.am | 22 + chalk/pics/chalk.svg | 509 + chalk/pics/deletelayer.png | Bin 0 -> 376 bytes chalk/pics/height.png | Bin 0 -> 202 bytes chalk/pics/hi128-app-chalk.png | Bin 0 -> 9549 bytes chalk/pics/hi16-app-chalk.png | Bin 0 -> 638 bytes chalk/pics/hi22-app-chalk.png | Bin 0 -> 930 bytes chalk/pics/hi32-app-chalk.png | Bin 0 -> 1487 bytes chalk/pics/hi48-app-chalk.png | Bin 0 -> 2587 bytes chalk/pics/hi64-app-chalk.png | Bin 0 -> 3836 bytes chalk/pics/linked.png | Bin 0 -> 528 bytes chalk/pics/locked.png | Bin 0 -> 557 bytes chalk/pics/lowerlayer.png | Bin 0 -> 363 bytes chalk/pics/newlayer.png | Bin 0 -> 426 bytes chalk/pics/novisible.png | Bin 0 -> 721 bytes chalk/pics/raiselayer.png | Bin 0 -> 344 bytes chalk/pics/shade.png | Bin 0 -> 235 bytes chalk/pics/tablet.png | Bin 0 -> 4454 bytes chalk/pics/tool_screenshot.png | Bin 0 -> 852 bytes chalk/pics/unlinked.png | Bin 0 -> 363 bytes chalk/pics/unlocked.png | Bin 0 -> 605 bytes chalk/pics/visible.png | Bin 0 -> 771 bytes chalk/pics/width.png | Bin 0 -> 179 bytes chalk/plugins/Makefile.am | 5 + chalk/plugins/README | 42 + chalk/plugins/configure.in.in | 2 + chalk/plugins/filters/Makefile.am | 4 + chalk/plugins/filters/blur/Makefile.am | 22 + chalk/plugins/filters/blur/blur.cc | 50 + chalk/plugins/filters/blur/blur.h | 37 + chalk/plugins/filters/blur/chalkblurfilter.desktop | 38 + chalk/plugins/filters/blur/kis_blur_filter.cc | 143 + chalk/plugins/filters/blur/kis_blur_filter.h | 49 + chalk/plugins/filters/blur/kis_wdg_blur.cc | 116 + chalk/plugins/filters/blur/kis_wdg_blur.h | 50 + chalk/plugins/filters/blur/wdgblur.ui | 227 + chalk/plugins/filters/bumpmap/Makefile.am | 19 + chalk/plugins/filters/bumpmap/bumpmap.cc | 533 + chalk/plugins/filters/bumpmap/bumpmap.h | 130 + .../filters/bumpmap/chalkbumpmapfilter.desktop | 71 + chalk/plugins/filters/bumpmap/wdgbumpmap.ui | 374 + chalk/plugins/filters/cimg/.kdev_ignore | 0 chalk/plugins/filters/cimg/CImg.h | 19174 +++++++ chalk/plugins/filters/cimg/Makefile.am | 35 + chalk/plugins/filters/cimg/chalkcimg.desktop | 79 + chalk/plugins/filters/cimg/kis_cimg_filter.cc | 711 + chalk/plugins/filters/cimg/kis_cimg_filter.h | 124 + chalk/plugins/filters/cimg/kis_cimg_plugin.cc | 44 + chalk/plugins/filters/cimg/kis_cimg_plugin.h | 32 + .../plugins/filters/cimg/kis_cimgconfig_widget.cc | 94 + chalk/plugins/filters/cimg/kis_cimgconfig_widget.h | 50 + chalk/plugins/filters/cimg/wdg_cimg.ui | 298 + chalk/plugins/filters/colorify/Colorify.cpp | 122 + chalk/plugins/filters/colorify/Colorify.h | 56 + chalk/plugins/filters/colorify/KisWdgColorify.cpp | 50 + chalk/plugins/filters/colorify/KisWdgColorify.h | 45 + chalk/plugins/filters/colorify/Makefile.am | 23 + chalk/plugins/filters/colorify/WdgColorifyBase.ui | 97 + .../filters/colorify/chalkcolorifyfilter.desktop | 42 + chalk/plugins/filters/colors/Makefile.am | 21 + .../colors/chalkextensioncolorsfilters.desktop | 42 + chalk/plugins/filters/colors/colors.cc | 53 + chalk/plugins/filters/colors/colors.h | 37 + chalk/plugins/filters/colors/kis_color_to_alpha.cc | 95 + chalk/plugins/filters/colors/kis_color_to_alpha.h | 47 + chalk/plugins/filters/colors/kis_minmax_filters.cc | 162 + chalk/plugins/filters/colors/kis_minmax_filters.h | 56 + .../filters/colors/kis_wdg_color_to_alpha.cc | 55 + .../filters/colors/kis_wdg_color_to_alpha.h | 45 + .../plugins/filters/colors/wdgcolortoalphabase.ui | 113 + chalk/plugins/filters/colorsfilters/Makefile.am | 26 + .../colorsfilters/chalkcolorsfilter.desktop | 94 + .../plugins/filters/colorsfilters/colorsfilters.cc | 315 + .../plugins/filters/colorsfilters/colorsfilters.h | 73 + .../kis_brightness_contrast_filter.cc | 347 + .../colorsfilters/kis_brightness_contrast_filter.h | 84 + .../filters/colorsfilters/kis_perchannel_filter.cc | 421 + .../filters/colorsfilters/kis_perchannel_filter.h | 100 + .../colorsfilters/wdg_brightness_contrast.ui | 292 + .../filters/colorsfilters/wdg_perchannel.ui | 190 + .../plugins/filters/convolutionfilters/Makefile.am | 28 + .../chalkconvolutionfilters.desktop | 75 + .../convolutionfilters/convolutionfilters.cc | 176 + .../convolutionfilters/convolutionfilters.h | 152 + .../convolutionfilters/kis_convolution_filter.cc | 138 + .../convolutionfilters/kis_convolution_filter.h | 99 + .../kis_custom_convolution_filter.cc | 93 + .../kis_custom_convolution_filter.h | 54 + ...convolution_filter_configuration_base_widget.ui | 189 + ...stom_convolution_filter_configuration_widget.cc | 83 + ...ustom_convolution_filter_configuration_widget.h | 46 + chalk/plugins/filters/cubismfilter/Makefile.am | 24 + .../filters/cubismfilter/chalkcubismfilter.desktop | 85 + .../filters/cubismfilter/kis_cubism_filter.cc | 453 + .../filters/cubismfilter/kis_cubism_filter.h | 78 + .../cubismfilter/kis_cubism_filter_plugin.cc | 42 + .../cubismfilter/kis_cubism_filter_plugin.h | 32 + chalk/plugins/filters/cubismfilter/kis_polygon.cc | 102 + chalk/plugins/filters/cubismfilter/kis_polygon.h | 37 + chalk/plugins/filters/embossfilter/Makefile.am | 24 + .../filters/embossfilter/chalkembossfilter.desktop | 71 + .../filters/embossfilter/kis_emboss_filter.cc | 179 + .../filters/embossfilter/kis_emboss_filter.h | 62 + .../embossfilter/kis_emboss_filter_plugin.cc | 40 + .../embossfilter/kis_emboss_filter_plugin.h | 32 + chalk/plugins/filters/example/Makefile.am | 22 + chalk/plugins/filters/example/chalkexample.desktop | 81 + chalk/plugins/filters/example/example.cc | 95 + chalk/plugins/filters/example/example.h | 47 + .../plugins/filters/fastcolortransfer/Makefile.am | 23 + .../chalkfastcolortransfer.desktop | 69 + .../filters/fastcolortransfer/fastcolortransfer.cc | 206 + .../filters/fastcolortransfer/fastcolortransfer.h | 55 + .../kis_wdg_fastcolortransfer.cpp | 50 + .../fastcolortransfer/kis_wdg_fastcolortransfer.h | 47 + .../fastcolortransfer/wdgfastcolortransfer.ui | 75 + chalk/plugins/filters/halftone/kis_halftone.cpp | 190 + chalk/plugins/filters/halftone/kis_halftone.h | 79 + chalk/plugins/filters/imageenhancement/Makefile.am | 27 + .../imageenhancement/chalkimageenhancement.desktop | 80 + .../filters/imageenhancement/imageenhancement.cpp | 73 + .../filters/imageenhancement/imageenhancement.h | 34 + .../imageenhancement/kis_simple_noise_reducer.cpp | 129 + .../imageenhancement/kis_simple_noise_reducer.h | 59 + .../kis_wavelet_noise_reduction.cpp | 130 + .../imageenhancement/kis_wavelet_noise_reduction.h | 68 + .../filters/lenscorrectionfilter/Makefile.am | 23 + .../chalklenscorrectionfilter.desktop | 69 + .../kis_wdg_lens_correction.cpp | 74 + .../lenscorrectionfilter/kis_wdg_lens_correction.h | 44 + .../lenscorrectionfilter/lenscorrectionfilter.cc | 152 + .../lenscorrectionfilter/lenscorrectionfilter.h | 53 + .../wdglenscorrectionoptions.ui | 229 + chalk/plugins/filters/levelfilter/Makefile.am | 25 + .../filters/levelfilter/chalklevelfilter.desktop | 73 + .../plugins/filters/levelfilter/kgradientslider.cc | 338 + .../plugins/filters/levelfilter/kgradientslider.h | 85 + .../filters/levelfilter/kis_level_filter.cc | 324 + .../plugins/filters/levelfilter/kis_level_filter.h | 94 + chalk/plugins/filters/levelfilter/levelfilter.cc | 67 + chalk/plugins/filters/levelfilter/levelfilter.h | 35 + chalk/plugins/filters/levelfilter/wdg_level.ui | 331 + chalk/plugins/filters/noisefilter/Makefile.am | 23 + .../filters/noisefilter/chalknoisefilter.desktop | 77 + .../plugins/filters/noisefilter/kis_wdg_noise.cpp | 59 + chalk/plugins/filters/noisefilter/kis_wdg_noise.h | 44 + chalk/plugins/filters/noisefilter/noisefilter.cc | 128 + chalk/plugins/filters/noisefilter/noisefilter.h | 52 + .../plugins/filters/noisefilter/wdgnoiseoptions.ui | 111 + chalk/plugins/filters/oilpaintfilter/Makefile.am | 24 + .../oilpaintfilter/chalkoilpaintfilter.desktop | 77 + .../filters/oilpaintfilter/kis_oilpaint_filter.cc | 256 + .../filters/oilpaintfilter/kis_oilpaint_filter.h | 69 + .../oilpaintfilter/kis_oilpaint_filter_plugin.cc | 43 + .../oilpaintfilter/kis_oilpaint_filter_plugin.h | 32 + chalk/plugins/filters/pixelizefilter/Makefile.am | 24 + .../pixelizefilter/chalkpixelizefilter.desktop | 83 + .../filters/pixelizefilter/kis_pixelize_filter.cc | 188 + .../filters/pixelizefilter/kis_pixelize_filter.h | 61 + .../pixelizefilter/kis_pixelize_filter_plugin.cc | 43 + .../pixelizefilter/kis_pixelize_filter_plugin.h | 32 + chalk/plugins/filters/raindropsfilter/Makefile.am | 24 + .../raindropsfilter/chalkraindropsfilter.desktop | 81 + .../raindropsfilter/kis_raindrops_filter.cc | 439 + .../filters/raindropsfilter/kis_raindrops_filter.h | 67 + .../raindropsfilter/kis_raindrops_filter_plugin.cc | 44 + .../raindropsfilter/kis_raindrops_filter_plugin.h | 33 + chalk/plugins/filters/randompickfilter/Makefile.am | 23 + .../randompickfilter/chalkrandompickfilter.desktop | 65 + .../randompickfilter/kis_wdg_random_pick.cpp | 64 + .../filters/randompickfilter/kis_wdg_random_pick.h | 44 + .../filters/randompickfilter/randompickfilter.cc | 131 + .../filters/randompickfilter/randompickfilter.h | 52 + .../randompickfilter/wdgrandompickoptions.ui | 135 + chalk/plugins/filters/roundcorners/Makefile.am | 23 + .../roundcorners/chalkroundcornersfilter.desktop | 39 + .../roundcorners/kis_round_corners_filter.cc | 158 + .../roundcorners/kis_round_corners_filter.h | 58 + .../kis_round_corners_filter_plugin.cc | 43 + .../roundcorners/kis_round_corners_filter_plugin.h | 32 + chalk/plugins/filters/smalltilesfilter/Makefile.am | 23 + .../smalltilesfilter/chalksmalltilesfilter.desktop | 39 + .../smalltilesfilter/kis_small_tiles_filter.cc | 187 + .../smalltilesfilter/kis_small_tiles_filter.h | 70 + .../kis_small_tiles_filter_plugin.cc | 43 + .../kis_small_tiles_filter_plugin.h | 32 + chalk/plugins/filters/sobelfilter/Makefile.am | 23 + .../filters/sobelfilter/chalksobelfilter.desktop | 39 + .../filters/sobelfilter/kis_sobel_filter.cc | 217 + .../plugins/filters/sobelfilter/kis_sobel_filter.h | 75 + .../filters/sobelfilter/kis_sobel_filter_plugin.cc | 43 + .../filters/sobelfilter/kis_sobel_filter_plugin.h | 32 + chalk/plugins/filters/threadtest/Makefile.am | 18 + .../filters/threadtest/chalkthreadtest.desktop | 38 + chalk/plugins/filters/threadtest/threadtest.cc | 140 + chalk/plugins/filters/threadtest/threadtest.h | 46 + chalk/plugins/filters/unsharp/Makefile.am | 20 + .../filters/unsharp/chalkunsharpfilter.desktop | 40 + .../plugins/filters/unsharp/kis_unsharp_filter.cc | 152 + chalk/plugins/filters/unsharp/kis_unsharp_filter.h | 47 + chalk/plugins/filters/unsharp/kis_wdg_unsharp.cc | 52 + chalk/plugins/filters/unsharp/kis_wdg_unsharp.h | 45 + chalk/plugins/filters/unsharp/unsharp.cc | 50 + chalk/plugins/filters/unsharp/unsharp.h | 37 + chalk/plugins/filters/unsharp/wdgunsharp.ui | 138 + chalk/plugins/filters/wavefilter/Makefile.am | 23 + .../filters/wavefilter/chalkwavefilter.desktop | 72 + chalk/plugins/filters/wavefilter/kis_wdg_wave.cpp | 90 + chalk/plugins/filters/wavefilter/kis_wdg_wave.h | 44 + chalk/plugins/filters/wavefilter/wavefilter.cc | 169 + chalk/plugins/filters/wavefilter/wavefilter.h | 53 + chalk/plugins/filters/wavefilter/wdgwaveoptions.ui | 281 + chalk/plugins/paintops/Makefile.am | 2 + chalk/plugins/paintops/defaultpaintops/Makefile.am | 39 + chalk/plugins/paintops/defaultpaintops/README | 3 + .../plugins/paintops/defaultpaintops/airbrush.png | Bin 0 -> 1038 bytes .../defaultpaintops/chalkdefaultpaintops.desktop | 93 + .../defaultpaintops/defaultpaintops_plugin.cc | 70 + .../defaultpaintops/defaultpaintops_plugin.h | 36 + chalk/plugins/paintops/defaultpaintops/eraser.png | Bin 0 -> 735 bytes .../paintops/defaultpaintops/kis_airbrushop.cc | 150 + .../paintops/defaultpaintops/kis_airbrushop.h | 60 + .../paintops/defaultpaintops/kis_brushop.cc | 284 + .../plugins/paintops/defaultpaintops/kis_brushop.h | 113 + .../paintops/defaultpaintops/kis_convolveop.cc | 58 + .../paintops/defaultpaintops/kis_convolveop.h | 56 + .../defaultpaintops/kis_dlgbrushcurvecontrol.ui | 271 + .../paintops/defaultpaintops/kis_duplicateop.cc | 341 + .../paintops/defaultpaintops/kis_duplicateop.h | 62 + .../paintops/defaultpaintops/kis_eraseop.cc | 140 + .../plugins/paintops/defaultpaintops/kis_eraseop.h | 56 + .../plugins/paintops/defaultpaintops/kis_penop.cc | 132 + chalk/plugins/paintops/defaultpaintops/kis_penop.h | 58 + .../paintops/defaultpaintops/kis_smudgeop.cc | 328 + .../paintops/defaultpaintops/kis_smudgeop.h | 118 + .../paintops/defaultpaintops/paintbrush.png | Bin 0 -> 770 bytes chalk/plugins/paintops/defaultpaintops/pencil.png | Bin 0 -> 794 bytes chalk/plugins/paintops/defaultpaintops/src/README | 2 + .../paintops/defaultpaintops/src/pencil_01.svg | 637 + .../src/pencil_jonathan_dietrich_01.svg | 434 + .../src/pennello_mauro_olivo_01.svg | 616 + chalk/plugins/tools/Makefile.am | 3 + chalk/plugins/tools/defaulttools/Makefile.am | 83 + .../tools/defaulttools/chalkdefaulttools.desktop | 56 + .../tools/defaulttools/closedhand_cursor.xpm | 28 + chalk/plugins/tools/defaulttools/default_tools.cc | 88 + chalk/plugins/tools/defaulttools/default_tools.h | 44 + chalk/plugins/tools/defaulttools/kis_tool_brush.cc | 167 + chalk/plugins/tools/defaulttools/kis_tool_brush.h | 87 + .../tools/defaulttools/kis_tool_colorpicker.cc | 298 + .../tools/defaulttools/kis_tool_colorpicker.h | 88 + .../tools/defaulttools/kis_tool_duplicate.cc | 255 + .../tools/defaulttools/kis_tool_duplicate.h | 92 + .../plugins/tools/defaulttools/kis_tool_ellipse.cc | 186 + .../plugins/tools/defaulttools/kis_tool_ellipse.h | 91 + chalk/plugins/tools/defaulttools/kis_tool_fill.cc | 233 + chalk/plugins/tools/defaulttools/kis_tool_fill.h | 109 + .../tools/defaulttools/kis_tool_gradient.cc | 309 + .../plugins/tools/defaulttools/kis_tool_gradient.h | 124 + chalk/plugins/tools/defaulttools/kis_tool_line.cc | 254 + chalk/plugins/tools/defaulttools/kis_tool_line.h | 100 + chalk/plugins/tools/defaulttools/kis_tool_move.cc | 181 + chalk/plugins/tools/defaulttools/kis_tool_move.h | 89 + chalk/plugins/tools/defaulttools/kis_tool_pan.cc | 96 + chalk/plugins/tools/defaulttools/kis_tool_pan.h | 80 + .../tools/defaulttools/kis_tool_rectangle.cc | 187 + .../tools/defaulttools/kis_tool_rectangle.h | 96 + chalk/plugins/tools/defaulttools/kis_tool_text.cc | 198 + chalk/plugins/tools/defaulttools/kis_tool_text.h | 81 + chalk/plugins/tools/defaulttools/kis_tool_zoom.cc | 191 + chalk/plugins/tools/defaulttools/kis_tool_zoom.h | 98 + .../plugins/tools/defaulttools/openhand_cursor.xpm | 28 + .../plugins/tools/defaulttools/tool_color_fill.png | Bin 0 -> 1102 bytes .../tools/defaulttools/tool_colorpicker.png | Bin 0 -> 713 bytes .../plugins/tools/defaulttools/tool_duplicate.png | Bin 0 -> 1087 bytes .../tools/defaulttools/tool_duplicate_cursor.png | Bin 0 -> 309 bytes chalk/plugins/tools/defaulttools/tool_ellipse.png | Bin 0 -> 524 bytes .../tools/defaulttools/tool_ellipse_cursor.png | Bin 0 -> 309 bytes .../tools/defaulttools/tool_fill_cursor.png | Bin 0 -> 516 bytes chalk/plugins/tools/defaulttools/tool_freehand.png | Bin 0 -> 658 bytes .../tools/defaulttools/tool_freehand_cursor.png | Bin 0 -> 261 bytes chalk/plugins/tools/defaulttools/tool_gradient.png | Bin 0 -> 386 bytes .../tools/defaulttools/tool_gradient_cursor.png | Bin 0 -> 294 bytes chalk/plugins/tools/defaulttools/tool_line.png | Bin 0 -> 354 bytes .../tools/defaulttools/tool_line_cursor.png | Bin 0 -> 248 bytes chalk/plugins/tools/defaulttools/tool_move.png | Bin 0 -> 664 bytes chalk/plugins/tools/defaulttools/tool_pan.png | Bin 0 -> 863 bytes .../plugins/tools/defaulttools/tool_rectangle.png | Bin 0 -> 334 bytes .../tools/defaulttools/tool_rectangle_cursor.png | Bin 0 -> 230 bytes chalk/plugins/tools/defaulttools/tool_text.png | Bin 0 -> 891 bytes .../tools/defaulttools/tool_text_cursor.png | Bin 0 -> 300 bytes chalk/plugins/tools/defaulttools/tool_zoom.png | Bin 0 -> 877 bytes .../tools/defaulttools/tool_zoom_minus_cursor.png | Bin 0 -> 283 bytes .../tools/defaulttools/tool_zoom_plus_cursor.png | Bin 0 -> 302 bytes chalk/plugins/tools/defaulttools/wdgcolorpicker.ui | 167 + chalk/plugins/tools/selectiontools/Makefile.am | 56 + .../selectiontools/chalkselectiontools.desktop | 52 + .../selectiontools/kis_tool_move_selection.cc | 223 + .../tools/selectiontools/kis_tool_move_selection.h | 75 + .../tools/selectiontools/kis_tool_select_brush.cc | 168 + .../tools/selectiontools/kis_tool_select_brush.h | 83 + .../selectiontools/kis_tool_select_contiguous.cc | 234 + .../selectiontools/kis_tool_select_contiguous.h | 95 + .../selectiontools/kis_tool_select_elliptical.cc | 321 + .../selectiontools/kis_tool_select_elliptical.h | 99 + .../tools/selectiontools/kis_tool_select_eraser.cc | 156 + .../tools/selectiontools/kis_tool_select_eraser.h | 82 + .../selectiontools/kis_tool_select_outline.cc | 295 + .../tools/selectiontools/kis_tool_select_outline.h | 101 + .../selectiontools/kis_tool_select_polygonal.cc | 315 + .../selectiontools/kis_tool_select_polygonal.h | 106 + .../selectiontools/kis_tool_select_rectangular.cc | 323 + .../selectiontools/kis_tool_select_rectangular.h | 95 + .../tools/selectiontools/selection_tools.cc | 77 + .../plugins/tools/selectiontools/selection_tools.h | 44 + .../tools/selectiontools/tool_brush_selection.png | Bin 0 -> 1052 bytes .../tools/selectiontools/tool_brush_selection.svg | 827 + .../selectiontools/tool_brush_selection_cursor.png | Bin 0 -> 339 bytes .../selectiontools/tool_contiguous_selection.png | Bin 0 -> 836 bytes .../tool_contiguous_selection_cursor.png | Bin 0 -> 321 bytes .../selectiontools/tool_elliptical_selection.png | Bin 0 -> 703 bytes .../selectiontools/tool_elliptical_selection.svg | 256 + .../tool_elliptical_selection_cursor.png | Bin 0 -> 296 bytes .../tools/selectiontools/tool_eraser_selection.png | Bin 0 -> 1087 bytes .../tools/selectiontools/tool_eraser_selection.svg | 1993 + .../tool_eraser_selection_cursor.png | Bin 0 -> 341 bytes .../selectiontools/tool_outline_selection.png | Bin 0 -> 556 bytes .../selectiontools/tool_outline_selection.svg | 329 + .../tool_outline_selection_cursor.png | Bin 0 -> 359 bytes .../selectiontools/tool_polygonal_selection.png | Bin 0 -> 576 bytes .../selectiontools/tool_polygonal_selection.svg | 364 + .../tool_polygonal_selection_cursor.png | Bin 0 -> 433 bytes .../tools/selectiontools/tool_rect_selection.png | Bin 0 -> 523 bytes .../tools/selectiontools/tool_rect_selection.svg | 191 + .../tool_rectangular_selection_cursor.png | Bin 0 -> 224 bytes chalk/plugins/tools/tool_crop/Makefile.am | 37 + .../plugins/tools/tool_crop/chalktoolcrop.desktop | 47 + chalk/plugins/tools/tool_crop/kis_tool_crop.cc | 925 + chalk/plugins/tools/tool_crop/kis_tool_crop.h | 149 + chalk/plugins/tools/tool_crop/tool_crop.cc | 62 + chalk/plugins/tools/tool_crop/tool_crop.h | 43 + chalk/plugins/tools/tool_crop/tool_crop.png | Bin 0 -> 693 bytes chalk/plugins/tools/tool_crop/tool_crop_cursor.png | Bin 0 -> 306 bytes chalk/plugins/tools/tool_crop/wdg_tool_crop.ui | 216 + chalk/plugins/tools/tool_curves/Makefile.am | 56 + .../tools/tool_curves/chalktoolcurves.desktop | 36 + .../tools/tool_curves/kis_curve_framework.cc | 260 + .../tools/tool_curves/kis_curve_framework.h | 354 + chalk/plugins/tools/tool_curves/kis_tool_bezier.cc | 366 + chalk/plugins/tools/tool_curves/kis_tool_bezier.h | 98 + .../tools/tool_curves/kis_tool_bezier_paint.cc | 115 + .../tools/tool_curves/kis_tool_bezier_paint.h | 63 + .../tools/tool_curves/kis_tool_bezier_select.cc | 104 + .../tools/tool_curves/kis_tool_bezier_select.h | 63 + chalk/plugins/tools/tool_curves/kis_tool_curve.cc | 593 + chalk/plugins/tools/tool_curves/kis_tool_curve.h | 205 + .../plugins/tools/tool_curves/kis_tool_example.cc | 108 + chalk/plugins/tools/tool_curves/kis_tool_example.h | 67 + .../plugins/tools/tool_curves/kis_tool_moutline.cc | 809 + .../plugins/tools/tool_curves/kis_tool_moutline.h | 132 + .../tools/tool_curves/tool_bezier_cursor.png | Bin 0 -> 2854 bytes .../tools/tool_curves/tool_bezier_paint.png | Bin 0 -> 680 bytes .../tools/tool_curves/tool_bezier_select.png | Bin 0 -> 637 bytes .../tools/tool_curves/tool_curve_dragging.png | Bin 0 -> 2956 bytes chalk/plugins/tools/tool_curves/tool_curves.cc | 67 + chalk/plugins/tools/tool_curves/tool_curves.h | 36 + chalk/plugins/tools/tool_curves/tool_example.png | Bin 0 -> 2918 bytes .../tools/tool_curves/tool_example_cursor.png | Bin 0 -> 2854 bytes chalk/plugins/tools/tool_curves/tool_moutline.png | Bin 0 -> 778 bytes .../tools/tool_curves/tool_moutline_cursor.png | Bin 0 -> 2858 bytes .../tools/tool_curves/tool_moutline_editing.png | Bin 0 -> 2968 bytes .../plugins/tools/tool_curves/wdg_tool_example.ui | 128 + chalk/plugins/tools/tool_filter/Makefile.am | 38 + .../tools/tool_filter/chalktoolfilter.desktop | 92 + chalk/plugins/tools/tool_filter/kis_filterop.cc | 154 + chalk/plugins/tools/tool_filter/kis_filterop.h | 63 + chalk/plugins/tools/tool_filter/kis_tool_filter.cc | 154 + chalk/plugins/tools/tool_filter/kis_tool_filter.h | 81 + chalk/plugins/tools/tool_filter/tool_filter.cc | 68 + chalk/plugins/tools/tool_filter/tool_filter.h | 43 + chalk/plugins/tools/tool_filter/tool_filter.png | Bin 0 -> 497 bytes chalk/plugins/tools/tool_filter/tool_filter.svg | 468 + .../tools/tool_filter/tool_filter_cursor.png | Bin 0 -> 295 bytes .../plugins/tools/tool_perspectivegrid/Makefile.am | 35 + .../chalktoolperspectivegrid.desktop | 35 + .../kis_tool_perspectivegrid.cc | 499 + .../kis_tool_perspectivegrid.h | 111 + .../tool_perspectivegrid/tool_perspectivegrid.cc | 62 + .../tool_perspectivegrid/tool_perspectivegrid.h | 43 + .../tool_perspectivegrid/tool_perspectivegrid.png | Bin 0 -> 738 bytes .../tool_perspectivegrid/tool_perspectivegrid.svg | 87 + .../tools/tool_perspectivetransform/Makefile.am | 35 + .../chalktoolperspectivetransform.desktop | 37 + .../kis_tool_perspectivetransform.cc | 742 + .../kis_tool_perspectivetransform.h | 131 + .../tool_perspectivetransform.cc | 63 + .../tool_perspectivetransform.h | 43 + .../tool_perspectivetransform.png | Bin 0 -> 691 bytes .../tool_perspectivetransform.svg | 87 + chalk/plugins/tools/tool_polygon/Makefile.am | 36 + .../tools/tool_polygon/chalktoolpolygon.desktop | 52 + .../plugins/tools/tool_polygon/kis_tool_polygon.cc | 252 + .../plugins/tools/tool_polygon/kis_tool_polygon.h | 102 + chalk/plugins/tools/tool_polygon/tool_polygon.cc | 62 + chalk/plugins/tools/tool_polygon/tool_polygon.h | 39 + chalk/plugins/tools/tool_polygon/tool_polygon.png | Bin 0 -> 773 bytes .../tools/tool_polygon/tool_polygon_cursor.png | Bin 0 -> 402 bytes chalk/plugins/tools/tool_polyline/Makefile.am | 36 + .../tools/tool_polyline/chalktoolpolyline.desktop | 49 + .../tools/tool_polyline/kis_tool_polyline.cc | 271 + .../tools/tool_polyline/kis_tool_polyline.h | 109 + chalk/plugins/tools/tool_polyline/polyline.png | Bin 0 -> 587 bytes chalk/plugins/tools/tool_polyline/tool_polyline.cc | 64 + chalk/plugins/tools/tool_polyline/tool_polyline.h | 43 + .../tools/tool_polyline/tool_polyline_cursor.png | Bin 0 -> 397 bytes chalk/plugins/tools/tool_selectsimilar/Makefile.am | 32 + .../chalktoolselectsimilar.desktop | 43 + .../tool_selectsimilar/kis_tool_selectsimilar.cc | 271 + .../tool_selectsimilar/kis_tool_selectsimilar.h | 102 + .../tools/tool_selectsimilar/selectsimilar.cc | 61 + .../tools/tool_selectsimilar/selectsimilar.h | 35 + .../tool_selectsimilar/tool_similar_selection.png | Bin 0 -> 724 bytes .../tool_selectsimilar/tool_similar_selection.svg | 2118 + .../tool_similar_selection_minus_cursor.png | Bin 0 -> 613 bytes .../tool_similar_selection_plus_cursor.png | Bin 0 -> 630 bytes chalk/plugins/tools/tool_star/Makefile.am | 37 + .../plugins/tools/tool_star/chalktoolstar.desktop | 52 + chalk/plugins/tools/tool_star/kis_tool_star.cc | 245 + chalk/plugins/tools/tool_star/kis_tool_star.h | 101 + chalk/plugins/tools/tool_star/tool_star.cc | 62 + chalk/plugins/tools/tool_star/tool_star.h | 43 + chalk/plugins/tools/tool_star/tool_star.png | Bin 0 -> 625 bytes chalk/plugins/tools/tool_star/tool_star_cursor.png | Bin 0 -> 367 bytes chalk/plugins/tools/tool_star/wdg_tool_star.ui | 128 + chalk/plugins/tools/tool_transform/Makefile.am | 37 + .../tool_transform/chalktooltransform.desktop | 46 + .../tools/tool_transform/kis_tool_transform.cc | 916 + .../tools/tool_transform/kis_tool_transform.h | 155 + .../plugins/tools/tool_transform/rotate_cursor.xpm | 29 + .../plugins/tools/tool_transform/tool_transform.cc | 64 + .../plugins/tools/tool_transform/tool_transform.h | 43 + .../tools/tool_transform/tool_transform.png | Bin 0 -> 458 bytes .../tools/tool_transform/wdg_tool_transform.ui | 243 + chalk/plugins/viewplugins/Makefile.am | 24 + chalk/plugins/viewplugins/colorrange/Makefile.am | 25 + .../viewplugins/colorrange/chalkcolorrange.desktop | 40 + chalk/plugins/viewplugins/colorrange/colorrange.cc | 82 + chalk/plugins/viewplugins/colorrange/colorrange.h | 45 + chalk/plugins/viewplugins/colorrange/colorrange.rc | 10 + .../viewplugins/colorrange/dlg_colorrange.cc | 351 + .../viewplugins/colorrange/dlg_colorrange.h | 100 + .../viewplugins/colorrange/wdg_colorrange.ui | 252 + .../viewplugins/colorspaceconversion/Makefile.am | 27 + .../chalkcolorspaceconversion.desktop | 40 + .../colorspaceconversion/colorspaceconversion.cc | 155 + .../colorspaceconversion/colorspaceconversion.h | 51 + .../colorspaceconversion/colorspaceconversion.rc | 11 + .../dlg_colorspaceconversion.cc | 91 + .../dlg_colorspaceconversion.h | 50 + .../colorspaceconversion/wdgconvertcolorspace.ui | 218 + chalk/plugins/viewplugins/dropshadow/Makefile.am | 31 + .../viewplugins/dropshadow/chalkdropshadow.desktop | 39 + .../viewplugins/dropshadow/dlg_dropshadow.cc | 117 + .../viewplugins/dropshadow/dlg_dropshadow.h | 60 + chalk/plugins/viewplugins/dropshadow/dropshadow.rc | 11 + .../viewplugins/dropshadow/kis_dropshadow.cc | 758 + .../viewplugins/dropshadow/kis_dropshadow.h | 72 + .../dropshadow/kis_dropshadow_plugin.cc | 91 + .../viewplugins/dropshadow/kis_dropshadow_plugin.h | 46 + .../viewplugins/dropshadow/wdg_dropshadow.ui | 235 + .../plugins/viewplugins/filtersgallery/Makefile.am | 26 + .../filtersgallery/chalkfiltersgallery.desktop | 45 + .../filtersgallery/chalkfiltersgallery.rc | 9 + .../viewplugins/filtersgallery/filters_gallery.cc | 138 + .../viewplugins/filtersgallery/filters_gallery.h | 54 + .../filtersgallery/kis_dlg_filtersgallery.cc | 133 + .../filtersgallery/kis_dlg_filtersgallery.h | 69 + .../filtersgallery/kis_wdg_filtersgallery.ui | 123 + chalk/plugins/viewplugins/histogram/Makefile.am | 25 + .../viewplugins/histogram/chalkhistogram.desktop | 43 + .../plugins/viewplugins/histogram/dlg_histogram.cc | 68 + .../plugins/viewplugins/histogram/dlg_histogram.h | 58 + chalk/plugins/viewplugins/histogram/histogram.cc | 105 + chalk/plugins/viewplugins/histogram/histogram.h | 50 + chalk/plugins/viewplugins/histogram/histogram.rc | 10 + .../viewplugins/histogram/kis_histogram_widget.cc | 147 + .../viewplugins/histogram/kis_histogram_widget.h | 55 + .../plugins/viewplugins/histogram/wdghistogram.ui | 229 + .../viewplugins/histogram_docker/Makefile.am | 22 + .../histogram_docker/chalkhistogramdocker.desktop | 40 + .../histogram_docker/chalkhistogramdocker.rc | 3 + .../histogram_docker/histogramdocker.cc | 192 + .../viewplugins/histogram_docker/histogramdocker.h | 81 + .../histogram_docker/kis_accumulating_producer.cc | 102 + .../histogram_docker/kis_accumulating_producer.h | 77 + .../histogram_docker/kis_cachedhistogram.cc | 37 + .../histogram_docker/kis_cachedhistogram.h | 53 + .../histogram_docker/kis_imagerasteredcache.cc | 162 + .../histogram_docker/kis_imagerasteredcache.h | 81 + .../plugins/viewplugins/history_docker/Makefile.am | 18 + .../history_docker/chalkhistorydocker.desktop | 73 + .../viewplugins/history_docker/historydocker.cc | 58 + .../viewplugins/history_docker/historydocker.h | 34 + chalk/plugins/viewplugins/imagesize/Makefile.am | 25 + .../viewplugins/imagesize/chalkimagesize.desktop | 39 + .../plugins/viewplugins/imagesize/configure.in.in | 1 + .../plugins/viewplugins/imagesize/dlg_imagesize.cc | 277 + .../plugins/viewplugins/imagesize/dlg_imagesize.h | 83 + .../plugins/viewplugins/imagesize/dlg_layersize.cc | 261 + .../plugins/viewplugins/imagesize/dlg_layersize.h | 74 + chalk/plugins/viewplugins/imagesize/imagesize.cc | 190 + chalk/plugins/viewplugins/imagesize/imagesize.h | 49 + chalk/plugins/viewplugins/imagesize/imagesize.rc | 15 + .../plugins/viewplugins/imagesize/wdg_imagesize.ui | 365 + .../plugins/viewplugins/imagesize/wdg_layersize.ui | 234 + .../viewplugins/imagesize/wdg_resolution.ui | 152 + .../viewplugins/modify_selection/Makefile.am | 27 + .../modify_selection/chalkmodifyselection.desktop | 40 + .../modify_selection/dlg_border_selection.cc | 76 + .../modify_selection/dlg_border_selection.h | 49 + .../modify_selection/dlg_grow_selection.cc | 76 + .../modify_selection/dlg_grow_selection.h | 49 + .../modify_selection/dlg_shrink_selection.cc | 81 + .../modify_selection/dlg_shrink_selection.h | 50 + .../modify_selection/modify_selection.cc | 158 + .../modify_selection/modify_selection.h | 47 + .../modify_selection/modify_selection.rc | 10 + .../modify_selection/wdg_border_selection.ui | 57 + .../modify_selection/wdg_grow_selection.ui | 57 + .../modify_selection/wdg_shrink_selection.ui | 68 + .../viewplugins/performancetest/Makefile.am | 25 + .../performancetest/chalkperftest.desktop | 41 + .../viewplugins/performancetest/dlg_perftest.cc | 110 + .../viewplugins/performancetest/dlg_perftest.h | 56 + .../viewplugins/performancetest/perftest.cc | 1198 + .../plugins/viewplugins/performancetest/perftest.h | 76 + .../viewplugins/performancetest/perftest.rc | 9 + .../viewplugins/performancetest/wdg_perftest.ui | 283 + chalk/plugins/viewplugins/rotateimage/Makefile.am | 25 + .../rotateimage/chalkrotateimage.desktop | 40 + .../viewplugins/rotateimage/dlg_rotateimage.cc | 147 + .../viewplugins/rotateimage/dlg_rotateimage.h | 66 + .../plugins/viewplugins/rotateimage/rotateimage.cc | 134 + .../plugins/viewplugins/rotateimage/rotateimage.h | 50 + .../plugins/viewplugins/rotateimage/rotateimage.rc | 25 + .../viewplugins/rotateimage/wdg_rotateimage.ui | 245 + chalk/plugins/viewplugins/screenshot/Makefile.am | 27 + .../viewplugins/screenshot/chalkscreenshot.desktop | 47 + chalk/plugins/viewplugins/screenshot/ksnapshot.cpp | 499 + chalk/plugins/viewplugins/screenshot/ksnapshot.h | 137 + .../viewplugins/screenshot/ksnapshotwidget.ui | 335 + .../viewplugins/screenshot/ksnapshotwidget.ui.h | 118 + chalk/plugins/viewplugins/screenshot/main.cpp | 38 + .../viewplugins/screenshot/regiongrabber.cpp | 170 + .../plugins/viewplugins/screenshot/regiongrabber.h | 72 + .../viewplugins/screenshot/screenshot-chalk.rc | 9 + .../screenshot/screenshot-kpresenter.rc | 9 + .../viewplugins/screenshot/screenshot-kword.rc | 9 + .../plugins/viewplugins/screenshot/screenshot.cpp | 78 + chalk/plugins/viewplugins/screenshot/screenshot.h | 43 + chalk/plugins/viewplugins/scripting/Makefile.am | 29 + .../viewplugins/scripting/chalkcore/Makefile.am | 30 + .../scripting/chalkcore/chalkcoremodule.cpp | 288 + .../scripting/chalkcore/chalkcoremodule.h | 205 + .../viewplugins/scripting/chalkcore/krs_brush.cpp | 41 + .../viewplugins/scripting/chalkcore/krs_brush.h | 48 + .../viewplugins/scripting/chalkcore/krs_color.cpp | 42 + .../viewplugins/scripting/chalkcore/krs_color.h | 49 + .../viewplugins/scripting/chalkcore/krs_doc.cpp | 46 + .../viewplugins/scripting/chalkcore/krs_doc.h | 53 + .../viewplugins/scripting/chalkcore/krs_filter.cpp | 76 + .../viewplugins/scripting/chalkcore/krs_filter.h | 76 + .../chalkcore/krs_filter_configuration.cpp | 72 + .../scripting/chalkcore/krs_filter_configuration.h | 65 + .../scripting/chalkcore/krs_histogram.cpp | 104 + .../scripting/chalkcore/krs_histogram.h | 115 + .../viewplugins/scripting/chalkcore/krs_image.cpp | 148 + .../viewplugins/scripting/chalkcore/krs_image.h | 94 + .../viewplugins/scripting/chalkcore/krs_iterator.h | 307 + .../scripting/chalkcore/krs_paint_layer.cpp | 207 + .../scripting/chalkcore/krs_paint_layer.h | 140 + .../scripting/chalkcore/krs_painter.cpp | 358 + .../viewplugins/scripting/chalkcore/krs_painter.h | 242 + .../scripting/chalkcore/krs_pattern.cpp | 39 + .../viewplugins/scripting/chalkcore/krs_pattern.h | 48 + .../scripting/chalkcore/krs_script_progress.cpp | 67 + .../scripting/chalkcore/krs_script_progress.h | 77 + .../scripting/chalkcore/krs_wavelet.cpp | 114 + .../viewplugins/scripting/chalkcore/krs_wavelet.h | 92 + .../viewplugins/scripting/chalkscripting.desktop | 81 + .../scripting/chalkscripting/Makefile.am | 19 + .../chalkscripting/kis_script_monitor.cpp | 51 + .../scripting/chalkscripting/kis_script_monitor.h | 51 + .../chalkscripting/kis_script_progress.cpp | 64 + .../scripting/chalkscripting/kis_script_progress.h | 54 + .../viewplugins/scripting/samples/Makefile.am | 3 + .../scripting/samples/python/Makefile.am | 5 + .../viewplugins/scripting/samples/python/invert.py | 48 + .../scripting/samples/python/invertpython.rc | 9 + .../scripting/samples/python/reshapehisto.py | 300 + .../scripting/samples/python/reshapehisto.rc | 9 + .../viewplugins/scripting/samples/ruby/Makefile.am | 18 + .../viewplugins/scripting/samples/ruby/changecs.rb | 5 + .../viewplugins/scripting/samples/ruby/changecs.rc | 9 + .../scripting/samples/ruby/filterstest.rb | 31 + .../scripting/samples/ruby/filterstest.rc | 9 + .../viewplugins/scripting/samples/ruby/invert.rb | 45 + .../scripting/samples/ruby/invertruby.rc | 9 + .../scripting/samples/ruby/randompaint.rb | 98 + .../scripting/samples/ruby/randompaint.rc | 9 + .../scripting/samples/ruby/torture-filters.rb | 70 + .../scripting/samples/ruby/torture-filters.rc | 9 + .../scripting/samples/ruby/torture-painting.rb | 133 + .../scripting/samples/ruby/torture-painting.rc | 9 + chalk/plugins/viewplugins/scripting/scripting.cc | 111 + chalk/plugins/viewplugins/scripting/scripting.h | 54 + chalk/plugins/viewplugins/scripting/scripting.rc | 10 + chalk/plugins/viewplugins/selectopaque/Makefile.am | 25 + .../selectopaque/chalkselectopaque.desktop | 26 + .../viewplugins/selectopaque/selectopaque.cc | 116 + .../viewplugins/selectopaque/selectopaque.h | 45 + .../viewplugins/selectopaque/selectopaque.rc | 10 + .../viewplugins/separate_channels/Makefile.am | 27 + .../chalkseparatechannels.desktop | 42 + .../viewplugins/separate_channels/dlg_separate.cc | 110 + .../viewplugins/separate_channels/dlg_separate.h | 68 + .../viewplugins/separate_channels/imageseparate.rc | 9 + .../separate_channels/kis_channel_separator.cc | 301 + .../separate_channels/kis_channel_separator.h | 70 + .../kis_separate_channels_plugin.cc | 96 + .../kis_separate_channels_plugin.h | 46 + .../separate_channels/wdg_separations.ui | 182 + chalk/plugins/viewplugins/shearimage/Makefile.am | 25 + .../viewplugins/shearimage/chalkshearimage.desktop | 37 + .../viewplugins/shearimage/dlg_shearimage.cc | 96 + .../viewplugins/shearimage/dlg_shearimage.h | 55 + chalk/plugins/viewplugins/shearimage/shearimage.cc | 113 + chalk/plugins/viewplugins/shearimage/shearimage.h | 47 + chalk/plugins/viewplugins/shearimage/shearimage.rc | 13 + .../viewplugins/shearimage/wdg_shearimage.ui | 102 + chalk/plugins/viewplugins/substrate/Makefile.am | 26 + .../viewplugins/substrate/chalksubstrate.desktop | 35 + .../plugins/viewplugins/substrate/dlg_substrate.cc | 59 + .../plugins/viewplugins/substrate/dlg_substrate.h | 62 + .../substrate/kis_repeating_substrate.cc | 0 .../substrate/kis_repeating_substrate.h | 69 + chalk/plugins/viewplugins/substrate/substrate.cc | 78 + chalk/plugins/viewplugins/substrate/substrate.h | 45 + chalk/plugins/viewplugins/substrate/substrate.rc | 8 + .../plugins/viewplugins/substrate/wdgsubstrate.ui | 221 + chalk/plugins/viewplugins/variations/Makefile.am | 26 + .../viewplugins/variations/chalkvariations.desktop | 40 + .../viewplugins/variations/dlg_variations.cc | 58 + .../viewplugins/variations/dlg_variations.h | 62 + chalk/plugins/viewplugins/variations/variations.cc | 88 + chalk/plugins/viewplugins/variations/variations.h | 45 + chalk/plugins/viewplugins/variations/variations.rc | 8 + .../viewplugins/variations/wdg_variations.ui | 897 + chalk/sdk/Makefile.am | 23 + chalk/sdk/kis_annotation.h | 89 + chalk/sdk/kis_canvas_controller.h | 200 + chalk/sdk/kis_canvas_observer.h | 55 + chalk/sdk/kis_canvas_subject.h | 192 + chalk/sdk/kis_debug_areas.h | 34 + chalk/sdk/kis_generic_registry.h | 166 + chalk/sdk/kis_global.h | 83 + chalk/sdk/kis_id.h | 108 + chalk/sdk/kis_integer_maths.h | 111 + chalk/sdk/kis_progress_display_interface.h | 76 + chalk/sdk/kis_progress_subject.cc | 29 + chalk/sdk/kis_progress_subject.h | 45 + chalk/sdk/kis_shared_ptr_vector.h | 70 + chalk/sdk/kis_undo_adapter.h | 67 + chalk/todo-1.6 | 74 + chalk/ui/Makefile.am | 75 + chalk/ui/imageviewer.cc | 78 + chalk/ui/imageviewer.h | 53 + chalk/ui/kcurve.cc | 450 + chalk/ui/kcurve.h | 80 + chalk/ui/kis_aboutdata.h | 68 + chalk/ui/kis_autobrush.cc | 177 + chalk/ui/kis_autobrush.h | 56 + chalk/ui/kis_autogradient.cc | 147 + chalk/ui/kis_autogradient.h | 53 + chalk/ui/kis_birdeye_box.cc | 311 + chalk/ui/kis_birdeye_box.h | 69 + chalk/ui/kis_boundary_painter.cc | 81 + chalk/ui/kis_boundary_painter.h | 33 + chalk/ui/kis_brush_chooser.cc | 102 + chalk/ui/kis_brush_chooser.h | 52 + chalk/ui/kis_button_event.h | 45 + chalk/ui/kis_button_press_event.h | 31 + chalk/ui/kis_button_release_event.h | 31 + chalk/ui/kis_canvas.cc | 1355 + chalk/ui/kis_canvas.h | 387 + chalk/ui/kis_canvas_painter.cc | 1440 + chalk/ui/kis_canvas_painter.h | 356 + chalk/ui/kis_clipboard.cc | 287 + chalk/ui/kis_clipboard.h | 80 + chalk/ui/kis_cmb_composite.cc | 88 + chalk/ui/kis_cmb_composite.h | 71 + chalk/ui/kis_cmb_idlist.cc | 97 + chalk/ui/kis_cmb_idlist.h | 68 + chalk/ui/kis_color_cup.cc | 118 + chalk/ui/kis_color_cup.h | 96 + chalk/ui/kis_config.cc | 442 + chalk/ui/kis_config.h | 143 + chalk/ui/kis_controlframe.cc | 343 + chalk/ui/kis_controlframe.h | 130 + chalk/ui/kis_cursor.cc | 374 + chalk/ui/kis_cursor.h | 73 + chalk/ui/kis_custom_brush.cc | 158 + chalk/ui/kis_custom_brush.h | 63 + chalk/ui/kis_custom_image_widget.cc | 110 + chalk/ui/kis_custom_image_widget.h | 58 + chalk/ui/kis_custom_palette.cc | 151 + chalk/ui/kis_custom_palette.h | 62 + chalk/ui/kis_custom_pattern.cc | 118 + chalk/ui/kis_custom_pattern.h | 61 + chalk/ui/kis_dlg_adj_layer_props.cc | 168 + chalk/ui/kis_dlg_adj_layer_props.h | 81 + chalk/ui/kis_dlg_adjustment_layer.cc | 193 + chalk/ui/kis_dlg_adjustment_layer.h | 86 + chalk/ui/kis_dlg_apply_profile.cc | 96 + chalk/ui/kis_dlg_apply_profile.h | 49 + chalk/ui/kis_dlg_image_properties.cc | 173 + chalk/ui/kis_dlg_image_properties.h | 62 + chalk/ui/kis_dlg_layer_properties.cc | 106 + chalk/ui/kis_dlg_layer_properties.h | 54 + chalk/ui/kis_dlg_new_layer.cc | 159 + chalk/ui/kis_dlg_new_layer.h | 61 + chalk/ui/kis_dlg_preferences.cc | 821 + chalk/ui/kis_dlg_preferences.h | 277 + chalk/ui/kis_doc.cc | 1171 + chalk/ui/kis_doc.h | 224 + chalk/ui/kis_doc_iface.cc | 67 + chalk/ui/kis_doc_iface.h | 50 + chalk/ui/kis_double_click_event.h | 31 + chalk/ui/kis_double_widget.cc | 147 + chalk/ui/kis_double_widget.h | 78 + chalk/ui/kis_event.h | 62 + chalk/ui/kis_factory.cc | 153 + chalk/ui/kis_factory.h | 59 + chalk/ui/kis_filter_manager.cc | 408 + chalk/ui/kis_filter_manager.h | 87 + chalk/ui/kis_filters_listview.cc | 250 + chalk/ui/kis_filters_listview.h | 143 + chalk/ui/kis_gradient_chooser.cc | 77 + chalk/ui/kis_gradient_chooser.h | 63 + chalk/ui/kis_gradient_slider_widget.cc | 219 + chalk/ui/kis_gradient_slider_widget.h | 80 + chalk/ui/kis_grid_drawer.cpp | 223 + chalk/ui/kis_grid_drawer.h | 71 + chalk/ui/kis_grid_manager.cpp | 156 + chalk/ui/kis_grid_manager.h | 65 + chalk/ui/kis_histogram_view.cc | 354 + chalk/ui/kis_histogram_view.h | 104 + chalk/ui/kis_icon_item.cc | 116 + chalk/ui/kis_icon_item.h | 48 + chalk/ui/kis_iconwidget.cc | 80 + chalk/ui/kis_iconwidget.h | 50 + chalk/ui/kis_import_catcher.cc | 80 + chalk/ui/kis_import_catcher.h | 58 + chalk/ui/kis_input_device.cc | 101 + chalk/ui/kis_input_device.h | 86 + chalk/ui/kis_int_spinbox.cc | 198 + chalk/ui/kis_int_spinbox.h | 200 + chalk/ui/kis_itemchooser.cc | 81 + chalk/ui/kis_itemchooser.h | 65 + chalk/ui/kis_label_cursor_pos.cc | 53 + chalk/ui/kis_label_cursor_pos.h | 43 + chalk/ui/kis_label_progress.cc | 214 + chalk/ui/kis_label_progress.h | 66 + chalk/ui/kis_label_zoom.cc | 21 + chalk/ui/kis_label_zoom.h | 34 + chalk/ui/kis_layerbox.cc | 675 + chalk/ui/kis_layerbox.h | 124 + chalk/ui/kis_layerlist.cc | 220 + chalk/ui/kis_layerlist.h | 80 + chalk/ui/kis_load_visitor.h | 187 + chalk/ui/kis_matrix_widget.ui | 210 + chalk/ui/kis_matrix_widget.ui.h | 17 + chalk/ui/kis_move_event.h | 31 + chalk/ui/kis_multi_bool_filter_widget.cc | 68 + chalk/ui/kis_multi_bool_filter_widget.h | 56 + chalk/ui/kis_multi_double_filter_widget.cc | 103 + chalk/ui/kis_multi_double_filter_widget.h | 79 + chalk/ui/kis_multi_integer_filter_widget.cc | 104 + chalk/ui/kis_multi_integer_filter_widget.h | 83 + chalk/ui/kis_opengl_canvas.cc | 127 + chalk/ui/kis_opengl_canvas.h | 76 + chalk/ui/kis_opengl_canvas_painter.cc | 849 + chalk/ui/kis_opengl_canvas_painter.h | 212 + chalk/ui/kis_opengl_image_context.cc | 371 + chalk/ui/kis_opengl_image_context.h | 157 + chalk/ui/kis_paintop_box.cc | 249 + chalk/ui/kis_paintop_box.h | 104 + chalk/ui/kis_palette_view.cc | 150 + chalk/ui/kis_palette_view.h | 70 + chalk/ui/kis_palette_widget.cc | 162 + chalk/ui/kis_palette_widget.h | 80 + chalk/ui/kis_part_layer.cc | 260 + chalk/ui/kis_part_layer.h | 148 + chalk/ui/kis_part_layer_handler.cc | 94 + chalk/ui/kis_part_layer_handler.h | 58 + chalk/ui/kis_pattern_chooser.cc | 57 + chalk/ui/kis_pattern_chooser.h | 42 + chalk/ui/kis_perspective_grid_manager.cpp | 159 + chalk/ui/kis_perspective_grid_manager.h | 55 + chalk/ui/kis_populate_visitor.h | 117 + chalk/ui/kis_previewdialog.cc | 46 + chalk/ui/kis_previewdialog.h | 45 + chalk/ui/kis_previewwidget.cc | 409 + chalk/ui/kis_previewwidget.h | 141 + chalk/ui/kis_previewwidgetbase.ui | 271 + chalk/ui/kis_qpaintdevice_canvas.cc | 120 + chalk/ui/kis_qpaintdevice_canvas.h | 71 + chalk/ui/kis_qpaintdevice_canvas_painter.cc | 667 + chalk/ui/kis_qpaintdevice_canvas_painter.h | 189 + chalk/ui/kis_resource_mediator.cc | 117 + chalk/ui/kis_resource_mediator.h | 73 + chalk/ui/kis_resourceserver.cc | 199 + chalk/ui/kis_resourceserver.h | 91 + chalk/ui/kis_ruler.cc | 367 + chalk/ui/kis_ruler.h | 81 + chalk/ui/kis_save_visitor.h | 171 + chalk/ui/kis_savexml_visitor.h | 144 + chalk/ui/kis_selection_manager.cc | 1643 + chalk/ui/kis_selection_manager.h | 137 + chalk/ui/kis_selection_options.cc | 70 + chalk/ui/kis_selection_options.h | 57 + chalk/ui/kis_text_brush.cc | 74 + chalk/ui/kis_text_brush.h | 71 + chalk/ui/kis_tool.cc | 69 + chalk/ui/kis_tool.h | 144 + chalk/ui/kis_tool_controller.h | 39 + chalk/ui/kis_tool_dummy.cc | 111 + chalk/ui/kis_tool_dummy.h | 85 + chalk/ui/kis_tool_factory.h | 41 + chalk/ui/kis_tool_freehand.cc | 354 + chalk/ui/kis_tool_freehand.h | 103 + chalk/ui/kis_tool_manager.cc | 303 + chalk/ui/kis_tool_manager.h | 103 + chalk/ui/kis_tool_non_paint.cc | 115 + chalk/ui/kis_tool_non_paint.h | 85 + chalk/ui/kis_tool_paint.cc | 260 + chalk/ui/kis_tool_paint.h | 119 + chalk/ui/kis_tool_registry.cc | 111 + chalk/ui/kis_tool_registry.h | 60 + chalk/ui/kis_tool_shape.cc | 67 + chalk/ui/kis_tool_shape.h | 53 + chalk/ui/kis_tool_types.h | 34 + chalk/ui/kis_view.cc | 4018 ++ chalk/ui/kis_view.h | 664 + chalk/ui/kis_view_iface.cc | 98 + chalk/ui/kis_view_iface.h | 58 + chalk/ui/kobirdeyepanel.cpp | 619 + chalk/ui/kobirdeyepanel.h | 263 + chalk/ui/layerlist.cpp | 1325 + chalk/ui/layerlist.h | 269 + chalk/ui/squeezedcombobox.cpp | 167 + chalk/ui/squeezedcombobox.h | 137 + chalk/ui/wdgapplyprofile.ui | 172 + chalk/ui/wdgautobrush.ui | 355 + chalk/ui/wdgautogradient.ui | 399 + chalk/ui/wdgbirdeye.ui | 304 + chalk/ui/wdgcolorsettings.ui | 357 + chalk/ui/wdgcustombrush.ui | 199 + chalk/ui/wdgcustompalette.ui | 88 + chalk/ui/wdgcustompattern.ui | 156 + chalk/ui/wdgdisplaysettings.ui | 90 + chalk/ui/wdggeneralsettings.ui | 183 + chalk/ui/wdggridsettings.ui | 468 + chalk/ui/wdglayerbox.ui | 299 + chalk/ui/wdglayerproperties.ui | 170 + chalk/ui/wdgnewimage.ui | 435 + chalk/ui/wdgpalettechooser.ui | 105 + chalk/ui/wdgperformancesettings.ui | 146 + chalk/ui/wdgpressuresettings.ui | 66 + chalk/ui/wdgselectionoptions.ui | 64 + chalk/ui/wdgshapeoptions.ui | 98 + chalk/ui/wdgtabletdevicesettings.ui | 193 + chalk/ui/wdgtabletsettings.ui | 104 + chalk/ui/wdgtextbrush.ui | 158 + changes-1.4 | 10 +- changes-1.5 | 16 +- configure.files | 26 +- configure.in | 292 +- doc/chalk/Makefile.am | 4 + doc/chalk/README.SCREENSHOTS | 7 + doc/chalk/commands-dialogs.docbook | 1411 + doc/chalk/commands-menus.docbook | 2158 + doc/chalk/commands-palettes.docbook | 769 + doc/chalk/commands-toolbars.docbook | 752 + doc/chalk/commands.docbook | 14 + doc/chalk/createdocument.png | Bin 0 -> 27560 bytes doc/chalk/credits.docbook | 63 + doc/chalk/crocusses-autocontrast.png | Bin 0 -> 499566 bytes doc/chalk/crocusses-blur.png | Bin 0 -> 468963 bytes doc/chalk/crocusses-brightnesscontrast.png | Bin 0 -> 546359 bytes doc/chalk/crocusses-bumpmap.png | Bin 0 -> 571359 bytes doc/chalk/crocusses-coloradjustment.png | Bin 0 -> 528837 bytes doc/chalk/crocusses-colortoalpha.png | Bin 0 -> 415308 bytes doc/chalk/crocusses-colortransfer.png | Bin 0 -> 555355 bytes doc/chalk/crocusses-customconvolution.png | Bin 0 -> 554020 bytes doc/chalk/crocusses-desaturate.png | Bin 0 -> 406993 bytes doc/chalk/crocusses-edgebottom.png | Bin 0 -> 559660 bytes doc/chalk/crocusses-edgeleft.png | Bin 0 -> 571228 bytes doc/chalk/crocusses-edgeright.png | Bin 0 -> 571084 bytes doc/chalk/crocusses-embossall.png | Bin 0 -> 510986 bytes doc/chalk/crocusses-embosshorvert.png | Bin 0 -> 458936 bytes doc/chalk/crocusses-embossvariable.png | Bin 0 -> 422056 bytes doc/chalk/crocusses-gaussianblur.png | Bin 0 -> 530129 bytes doc/chalk/crocusses-gaussiannoise.png | Bin 0 -> 286299 bytes doc/chalk/crocusses-invert.png | Bin 0 -> 539223 bytes doc/chalk/crocusses-lenscorrection.png | Bin 0 -> 508845 bytes doc/chalk/crocusses-maximizechannel.png | Bin 0 -> 459662 bytes doc/chalk/crocusses-meanremoval.png | Bin 0 -> 567175 bytes doc/chalk/crocusses-minimizechannel.png | Bin 0 -> 425665 bytes doc/chalk/crocusses-oilpaint.png | Bin 0 -> 495456 bytes doc/chalk/crocusses-pixelize.png | Bin 0 -> 478589 bytes doc/chalk/crocusses-raindrops.png | Bin 0 -> 534756 bytes doc/chalk/crocusses-randomnoise.png | Bin 0 -> 564986 bytes doc/chalk/crocusses-randompick.png | Bin 0 -> 519596 bytes doc/chalk/crocusses-roundcorners.png | Bin 0 -> 539417 bytes doc/chalk/crocusses-sharpen.png | Bin 0 -> 553923 bytes doc/chalk/crocusses-smalltiles.png | Bin 0 -> 361991 bytes doc/chalk/crocusses-sobel.png | Bin 0 -> 471366 bytes doc/chalk/crocusses-topedge.png | Bin 0 -> 559862 bytes doc/chalk/crocusses-unsharpmask.png | Bin 0 -> 428074 bytes doc/chalk/crocusses-wave.png | Bin 0 -> 523440 bytes doc/chalk/crocusses-waveletnoise.png | Bin 0 -> 529842 bytes doc/chalk/crocusses.png | Bin 0 -> 793765 bytes doc/chalk/developers-plugins.docbook | 1553 + doc/chalk/developers-scripting.docbook | 534 + doc/chalk/developers.docbook | 13 + doc/chalk/dialogs-addpalette.png | Bin 0 -> 4551 bytes doc/chalk/dialogs-blur.png | Bin 0 -> 48397 bytes doc/chalk/dialogs-brightnesscontrast.png | Bin 0 -> 49053 bytes doc/chalk/dialogs-bumpmap.png | Bin 0 -> 67767 bytes doc/chalk/dialogs-coloradjustment.png | Bin 0 -> 51960 bytes doc/chalk/dialogs-colorrange.png | Bin 0 -> 15922 bytes doc/chalk/dialogs-colortoalpha.png | Bin 0 -> 87706 bytes doc/chalk/dialogs-colortransfer.png | Bin 0 -> 95725 bytes doc/chalk/dialogs-convertimagetype.png | Bin 0 -> 20431 bytes doc/chalk/dialogs-convertlayertype.png | Bin 0 -> 20122 bytes doc/chalk/dialogs-cubism.png | Bin 0 -> 24275 bytes doc/chalk/dialogs-customconvolution.png | Bin 0 -> 56964 bytes doc/chalk/dialogs-documentinformation.png | Bin 0 -> 15469 bytes doc/chalk/dialogs-dropshadow.png | Bin 0 -> 7698 bytes doc/chalk/dialogs-emboss.png | Bin 0 -> 43741 bytes doc/chalk/dialogs-filtersgallery.png | Bin 0 -> 96050 bytes doc/chalk/dialogs-gaussiannoise.png | Bin 0 -> 90251 bytes doc/chalk/dialogs-histogram.png | Bin 0 -> 16401 bytes doc/chalk/dialogs-imageproperties.png | Bin 0 -> 7708 bytes doc/chalk/dialogs-imagerestoration.png | Bin 0 -> 50998 bytes doc/chalk/dialogs-imagesize.png | Bin 0 -> 16604 bytes doc/chalk/dialogs-layerproperties.png | Bin 0 -> 14492 bytes doc/chalk/dialogs-layersize.png | Bin 0 -> 13466 bytes doc/chalk/dialogs-lenscorrection.png | Bin 0 -> 94890 bytes doc/chalk/dialogs-newadjustmentlayer.png | Bin 0 -> 93986 bytes doc/chalk/dialogs-newlayer.png | Bin 0 -> 5868 bytes doc/chalk/dialogs-oilpaint.png | Bin 0 -> 37142 bytes doc/chalk/dialogs-pixelize.png | Bin 0 -> 16146 bytes doc/chalk/dialogs-raindrops.png | Bin 0 -> 45473 bytes doc/chalk/dialogs-randomnoise.png | Bin 0 -> 139396 bytes doc/chalk/dialogs-randompick.png | Bin 0 -> 91945 bytes doc/chalk/dialogs-rotateimage.png | Bin 0 -> 16183 bytes doc/chalk/dialogs-rotatelayer.png | Bin 0 -> 20300 bytes doc/chalk/dialogs-roundcorners.png | Bin 0 -> 46187 bytes doc/chalk/dialogs-separateimage.png | Bin 0 -> 7936 bytes doc/chalk/dialogs-shearimage.png | Bin 0 -> 9517 bytes doc/chalk/dialogs-shearlayer.png | Bin 0 -> 7941 bytes doc/chalk/dialogs-smalltiles.png | Bin 0 -> 32127 bytes doc/chalk/dialogs-sobel.png | Bin 0 -> 83673 bytes doc/chalk/dialogs-substrate.png | Bin 0 -> 22652 bytes doc/chalk/dialogs-unsharpmask.png | Bin 0 -> 93324 bytes doc/chalk/dialogs-wave.png | Bin 0 -> 99302 bytes doc/chalk/dialogs-waveletnoise.png | Bin 0 -> 77064 bytes doc/chalk/faq.docbook | 51 + doc/chalk/index.docbook | 138 + doc/chalk/installation.docbook | 73 + doc/chalk/introduction.docbook | 153 + doc/chalk/mainscreen.png | Bin 0 -> 79116 bytes doc/chalk/mountains-burn.png | Bin 0 -> 160961 bytes doc/chalk/mountains-color.png | Bin 0 -> 192281 bytes doc/chalk/mountains-darken.png | Bin 0 -> 159111 bytes doc/chalk/mountains-divide.png | Bin 0 -> 173190 bytes doc/chalk/mountains-dodge.png | Bin 0 -> 173312 bytes doc/chalk/mountains-hue.png | Bin 0 -> 234147 bytes doc/chalk/mountains-lighten.png | Bin 0 -> 149118 bytes doc/chalk/mountains-multiply.png | Bin 0 -> 172594 bytes doc/chalk/mountains-normal.png | Bin 0 -> 3514 bytes doc/chalk/mountains-original.png | Bin 0 -> 238432 bytes doc/chalk/mountains-overlay.png | Bin 0 -> 249222 bytes doc/chalk/mountains-saturation.png | Bin 0 -> 231772 bytes doc/chalk/mountains-screen.png | Bin 0 -> 172229 bytes doc/chalk/mountains-value.png | Bin 0 -> 218819 bytes doc/chalk/mountains.png | Bin 0 -> 975941 bytes doc/chalk/newimage.png | Bin 0 -> 29884 bytes doc/chalk/palettes-colors-gray.png | Bin 0 -> 1426 bytes doc/chalk/palettes-colors-hsv.png | Bin 0 -> 10419 bytes doc/chalk/palettes-colors-palettes.png | Bin 0 -> 3356 bytes doc/chalk/palettes-colors-rgb.png | Bin 0 -> 1841 bytes doc/chalk/palettes-colors-watercolors.png | Bin 0 -> 3031 bytes doc/chalk/palettes-controlbox-bezier.png | Bin 0 -> 2961 bytes doc/chalk/palettes-controlbox-brush.png | Bin 0 -> 3644 bytes doc/chalk/palettes-controlbox-colorpicker.png | Bin 0 -> 7578 bytes doc/chalk/palettes-controlbox-contiguousfill.png | Bin 0 -> 5642 bytes doc/chalk/palettes-controlbox-crop.png | Bin 0 -> 4123 bytes doc/chalk/palettes-controlbox-duplicate.png | Bin 0 -> 5857 bytes doc/chalk/palettes-controlbox-ellipse.png | Bin 0 -> 3444 bytes doc/chalk/palettes-controlbox-fill.png | Bin 0 -> 5468 bytes doc/chalk/palettes-controlbox-gradient.png | Bin 0 -> 6695 bytes doc/chalk/palettes-controlbox-histogram.png | Bin 0 -> 1597 bytes doc/chalk/palettes-controlbox-line.png | Bin 0 -> 3815 bytes doc/chalk/palettes-controlbox-overview.png | Bin 0 -> 20949 bytes doc/chalk/palettes-controlbox-paintwithfilters.png | Bin 0 -> 7826 bytes doc/chalk/palettes-controlbox-polygon.png | Bin 0 -> 4286 bytes doc/chalk/palettes-controlbox-polyline.png | Bin 0 -> 3815 bytes doc/chalk/palettes-controlbox-rectangle.png | Bin 0 -> 3444 bytes doc/chalk/palettes-controlbox-select.png | Bin 0 -> 1538 bytes doc/chalk/palettes-controlbox-selectcontiguous.png | Bin 0 -> 3525 bytes doc/chalk/palettes-controlbox-selectmagnetic.png | Bin 0 -> 3765 bytes doc/chalk/palettes-controlbox-selectsimilar.png | Bin 0 -> 2806 bytes doc/chalk/palettes-controlbox-star.png | Bin 0 -> 5078 bytes doc/chalk/palettes-controlbox-text.png | Bin 0 -> 4120 bytes doc/chalk/palettes-controlbox-transform.png | Bin 0 -> 1529 bytes doc/chalk/palettes-layers-layers.png | Bin 0 -> 2825 bytes doc/chalk/palettes-layers-scriptsmanager.png | Bin 0 -> 10082 bytes doc/chalk/preferences-color.png | Bin 0 -> 9181 bytes doc/chalk/preferences-display.png | Bin 0 -> 2053 bytes doc/chalk/preferences-general.png | Bin 0 -> 4016 bytes doc/chalk/preferences-grid.png | Bin 0 -> 4554 bytes doc/chalk/preferences-performance.png | Bin 0 -> 2846 bytes doc/chalk/preferences-sidebar.png | Bin 0 -> 8953 bytes doc/chalk/preferences-tablet.png | Bin 0 -> 3391 bytes doc/chalk/settings.docbook | 229 + doc/chalk/tool-bezier-example.png | Bin 0 -> 3300 bytes doc/chalk/tool-bezier-example2.png | Bin 0 -> 3588 bytes doc/chalk/tool-bezier-example3.png | Bin 0 -> 8637 bytes doc/chalk/tool-bezier.png | Bin 0 -> 862 bytes doc/chalk/tool-brush.png | Bin 0 -> 759 bytes doc/chalk/tool-colorpicker.png | Bin 0 -> 821 bytes doc/chalk/tool-contiguousfill.png | Bin 0 -> 1197 bytes doc/chalk/tool-crop.png | Bin 0 -> 902 bytes doc/chalk/tool-duplicate.png | Bin 0 -> 1235 bytes doc/chalk/tool-ellipse.png | Bin 0 -> 885 bytes doc/chalk/tool-eraseselection.png | Bin 0 -> 1178 bytes doc/chalk/tool-gradient.png | Bin 0 -> 481 bytes doc/chalk/tool-line.png | Bin 0 -> 574 bytes doc/chalk/tool-move.png | Bin 0 -> 883 bytes doc/chalk/tool-paintselection.png | Bin 0 -> 1073 bytes doc/chalk/tool-paintwithfilters-example.png | Bin 0 -> 236144 bytes doc/chalk/tool-paintwithfilters.png | Bin 0 -> 882 bytes doc/chalk/tool-pan.png | Bin 0 -> 913 bytes doc/chalk/tool-perspectivegrid.png | Bin 0 -> 1044 bytes doc/chalk/tool-perspectivetransform.png | Bin 0 -> 883 bytes doc/chalk/tool-polygon.png | Bin 0 -> 898 bytes doc/chalk/tool-polyline.png | Bin 0 -> 708 bytes doc/chalk/tool-rectangle.png | Bin 0 -> 539 bytes doc/chalk/tool-selectbezier.png | Bin 0 -> 797 bytes doc/chalk/tool-selectcontiguous.png | Bin 0 -> 876 bytes doc/chalk/tool-selectelliptical.png | Bin 0 -> 775 bytes doc/chalk/tool-selectmagnetic.png | Bin 0 -> 1123 bytes doc/chalk/tool-selectoutline.png | Bin 0 -> 927 bytes doc/chalk/tool-selectpolygonal.png | Bin 0 -> 939 bytes doc/chalk/tool-selectrectangular.png | Bin 0 -> 637 bytes doc/chalk/tool-selectsimilar.png | Bin 0 -> 835 bytes doc/chalk/tool-star.png | Bin 0 -> 1042 bytes doc/chalk/tool-text.png | Bin 0 -> 1008 bytes doc/chalk/tool-transform.png | Bin 0 -> 616 bytes doc/chalk/tool-zoom.png | Bin 0 -> 981 bytes .../toolbar-brushes-brushshapes-autobrush.png | Bin 0 -> 6981 bytes .../toolbar-brushes-brushshapes-custombrush.png | Bin 0 -> 24320 bytes .../toolbar-brushes-brushshapes-predefined.png | Bin 0 -> 5756 bytes doc/chalk/toolbar-brushes-gradients.png | Bin 0 -> 12138 bytes .../toolbar-brushes-patterns-custompattern.png | Bin 0 -> 18845 bytes doc/chalk/toolbar-brushes-patterns.png | Bin 0 -> 37517 bytes doc/chalk/toolbar-brushesandstuff.png | Bin 0 -> 4514 bytes doc/chalk/toolbar-chalk.png | Bin 0 -> 21661 bytes doc/chalk/toolbar-edit.png | Bin 0 -> 1852 bytes doc/chalk/toolbar-file.png | Bin 0 -> 3617 bytes doc/chalk/toolbar-navigation.png | Bin 0 -> 1196 bytes doc/chalk/toolbar-transformationtools.png | Bin 0 -> 2339 bytes doc/chalk/toolbars-button-zoomin.png | Bin 0 -> 1079 bytes doc/chalk/toolbars-button-zoomout.png | Bin 0 -> 1040 bytes doc/chalk/tutorial-quick-starts.docbook | 183 + doc/chalk/tutorial-quick-starts1.png | Bin 0 -> 517486 bytes doc/chalk/tutorial-quick-starts10.png | Bin 0 -> 5261 bytes doc/chalk/tutorial-quick-starts11.png | Bin 0 -> 15273 bytes doc/chalk/tutorial-quick-starts12.png | Bin 0 -> 64871 bytes doc/chalk/tutorial-quick-starts2.png | Bin 0 -> 13703 bytes doc/chalk/tutorial-quick-starts3.png | Bin 0 -> 376212 bytes doc/chalk/tutorial-quick-starts4.png | Bin 0 -> 5868 bytes doc/chalk/tutorial-quick-starts5.png | Bin 0 -> 251715 bytes doc/chalk/tutorial-quick-starts6.png | Bin 0 -> 45704 bytes doc/chalk/tutorial-quick-starts7.png | Bin 0 -> 73296 bytes doc/chalk/tutorial-quick-starts8.png | Bin 0 -> 3636 bytes doc/chalk/tutorial-quick-starts9.png | Bin 0 -> 7115 bytes doc/chalk/tutorial-select-layer-1.png | Bin 0 -> 99976 bytes doc/chalk/tutorial-select-layer-10.png | Bin 0 -> 21980 bytes doc/chalk/tutorial-select-layer-11.png | Bin 0 -> 28349 bytes doc/chalk/tutorial-select-layer-12.png | Bin 0 -> 2908 bytes doc/chalk/tutorial-select-layer-13.png | Bin 0 -> 5912 bytes doc/chalk/tutorial-select-layer-2.png | Bin 0 -> 7974 bytes doc/chalk/tutorial-select-layer-3.png | Bin 0 -> 17499 bytes doc/chalk/tutorial-select-layer-4.png | Bin 0 -> 3852 bytes doc/chalk/tutorial-select-layer-5.png | Bin 0 -> 5555 bytes doc/chalk/tutorial-select-layer-6.png | Bin 0 -> 14353 bytes doc/chalk/tutorial-select-layer-7.png | Bin 0 -> 5173 bytes doc/chalk/tutorial-select-layer-8.png | Bin 0 -> 6463 bytes doc/chalk/tutorial-select-layer-9.png | Bin 0 -> 21072 bytes doc/chalk/tutorial-select-layer-sample.png | Bin 0 -> 5905 bytes doc/chalk/tutorial-select-layer.docbook | 263 + doc/chalk/tutorial-starting.docbook | 117 + doc/chalk/tutorial-tablet-1.png | Bin 0 -> 99770 bytes doc/chalk/tutorial-tablet-2.png | Bin 0 -> 27896 bytes doc/chalk/tutorial-tablet-3.png | Bin 0 -> 33492 bytes doc/chalk/tutorial-tablet.docbook | 141 + doc/chalk/tutorial.docbook | 14 + doc/chalk/using-colorspaces.docbook | 149 + doc/chalk/using-filters.docbook | 923 + doc/chalk/using-images.docbook | 66 + doc/chalk/using-layers.docbook | 620 + doc/chalk/using-selections-1.png | Bin 0 -> 115987 bytes doc/chalk/using-selections-2.png | Bin 0 -> 128193 bytes doc/chalk/using-selections-3.png | Bin 0 -> 131771 bytes doc/chalk/using-selections-4.png | Bin 0 -> 29987 bytes doc/chalk/using-selections-5.png | Bin 0 -> 24734 bytes doc/chalk/using-selections-6.png | Bin 0 -> 194321 bytes doc/chalk/using-selections.docbook | 200 + doc/chalk/using-views.docbook | 167 + doc/kchart/index.docbook | 7 +- doc/kivio/working.docbook | 2 +- doc/koffice/index.docbook | 3 +- doc/koshell/index.docbook | 5 +- doc/kword/index.docbook | 3 +- filters/Makefile.am | 2 +- filters/chalk/Makefile.am | 34 + filters/chalk/configure.in.in | 66 + filters/chalk/gmagick/Makefile.am | 44 + filters/chalk/gmagick/chalk_magick.desktop | 57 + filters/chalk/gmagick/chalk_magick_export.desktop | 55 + filters/chalk/gmagick/chalk_magick_import.desktop | 61 + filters/chalk/gmagick/configure.in.bot | 23 + .../chalk/gmagick/kis_image_magick_converter.cc | 1142 + filters/chalk/gmagick/kis_image_magick_converter.h | 104 + filters/chalk/gmagick/magickexport.cpp | 78 + filters/chalk/gmagick/magickexport.h | 37 + filters/chalk/gmagick/magickimport.cpp | 105 + filters/chalk/gmagick/magickimport.h | 37 + filters/chalk/jpeg/Makefile.am | 51 + filters/chalk/jpeg/chalk_jpeg.desktop | 58 + filters/chalk/jpeg/chalk_jpeg_export.desktop | 52 + filters/chalk/jpeg/chalk_jpeg_import.desktop | 52 + filters/chalk/jpeg/configure.in.bot | 7 + filters/chalk/jpeg/iccjpeg.c | 270 + filters/chalk/jpeg/iccjpeg.h | 99 + filters/chalk/jpeg/kis_jpeg_converter.cc | 542 + filters/chalk/jpeg/kis_jpeg_converter.h | 91 + filters/chalk/jpeg/kis_jpeg_export.cc | 152 + filters/chalk/jpeg/kis_jpeg_export.h | 35 + filters/chalk/jpeg/kis_jpeg_import.cc | 105 + filters/chalk/jpeg/kis_jpeg_import.h | 34 + filters/chalk/jpeg/kis_wdg_options_jpeg.ui | 149 + filters/chalk/libkisexif/Makefile.am | 20 + filters/chalk/libkisexif/kis_exif_io.cpp | 177 + filters/chalk/libkisexif/kis_exif_io.h | 45 + filters/chalk/magick/Makefile.am | 44 + filters/chalk/magick/chalk_magick.desktop | 58 + filters/chalk/magick/chalk_magick_export.desktop | 55 + filters/chalk/magick/chalk_magick_import.desktop | 61 + filters/chalk/magick/configure.in.bot | 15 + filters/chalk/magick/kis_image_magick_converter.cc | 1087 + filters/chalk/magick/kis_image_magick_converter.h | 104 + filters/chalk/magick/magickexport.cpp | 78 + filters/chalk/magick/magickexport.h | 37 + filters/chalk/magick/magickimport.cpp | 105 + filters/chalk/magick/magickimport.h | 37 + filters/chalk/openexr/Makefile.am | 51 + filters/chalk/openexr/chalk_openexr.desktop | 57 + filters/chalk/openexr/chalk_openexr_export.desktop | 52 + filters/chalk/openexr/chalk_openexr_import.desktop | 52 + filters/chalk/openexr/configure.in.bot | 9 + filters/chalk/openexr/kis_openexr_export.cpp | 155 + filters/chalk/openexr/kis_openexr_export.h | 38 + filters/chalk/openexr/kis_openexr_import.cpp | 160 + filters/chalk/openexr/kis_openexr_import.h | 38 + filters/chalk/pdf/Makefile.am | 30 + filters/chalk/pdf/chalk_pdf.desktop | 63 + filters/chalk/pdf/chalk_pdf_import.desktop | 51 + filters/chalk/pdf/configure.in.bot | 7 + filters/chalk/pdf/configure.in.in | 4 + filters/chalk/pdf/kis_pdf_import.cpp | 158 + filters/chalk/pdf/kis_pdf_import.h | 35 + filters/chalk/pdf/kis_pdf_import_widget.cpp | 147 + filters/chalk/pdf/kis_pdf_import_widget.h | 55 + filters/chalk/pdf/pdfimportwidgetbase.ui | 321 + filters/chalk/png/Makefile.am | 44 + filters/chalk/png/chalk_png.desktop | 57 + filters/chalk/png/chalk_png_export.desktop | 51 + filters/chalk/png/chalk_png_import.desktop | 51 + filters/chalk/png/configure.in.bot | 8 + filters/chalk/png/kis_png_converter.cc | 794 + filters/chalk/png/kis_png_converter.h | 82 + filters/chalk/png/kis_png_export.cc | 124 + filters/chalk/png/kis_png_export.h | 35 + filters/chalk/png/kis_png_import.cc | 105 + filters/chalk/png/kis_png_import.h | 34 + filters/chalk/png/kis_wdg_options_png.ui | 183 + filters/chalk/raw/Makefile.am | 35 + filters/chalk/raw/chalk_raw.desktop | 57 + filters/chalk/raw/chalk_raw_import.desktop | 51 + filters/chalk/raw/dcraw.1 | 182 + filters/chalk/raw/dcraw.c | 5999 ++ filters/chalk/raw/kis_raw_import.cpp | 630 + filters/chalk/raw/kis_raw_import.h | 71 + filters/chalk/raw/wdgrawimport.ui | 496 + filters/chalk/tiff/Makefile.am | 55 + filters/chalk/tiff/chalk_tiff.desktop | 63 + filters/chalk/tiff/chalk_tiff_export.desktop | 52 + filters/chalk/tiff/chalk_tiff_import.desktop | 52 + filters/chalk/tiff/configure.in.bot | 7 + filters/chalk/tiff/kis_dlg_options_tiff.cpp | 134 + filters/chalk/tiff/kis_dlg_options_tiff.h | 45 + filters/chalk/tiff/kis_tiff_converter.cc | 677 + filters/chalk/tiff/kis_tiff_converter.h | 94 + filters/chalk/tiff/kis_tiff_export.cc | 123 + filters/chalk/tiff/kis_tiff_export.h | 35 + filters/chalk/tiff/kis_tiff_import.cc | 105 + filters/chalk/tiff/kis_tiff_import.h | 34 + filters/chalk/tiff/kis_tiff_reader.cc | 121 + filters/chalk/tiff/kis_tiff_reader.h | 206 + filters/chalk/tiff/kis_tiff_stream.cc | 164 + filters/chalk/tiff/kis_tiff_stream.h | 81 + filters/chalk/tiff/kis_tiff_writer_visitor.cpp | 237 + filters/chalk/tiff/kis_tiff_writer_visitor.h | 53 + filters/chalk/tiff/kis_tiff_ycbcr_reader.cc | 170 + filters/chalk/tiff/kis_tiff_ycbcr_reader.h | 73 + filters/chalk/tiff/kis_wdg_options_tiff.ui | 741 + filters/chalk/tiff/kis_ycbcr_colorspace.h | 27 + filters/chalk/xcf/Makefile.am | 42 + filters/chalk/xcf/chalk_xcf_export.desktop | 52 + filters/chalk/xcf/chalk_xcf_import.desktop | 52 + filters/chalk/xcf/xcf/README | 2 + filters/chalk/xcf/xcf/xcf-load.cc | 1740 + filters/chalk/xcf/xcf/xcf-load.h | 27 + filters/chalk/xcf/xcf/xcf-private.h | 95 + filters/chalk/xcf/xcf/xcf-read.cc | 118 + filters/chalk/xcf/xcf/xcf-read.h | 37 + filters/chalk/xcf/xcf/xcf-save.cc | 1826 + filters/chalk/xcf/xcf/xcf-save.h | 29 + filters/chalk/xcf/xcf/xcf-seek.cc | 79 + filters/chalk/xcf/xcf/xcf-seek.h | 30 + filters/chalk/xcf/xcf/xcf-write.cc | 104 + filters/chalk/xcf/xcf/xcf-write.h | 39 + filters/chalk/xcf/xcfexport.cpp | 78 + filters/chalk/xcf/xcfexport.h | 37 + filters/chalk/xcf/xcfimport.cpp | 99 + filters/chalk/xcf/xcfimport.h | 37 + filters/configure.in.mid | 4 +- filters/filterstatus.xml | 36 +- filters/kspread/gnumeric/gnumericimport.cc | 6 +- filters/tests/global-filter-test.sh | 8 +- karbon/CHANGES | 2 +- karbon/GRAPHICS_MEETING | 2 +- karbon/TODO | 2 +- karbon/karbon_factory.cc | 4 +- karbon/tools/vcurvefit.cc | 2 +- karbon/tools/vdefaulttools.cc | 2 +- karbon/tools/vellipsetool.cc | 2 +- karbon/tools/vellipsetool.h | 2 +- karbon/tools/vpenciltool.cc | 2 +- karbon/tools/vpolygontool.cc | 2 +- karbon/tools/vpolygontool.h | 2 +- karbon/tools/vpolylinetool.cc | 2 +- karbon/tools/vrectangletool.cc | 2 +- karbon/tools/vrectangletool.h | 2 +- karbon/tools/vroundrecttool.cc | 2 +- karbon/tools/vroundrecttool.h | 2 +- karbon/tools/vshapetool.cc | 4 +- karbon/tools/vsinustool.cc | 2 +- karbon/tools/vsinustool.h | 2 +- karbon/tools/vspiraltool.cc | 2 +- karbon/tools/vspiraltool.h | 2 +- karbon/tools/vstartool.cc | 2 +- karbon/tools/vstartool.h | 2 +- karbon/widgets/vruler.h | 2 +- kchart/kdchart/KDChartAxisParams.h | 4 +- kchart/kdchart/KDChartParams.h | 6 +- kchart/kdchart/KDChartPropertySet.h | 4 +- kchart/kdchart/KDChartTableBase.cpp | 4 +- kchart/kdchart/KDChartTableBase.h | 2 +- kexi/3rdparty/kolibs/koGlobal.cc | 2 +- kexi/main/keximainwindowimpl.cpp | 2 +- kexi/migration/mysql/mysqlmigrate.cpp | 2 +- kexi/widget/kexibrowser.cpp | 2 +- kivio/kiviopart/stencilbardockmanager.cpp | 16 +- kivio/kiviopart/stencilbardockmanager.h | 8 +- kplato/Makefile.am | 2 +- kspread/kspread_editors.cc | 2 +- .../scripting/kspreadcore/kspreadcoremodule.h | 4 +- kword/mailmerge/sql/KWMySqlCursor.h | 4 +- kword/mailmerge/sql/KWQtSqlEasyFilter.cpp | 12 +- kword/mailmerge/sql/KWQtSqlEasyFilter.h | 10 +- kword/mailmerge/sql/KWQtSqlMailMergeOpen.cpp | 20 +- kword/mailmerge/sql/KWQtSqlMailMergeOpen.h | 20 +- .../mailmerge/sql/KWQtSqlPowerSerialDataSource.cpp | 58 +- kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.h | 32 +- kword/mailmerge/sql/KWQtSqlSerialDataSource.cpp | 50 +- kword/mailmerge/sql/KWQtSqlSerialDataSource.h | 30 +- .../mailmerge/sql/KWQtSqlSerialDataSourceBase.cpp | 22 +- kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.h | 18 +- kword/mailmerge/sql/qtsqldatasourceeditor.ui.h | 2 +- lib/configure.in.mid | 4 +- lib/kofficecore/KoGlobal.cpp | 2 +- lib/kofficecore/tests/filterchain_test.cpp | 6 +- lib/kofficecore/tests/koxmlreadertest.cpp | 2 +- lib/kopainter/koIconChooser.h | 2 +- lib/kopainter/ko_rgb_widget.cc | 2 +- lib/kopainter/kogradientmanager.cc | 4 +- lib/kopainter/kogradientmanager.h | 2 +- lib/kotext/KoTextZoomHandler.cpp | 2 +- lib/kross/test/testcase.rb | 2 +- .../kde33/vnd.oasis.opendocument.image.desktop | 2 +- plugins/scan/Makefile.am | 6 +- plugins/scan/scan-chalk.rc | 9 + subdirs | 2 +- tools/kfile-plugins/koffice/kfile_koffice.cpp | 2 +- tools/quickprint/Makefile.am | 2 +- tools/quickprint/chalk_konqi.desktop | 63 + tools/thumbnail/kofficethumbnail.desktop | 2 +- 2074 files changed, 389424 insertions(+), 437 deletions(-) create mode 100644 chalk/AUTHORS create mode 100644 chalk/ChangeLog create mode 100644 chalk/HACKING create mode 100644 chalk/IMAGE_LIBRARIES create mode 100644 chalk/Makefile.am create mode 100644 chalk/README create mode 100644 chalk/TODO create mode 100644 chalk/UIcomments create mode 100644 chalk/chalk.desktop create mode 100644 chalk/chalk.rc create mode 100644 chalk/chalk_part_init.cc create mode 100644 chalk/chalk_readonly.rc create mode 100644 chalk/chalkcolor/Makefile.am create mode 100644 chalk/chalkcolor/README create mode 100644 chalk/chalkcolor/TODO create mode 100644 chalk/chalkcolor/chalk_colorspace.desktop create mode 100644 chalk/chalkcolor/colorspaces/Makefile.am create mode 100644 chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc create mode 100644 chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h create mode 100644 chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc create mode 100644 chalk/chalkcolor/colorspaces/kis_lab_colorspace.h create mode 100644 chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc create mode 100644 chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h create mode 100644 chalk/chalkcolor/kis_abstract_colorspace.cc create mode 100644 chalk/chalkcolor/kis_abstract_colorspace.h create mode 100644 chalk/chalkcolor/kis_basic_histogram_producers.cc create mode 100644 chalk/chalkcolor/kis_basic_histogram_producers.h create mode 100644 chalk/chalkcolor/kis_channelinfo.h create mode 100644 chalk/chalkcolor/kis_color.cc create mode 100644 chalk/chalkcolor/kis_color.h create mode 100644 chalk/chalkcolor/kis_color_conversions.cc create mode 100644 chalk/chalkcolor/kis_color_conversions.h create mode 100644 chalk/chalkcolor/kis_colorspace.cc create mode 100644 chalk/chalkcolor/kis_colorspace.h create mode 100644 chalk/chalkcolor/kis_colorspace_factory_registry.cc create mode 100644 chalk/chalkcolor/kis_colorspace_factory_registry.h create mode 100644 chalk/chalkcolor/kis_colorspace_iface.cc create mode 100644 chalk/chalkcolor/kis_colorspace_iface.h create mode 100644 chalk/chalkcolor/kis_composite_op.cc create mode 100644 chalk/chalkcolor/kis_composite_op.h create mode 100644 chalk/chalkcolor/kis_f16half_base_colorspace.cc create mode 100644 chalk/chalkcolor/kis_f16half_base_colorspace.h create mode 100644 chalk/chalkcolor/kis_f32_base_colorspace.cc create mode 100644 chalk/chalkcolor/kis_f32_base_colorspace.h create mode 100644 chalk/chalkcolor/kis_histogram_producer.cc create mode 100644 chalk/chalkcolor/kis_histogram_producer.h create mode 100644 chalk/chalkcolor/kis_profile.cc create mode 100644 chalk/chalkcolor/kis_profile.h create mode 100644 chalk/chalkcolor/kis_u16_base_colorspace.cc create mode 100644 chalk/chalkcolor/kis_u16_base_colorspace.h create mode 100644 chalk/chalkcolor/kis_u8_base_colorspace.cc create mode 100644 chalk/chalkcolor/kis_u8_base_colorspace.h create mode 100644 chalk/chalkcolor/tests/Makefile.am create mode 100644 chalk/chalkcolor/tests/kis_color_conversions_tester.cpp create mode 100644 chalk/chalkcolor/tests/kis_color_conversions_tester.h create mode 100644 chalk/chalkpart.desktop create mode 100644 chalk/colorspaces/Makefile.am create mode 100644 chalk/colorspaces/README create mode 100644 chalk/colorspaces/cmyk_u16/Makefile.am create mode 100644 chalk/colorspaces/cmyk_u16/chalk_cmyk_u16_plugin.desktop create mode 100644 chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.cc create mode 100644 chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.h create mode 100644 chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc create mode 100644 chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h create mode 100644 chalk/colorspaces/cmyk_u8/Makefile.am create mode 100644 chalk/colorspaces/cmyk_u8/chalkcmykplugin.desktop create mode 100644 chalk/colorspaces/cmyk_u8/cmyk_plugin.cc create mode 100644 chalk/colorspaces/cmyk_u8/cmyk_plugin.h create mode 100644 chalk/colorspaces/cmyk_u8/cmykplugin.rc create mode 100644 chalk/colorspaces/cmyk_u8/composite.h create mode 100644 chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc create mode 100644 chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.h create mode 100644 chalk/colorspaces/cmyk_u8/templates/.directory create mode 100644 chalk/colorspaces/cmyk_u8/templates/Makefile.am create mode 100644 chalk/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png create mode 100644 chalk/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz create mode 100644 chalk/colorspaces/cmyk_u8/templates/white_2000x800.desktop create mode 100644 chalk/colorspaces/cmyk_u8/templates/white_2000x800.kra create mode 100644 chalk/colorspaces/gray_u16/Makefile.am create mode 100644 chalk/colorspaces/gray_u16/chalk_gray_u16_plugin.desktop create mode 100644 chalk/colorspaces/gray_u16/gray_u16_plugin.cc create mode 100644 chalk/colorspaces/gray_u16/gray_u16_plugin.h create mode 100644 chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.cc create mode 100644 chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.h create mode 100644 chalk/colorspaces/gray_u8/Makefile.am create mode 100644 chalk/colorspaces/gray_u8/chalkgrayplugin.desktop create mode 100644 chalk/colorspaces/gray_u8/gray_plugin.cc create mode 100644 chalk/colorspaces/gray_u8/gray_plugin.h create mode 100644 chalk/colorspaces/gray_u8/grayplugin.rc create mode 100644 chalk/colorspaces/gray_u8/kis_gray_colorspace.cc create mode 100644 chalk/colorspaces/gray_u8/kis_gray_colorspace.h create mode 100644 chalk/colorspaces/gray_u8/templates/.directory create mode 100644 chalk/colorspaces/gray_u8/templates/Makefile.am create mode 100644 chalk/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png create mode 100644 chalk/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz create mode 100644 chalk/colorspaces/gray_u8/templates/white_640x480.desktop create mode 100644 chalk/colorspaces/gray_u8/templates/white_640x480.kra create mode 100644 chalk/colorspaces/gray_u8/tests/Makefile.am create mode 100644 chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp create mode 100644 chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h create mode 100644 chalk/colorspaces/lms_f32/Makefile.am create mode 100644 chalk/colorspaces/lms_f32/chalk_lms_f32_plugin.desktop create mode 100644 chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.cc create mode 100644 chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.h create mode 100644 chalk/colorspaces/lms_f32/lms_f32_plugin.cc create mode 100644 chalk/colorspaces/lms_f32/lms_f32_plugin.h create mode 100644 chalk/colorspaces/lms_f32/lms_f32_plugin.rc create mode 100644 chalk/colorspaces/rgb_f16half/Makefile.am create mode 100644 chalk/colorspaces/rgb_f16half/chalk_rgb_f16half_plugin.desktop create mode 100644 chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc create mode 100644 chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h create mode 100644 chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.cc create mode 100644 chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.h create mode 100644 chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.rc create mode 100644 chalk/colorspaces/rgb_f16half/tests/Makefile.am create mode 100644 chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc create mode 100644 chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h create mode 100644 chalk/colorspaces/rgb_f32/Makefile.am create mode 100644 chalk/colorspaces/rgb_f32/chalk_rgb_f32_plugin.desktop create mode 100644 chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc create mode 100644 chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h create mode 100644 chalk/colorspaces/rgb_f32/rgb_f32_plugin.cc create mode 100644 chalk/colorspaces/rgb_f32/rgb_f32_plugin.h create mode 100644 chalk/colorspaces/rgb_f32/rgb_f32_plugin.rc create mode 100644 chalk/colorspaces/rgb_f32/tests/Makefile.am create mode 100644 chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc create mode 100644 chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h create mode 100644 chalk/colorspaces/rgb_u16/Makefile.am create mode 100644 chalk/colorspaces/rgb_u16/chalk_rgb_u16_plugin.desktop create mode 100644 chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc create mode 100644 chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h create mode 100644 chalk/colorspaces/rgb_u16/rgb_u16_plugin.cc create mode 100644 chalk/colorspaces/rgb_u16/rgb_u16_plugin.h create mode 100644 chalk/colorspaces/rgb_u16/tests/Makefile.am create mode 100644 chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc create mode 100644 chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h create mode 100644 chalk/colorspaces/rgb_u8/Makefile.am create mode 100644 chalk/colorspaces/rgb_u8/chalkrgbplugin.desktop create mode 100644 chalk/colorspaces/rgb_u8/composite.h create mode 100644 chalk/colorspaces/rgb_u8/kis_rgb_colorspace.cc create mode 100644 chalk/colorspaces/rgb_u8/kis_rgb_colorspace.h create mode 100644 chalk/colorspaces/rgb_u8/rgb_plugin.cc create mode 100644 chalk/colorspaces/rgb_u8/rgb_plugin.h create mode 100644 chalk/colorspaces/rgb_u8/rgbplugin.rc create mode 100644 chalk/colorspaces/rgb_u8/templates/.directory create mode 100644 chalk/colorspaces/rgb_u8/templates/Makefile.am create mode 100644 chalk/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png create mode 100644 chalk/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1024x768.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1024x768.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_640x480.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/transparent_640x480.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1024x768.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1024x768.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1280x1024.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1280x1024.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1600x1200.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/white_1600x1200.kra create mode 100644 chalk/colorspaces/rgb_u8/templates/white_640x480.desktop create mode 100644 chalk/colorspaces/rgb_u8/templates/white_640x480.kra create mode 100644 chalk/colorspaces/rgb_u8/tests/Makefile.am create mode 100644 chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp create mode 100644 chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h create mode 100644 chalk/colorspaces/wet/Makefile.am create mode 100644 chalk/colorspaces/wet/chalkwetplugin.desktop create mode 100644 chalk/colorspaces/wet/kis_texture_filter.cc create mode 100644 chalk/colorspaces/wet/kis_texture_filter.h create mode 100644 chalk/colorspaces/wet/kis_texture_painter.cc create mode 100644 chalk/colorspaces/wet/kis_texture_painter.h create mode 100644 chalk/colorspaces/wet/kis_wet_colorspace.cc create mode 100644 chalk/colorspaces/wet/kis_wet_colorspace.h create mode 100644 chalk/colorspaces/wet/kis_wet_palette_widget.cc create mode 100644 chalk/colorspaces/wet/kis_wet_palette_widget.h create mode 100644 chalk/colorspaces/wet/kis_wetness_visualisation_filter.cc create mode 100644 chalk/colorspaces/wet/kis_wetness_visualisation_filter.h create mode 100644 chalk/colorspaces/wet/kis_wetop.cc create mode 100644 chalk/colorspaces/wet/kis_wetop.h create mode 100644 chalk/colorspaces/wet/todo create mode 100644 chalk/colorspaces/wet/wdgpressure.ui create mode 100644 chalk/colorspaces/wet/wet_plugin.cc create mode 100644 chalk/colorspaces/wet/wet_plugin.h create mode 100644 chalk/colorspaces/wet/wetdreams/Makefile create mode 100644 chalk/colorspaces/wet/wetdreams/wetmain.c create mode 100644 chalk/colorspaces/wet/wetdreams/wetpaint.c create mode 100644 chalk/colorspaces/wet/wetdreams/wetpaint.h create mode 100644 chalk/colorspaces/wet/wetdreams/wetphysics.c create mode 100644 chalk/colorspaces/wet/wetdreams/wetphysics.h create mode 100644 chalk/colorspaces/wet/wetdreams/wetpix.c create mode 100644 chalk/colorspaces/wet/wetdreams/wetpix.h create mode 100644 chalk/colorspaces/wet/wetdreams/wettexture.c create mode 100644 chalk/colorspaces/wet/wetdreams/wettexture.h create mode 100644 chalk/colorspaces/wet/wetphysicsfilter.cc create mode 100644 chalk/colorspaces/wet/wetphysicsfilter.h create mode 100644 chalk/colorspaces/wet/wetplugin.rc create mode 100644 chalk/colorspaces/wetsticky/Makefile.am create mode 100644 chalk/colorspaces/wetsticky/README create mode 100644 chalk/colorspaces/wetsticky/TODO create mode 100644 chalk/colorspaces/wetsticky/brushop/Makefile.am create mode 100644 chalk/colorspaces/wetsticky/brushop/README create mode 100644 chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop create mode 100644 chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc create mode 100644 chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h create mode 100644 chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png create mode 100644 chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc create mode 100644 chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h create mode 100644 chalk/colorspaces/wetsticky/chalkwsplugin.desktop create mode 100644 chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc create mode 100644 chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h create mode 100644 chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc create mode 100644 chalk/colorspaces/wetsticky/kis_ws_engine_filter.h create mode 100644 chalk/colorspaces/wetsticky/wet_sticky_plugin.cc create mode 100644 chalk/colorspaces/wetsticky/wet_sticky_plugin.h create mode 100644 chalk/colorspaces/wetsticky/ws/GNU create mode 100644 chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt create mode 100644 chalk/colorspaces/wetsticky/ws/README create mode 100644 chalk/colorspaces/wetsticky/ws/TODO create mode 100644 chalk/colorspaces/wetsticky/ws/after.jpg create mode 100644 chalk/colorspaces/wetsticky/ws/anim.c create mode 100644 chalk/colorspaces/wetsticky/ws/before.jpg create mode 100644 chalk/colorspaces/wetsticky/ws/canvas.c create mode 100644 chalk/colorspaces/wetsticky/ws/canvas.h create mode 100644 chalk/colorspaces/wetsticky/ws/cmap.c create mode 100644 chalk/colorspaces/wetsticky/ws/constants.h create mode 100644 chalk/colorspaces/wetsticky/ws/engine.c create mode 100644 chalk/colorspaces/wetsticky/ws/engine.h create mode 100644 chalk/colorspaces/wetsticky/ws/engine3.c create mode 100644 chalk/colorspaces/wetsticky/ws/load_ppm.c create mode 100644 chalk/colorspaces/wetsticky/ws/main.c create mode 100644 chalk/colorspaces/wetsticky/ws/makefile create mode 100644 chalk/colorspaces/wetsticky/ws/mona.pgm create mode 100644 chalk/colorspaces/wetsticky/ws/ogl_interface.c create mode 100644 chalk/colorspaces/wetsticky/ws/test2.jpg create mode 100644 chalk/colorspaces/wetsticky/ws/test3.jpg create mode 100644 chalk/colorspaces/wetsticky/ws/types.h create mode 100644 chalk/colorspaces/wetsticky/ws/win_interface.h create mode 100644 chalk/colorspaces/wetsticky/ws/x_interface.c create mode 100644 chalk/colorspaces/wetsticky/wstool.ui create mode 100644 chalk/colorspaces/ycbcr_u16/Makefile.am create mode 100644 chalk/colorspaces/ycbcr_u16/chalk_ycbcr_u16_plugin.desktop create mode 100644 chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc create mode 100644 chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h create mode 100644 chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc create mode 100644 chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h create mode 100644 chalk/colorspaces/ycbcr_u8/Makefile.am create mode 100644 chalk/colorspaces/ycbcr_u8/chalk_ycbcr_u8_plugin.desktop create mode 100644 chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc create mode 100644 chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h create mode 100644 chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc create mode 100644 chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h create mode 100644 chalk/configure.in.bot create mode 100644 chalk/configure.in.in create mode 100644 chalk/core/Makefile.am create mode 100755 chalk/core/createdcop.py create mode 100644 chalk/core/kis_adjustment_layer.cc create mode 100644 chalk/core/kis_adjustment_layer.h create mode 100644 chalk/core/kis_alpha_mask.cc create mode 100644 chalk/core/kis_alpha_mask.h create mode 100644 chalk/core/kis_autobrush_resource.cc create mode 100644 chalk/core/kis_autobrush_resource.h create mode 100644 chalk/core/kis_autogradient_resource.cc create mode 100644 chalk/core/kis_autogradient_resource.h create mode 100644 chalk/core/kis_background.cc create mode 100644 chalk/core/kis_background.h create mode 100644 chalk/core/kis_basic_math_toolbox.cpp create mode 100644 chalk/core/kis_basic_math_toolbox.h create mode 100644 chalk/core/kis_boundary.cc create mode 100644 chalk/core/kis_boundary.h create mode 100644 chalk/core/kis_brush.cc create mode 100644 chalk/core/kis_brush.h create mode 100644 chalk/core/kis_change_profile_visitor.h create mode 100644 chalk/core/kis_colorspace_convert_visitor.h create mode 100644 chalk/core/kis_command.cc create mode 100644 chalk/core/kis_command.h create mode 100644 chalk/core/kis_convolution_painter.cc create mode 100644 chalk/core/kis_convolution_painter.h create mode 100644 chalk/core/kis_crop_visitor.h create mode 100644 chalk/core/kis_datamanager.h create mode 100644 chalk/core/kis_exif_info.cc create mode 100644 chalk/core/kis_exif_info.h create mode 100644 chalk/core/kis_exif_value.cc create mode 100644 chalk/core/kis_exif_value.h create mode 100644 chalk/core/kis_fill_painter.cc create mode 100644 chalk/core/kis_fill_painter.h create mode 100644 chalk/core/kis_filter.cc create mode 100644 chalk/core/kis_filter.h create mode 100644 chalk/core/kis_filter_config_widget.cc create mode 100644 chalk/core/kis_filter_config_widget.h create mode 100644 chalk/core/kis_filter_configuration.cc create mode 100644 chalk/core/kis_filter_configuration.h create mode 100644 chalk/core/kis_filter_registry.cc create mode 100644 chalk/core/kis_filter_registry.h create mode 100644 chalk/core/kis_filter_strategy.cc create mode 100644 chalk/core/kis_filter_strategy.h create mode 100644 chalk/core/kis_gradient.cc create mode 100644 chalk/core/kis_gradient.h create mode 100644 chalk/core/kis_gradient_painter.cc create mode 100644 chalk/core/kis_gradient_painter.h create mode 100644 chalk/core/kis_group_layer.cc create mode 100644 chalk/core/kis_group_layer.h create mode 100644 chalk/core/kis_histogram.cc create mode 100644 chalk/core/kis_histogram.h create mode 100644 chalk/core/kis_image.cc create mode 100644 chalk/core/kis_image.h create mode 100644 chalk/core/kis_image_iface.cc create mode 100644 chalk/core/kis_image_iface.h create mode 100644 chalk/core/kis_imagepipe_brush.cc create mode 100644 chalk/core/kis_imagepipe_brush.h create mode 100644 chalk/core/kis_iterator.cc create mode 100644 chalk/core/kis_iterator.h create mode 100644 chalk/core/kis_iteratorpixeltrait.h create mode 100644 chalk/core/kis_iterators_pixel.cc create mode 100644 chalk/core/kis_iterators_pixel.h create mode 100644 chalk/core/kis_layer.cc create mode 100644 chalk/core/kis_layer.h create mode 100644 chalk/core/kis_layer_visitor.h create mode 100644 chalk/core/kis_math_toolbox.cpp create mode 100644 chalk/core/kis_math_toolbox.h create mode 100644 chalk/core/kis_merge_visitor.h create mode 100644 chalk/core/kis_meta_registry.cc create mode 100644 chalk/core/kis_meta_registry.h create mode 100644 chalk/core/kis_nameserver.cc create mode 100644 chalk/core/kis_nameserver.h create mode 100644 chalk/core/kis_paint_device.cc create mode 100644 chalk/core/kis_paint_device.h create mode 100644 chalk/core/kis_paint_device_action.h create mode 100644 chalk/core/kis_paint_device_iface.cc create mode 100644 chalk/core/kis_paint_device_iface.h create mode 100644 chalk/core/kis_paint_layer.cc create mode 100644 chalk/core/kis_paint_layer.h create mode 100644 chalk/core/kis_painter.cc create mode 100644 chalk/core/kis_painter.h create mode 100644 chalk/core/kis_paintop.cc create mode 100644 chalk/core/kis_paintop.h create mode 100644 chalk/core/kis_paintop_registry.cc create mode 100644 chalk/core/kis_paintop_registry.h create mode 100644 chalk/core/kis_palette.cc create mode 100644 chalk/core/kis_palette.h create mode 100644 chalk/core/kis_part_layer_iface.h create mode 100644 chalk/core/kis_pattern.cc create mode 100644 chalk/core/kis_pattern.h create mode 100644 chalk/core/kis_perspective_grid.cpp create mode 100644 chalk/core/kis_perspective_grid.h create mode 100644 chalk/core/kis_perspective_math.cpp create mode 100644 chalk/core/kis_perspective_math.h create mode 100644 chalk/core/kis_perspectivetransform_worker.cpp create mode 100644 chalk/core/kis_perspectivetransform_worker.h create mode 100644 chalk/core/kis_point.h create mode 100644 chalk/core/kis_random_accessor.cpp create mode 100644 chalk/core/kis_random_accessor.h create mode 100644 chalk/core/kis_random_sub_accessor.cpp create mode 100644 chalk/core/kis_random_sub_accessor.h create mode 100644 chalk/core/kis_rect.cc create mode 100644 chalk/core/kis_rect.h create mode 100644 chalk/core/kis_resource.cc create mode 100644 chalk/core/kis_resource.h create mode 100644 chalk/core/kis_rotate_visitor.cc create mode 100644 chalk/core/kis_rotate_visitor.h create mode 100644 chalk/core/kis_scale_visitor.cc create mode 100644 chalk/core/kis_scale_visitor.h create mode 100644 chalk/core/kis_selected_transaction.cc create mode 100644 chalk/core/kis_selected_transaction.h create mode 100644 chalk/core/kis_selection.cc create mode 100644 chalk/core/kis_selection.h create mode 100644 chalk/core/kis_shear_visitor.h create mode 100644 chalk/core/kis_strategy_move.cc create mode 100644 chalk/core/kis_strategy_move.h create mode 100644 chalk/core/kis_substrate.h create mode 100644 chalk/core/kis_thread.h create mode 100644 chalk/core/kis_thread_pool.cc create mode 100644 chalk/core/kis_thread_pool.h create mode 100644 chalk/core/kis_transaction.cc create mode 100644 chalk/core/kis_transaction.h create mode 100644 chalk/core/kis_transform_visitor.h create mode 100644 chalk/core/kis_transform_worker.cc create mode 100644 chalk/core/kis_transform_worker.h create mode 100644 chalk/core/kis_types.h create mode 100644 chalk/core/kis_vec.cc create mode 100644 chalk/core/kis_vec.h create mode 100644 chalk/core/tests/Makefile.am create mode 100644 chalk/core/tests/kis_filter_configuration_tester.cc create mode 100644 chalk/core/tests/kis_filter_configuration_tester.h create mode 100644 chalk/core/tests/kis_image_tester.cpp create mode 100644 chalk/core/tests/kis_image_tester.h create mode 100644 chalk/core/tests/kis_integer_maths_tester.cpp create mode 100644 chalk/core/tests/kis_integer_maths_tester.h create mode 100644 chalk/core/tiles/Makefile.am create mode 100644 chalk/core/tiles/kis_memento.cc create mode 100644 chalk/core/tiles/kis_memento.h create mode 100644 chalk/core/tiles/kis_tile.cc create mode 100644 chalk/core/tiles/kis_tile.h create mode 100644 chalk/core/tiles/kis_tile_global.h create mode 100644 chalk/core/tiles/kis_tiled_random_accessor.cc create mode 100644 chalk/core/tiles/kis_tiled_random_accessor.h create mode 100644 chalk/core/tiles/kis_tileddatamanager.cc create mode 100644 chalk/core/tiles/kis_tileddatamanager.h create mode 100644 chalk/core/tiles/kis_tiledhlineiterator.cc create mode 100644 chalk/core/tiles/kis_tilediterator.cc create mode 100644 chalk/core/tiles/kis_tilediterator.h create mode 100644 chalk/core/tiles/kis_tiledrectiterator.cc create mode 100644 chalk/core/tiles/kis_tiledvlineiterator.cc create mode 100644 chalk/core/tiles/kis_tilemanager.cc create mode 100644 chalk/core/tiles/kis_tilemanager.h create mode 100644 chalk/core/tiles/tests/Makefile.am create mode 100644 chalk/core/tiles/tests/kis_tiled_data_tester.cpp create mode 100644 chalk/core/tiles/tests/kis_tiled_data_tester.h create mode 100644 chalk/data/Makefile.am create mode 100644 chalk/data/README create mode 100644 chalk/data/brushes/10x10square.gbr create mode 100644 chalk/data/brushes/10x10squareBlur.gbr create mode 100644 chalk/data/brushes/11circle.gbr create mode 100644 chalk/data/brushes/11fcircle.gbr create mode 100644 chalk/data/brushes/13circle.gbr create mode 100644 chalk/data/brushes/13fcircle.gbr create mode 100644 chalk/data/brushes/15circle.gbr create mode 100644 chalk/data/brushes/15fcircle.gbr create mode 100644 chalk/data/brushes/17circle.gbr create mode 100644 chalk/data/brushes/17fcircle.gbr create mode 100644 chalk/data/brushes/19circle.gbr create mode 100644 chalk/data/brushes/19fcircle.gbr create mode 100644 chalk/data/brushes/1circle.gbr create mode 100644 chalk/data/brushes/20x20square.gbr create mode 100644 chalk/data/brushes/20x20squareBlur.gbr create mode 100644 chalk/data/brushes/3circle.gbr create mode 100644 chalk/data/brushes/3fcircle.gbr create mode 100644 chalk/data/brushes/5circle.gbr create mode 100644 chalk/data/brushes/5fcircle.gbr create mode 100644 chalk/data/brushes/5x5square.gbr create mode 100644 chalk/data/brushes/5x5squareBlur.gbr create mode 100644 chalk/data/brushes/7circle.gbr create mode 100644 chalk/data/brushes/7fcircle.gbr create mode 100644 chalk/data/brushes/9circle.gbr create mode 100644 chalk/data/brushes/9fcircle.gbr create mode 100644 chalk/data/brushes/BRUSHES.README create mode 100644 chalk/data/brushes/COPYING create mode 100644 chalk/data/brushes/DStar11.gbr create mode 100644 chalk/data/brushes/DStar17.gbr create mode 100644 chalk/data/brushes/DStar25.gbr create mode 100644 chalk/data/brushes/Makefile.am create mode 100644 chalk/data/brushes/SketchBrush-16.gih create mode 100644 chalk/data/brushes/SketchBrush-32.gih create mode 100644 chalk/data/brushes/SketchBrush-64.gih create mode 100644 chalk/data/brushes/callig1.gbr create mode 100644 chalk/data/brushes/callig2.gbr create mode 100644 chalk/data/brushes/callig3.gbr create mode 100644 chalk/data/brushes/callig4.gbr create mode 100644 chalk/data/brushes/confetti.gbr create mode 100644 chalk/data/brushes/confetti.gih create mode 100644 chalk/data/brushes/cursor.gbr create mode 100644 chalk/data/brushes/cursor_big_lb.gbr create mode 100644 chalk/data/brushes/cursor_big_lw.gbr create mode 100644 chalk/data/brushes/cursor_big_rb.gbr create mode 100644 chalk/data/brushes/cursor_big_rw.gbr create mode 100644 chalk/data/brushes/cursor_lw.gbr create mode 100644 chalk/data/brushes/cursor_resize_diag_1.gbr create mode 100644 chalk/data/brushes/cursor_resize_diag_2.gbr create mode 100644 chalk/data/brushes/cursor_resize_hor.gbr create mode 100644 chalk/data/brushes/cursor_resize_vert.gbr create mode 100644 chalk/data/brushes/cursor_rw.gbr create mode 100644 chalk/data/brushes/cursor_small_lb.gbr create mode 100644 chalk/data/brushes/cursor_small_lw.gbr create mode 100644 chalk/data/brushes/cursor_small_rb.gbr create mode 100644 chalk/data/brushes/cursor_small_rw.gbr create mode 100644 chalk/data/brushes/cursor_tiny_lw.gbr create mode 100644 chalk/data/brushes/cursor_tiny_rw.gbr create mode 100644 chalk/data/brushes/cursor_up.gbr create mode 100644 chalk/data/brushes/dunes.gbr create mode 100644 chalk/data/brushes/feltpen.gih create mode 100644 chalk/data/brushes/galaxy.gbr create mode 100644 chalk/data/brushes/galaxy_big.gbr create mode 100644 chalk/data/brushes/galaxy_small.gbr create mode 100644 chalk/data/brushes/hsparks.gih create mode 100644 chalk/data/brushes/pepper.gbr create mode 100644 chalk/data/brushes/pixel.gbr create mode 100644 chalk/data/brushes/vine.gih create mode 100644 chalk/data/chalk_filter.desktop create mode 100644 chalk/data/chalk_paintop.desktop create mode 100644 chalk/data/chalk_plugin.desktop create mode 100644 chalk/data/chalk_tool.desktop create mode 100644 chalk/data/gradients/Abstract_1.ggr create mode 100644 chalk/data/gradients/Abstract_2.ggr create mode 100644 chalk/data/gradients/Abstract_3.ggr create mode 100644 chalk/data/gradients/Aneurism.ggr create mode 100644 chalk/data/gradients/Blinds.ggr create mode 100644 chalk/data/gradients/Blue_Green.ggr create mode 100644 chalk/data/gradients/Browns.ggr create mode 100644 chalk/data/gradients/Brushed_Aluminium.ggr create mode 100644 chalk/data/gradients/Burning_Paper.ggr create mode 100644 chalk/data/gradients/Burning_Transparency.ggr create mode 100644 chalk/data/gradients/CD.ggr create mode 100644 chalk/data/gradients/CD_Half.ggr create mode 100644 chalk/data/gradients/Caribbean_Blues.ggr create mode 100644 chalk/data/gradients/Coffee.ggr create mode 100644 chalk/data/gradients/Cold_Steel.ggr create mode 100644 chalk/data/gradients/Cold_Steel_2.ggr create mode 100644 chalk/data/gradients/Crown_molding.ggr create mode 100644 chalk/data/gradients/Dark_1.ggr create mode 100644 chalk/data/gradients/Deep_Sea.ggr create mode 100644 chalk/data/gradients/Default.ggr create mode 100644 chalk/data/gradients/Flare_Glow_Angular_1.ggr create mode 100644 chalk/data/gradients/Flare_Glow_Radial_1.ggr create mode 100644 chalk/data/gradients/Flare_Glow_Radial_2.ggr create mode 100644 chalk/data/gradients/Flare_Glow_Radial_3.ggr create mode 100644 chalk/data/gradients/Flare_Glow_Radial_4.ggr create mode 100644 chalk/data/gradients/Flare_Radial_101.ggr create mode 100644 chalk/data/gradients/Flare_Radial_102.ggr create mode 100644 chalk/data/gradients/Flare_Radial_103.ggr create mode 100644 chalk/data/gradients/Flare_Rays_Radial_1.ggr create mode 100644 chalk/data/gradients/Flare_Rays_Radial_2.ggr create mode 100644 chalk/data/gradients/Flare_Rays_Size_1.ggr create mode 100644 chalk/data/gradients/Flare_Sizefac_101.ggr create mode 100644 chalk/data/gradients/Four_bars.ggr create mode 100644 chalk/data/gradients/French_flag.ggr create mode 100644 chalk/data/gradients/French_flag_smooth.ggr create mode 100644 chalk/data/gradients/Full_saturation_spectrum_CCW.ggr create mode 100644 chalk/data/gradients/Full_saturation_spectrum_CW.ggr create mode 100644 chalk/data/gradients/German_flag.ggr create mode 100644 chalk/data/gradients/German_flag_smooth.ggr create mode 100644 chalk/data/gradients/Golden.ggr create mode 100644 chalk/data/gradients/Greens.ggr create mode 100644 chalk/data/gradients/Horizon_1.ggr create mode 100644 chalk/data/gradients/Horizon_2.ggr create mode 100644 chalk/data/gradients/Incandescent.ggr create mode 100644 chalk/data/gradients/Land_1.ggr create mode 100644 chalk/data/gradients/Land_and_Sea.ggr create mode 100644 chalk/data/gradients/Makefile.am create mode 100644 chalk/data/gradients/Metallic_Something.ggr create mode 100644 chalk/data/gradients/Mexican_flag.ggr create mode 100644 chalk/data/gradients/Mexican_flag_smooth.ggr create mode 100644 chalk/data/gradients/Nauseating_Headache.ggr create mode 100644 chalk/data/gradients/Neon_Cyan.ggr create mode 100644 chalk/data/gradients/Neon_Green.ggr create mode 100644 chalk/data/gradients/Neon_Yellow.ggr create mode 100644 chalk/data/gradients/Pastel_Rainbow.ggr create mode 100644 chalk/data/gradients/Pastels.ggr create mode 100644 chalk/data/gradients/Purples.ggr create mode 100644 chalk/data/gradients/Radial_Eyeball_Blue.ggr create mode 100644 chalk/data/gradients/Radial_Eyeball_Brown.ggr create mode 100644 chalk/data/gradients/Radial_Eyeball_Green.ggr create mode 100644 chalk/data/gradients/Radial_Glow_1.ggr create mode 100644 chalk/data/gradients/Radial_Rainbow_Hoop.ggr create mode 100644 chalk/data/gradients/Romanian_flag.ggr create mode 100644 chalk/data/gradients/Romanian_flag_smooth.ggr create mode 100644 chalk/data/gradients/Rounded_edge.ggr create mode 100644 chalk/data/gradients/Shadows_1.ggr create mode 100644 chalk/data/gradients/Shadows_2.ggr create mode 100644 chalk/data/gradients/Shadows_3.ggr create mode 100644 chalk/data/gradients/Skyline.ggr create mode 100644 chalk/data/gradients/Skyline_polluted.ggr create mode 100644 chalk/data/gradients/Square_Wood_Frame.ggr create mode 100644 chalk/data/gradients/Sunrise.ggr create mode 100644 chalk/data/gradients/Three_bars_sin.ggr create mode 100644 chalk/data/gradients/Tropical_Colors.ggr create mode 100644 chalk/data/gradients/Tube_Red.ggr create mode 100644 chalk/data/gradients/Wood_1.ggr create mode 100644 chalk/data/gradients/Wood_2.ggr create mode 100644 chalk/data/gradients/Yellow_Contrast.ggr create mode 100644 chalk/data/gradients/Yellow_Orange.ggr create mode 100644 chalk/data/images/Azay-Le-Rideau.jpg create mode 100644 chalk/data/images/Makefile.am create mode 100644 chalk/data/images/WeyDesc.png create mode 100644 chalk/data/images/evenings.jpg create mode 100644 chalk/data/images/hakonepa.jpg create mode 100644 chalk/data/images/hiro_awate.jpg create mode 100644 chalk/data/images/paintbrush.png create mode 100644 chalk/data/images/previewfilter.png create mode 100644 chalk/data/palettes/40_Colors.gpl create mode 100644 chalk/data/palettes/Anchor.gpl create mode 100644 chalk/data/palettes/Bears.gpl create mode 100644 chalk/data/palettes/Bgold.gpl create mode 100644 chalk/data/palettes/Blues.gpl create mode 100644 chalk/data/palettes/Borders.gpl create mode 100644 chalk/data/palettes/Browns_And_Yellows.gpl create mode 100644 chalk/data/palettes/Caramel.gpl create mode 100644 chalk/data/palettes/Cascade.gpl create mode 100644 chalk/data/palettes/China.gpl create mode 100644 chalk/data/palettes/Coldfire.gpl create mode 100644 chalk/data/palettes/Cool_Colors.gpl create mode 100644 chalk/data/palettes/Cranes.gpl create mode 100644 chalk/data/palettes/DMC.gpl create mode 100644 chalk/data/palettes/Dark_pastels.gpl create mode 100644 chalk/data/palettes/Default.gpl create mode 100644 chalk/data/palettes/Ega.gpl create mode 100644 chalk/data/palettes/Firecode.gpl create mode 100644 chalk/data/palettes/Gold.gpl create mode 100644 chalk/data/palettes/GrayViolet.gpl create mode 100644 chalk/data/palettes/Grayblue.gpl create mode 100644 chalk/data/palettes/Grays.gpl create mode 100644 chalk/data/palettes/Greens.gpl create mode 100644 chalk/data/palettes/Hilite.gpl create mode 100644 chalk/data/palettes/Khaki.gpl create mode 100644 chalk/data/palettes/Lights.gpl create mode 100644 chalk/data/palettes/Madeira.gpl create mode 100644 chalk/data/palettes/Makefile.am create mode 100644 chalk/data/palettes/Muted.gpl create mode 100644 chalk/data/palettes/Named_Colors.gpl create mode 100644 chalk/data/palettes/News3.gpl create mode 100644 chalk/data/palettes/Op2.gpl create mode 100644 chalk/data/palettes/Paintjet.gpl create mode 100644 chalk/data/palettes/Pantone_Coated_Approx.gpl create mode 100644 chalk/data/palettes/Pastels.gpl create mode 100644 chalk/data/palettes/Plasma.gpl create mode 100644 chalk/data/palettes/Reds.gpl create mode 100644 chalk/data/palettes/Reds_And_Purples.gpl create mode 100644 chalk/data/palettes/Royal.gpl create mode 100644 chalk/data/palettes/Topographic.gpl create mode 100644 chalk/data/palettes/Visibone.gpl create mode 100644 chalk/data/palettes/Visibone_2.gpl create mode 100644 chalk/data/palettes/Volcano.gpl create mode 100644 chalk/data/palettes/Warm_Colors.gpl create mode 100644 chalk/data/palettes/Web.gpl create mode 100644 chalk/data/palettes/new_kde.gpl create mode 100644 chalk/data/patterns/3dgreen.pat create mode 100644 chalk/data/patterns/Craters.pat create mode 100644 chalk/data/patterns/Makefile.am create mode 100644 chalk/data/patterns/Moonfoot.pat create mode 100644 chalk/data/patterns/Stripes1px.pat create mode 100644 chalk/data/patterns/Stripes2px.pat create mode 100644 chalk/data/patterns/amethyst.pat create mode 100644 chalk/data/patterns/bark.pat create mode 100644 chalk/data/patterns/blue.pat create mode 100644 chalk/data/patterns/bluegrid.pat create mode 100644 chalk/data/patterns/bluesquares.pat create mode 100644 chalk/data/patterns/blueweb.pat create mode 100644 chalk/data/patterns/brick.pat create mode 100644 chalk/data/patterns/burlap.pat create mode 100644 chalk/data/patterns/burlwood.pat create mode 100644 chalk/data/patterns/choc_swirl.pat create mode 100644 chalk/data/patterns/corkboard.pat create mode 100644 chalk/data/patterns/cracked.pat create mode 100644 chalk/data/patterns/crinklepaper.pat create mode 100644 chalk/data/patterns/electric.pat create mode 100644 chalk/data/patterns/fibers.pat create mode 100644 chalk/data/patterns/granite1.pat create mode 100644 chalk/data/patterns/ground1.pat create mode 100644 chalk/data/patterns/ice.pat create mode 100644 chalk/data/patterns/java.pat create mode 100644 chalk/data/patterns/leather.pat create mode 100644 chalk/data/patterns/leaves.pat create mode 100644 chalk/data/patterns/leopard.pat create mode 100644 chalk/data/patterns/lightning.pat create mode 100644 chalk/data/patterns/marble1.pat create mode 100644 chalk/data/patterns/marble2.pat create mode 100644 chalk/data/patterns/marble3.pat create mode 100644 chalk/data/patterns/nops.pat create mode 100644 chalk/data/patterns/paper.pat create mode 100644 chalk/data/patterns/parque1.pat create mode 100644 chalk/data/patterns/parque2.pat create mode 100644 chalk/data/patterns/parque3.pat create mode 100644 chalk/data/patterns/pastel.pat create mode 100644 chalk/data/patterns/pine.pat create mode 100644 chalk/data/patterns/pink_marble.pat create mode 100644 chalk/data/patterns/pool.pat create mode 100644 chalk/data/patterns/qube1.pat create mode 100644 chalk/data/patterns/rain.pat create mode 100644 chalk/data/patterns/recessed.pat create mode 100644 chalk/data/patterns/redcube.pat create mode 100644 chalk/data/patterns/rock.pat create mode 100644 chalk/data/patterns/sky.pat create mode 100644 chalk/data/patterns/slate.pat create mode 100644 chalk/data/patterns/sm_squares.pat create mode 100644 chalk/data/patterns/starfield.pat create mode 100644 chalk/data/patterns/stone33.pat create mode 100644 chalk/data/patterns/terra.pat create mode 100644 chalk/data/patterns/walnut.pat create mode 100644 chalk/data/patterns/warning.pat create mode 100644 chalk/data/patterns/wood1.pat create mode 100644 chalk/data/patterns/wood2.pat create mode 100644 chalk/data/patterns/wood3.pat create mode 100644 chalk/data/patterns/wood4.pat create mode 100644 chalk/data/patterns/wood5.pat create mode 100644 chalk/data/profiles/Adobe.icm create mode 100644 chalk/data/profiles/Apple.icm create mode 100644 chalk/data/profiles/CIE.icm create mode 100644 chalk/data/profiles/CMY.icm create mode 100644 chalk/data/profiles/ColorMatch.icm create mode 100644 chalk/data/profiles/Makefile.am create mode 100644 chalk/data/profiles/NTSC.icm create mode 100644 chalk/data/profiles/PAL.icm create mode 100644 chalk/data/profiles/README create mode 100644 chalk/data/profiles/SMPTE-C.icm create mode 100644 chalk/data/profiles/WideGamut.icm create mode 100644 chalk/data/profiles/cmyk.icm create mode 100644 chalk/data/profiles/fogra27l.icm create mode 100644 chalk/data/profiles/lcmslabi.icm create mode 100644 chalk/data/profiles/lcmsxyzi.icm create mode 100644 chalk/data/profiles/monoscnr.icm create mode 100644 chalk/data/profiles/sRGB.icm create mode 100644 chalk/data/profiles/srgb_color_space_profile.icm create mode 100644 chalk/data/profiles/srgbspac.icm create mode 100644 chalk/data/profiles/tifflab8spac.icm create mode 100644 chalk/data/profiles/ycc601.icm create mode 100644 chalk/data/profiles/ycc709.icm create mode 100644 chalk/data/templates/.directory create mode 100644 chalk/design.h create mode 100644 chalk/doc/DESIGN.obsolete create mode 100644 chalk/doc/Developing Chalk Plugins.odt create mode 100644 chalk/doc/autoextending paintdevices create mode 100644 chalk/doc/background_paper.txt create mode 100644 chalk/doc/brush.txt create mode 100644 chalk/doc/chalk-features create mode 100644 chalk/doc/chalk.kpr create mode 100644 chalk/doc/chalk.pdf create mode 100644 chalk/doc/chalk.xmi create mode 100644 chalk/doc/channels_masks_selections create mode 100644 chalk/doc/colordiff create mode 100644 chalk/doc/colorspaces.xmi create mode 100644 chalk/doc/colorstrategyAPI create mode 100644 chalk/doc/controller.xmi create mode 100644 chalk/doc/coordinates.txt create mode 100644 chalk/doc/dirty.txt create mode 100644 chalk/doc/doc-outline create mode 100644 chalk/doc/histograms.xmi create mode 100644 chalk/doc/hooks create mode 100644 chalk/doc/howtofilters.txt create mode 100644 chalk/doc/impexp.txt create mode 100644 chalk/doc/large_files create mode 100644 chalk/doc/layersupdatesignals.flw create mode 100644 chalk/doc/manual/chalk.kwd create mode 100644 chalk/doc/oasis create mode 100644 chalk/doc/paint_device.txt create mode 100644 chalk/doc/palettedesign.txt create mode 100644 chalk/doc/plugins.txt create mode 100644 chalk/doc/profiles.txt create mode 100644 chalk/doc/resolution.txt create mode 100644 chalk/doc/scripts/dcop.py create mode 100644 chalk/doc/sdk create mode 100644 chalk/doc/selections create mode 100644 chalk/doc/the preview widget create mode 100644 chalk/doc/transform_undo.txt create mode 100644 chalk/dtd/Makefile.am create mode 100644 chalk/dtd/chalk.dtd create mode 100755 chalk/extracti18n.pl create mode 100644 chalk/main.cc create mode 100644 chalk/pics/Makefile.am create mode 100644 chalk/pics/chalk.svg create mode 100644 chalk/pics/deletelayer.png create mode 100644 chalk/pics/height.png create mode 100644 chalk/pics/hi128-app-chalk.png create mode 100644 chalk/pics/hi16-app-chalk.png create mode 100644 chalk/pics/hi22-app-chalk.png create mode 100644 chalk/pics/hi32-app-chalk.png create mode 100644 chalk/pics/hi48-app-chalk.png create mode 100644 chalk/pics/hi64-app-chalk.png create mode 100644 chalk/pics/linked.png create mode 100644 chalk/pics/locked.png create mode 100644 chalk/pics/lowerlayer.png create mode 100644 chalk/pics/newlayer.png create mode 100644 chalk/pics/novisible.png create mode 100644 chalk/pics/raiselayer.png create mode 100644 chalk/pics/shade.png create mode 100644 chalk/pics/tablet.png create mode 100644 chalk/pics/tool_screenshot.png create mode 100644 chalk/pics/unlinked.png create mode 100644 chalk/pics/unlocked.png create mode 100644 chalk/pics/visible.png create mode 100644 chalk/pics/width.png create mode 100644 chalk/plugins/Makefile.am create mode 100644 chalk/plugins/README create mode 100644 chalk/plugins/configure.in.in create mode 100644 chalk/plugins/filters/Makefile.am create mode 100644 chalk/plugins/filters/blur/Makefile.am create mode 100644 chalk/plugins/filters/blur/blur.cc create mode 100644 chalk/plugins/filters/blur/blur.h create mode 100644 chalk/plugins/filters/blur/chalkblurfilter.desktop create mode 100644 chalk/plugins/filters/blur/kis_blur_filter.cc create mode 100644 chalk/plugins/filters/blur/kis_blur_filter.h create mode 100644 chalk/plugins/filters/blur/kis_wdg_blur.cc create mode 100644 chalk/plugins/filters/blur/kis_wdg_blur.h create mode 100644 chalk/plugins/filters/blur/wdgblur.ui create mode 100644 chalk/plugins/filters/bumpmap/Makefile.am create mode 100644 chalk/plugins/filters/bumpmap/bumpmap.cc create mode 100644 chalk/plugins/filters/bumpmap/bumpmap.h create mode 100644 chalk/plugins/filters/bumpmap/chalkbumpmapfilter.desktop create mode 100644 chalk/plugins/filters/bumpmap/wdgbumpmap.ui create mode 100644 chalk/plugins/filters/cimg/.kdev_ignore create mode 100644 chalk/plugins/filters/cimg/CImg.h create mode 100644 chalk/plugins/filters/cimg/Makefile.am create mode 100644 chalk/plugins/filters/cimg/chalkcimg.desktop create mode 100644 chalk/plugins/filters/cimg/kis_cimg_filter.cc create mode 100644 chalk/plugins/filters/cimg/kis_cimg_filter.h create mode 100644 chalk/plugins/filters/cimg/kis_cimg_plugin.cc create mode 100644 chalk/plugins/filters/cimg/kis_cimg_plugin.h create mode 100644 chalk/plugins/filters/cimg/kis_cimgconfig_widget.cc create mode 100644 chalk/plugins/filters/cimg/kis_cimgconfig_widget.h create mode 100644 chalk/plugins/filters/cimg/wdg_cimg.ui create mode 100644 chalk/plugins/filters/colorify/Colorify.cpp create mode 100644 chalk/plugins/filters/colorify/Colorify.h create mode 100644 chalk/plugins/filters/colorify/KisWdgColorify.cpp create mode 100644 chalk/plugins/filters/colorify/KisWdgColorify.h create mode 100644 chalk/plugins/filters/colorify/Makefile.am create mode 100644 chalk/plugins/filters/colorify/WdgColorifyBase.ui create mode 100644 chalk/plugins/filters/colorify/chalkcolorifyfilter.desktop create mode 100644 chalk/plugins/filters/colors/Makefile.am create mode 100644 chalk/plugins/filters/colors/chalkextensioncolorsfilters.desktop create mode 100644 chalk/plugins/filters/colors/colors.cc create mode 100644 chalk/plugins/filters/colors/colors.h create mode 100644 chalk/plugins/filters/colors/kis_color_to_alpha.cc create mode 100644 chalk/plugins/filters/colors/kis_color_to_alpha.h create mode 100644 chalk/plugins/filters/colors/kis_minmax_filters.cc create mode 100644 chalk/plugins/filters/colors/kis_minmax_filters.h create mode 100644 chalk/plugins/filters/colors/kis_wdg_color_to_alpha.cc create mode 100644 chalk/plugins/filters/colors/kis_wdg_color_to_alpha.h create mode 100644 chalk/plugins/filters/colors/wdgcolortoalphabase.ui create mode 100644 chalk/plugins/filters/colorsfilters/Makefile.am create mode 100644 chalk/plugins/filters/colorsfilters/chalkcolorsfilter.desktop create mode 100644 chalk/plugins/filters/colorsfilters/colorsfilters.cc create mode 100644 chalk/plugins/filters/colorsfilters/colorsfilters.h create mode 100644 chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc create mode 100644 chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h create mode 100644 chalk/plugins/filters/colorsfilters/kis_perchannel_filter.cc create mode 100644 chalk/plugins/filters/colorsfilters/kis_perchannel_filter.h create mode 100644 chalk/plugins/filters/colorsfilters/wdg_brightness_contrast.ui create mode 100644 chalk/plugins/filters/colorsfilters/wdg_perchannel.ui create mode 100644 chalk/plugins/filters/convolutionfilters/Makefile.am create mode 100644 chalk/plugins/filters/convolutionfilters/chalkconvolutionfilters.desktop create mode 100644 chalk/plugins/filters/convolutionfilters/convolutionfilters.cc create mode 100644 chalk/plugins/filters/convolutionfilters/convolutionfilters.h create mode 100644 chalk/plugins/filters/convolutionfilters/kis_convolution_filter.cc create mode 100644 chalk/plugins/filters/convolutionfilters/kis_convolution_filter.h create mode 100644 chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc create mode 100644 chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h create mode 100644 chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui create mode 100644 chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc create mode 100644 chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h create mode 100644 chalk/plugins/filters/cubismfilter/Makefile.am create mode 100644 chalk/plugins/filters/cubismfilter/chalkcubismfilter.desktop create mode 100644 chalk/plugins/filters/cubismfilter/kis_cubism_filter.cc create mode 100644 chalk/plugins/filters/cubismfilter/kis_cubism_filter.h create mode 100644 chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc create mode 100644 chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h create mode 100644 chalk/plugins/filters/cubismfilter/kis_polygon.cc create mode 100644 chalk/plugins/filters/cubismfilter/kis_polygon.h create mode 100644 chalk/plugins/filters/embossfilter/Makefile.am create mode 100644 chalk/plugins/filters/embossfilter/chalkembossfilter.desktop create mode 100644 chalk/plugins/filters/embossfilter/kis_emboss_filter.cc create mode 100644 chalk/plugins/filters/embossfilter/kis_emboss_filter.h create mode 100644 chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc create mode 100644 chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.h create mode 100644 chalk/plugins/filters/example/Makefile.am create mode 100644 chalk/plugins/filters/example/chalkexample.desktop create mode 100644 chalk/plugins/filters/example/example.cc create mode 100644 chalk/plugins/filters/example/example.h create mode 100644 chalk/plugins/filters/fastcolortransfer/Makefile.am create mode 100644 chalk/plugins/filters/fastcolortransfer/chalkfastcolortransfer.desktop create mode 100644 chalk/plugins/filters/fastcolortransfer/fastcolortransfer.cc create mode 100644 chalk/plugins/filters/fastcolortransfer/fastcolortransfer.h create mode 100644 chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp create mode 100644 chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h create mode 100644 chalk/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui create mode 100644 chalk/plugins/filters/halftone/kis_halftone.cpp create mode 100644 chalk/plugins/filters/halftone/kis_halftone.h create mode 100644 chalk/plugins/filters/imageenhancement/Makefile.am create mode 100644 chalk/plugins/filters/imageenhancement/chalkimageenhancement.desktop create mode 100644 chalk/plugins/filters/imageenhancement/imageenhancement.cpp create mode 100644 chalk/plugins/filters/imageenhancement/imageenhancement.h create mode 100644 chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp create mode 100644 chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.h create mode 100644 chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp create mode 100644 chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h create mode 100644 chalk/plugins/filters/lenscorrectionfilter/Makefile.am create mode 100644 chalk/plugins/filters/lenscorrectionfilter/chalklenscorrectionfilter.desktop create mode 100644 chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp create mode 100644 chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h create mode 100644 chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc create mode 100644 chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h create mode 100644 chalk/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui create mode 100644 chalk/plugins/filters/levelfilter/Makefile.am create mode 100644 chalk/plugins/filters/levelfilter/chalklevelfilter.desktop create mode 100644 chalk/plugins/filters/levelfilter/kgradientslider.cc create mode 100644 chalk/plugins/filters/levelfilter/kgradientslider.h create mode 100644 chalk/plugins/filters/levelfilter/kis_level_filter.cc create mode 100644 chalk/plugins/filters/levelfilter/kis_level_filter.h create mode 100644 chalk/plugins/filters/levelfilter/levelfilter.cc create mode 100644 chalk/plugins/filters/levelfilter/levelfilter.h create mode 100644 chalk/plugins/filters/levelfilter/wdg_level.ui create mode 100644 chalk/plugins/filters/noisefilter/Makefile.am create mode 100644 chalk/plugins/filters/noisefilter/chalknoisefilter.desktop create mode 100644 chalk/plugins/filters/noisefilter/kis_wdg_noise.cpp create mode 100644 chalk/plugins/filters/noisefilter/kis_wdg_noise.h create mode 100644 chalk/plugins/filters/noisefilter/noisefilter.cc create mode 100644 chalk/plugins/filters/noisefilter/noisefilter.h create mode 100644 chalk/plugins/filters/noisefilter/wdgnoiseoptions.ui create mode 100644 chalk/plugins/filters/oilpaintfilter/Makefile.am create mode 100644 chalk/plugins/filters/oilpaintfilter/chalkoilpaintfilter.desktop create mode 100644 chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc create mode 100644 chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h create mode 100644 chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc create mode 100644 chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h create mode 100644 chalk/plugins/filters/pixelizefilter/Makefile.am create mode 100644 chalk/plugins/filters/pixelizefilter/chalkpixelizefilter.desktop create mode 100644 chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.cc create mode 100644 chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.h create mode 100644 chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc create mode 100644 chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h create mode 100644 chalk/plugins/filters/raindropsfilter/Makefile.am create mode 100644 chalk/plugins/filters/raindropsfilter/chalkraindropsfilter.desktop create mode 100644 chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.cc create mode 100644 chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.h create mode 100644 chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc create mode 100644 chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h create mode 100644 chalk/plugins/filters/randompickfilter/Makefile.am create mode 100644 chalk/plugins/filters/randompickfilter/chalkrandompickfilter.desktop create mode 100644 chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp create mode 100644 chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.h create mode 100644 chalk/plugins/filters/randompickfilter/randompickfilter.cc create mode 100644 chalk/plugins/filters/randompickfilter/randompickfilter.h create mode 100644 chalk/plugins/filters/randompickfilter/wdgrandompickoptions.ui create mode 100644 chalk/plugins/filters/roundcorners/Makefile.am create mode 100644 chalk/plugins/filters/roundcorners/chalkroundcornersfilter.desktop create mode 100644 chalk/plugins/filters/roundcorners/kis_round_corners_filter.cc create mode 100644 chalk/plugins/filters/roundcorners/kis_round_corners_filter.h create mode 100644 chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc create mode 100644 chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h create mode 100644 chalk/plugins/filters/smalltilesfilter/Makefile.am create mode 100644 chalk/plugins/filters/smalltilesfilter/chalksmalltilesfilter.desktop create mode 100644 chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc create mode 100644 chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h create mode 100644 chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc create mode 100644 chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h create mode 100644 chalk/plugins/filters/sobelfilter/Makefile.am create mode 100644 chalk/plugins/filters/sobelfilter/chalksobelfilter.desktop create mode 100644 chalk/plugins/filters/sobelfilter/kis_sobel_filter.cc create mode 100644 chalk/plugins/filters/sobelfilter/kis_sobel_filter.h create mode 100644 chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc create mode 100644 chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h create mode 100644 chalk/plugins/filters/threadtest/Makefile.am create mode 100644 chalk/plugins/filters/threadtest/chalkthreadtest.desktop create mode 100644 chalk/plugins/filters/threadtest/threadtest.cc create mode 100644 chalk/plugins/filters/threadtest/threadtest.h create mode 100644 chalk/plugins/filters/unsharp/Makefile.am create mode 100644 chalk/plugins/filters/unsharp/chalkunsharpfilter.desktop create mode 100644 chalk/plugins/filters/unsharp/kis_unsharp_filter.cc create mode 100644 chalk/plugins/filters/unsharp/kis_unsharp_filter.h create mode 100644 chalk/plugins/filters/unsharp/kis_wdg_unsharp.cc create mode 100644 chalk/plugins/filters/unsharp/kis_wdg_unsharp.h create mode 100644 chalk/plugins/filters/unsharp/unsharp.cc create mode 100644 chalk/plugins/filters/unsharp/unsharp.h create mode 100644 chalk/plugins/filters/unsharp/wdgunsharp.ui create mode 100644 chalk/plugins/filters/wavefilter/Makefile.am create mode 100644 chalk/plugins/filters/wavefilter/chalkwavefilter.desktop create mode 100644 chalk/plugins/filters/wavefilter/kis_wdg_wave.cpp create mode 100644 chalk/plugins/filters/wavefilter/kis_wdg_wave.h create mode 100644 chalk/plugins/filters/wavefilter/wavefilter.cc create mode 100644 chalk/plugins/filters/wavefilter/wavefilter.h create mode 100644 chalk/plugins/filters/wavefilter/wdgwaveoptions.ui create mode 100644 chalk/plugins/paintops/Makefile.am create mode 100644 chalk/plugins/paintops/defaultpaintops/Makefile.am create mode 100644 chalk/plugins/paintops/defaultpaintops/README create mode 100644 chalk/plugins/paintops/defaultpaintops/airbrush.png create mode 100644 chalk/plugins/paintops/defaultpaintops/chalkdefaultpaintops.desktop create mode 100644 chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h create mode 100644 chalk/plugins/paintops/defaultpaintops/eraser.png create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_airbrushop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_airbrushop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_brushop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_brushop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_convolveop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_convolveop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_duplicateop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_duplicateop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_eraseop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_eraseop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_penop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_penop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_smudgeop.cc create mode 100644 chalk/plugins/paintops/defaultpaintops/kis_smudgeop.h create mode 100644 chalk/plugins/paintops/defaultpaintops/paintbrush.png create mode 100644 chalk/plugins/paintops/defaultpaintops/pencil.png create mode 100644 chalk/plugins/paintops/defaultpaintops/src/README create mode 100644 chalk/plugins/paintops/defaultpaintops/src/pencil_01.svg create mode 100644 chalk/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg create mode 100644 chalk/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg create mode 100644 chalk/plugins/tools/Makefile.am create mode 100644 chalk/plugins/tools/defaulttools/Makefile.am create mode 100644 chalk/plugins/tools/defaulttools/chalkdefaulttools.desktop create mode 100644 chalk/plugins/tools/defaulttools/closedhand_cursor.xpm create mode 100644 chalk/plugins/tools/defaulttools/default_tools.cc create mode 100644 chalk/plugins/tools/defaulttools/default_tools.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_brush.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_brush.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_colorpicker.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_colorpicker.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_duplicate.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_duplicate.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_ellipse.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_ellipse.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_fill.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_fill.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_gradient.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_gradient.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_line.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_line.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_move.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_move.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_pan.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_pan.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_rectangle.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_rectangle.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_text.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_text.h create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_zoom.cc create mode 100644 chalk/plugins/tools/defaulttools/kis_tool_zoom.h create mode 100644 chalk/plugins/tools/defaulttools/openhand_cursor.xpm create mode 100644 chalk/plugins/tools/defaulttools/tool_color_fill.png create mode 100644 chalk/plugins/tools/defaulttools/tool_colorpicker.png create mode 100644 chalk/plugins/tools/defaulttools/tool_duplicate.png create mode 100644 chalk/plugins/tools/defaulttools/tool_duplicate_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_ellipse.png create mode 100644 chalk/plugins/tools/defaulttools/tool_ellipse_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_fill_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_freehand.png create mode 100644 chalk/plugins/tools/defaulttools/tool_freehand_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_gradient.png create mode 100644 chalk/plugins/tools/defaulttools/tool_gradient_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_line.png create mode 100644 chalk/plugins/tools/defaulttools/tool_line_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_move.png create mode 100644 chalk/plugins/tools/defaulttools/tool_pan.png create mode 100644 chalk/plugins/tools/defaulttools/tool_rectangle.png create mode 100644 chalk/plugins/tools/defaulttools/tool_rectangle_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_text.png create mode 100644 chalk/plugins/tools/defaulttools/tool_text_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_zoom.png create mode 100644 chalk/plugins/tools/defaulttools/tool_zoom_minus_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/tool_zoom_plus_cursor.png create mode 100644 chalk/plugins/tools/defaulttools/wdgcolorpicker.ui create mode 100644 chalk/plugins/tools/selectiontools/Makefile.am create mode 100644 chalk/plugins/tools/selectiontools/chalkselectiontools.desktop create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_move_selection.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_move_selection.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_brush.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_brush.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_eraser.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_eraser.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_outline.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_outline.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.h create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.cc create mode 100644 chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.h create mode 100644 chalk/plugins/tools/selectiontools/selection_tools.cc create mode 100644 chalk/plugins/tools/selectiontools/selection_tools.h create mode 100644 chalk/plugins/tools/selectiontools/tool_brush_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_brush_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_brush_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_contiguous_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_elliptical_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_elliptical_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_eraser_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_eraser_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_eraser_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_outline_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_outline_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_outline_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_polygonal_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_polygonal_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png create mode 100644 chalk/plugins/tools/selectiontools/tool_rect_selection.png create mode 100644 chalk/plugins/tools/selectiontools/tool_rect_selection.svg create mode 100644 chalk/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png create mode 100644 chalk/plugins/tools/tool_crop/Makefile.am create mode 100644 chalk/plugins/tools/tool_crop/chalktoolcrop.desktop create mode 100644 chalk/plugins/tools/tool_crop/kis_tool_crop.cc create mode 100644 chalk/plugins/tools/tool_crop/kis_tool_crop.h create mode 100644 chalk/plugins/tools/tool_crop/tool_crop.cc create mode 100644 chalk/plugins/tools/tool_crop/tool_crop.h create mode 100644 chalk/plugins/tools/tool_crop/tool_crop.png create mode 100644 chalk/plugins/tools/tool_crop/tool_crop_cursor.png create mode 100644 chalk/plugins/tools/tool_crop/wdg_tool_crop.ui create mode 100644 chalk/plugins/tools/tool_curves/Makefile.am create mode 100644 chalk/plugins/tools/tool_curves/chalktoolcurves.desktop create mode 100644 chalk/plugins/tools/tool_curves/kis_curve_framework.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_curve_framework.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier_select.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_bezier_select.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_curve.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_curve.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_example.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_example.h create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_moutline.cc create mode 100644 chalk/plugins/tools/tool_curves/kis_tool_moutline.h create mode 100644 chalk/plugins/tools/tool_curves/tool_bezier_cursor.png create mode 100644 chalk/plugins/tools/tool_curves/tool_bezier_paint.png create mode 100644 chalk/plugins/tools/tool_curves/tool_bezier_select.png create mode 100644 chalk/plugins/tools/tool_curves/tool_curve_dragging.png create mode 100644 chalk/plugins/tools/tool_curves/tool_curves.cc create mode 100644 chalk/plugins/tools/tool_curves/tool_curves.h create mode 100644 chalk/plugins/tools/tool_curves/tool_example.png create mode 100644 chalk/plugins/tools/tool_curves/tool_example_cursor.png create mode 100644 chalk/plugins/tools/tool_curves/tool_moutline.png create mode 100644 chalk/plugins/tools/tool_curves/tool_moutline_cursor.png create mode 100644 chalk/plugins/tools/tool_curves/tool_moutline_editing.png create mode 100644 chalk/plugins/tools/tool_curves/wdg_tool_example.ui create mode 100644 chalk/plugins/tools/tool_filter/Makefile.am create mode 100644 chalk/plugins/tools/tool_filter/chalktoolfilter.desktop create mode 100644 chalk/plugins/tools/tool_filter/kis_filterop.cc create mode 100644 chalk/plugins/tools/tool_filter/kis_filterop.h create mode 100644 chalk/plugins/tools/tool_filter/kis_tool_filter.cc create mode 100644 chalk/plugins/tools/tool_filter/kis_tool_filter.h create mode 100644 chalk/plugins/tools/tool_filter/tool_filter.cc create mode 100644 chalk/plugins/tools/tool_filter/tool_filter.h create mode 100644 chalk/plugins/tools/tool_filter/tool_filter.png create mode 100644 chalk/plugins/tools/tool_filter/tool_filter.svg create mode 100644 chalk/plugins/tools/tool_filter/tool_filter_cursor.png create mode 100644 chalk/plugins/tools/tool_perspectivegrid/Makefile.am create mode 100644 chalk/plugins/tools/tool_perspectivegrid/chalktoolperspectivegrid.desktop create mode 100644 chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc create mode 100644 chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h create mode 100644 chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc create mode 100644 chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h create mode 100644 chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png create mode 100644 chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg create mode 100644 chalk/plugins/tools/tool_perspectivetransform/Makefile.am create mode 100644 chalk/plugins/tools/tool_perspectivetransform/chalktoolperspectivetransform.desktop create mode 100644 chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc create mode 100644 chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h create mode 100644 chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc create mode 100644 chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h create mode 100644 chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png create mode 100644 chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg create mode 100644 chalk/plugins/tools/tool_polygon/Makefile.am create mode 100644 chalk/plugins/tools/tool_polygon/chalktoolpolygon.desktop create mode 100644 chalk/plugins/tools/tool_polygon/kis_tool_polygon.cc create mode 100644 chalk/plugins/tools/tool_polygon/kis_tool_polygon.h create mode 100644 chalk/plugins/tools/tool_polygon/tool_polygon.cc create mode 100644 chalk/plugins/tools/tool_polygon/tool_polygon.h create mode 100644 chalk/plugins/tools/tool_polygon/tool_polygon.png create mode 100644 chalk/plugins/tools/tool_polygon/tool_polygon_cursor.png create mode 100644 chalk/plugins/tools/tool_polyline/Makefile.am create mode 100644 chalk/plugins/tools/tool_polyline/chalktoolpolyline.desktop create mode 100644 chalk/plugins/tools/tool_polyline/kis_tool_polyline.cc create mode 100644 chalk/plugins/tools/tool_polyline/kis_tool_polyline.h create mode 100644 chalk/plugins/tools/tool_polyline/polyline.png create mode 100644 chalk/plugins/tools/tool_polyline/tool_polyline.cc create mode 100644 chalk/plugins/tools/tool_polyline/tool_polyline.h create mode 100644 chalk/plugins/tools/tool_polyline/tool_polyline_cursor.png create mode 100644 chalk/plugins/tools/tool_selectsimilar/Makefile.am create mode 100644 chalk/plugins/tools/tool_selectsimilar/chalktoolselectsimilar.desktop create mode 100644 chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc create mode 100644 chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h create mode 100644 chalk/plugins/tools/tool_selectsimilar/selectsimilar.cc create mode 100644 chalk/plugins/tools/tool_selectsimilar/selectsimilar.h create mode 100644 chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.png create mode 100644 chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.svg create mode 100644 chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png create mode 100644 chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png create mode 100644 chalk/plugins/tools/tool_star/Makefile.am create mode 100644 chalk/plugins/tools/tool_star/chalktoolstar.desktop create mode 100644 chalk/plugins/tools/tool_star/kis_tool_star.cc create mode 100644 chalk/plugins/tools/tool_star/kis_tool_star.h create mode 100644 chalk/plugins/tools/tool_star/tool_star.cc create mode 100644 chalk/plugins/tools/tool_star/tool_star.h create mode 100644 chalk/plugins/tools/tool_star/tool_star.png create mode 100644 chalk/plugins/tools/tool_star/tool_star_cursor.png create mode 100644 chalk/plugins/tools/tool_star/wdg_tool_star.ui create mode 100644 chalk/plugins/tools/tool_transform/Makefile.am create mode 100644 chalk/plugins/tools/tool_transform/chalktooltransform.desktop create mode 100644 chalk/plugins/tools/tool_transform/kis_tool_transform.cc create mode 100644 chalk/plugins/tools/tool_transform/kis_tool_transform.h create mode 100644 chalk/plugins/tools/tool_transform/rotate_cursor.xpm create mode 100644 chalk/plugins/tools/tool_transform/tool_transform.cc create mode 100644 chalk/plugins/tools/tool_transform/tool_transform.h create mode 100644 chalk/plugins/tools/tool_transform/tool_transform.png create mode 100644 chalk/plugins/tools/tool_transform/wdg_tool_transform.ui create mode 100644 chalk/plugins/viewplugins/Makefile.am create mode 100644 chalk/plugins/viewplugins/colorrange/Makefile.am create mode 100644 chalk/plugins/viewplugins/colorrange/chalkcolorrange.desktop create mode 100644 chalk/plugins/viewplugins/colorrange/colorrange.cc create mode 100644 chalk/plugins/viewplugins/colorrange/colorrange.h create mode 100644 chalk/plugins/viewplugins/colorrange/colorrange.rc create mode 100644 chalk/plugins/viewplugins/colorrange/dlg_colorrange.cc create mode 100644 chalk/plugins/viewplugins/colorrange/dlg_colorrange.h create mode 100644 chalk/plugins/viewplugins/colorrange/wdg_colorrange.ui create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/Makefile.am create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/chalkcolorspaceconversion.desktop create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h create mode 100644 chalk/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui create mode 100644 chalk/plugins/viewplugins/dropshadow/Makefile.am create mode 100644 chalk/plugins/viewplugins/dropshadow/chalkdropshadow.desktop create mode 100644 chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.cc create mode 100644 chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.h create mode 100644 chalk/plugins/viewplugins/dropshadow/dropshadow.rc create mode 100644 chalk/plugins/viewplugins/dropshadow/kis_dropshadow.cc create mode 100644 chalk/plugins/viewplugins/dropshadow/kis_dropshadow.h create mode 100644 chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc create mode 100644 chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h create mode 100644 chalk/plugins/viewplugins/dropshadow/wdg_dropshadow.ui create mode 100644 chalk/plugins/viewplugins/filtersgallery/Makefile.am create mode 100644 chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.desktop create mode 100644 chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.rc create mode 100644 chalk/plugins/viewplugins/filtersgallery/filters_gallery.cc create mode 100644 chalk/plugins/viewplugins/filtersgallery/filters_gallery.h create mode 100644 chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc create mode 100644 chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h create mode 100644 chalk/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui create mode 100644 chalk/plugins/viewplugins/histogram/Makefile.am create mode 100644 chalk/plugins/viewplugins/histogram/chalkhistogram.desktop create mode 100644 chalk/plugins/viewplugins/histogram/dlg_histogram.cc create mode 100644 chalk/plugins/viewplugins/histogram/dlg_histogram.h create mode 100644 chalk/plugins/viewplugins/histogram/histogram.cc create mode 100644 chalk/plugins/viewplugins/histogram/histogram.h create mode 100644 chalk/plugins/viewplugins/histogram/histogram.rc create mode 100644 chalk/plugins/viewplugins/histogram/kis_histogram_widget.cc create mode 100644 chalk/plugins/viewplugins/histogram/kis_histogram_widget.h create mode 100644 chalk/plugins/viewplugins/histogram/wdghistogram.ui create mode 100644 chalk/plugins/viewplugins/histogram_docker/Makefile.am create mode 100644 chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.desktop create mode 100644 chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.rc create mode 100644 chalk/plugins/viewplugins/histogram_docker/histogramdocker.cc create mode 100644 chalk/plugins/viewplugins/histogram_docker/histogramdocker.h create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc create mode 100644 chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h create mode 100644 chalk/plugins/viewplugins/history_docker/Makefile.am create mode 100644 chalk/plugins/viewplugins/history_docker/chalkhistorydocker.desktop create mode 100644 chalk/plugins/viewplugins/history_docker/historydocker.cc create mode 100644 chalk/plugins/viewplugins/history_docker/historydocker.h create mode 100644 chalk/plugins/viewplugins/imagesize/Makefile.am create mode 100644 chalk/plugins/viewplugins/imagesize/chalkimagesize.desktop create mode 100644 chalk/plugins/viewplugins/imagesize/configure.in.in create mode 100644 chalk/plugins/viewplugins/imagesize/dlg_imagesize.cc create mode 100644 chalk/plugins/viewplugins/imagesize/dlg_imagesize.h create mode 100644 chalk/plugins/viewplugins/imagesize/dlg_layersize.cc create mode 100644 chalk/plugins/viewplugins/imagesize/dlg_layersize.h create mode 100644 chalk/plugins/viewplugins/imagesize/imagesize.cc create mode 100644 chalk/plugins/viewplugins/imagesize/imagesize.h create mode 100644 chalk/plugins/viewplugins/imagesize/imagesize.rc create mode 100644 chalk/plugins/viewplugins/imagesize/wdg_imagesize.ui create mode 100644 chalk/plugins/viewplugins/imagesize/wdg_layersize.ui create mode 100644 chalk/plugins/viewplugins/imagesize/wdg_resolution.ui create mode 100644 chalk/plugins/viewplugins/modify_selection/Makefile.am create mode 100644 chalk/plugins/viewplugins/modify_selection/chalkmodifyselection.desktop create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_border_selection.cc create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_border_selection.h create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.cc create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.h create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc create mode 100644 chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.h create mode 100644 chalk/plugins/viewplugins/modify_selection/modify_selection.cc create mode 100644 chalk/plugins/viewplugins/modify_selection/modify_selection.h create mode 100644 chalk/plugins/viewplugins/modify_selection/modify_selection.rc create mode 100644 chalk/plugins/viewplugins/modify_selection/wdg_border_selection.ui create mode 100644 chalk/plugins/viewplugins/modify_selection/wdg_grow_selection.ui create mode 100644 chalk/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui create mode 100644 chalk/plugins/viewplugins/performancetest/Makefile.am create mode 100644 chalk/plugins/viewplugins/performancetest/chalkperftest.desktop create mode 100644 chalk/plugins/viewplugins/performancetest/dlg_perftest.cc create mode 100644 chalk/plugins/viewplugins/performancetest/dlg_perftest.h create mode 100644 chalk/plugins/viewplugins/performancetest/perftest.cc create mode 100644 chalk/plugins/viewplugins/performancetest/perftest.h create mode 100644 chalk/plugins/viewplugins/performancetest/perftest.rc create mode 100644 chalk/plugins/viewplugins/performancetest/wdg_perftest.ui create mode 100644 chalk/plugins/viewplugins/rotateimage/Makefile.am create mode 100644 chalk/plugins/viewplugins/rotateimage/chalkrotateimage.desktop create mode 100644 chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.cc create mode 100644 chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.h create mode 100644 chalk/plugins/viewplugins/rotateimage/rotateimage.cc create mode 100644 chalk/plugins/viewplugins/rotateimage/rotateimage.h create mode 100644 chalk/plugins/viewplugins/rotateimage/rotateimage.rc create mode 100644 chalk/plugins/viewplugins/rotateimage/wdg_rotateimage.ui create mode 100644 chalk/plugins/viewplugins/screenshot/Makefile.am create mode 100644 chalk/plugins/viewplugins/screenshot/chalkscreenshot.desktop create mode 100644 chalk/plugins/viewplugins/screenshot/ksnapshot.cpp create mode 100644 chalk/plugins/viewplugins/screenshot/ksnapshot.h create mode 100644 chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui create mode 100644 chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h create mode 100644 chalk/plugins/viewplugins/screenshot/main.cpp create mode 100644 chalk/plugins/viewplugins/screenshot/regiongrabber.cpp create mode 100644 chalk/plugins/viewplugins/screenshot/regiongrabber.h create mode 100644 chalk/plugins/viewplugins/screenshot/screenshot-chalk.rc create mode 100644 chalk/plugins/viewplugins/screenshot/screenshot-kpresenter.rc create mode 100644 chalk/plugins/viewplugins/screenshot/screenshot-kword.rc create mode 100644 chalk/plugins/viewplugins/screenshot/screenshot.cpp create mode 100644 chalk/plugins/viewplugins/screenshot/screenshot.h create mode 100644 chalk/plugins/viewplugins/scripting/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_color.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_color.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_image.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_image.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_iterator.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting.desktop create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.h create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.cpp create mode 100644 chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.h create mode 100644 chalk/plugins/viewplugins/scripting/samples/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/samples/python/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/samples/python/invert.py create mode 100644 chalk/plugins/viewplugins/scripting/samples/python/invertpython.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.py create mode 100644 chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/Makefile.am create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/invert.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/invertruby.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb create mode 100644 chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc create mode 100644 chalk/plugins/viewplugins/scripting/scripting.cc create mode 100644 chalk/plugins/viewplugins/scripting/scripting.h create mode 100644 chalk/plugins/viewplugins/scripting/scripting.rc create mode 100644 chalk/plugins/viewplugins/selectopaque/Makefile.am create mode 100644 chalk/plugins/viewplugins/selectopaque/chalkselectopaque.desktop create mode 100644 chalk/plugins/viewplugins/selectopaque/selectopaque.cc create mode 100644 chalk/plugins/viewplugins/selectopaque/selectopaque.h create mode 100644 chalk/plugins/viewplugins/selectopaque/selectopaque.rc create mode 100644 chalk/plugins/viewplugins/separate_channels/Makefile.am create mode 100644 chalk/plugins/viewplugins/separate_channels/chalkseparatechannels.desktop create mode 100644 chalk/plugins/viewplugins/separate_channels/dlg_separate.cc create mode 100644 chalk/plugins/viewplugins/separate_channels/dlg_separate.h create mode 100644 chalk/plugins/viewplugins/separate_channels/imageseparate.rc create mode 100644 chalk/plugins/viewplugins/separate_channels/kis_channel_separator.cc create mode 100644 chalk/plugins/viewplugins/separate_channels/kis_channel_separator.h create mode 100644 chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc create mode 100644 chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h create mode 100644 chalk/plugins/viewplugins/separate_channels/wdg_separations.ui create mode 100644 chalk/plugins/viewplugins/shearimage/Makefile.am create mode 100644 chalk/plugins/viewplugins/shearimage/chalkshearimage.desktop create mode 100644 chalk/plugins/viewplugins/shearimage/dlg_shearimage.cc create mode 100644 chalk/plugins/viewplugins/shearimage/dlg_shearimage.h create mode 100644 chalk/plugins/viewplugins/shearimage/shearimage.cc create mode 100644 chalk/plugins/viewplugins/shearimage/shearimage.h create mode 100644 chalk/plugins/viewplugins/shearimage/shearimage.rc create mode 100644 chalk/plugins/viewplugins/shearimage/wdg_shearimage.ui create mode 100644 chalk/plugins/viewplugins/substrate/Makefile.am create mode 100644 chalk/plugins/viewplugins/substrate/chalksubstrate.desktop create mode 100644 chalk/plugins/viewplugins/substrate/dlg_substrate.cc create mode 100644 chalk/plugins/viewplugins/substrate/dlg_substrate.h create mode 100644 chalk/plugins/viewplugins/substrate/kis_repeating_substrate.cc create mode 100644 chalk/plugins/viewplugins/substrate/kis_repeating_substrate.h create mode 100644 chalk/plugins/viewplugins/substrate/substrate.cc create mode 100644 chalk/plugins/viewplugins/substrate/substrate.h create mode 100644 chalk/plugins/viewplugins/substrate/substrate.rc create mode 100644 chalk/plugins/viewplugins/substrate/wdgsubstrate.ui create mode 100644 chalk/plugins/viewplugins/variations/Makefile.am create mode 100644 chalk/plugins/viewplugins/variations/chalkvariations.desktop create mode 100644 chalk/plugins/viewplugins/variations/dlg_variations.cc create mode 100644 chalk/plugins/viewplugins/variations/dlg_variations.h create mode 100644 chalk/plugins/viewplugins/variations/variations.cc create mode 100644 chalk/plugins/viewplugins/variations/variations.h create mode 100644 chalk/plugins/viewplugins/variations/variations.rc create mode 100644 chalk/plugins/viewplugins/variations/wdg_variations.ui create mode 100644 chalk/sdk/Makefile.am create mode 100644 chalk/sdk/kis_annotation.h create mode 100644 chalk/sdk/kis_canvas_controller.h create mode 100644 chalk/sdk/kis_canvas_observer.h create mode 100644 chalk/sdk/kis_canvas_subject.h create mode 100644 chalk/sdk/kis_debug_areas.h create mode 100644 chalk/sdk/kis_generic_registry.h create mode 100644 chalk/sdk/kis_global.h create mode 100644 chalk/sdk/kis_id.h create mode 100644 chalk/sdk/kis_integer_maths.h create mode 100644 chalk/sdk/kis_progress_display_interface.h create mode 100644 chalk/sdk/kis_progress_subject.cc create mode 100644 chalk/sdk/kis_progress_subject.h create mode 100644 chalk/sdk/kis_shared_ptr_vector.h create mode 100644 chalk/sdk/kis_undo_adapter.h create mode 100644 chalk/todo-1.6 create mode 100644 chalk/ui/Makefile.am create mode 100644 chalk/ui/imageviewer.cc create mode 100644 chalk/ui/imageviewer.h create mode 100644 chalk/ui/kcurve.cc create mode 100644 chalk/ui/kcurve.h create mode 100644 chalk/ui/kis_aboutdata.h create mode 100644 chalk/ui/kis_autobrush.cc create mode 100644 chalk/ui/kis_autobrush.h create mode 100644 chalk/ui/kis_autogradient.cc create mode 100644 chalk/ui/kis_autogradient.h create mode 100644 chalk/ui/kis_birdeye_box.cc create mode 100644 chalk/ui/kis_birdeye_box.h create mode 100644 chalk/ui/kis_boundary_painter.cc create mode 100644 chalk/ui/kis_boundary_painter.h create mode 100644 chalk/ui/kis_brush_chooser.cc create mode 100644 chalk/ui/kis_brush_chooser.h create mode 100644 chalk/ui/kis_button_event.h create mode 100644 chalk/ui/kis_button_press_event.h create mode 100644 chalk/ui/kis_button_release_event.h create mode 100644 chalk/ui/kis_canvas.cc create mode 100644 chalk/ui/kis_canvas.h create mode 100644 chalk/ui/kis_canvas_painter.cc create mode 100644 chalk/ui/kis_canvas_painter.h create mode 100644 chalk/ui/kis_clipboard.cc create mode 100644 chalk/ui/kis_clipboard.h create mode 100644 chalk/ui/kis_cmb_composite.cc create mode 100644 chalk/ui/kis_cmb_composite.h create mode 100644 chalk/ui/kis_cmb_idlist.cc create mode 100644 chalk/ui/kis_cmb_idlist.h create mode 100644 chalk/ui/kis_color_cup.cc create mode 100644 chalk/ui/kis_color_cup.h create mode 100644 chalk/ui/kis_config.cc create mode 100644 chalk/ui/kis_config.h create mode 100644 chalk/ui/kis_controlframe.cc create mode 100644 chalk/ui/kis_controlframe.h create mode 100644 chalk/ui/kis_cursor.cc create mode 100644 chalk/ui/kis_cursor.h create mode 100644 chalk/ui/kis_custom_brush.cc create mode 100644 chalk/ui/kis_custom_brush.h create mode 100644 chalk/ui/kis_custom_image_widget.cc create mode 100644 chalk/ui/kis_custom_image_widget.h create mode 100644 chalk/ui/kis_custom_palette.cc create mode 100644 chalk/ui/kis_custom_palette.h create mode 100644 chalk/ui/kis_custom_pattern.cc create mode 100644 chalk/ui/kis_custom_pattern.h create mode 100644 chalk/ui/kis_dlg_adj_layer_props.cc create mode 100644 chalk/ui/kis_dlg_adj_layer_props.h create mode 100644 chalk/ui/kis_dlg_adjustment_layer.cc create mode 100644 chalk/ui/kis_dlg_adjustment_layer.h create mode 100644 chalk/ui/kis_dlg_apply_profile.cc create mode 100644 chalk/ui/kis_dlg_apply_profile.h create mode 100644 chalk/ui/kis_dlg_image_properties.cc create mode 100644 chalk/ui/kis_dlg_image_properties.h create mode 100644 chalk/ui/kis_dlg_layer_properties.cc create mode 100644 chalk/ui/kis_dlg_layer_properties.h create mode 100644 chalk/ui/kis_dlg_new_layer.cc create mode 100644 chalk/ui/kis_dlg_new_layer.h create mode 100644 chalk/ui/kis_dlg_preferences.cc create mode 100644 chalk/ui/kis_dlg_preferences.h create mode 100644 chalk/ui/kis_doc.cc create mode 100644 chalk/ui/kis_doc.h create mode 100644 chalk/ui/kis_doc_iface.cc create mode 100644 chalk/ui/kis_doc_iface.h create mode 100644 chalk/ui/kis_double_click_event.h create mode 100644 chalk/ui/kis_double_widget.cc create mode 100644 chalk/ui/kis_double_widget.h create mode 100644 chalk/ui/kis_event.h create mode 100644 chalk/ui/kis_factory.cc create mode 100644 chalk/ui/kis_factory.h create mode 100644 chalk/ui/kis_filter_manager.cc create mode 100644 chalk/ui/kis_filter_manager.h create mode 100644 chalk/ui/kis_filters_listview.cc create mode 100644 chalk/ui/kis_filters_listview.h create mode 100644 chalk/ui/kis_gradient_chooser.cc create mode 100644 chalk/ui/kis_gradient_chooser.h create mode 100644 chalk/ui/kis_gradient_slider_widget.cc create mode 100644 chalk/ui/kis_gradient_slider_widget.h create mode 100644 chalk/ui/kis_grid_drawer.cpp create mode 100644 chalk/ui/kis_grid_drawer.h create mode 100644 chalk/ui/kis_grid_manager.cpp create mode 100644 chalk/ui/kis_grid_manager.h create mode 100644 chalk/ui/kis_histogram_view.cc create mode 100644 chalk/ui/kis_histogram_view.h create mode 100644 chalk/ui/kis_icon_item.cc create mode 100644 chalk/ui/kis_icon_item.h create mode 100644 chalk/ui/kis_iconwidget.cc create mode 100644 chalk/ui/kis_iconwidget.h create mode 100644 chalk/ui/kis_import_catcher.cc create mode 100644 chalk/ui/kis_import_catcher.h create mode 100644 chalk/ui/kis_input_device.cc create mode 100644 chalk/ui/kis_input_device.h create mode 100644 chalk/ui/kis_int_spinbox.cc create mode 100644 chalk/ui/kis_int_spinbox.h create mode 100644 chalk/ui/kis_itemchooser.cc create mode 100644 chalk/ui/kis_itemchooser.h create mode 100644 chalk/ui/kis_label_cursor_pos.cc create mode 100644 chalk/ui/kis_label_cursor_pos.h create mode 100644 chalk/ui/kis_label_progress.cc create mode 100644 chalk/ui/kis_label_progress.h create mode 100644 chalk/ui/kis_label_zoom.cc create mode 100644 chalk/ui/kis_label_zoom.h create mode 100644 chalk/ui/kis_layerbox.cc create mode 100644 chalk/ui/kis_layerbox.h create mode 100644 chalk/ui/kis_layerlist.cc create mode 100644 chalk/ui/kis_layerlist.h create mode 100644 chalk/ui/kis_load_visitor.h create mode 100644 chalk/ui/kis_matrix_widget.ui create mode 100644 chalk/ui/kis_matrix_widget.ui.h create mode 100644 chalk/ui/kis_move_event.h create mode 100644 chalk/ui/kis_multi_bool_filter_widget.cc create mode 100644 chalk/ui/kis_multi_bool_filter_widget.h create mode 100644 chalk/ui/kis_multi_double_filter_widget.cc create mode 100644 chalk/ui/kis_multi_double_filter_widget.h create mode 100644 chalk/ui/kis_multi_integer_filter_widget.cc create mode 100644 chalk/ui/kis_multi_integer_filter_widget.h create mode 100644 chalk/ui/kis_opengl_canvas.cc create mode 100644 chalk/ui/kis_opengl_canvas.h create mode 100644 chalk/ui/kis_opengl_canvas_painter.cc create mode 100644 chalk/ui/kis_opengl_canvas_painter.h create mode 100644 chalk/ui/kis_opengl_image_context.cc create mode 100644 chalk/ui/kis_opengl_image_context.h create mode 100644 chalk/ui/kis_paintop_box.cc create mode 100644 chalk/ui/kis_paintop_box.h create mode 100644 chalk/ui/kis_palette_view.cc create mode 100644 chalk/ui/kis_palette_view.h create mode 100644 chalk/ui/kis_palette_widget.cc create mode 100644 chalk/ui/kis_palette_widget.h create mode 100644 chalk/ui/kis_part_layer.cc create mode 100644 chalk/ui/kis_part_layer.h create mode 100644 chalk/ui/kis_part_layer_handler.cc create mode 100644 chalk/ui/kis_part_layer_handler.h create mode 100644 chalk/ui/kis_pattern_chooser.cc create mode 100644 chalk/ui/kis_pattern_chooser.h create mode 100644 chalk/ui/kis_perspective_grid_manager.cpp create mode 100644 chalk/ui/kis_perspective_grid_manager.h create mode 100644 chalk/ui/kis_populate_visitor.h create mode 100644 chalk/ui/kis_previewdialog.cc create mode 100644 chalk/ui/kis_previewdialog.h create mode 100644 chalk/ui/kis_previewwidget.cc create mode 100644 chalk/ui/kis_previewwidget.h create mode 100644 chalk/ui/kis_previewwidgetbase.ui create mode 100644 chalk/ui/kis_qpaintdevice_canvas.cc create mode 100644 chalk/ui/kis_qpaintdevice_canvas.h create mode 100644 chalk/ui/kis_qpaintdevice_canvas_painter.cc create mode 100644 chalk/ui/kis_qpaintdevice_canvas_painter.h create mode 100644 chalk/ui/kis_resource_mediator.cc create mode 100644 chalk/ui/kis_resource_mediator.h create mode 100644 chalk/ui/kis_resourceserver.cc create mode 100644 chalk/ui/kis_resourceserver.h create mode 100644 chalk/ui/kis_ruler.cc create mode 100644 chalk/ui/kis_ruler.h create mode 100644 chalk/ui/kis_save_visitor.h create mode 100644 chalk/ui/kis_savexml_visitor.h create mode 100644 chalk/ui/kis_selection_manager.cc create mode 100644 chalk/ui/kis_selection_manager.h create mode 100644 chalk/ui/kis_selection_options.cc create mode 100644 chalk/ui/kis_selection_options.h create mode 100644 chalk/ui/kis_text_brush.cc create mode 100644 chalk/ui/kis_text_brush.h create mode 100644 chalk/ui/kis_tool.cc create mode 100644 chalk/ui/kis_tool.h create mode 100644 chalk/ui/kis_tool_controller.h create mode 100644 chalk/ui/kis_tool_dummy.cc create mode 100644 chalk/ui/kis_tool_dummy.h create mode 100644 chalk/ui/kis_tool_factory.h create mode 100644 chalk/ui/kis_tool_freehand.cc create mode 100644 chalk/ui/kis_tool_freehand.h create mode 100644 chalk/ui/kis_tool_manager.cc create mode 100644 chalk/ui/kis_tool_manager.h create mode 100644 chalk/ui/kis_tool_non_paint.cc create mode 100644 chalk/ui/kis_tool_non_paint.h create mode 100644 chalk/ui/kis_tool_paint.cc create mode 100644 chalk/ui/kis_tool_paint.h create mode 100644 chalk/ui/kis_tool_registry.cc create mode 100644 chalk/ui/kis_tool_registry.h create mode 100644 chalk/ui/kis_tool_shape.cc create mode 100644 chalk/ui/kis_tool_shape.h create mode 100644 chalk/ui/kis_tool_types.h create mode 100644 chalk/ui/kis_view.cc create mode 100644 chalk/ui/kis_view.h create mode 100644 chalk/ui/kis_view_iface.cc create mode 100644 chalk/ui/kis_view_iface.h create mode 100644 chalk/ui/kobirdeyepanel.cpp create mode 100644 chalk/ui/kobirdeyepanel.h create mode 100644 chalk/ui/layerlist.cpp create mode 100644 chalk/ui/layerlist.h create mode 100644 chalk/ui/squeezedcombobox.cpp create mode 100644 chalk/ui/squeezedcombobox.h create mode 100644 chalk/ui/wdgapplyprofile.ui create mode 100644 chalk/ui/wdgautobrush.ui create mode 100644 chalk/ui/wdgautogradient.ui create mode 100644 chalk/ui/wdgbirdeye.ui create mode 100644 chalk/ui/wdgcolorsettings.ui create mode 100644 chalk/ui/wdgcustombrush.ui create mode 100644 chalk/ui/wdgcustompalette.ui create mode 100644 chalk/ui/wdgcustompattern.ui create mode 100644 chalk/ui/wdgdisplaysettings.ui create mode 100644 chalk/ui/wdggeneralsettings.ui create mode 100644 chalk/ui/wdggridsettings.ui create mode 100644 chalk/ui/wdglayerbox.ui create mode 100644 chalk/ui/wdglayerproperties.ui create mode 100644 chalk/ui/wdgnewimage.ui create mode 100644 chalk/ui/wdgpalettechooser.ui create mode 100644 chalk/ui/wdgperformancesettings.ui create mode 100644 chalk/ui/wdgpressuresettings.ui create mode 100644 chalk/ui/wdgselectionoptions.ui create mode 100644 chalk/ui/wdgshapeoptions.ui create mode 100644 chalk/ui/wdgtabletdevicesettings.ui create mode 100644 chalk/ui/wdgtabletsettings.ui create mode 100644 chalk/ui/wdgtextbrush.ui create mode 100644 doc/chalk/Makefile.am create mode 100644 doc/chalk/README.SCREENSHOTS create mode 100644 doc/chalk/commands-dialogs.docbook create mode 100644 doc/chalk/commands-menus.docbook create mode 100644 doc/chalk/commands-palettes.docbook create mode 100644 doc/chalk/commands-toolbars.docbook create mode 100644 doc/chalk/commands.docbook create mode 100644 doc/chalk/createdocument.png create mode 100644 doc/chalk/credits.docbook create mode 100644 doc/chalk/crocusses-autocontrast.png create mode 100644 doc/chalk/crocusses-blur.png create mode 100644 doc/chalk/crocusses-brightnesscontrast.png create mode 100644 doc/chalk/crocusses-bumpmap.png create mode 100644 doc/chalk/crocusses-coloradjustment.png create mode 100644 doc/chalk/crocusses-colortoalpha.png create mode 100644 doc/chalk/crocusses-colortransfer.png create mode 100644 doc/chalk/crocusses-customconvolution.png create mode 100644 doc/chalk/crocusses-desaturate.png create mode 100644 doc/chalk/crocusses-edgebottom.png create mode 100644 doc/chalk/crocusses-edgeleft.png create mode 100644 doc/chalk/crocusses-edgeright.png create mode 100644 doc/chalk/crocusses-embossall.png create mode 100644 doc/chalk/crocusses-embosshorvert.png create mode 100644 doc/chalk/crocusses-embossvariable.png create mode 100644 doc/chalk/crocusses-gaussianblur.png create mode 100644 doc/chalk/crocusses-gaussiannoise.png create mode 100644 doc/chalk/crocusses-invert.png create mode 100644 doc/chalk/crocusses-lenscorrection.png create mode 100644 doc/chalk/crocusses-maximizechannel.png create mode 100644 doc/chalk/crocusses-meanremoval.png create mode 100644 doc/chalk/crocusses-minimizechannel.png create mode 100644 doc/chalk/crocusses-oilpaint.png create mode 100644 doc/chalk/crocusses-pixelize.png create mode 100644 doc/chalk/crocusses-raindrops.png create mode 100644 doc/chalk/crocusses-randomnoise.png create mode 100644 doc/chalk/crocusses-randompick.png create mode 100644 doc/chalk/crocusses-roundcorners.png create mode 100644 doc/chalk/crocusses-sharpen.png create mode 100644 doc/chalk/crocusses-smalltiles.png create mode 100644 doc/chalk/crocusses-sobel.png create mode 100644 doc/chalk/crocusses-topedge.png create mode 100644 doc/chalk/crocusses-unsharpmask.png create mode 100644 doc/chalk/crocusses-wave.png create mode 100644 doc/chalk/crocusses-waveletnoise.png create mode 100644 doc/chalk/crocusses.png create mode 100644 doc/chalk/developers-plugins.docbook create mode 100644 doc/chalk/developers-scripting.docbook create mode 100644 doc/chalk/developers.docbook create mode 100644 doc/chalk/dialogs-addpalette.png create mode 100644 doc/chalk/dialogs-blur.png create mode 100644 doc/chalk/dialogs-brightnesscontrast.png create mode 100644 doc/chalk/dialogs-bumpmap.png create mode 100644 doc/chalk/dialogs-coloradjustment.png create mode 100644 doc/chalk/dialogs-colorrange.png create mode 100644 doc/chalk/dialogs-colortoalpha.png create mode 100644 doc/chalk/dialogs-colortransfer.png create mode 100644 doc/chalk/dialogs-convertimagetype.png create mode 100644 doc/chalk/dialogs-convertlayertype.png create mode 100644 doc/chalk/dialogs-cubism.png create mode 100644 doc/chalk/dialogs-customconvolution.png create mode 100644 doc/chalk/dialogs-documentinformation.png create mode 100644 doc/chalk/dialogs-dropshadow.png create mode 100644 doc/chalk/dialogs-emboss.png create mode 100644 doc/chalk/dialogs-filtersgallery.png create mode 100644 doc/chalk/dialogs-gaussiannoise.png create mode 100644 doc/chalk/dialogs-histogram.png create mode 100644 doc/chalk/dialogs-imageproperties.png create mode 100644 doc/chalk/dialogs-imagerestoration.png create mode 100644 doc/chalk/dialogs-imagesize.png create mode 100644 doc/chalk/dialogs-layerproperties.png create mode 100644 doc/chalk/dialogs-layersize.png create mode 100644 doc/chalk/dialogs-lenscorrection.png create mode 100644 doc/chalk/dialogs-newadjustmentlayer.png create mode 100644 doc/chalk/dialogs-newlayer.png create mode 100644 doc/chalk/dialogs-oilpaint.png create mode 100644 doc/chalk/dialogs-pixelize.png create mode 100644 doc/chalk/dialogs-raindrops.png create mode 100644 doc/chalk/dialogs-randomnoise.png create mode 100644 doc/chalk/dialogs-randompick.png create mode 100644 doc/chalk/dialogs-rotateimage.png create mode 100644 doc/chalk/dialogs-rotatelayer.png create mode 100644 doc/chalk/dialogs-roundcorners.png create mode 100644 doc/chalk/dialogs-separateimage.png create mode 100644 doc/chalk/dialogs-shearimage.png create mode 100644 doc/chalk/dialogs-shearlayer.png create mode 100644 doc/chalk/dialogs-smalltiles.png create mode 100644 doc/chalk/dialogs-sobel.png create mode 100644 doc/chalk/dialogs-substrate.png create mode 100644 doc/chalk/dialogs-unsharpmask.png create mode 100644 doc/chalk/dialogs-wave.png create mode 100644 doc/chalk/dialogs-waveletnoise.png create mode 100644 doc/chalk/faq.docbook create mode 100644 doc/chalk/index.docbook create mode 100644 doc/chalk/installation.docbook create mode 100644 doc/chalk/introduction.docbook create mode 100644 doc/chalk/mainscreen.png create mode 100644 doc/chalk/mountains-burn.png create mode 100644 doc/chalk/mountains-color.png create mode 100644 doc/chalk/mountains-darken.png create mode 100644 doc/chalk/mountains-divide.png create mode 100644 doc/chalk/mountains-dodge.png create mode 100644 doc/chalk/mountains-hue.png create mode 100644 doc/chalk/mountains-lighten.png create mode 100644 doc/chalk/mountains-multiply.png create mode 100644 doc/chalk/mountains-normal.png create mode 100644 doc/chalk/mountains-original.png create mode 100644 doc/chalk/mountains-overlay.png create mode 100644 doc/chalk/mountains-saturation.png create mode 100644 doc/chalk/mountains-screen.png create mode 100644 doc/chalk/mountains-value.png create mode 100644 doc/chalk/mountains.png create mode 100644 doc/chalk/newimage.png create mode 100644 doc/chalk/palettes-colors-gray.png create mode 100644 doc/chalk/palettes-colors-hsv.png create mode 100644 doc/chalk/palettes-colors-palettes.png create mode 100644 doc/chalk/palettes-colors-rgb.png create mode 100644 doc/chalk/palettes-colors-watercolors.png create mode 100644 doc/chalk/palettes-controlbox-bezier.png create mode 100644 doc/chalk/palettes-controlbox-brush.png create mode 100644 doc/chalk/palettes-controlbox-colorpicker.png create mode 100644 doc/chalk/palettes-controlbox-contiguousfill.png create mode 100644 doc/chalk/palettes-controlbox-crop.png create mode 100644 doc/chalk/palettes-controlbox-duplicate.png create mode 100644 doc/chalk/palettes-controlbox-ellipse.png create mode 100644 doc/chalk/palettes-controlbox-fill.png create mode 100644 doc/chalk/palettes-controlbox-gradient.png create mode 100644 doc/chalk/palettes-controlbox-histogram.png create mode 100644 doc/chalk/palettes-controlbox-line.png create mode 100644 doc/chalk/palettes-controlbox-overview.png create mode 100644 doc/chalk/palettes-controlbox-paintwithfilters.png create mode 100644 doc/chalk/palettes-controlbox-polygon.png create mode 100644 doc/chalk/palettes-controlbox-polyline.png create mode 100644 doc/chalk/palettes-controlbox-rectangle.png create mode 100644 doc/chalk/palettes-controlbox-select.png create mode 100644 doc/chalk/palettes-controlbox-selectcontiguous.png create mode 100644 doc/chalk/palettes-controlbox-selectmagnetic.png create mode 100644 doc/chalk/palettes-controlbox-selectsimilar.png create mode 100644 doc/chalk/palettes-controlbox-star.png create mode 100644 doc/chalk/palettes-controlbox-text.png create mode 100644 doc/chalk/palettes-controlbox-transform.png create mode 100644 doc/chalk/palettes-layers-layers.png create mode 100644 doc/chalk/palettes-layers-scriptsmanager.png create mode 100644 doc/chalk/preferences-color.png create mode 100644 doc/chalk/preferences-display.png create mode 100644 doc/chalk/preferences-general.png create mode 100644 doc/chalk/preferences-grid.png create mode 100644 doc/chalk/preferences-performance.png create mode 100644 doc/chalk/preferences-sidebar.png create mode 100644 doc/chalk/preferences-tablet.png create mode 100644 doc/chalk/settings.docbook create mode 100644 doc/chalk/tool-bezier-example.png create mode 100644 doc/chalk/tool-bezier-example2.png create mode 100644 doc/chalk/tool-bezier-example3.png create mode 100644 doc/chalk/tool-bezier.png create mode 100644 doc/chalk/tool-brush.png create mode 100644 doc/chalk/tool-colorpicker.png create mode 100644 doc/chalk/tool-contiguousfill.png create mode 100644 doc/chalk/tool-crop.png create mode 100644 doc/chalk/tool-duplicate.png create mode 100644 doc/chalk/tool-ellipse.png create mode 100644 doc/chalk/tool-eraseselection.png create mode 100644 doc/chalk/tool-gradient.png create mode 100644 doc/chalk/tool-line.png create mode 100644 doc/chalk/tool-move.png create mode 100644 doc/chalk/tool-paintselection.png create mode 100644 doc/chalk/tool-paintwithfilters-example.png create mode 100644 doc/chalk/tool-paintwithfilters.png create mode 100644 doc/chalk/tool-pan.png create mode 100644 doc/chalk/tool-perspectivegrid.png create mode 100644 doc/chalk/tool-perspectivetransform.png create mode 100644 doc/chalk/tool-polygon.png create mode 100644 doc/chalk/tool-polyline.png create mode 100644 doc/chalk/tool-rectangle.png create mode 100644 doc/chalk/tool-selectbezier.png create mode 100644 doc/chalk/tool-selectcontiguous.png create mode 100644 doc/chalk/tool-selectelliptical.png create mode 100644 doc/chalk/tool-selectmagnetic.png create mode 100644 doc/chalk/tool-selectoutline.png create mode 100644 doc/chalk/tool-selectpolygonal.png create mode 100644 doc/chalk/tool-selectrectangular.png create mode 100644 doc/chalk/tool-selectsimilar.png create mode 100644 doc/chalk/tool-star.png create mode 100644 doc/chalk/tool-text.png create mode 100644 doc/chalk/tool-transform.png create mode 100644 doc/chalk/tool-zoom.png create mode 100644 doc/chalk/toolbar-brushes-brushshapes-autobrush.png create mode 100644 doc/chalk/toolbar-brushes-brushshapes-custombrush.png create mode 100644 doc/chalk/toolbar-brushes-brushshapes-predefined.png create mode 100644 doc/chalk/toolbar-brushes-gradients.png create mode 100644 doc/chalk/toolbar-brushes-patterns-custompattern.png create mode 100644 doc/chalk/toolbar-brushes-patterns.png create mode 100644 doc/chalk/toolbar-brushesandstuff.png create mode 100644 doc/chalk/toolbar-chalk.png create mode 100644 doc/chalk/toolbar-edit.png create mode 100644 doc/chalk/toolbar-file.png create mode 100644 doc/chalk/toolbar-navigation.png create mode 100644 doc/chalk/toolbar-transformationtools.png create mode 100644 doc/chalk/toolbars-button-zoomin.png create mode 100644 doc/chalk/toolbars-button-zoomout.png create mode 100644 doc/chalk/tutorial-quick-starts.docbook create mode 100644 doc/chalk/tutorial-quick-starts1.png create mode 100644 doc/chalk/tutorial-quick-starts10.png create mode 100644 doc/chalk/tutorial-quick-starts11.png create mode 100644 doc/chalk/tutorial-quick-starts12.png create mode 100644 doc/chalk/tutorial-quick-starts2.png create mode 100644 doc/chalk/tutorial-quick-starts3.png create mode 100644 doc/chalk/tutorial-quick-starts4.png create mode 100644 doc/chalk/tutorial-quick-starts5.png create mode 100644 doc/chalk/tutorial-quick-starts6.png create mode 100644 doc/chalk/tutorial-quick-starts7.png create mode 100644 doc/chalk/tutorial-quick-starts8.png create mode 100644 doc/chalk/tutorial-quick-starts9.png create mode 100644 doc/chalk/tutorial-select-layer-1.png create mode 100644 doc/chalk/tutorial-select-layer-10.png create mode 100644 doc/chalk/tutorial-select-layer-11.png create mode 100644 doc/chalk/tutorial-select-layer-12.png create mode 100644 doc/chalk/tutorial-select-layer-13.png create mode 100644 doc/chalk/tutorial-select-layer-2.png create mode 100644 doc/chalk/tutorial-select-layer-3.png create mode 100644 doc/chalk/tutorial-select-layer-4.png create mode 100644 doc/chalk/tutorial-select-layer-5.png create mode 100644 doc/chalk/tutorial-select-layer-6.png create mode 100644 doc/chalk/tutorial-select-layer-7.png create mode 100644 doc/chalk/tutorial-select-layer-8.png create mode 100644 doc/chalk/tutorial-select-layer-9.png create mode 100644 doc/chalk/tutorial-select-layer-sample.png create mode 100644 doc/chalk/tutorial-select-layer.docbook create mode 100644 doc/chalk/tutorial-starting.docbook create mode 100644 doc/chalk/tutorial-tablet-1.png create mode 100644 doc/chalk/tutorial-tablet-2.png create mode 100644 doc/chalk/tutorial-tablet-3.png create mode 100644 doc/chalk/tutorial-tablet.docbook create mode 100644 doc/chalk/tutorial.docbook create mode 100644 doc/chalk/using-colorspaces.docbook create mode 100644 doc/chalk/using-filters.docbook create mode 100644 doc/chalk/using-images.docbook create mode 100644 doc/chalk/using-layers.docbook create mode 100644 doc/chalk/using-selections-1.png create mode 100644 doc/chalk/using-selections-2.png create mode 100644 doc/chalk/using-selections-3.png create mode 100644 doc/chalk/using-selections-4.png create mode 100644 doc/chalk/using-selections-5.png create mode 100644 doc/chalk/using-selections-6.png create mode 100644 doc/chalk/using-selections.docbook create mode 100644 doc/chalk/using-views.docbook create mode 100644 filters/chalk/Makefile.am create mode 100644 filters/chalk/configure.in.in create mode 100644 filters/chalk/gmagick/Makefile.am create mode 100644 filters/chalk/gmagick/chalk_magick.desktop create mode 100644 filters/chalk/gmagick/chalk_magick_export.desktop create mode 100644 filters/chalk/gmagick/chalk_magick_import.desktop create mode 100644 filters/chalk/gmagick/configure.in.bot create mode 100644 filters/chalk/gmagick/kis_image_magick_converter.cc create mode 100644 filters/chalk/gmagick/kis_image_magick_converter.h create mode 100644 filters/chalk/gmagick/magickexport.cpp create mode 100644 filters/chalk/gmagick/magickexport.h create mode 100644 filters/chalk/gmagick/magickimport.cpp create mode 100644 filters/chalk/gmagick/magickimport.h create mode 100644 filters/chalk/jpeg/Makefile.am create mode 100644 filters/chalk/jpeg/chalk_jpeg.desktop create mode 100644 filters/chalk/jpeg/chalk_jpeg_export.desktop create mode 100644 filters/chalk/jpeg/chalk_jpeg_import.desktop create mode 100644 filters/chalk/jpeg/configure.in.bot create mode 100644 filters/chalk/jpeg/iccjpeg.c create mode 100644 filters/chalk/jpeg/iccjpeg.h create mode 100644 filters/chalk/jpeg/kis_jpeg_converter.cc create mode 100644 filters/chalk/jpeg/kis_jpeg_converter.h create mode 100644 filters/chalk/jpeg/kis_jpeg_export.cc create mode 100644 filters/chalk/jpeg/kis_jpeg_export.h create mode 100644 filters/chalk/jpeg/kis_jpeg_import.cc create mode 100644 filters/chalk/jpeg/kis_jpeg_import.h create mode 100644 filters/chalk/jpeg/kis_wdg_options_jpeg.ui create mode 100644 filters/chalk/libkisexif/Makefile.am create mode 100644 filters/chalk/libkisexif/kis_exif_io.cpp create mode 100644 filters/chalk/libkisexif/kis_exif_io.h create mode 100644 filters/chalk/magick/Makefile.am create mode 100644 filters/chalk/magick/chalk_magick.desktop create mode 100644 filters/chalk/magick/chalk_magick_export.desktop create mode 100644 filters/chalk/magick/chalk_magick_import.desktop create mode 100644 filters/chalk/magick/configure.in.bot create mode 100644 filters/chalk/magick/kis_image_magick_converter.cc create mode 100644 filters/chalk/magick/kis_image_magick_converter.h create mode 100644 filters/chalk/magick/magickexport.cpp create mode 100644 filters/chalk/magick/magickexport.h create mode 100644 filters/chalk/magick/magickimport.cpp create mode 100644 filters/chalk/magick/magickimport.h create mode 100644 filters/chalk/openexr/Makefile.am create mode 100644 filters/chalk/openexr/chalk_openexr.desktop create mode 100644 filters/chalk/openexr/chalk_openexr_export.desktop create mode 100644 filters/chalk/openexr/chalk_openexr_import.desktop create mode 100644 filters/chalk/openexr/configure.in.bot create mode 100644 filters/chalk/openexr/kis_openexr_export.cpp create mode 100644 filters/chalk/openexr/kis_openexr_export.h create mode 100644 filters/chalk/openexr/kis_openexr_import.cpp create mode 100644 filters/chalk/openexr/kis_openexr_import.h create mode 100644 filters/chalk/pdf/Makefile.am create mode 100644 filters/chalk/pdf/chalk_pdf.desktop create mode 100644 filters/chalk/pdf/chalk_pdf_import.desktop create mode 100644 filters/chalk/pdf/configure.in.bot create mode 100644 filters/chalk/pdf/configure.in.in create mode 100644 filters/chalk/pdf/kis_pdf_import.cpp create mode 100644 filters/chalk/pdf/kis_pdf_import.h create mode 100644 filters/chalk/pdf/kis_pdf_import_widget.cpp create mode 100644 filters/chalk/pdf/kis_pdf_import_widget.h create mode 100644 filters/chalk/pdf/pdfimportwidgetbase.ui create mode 100644 filters/chalk/png/Makefile.am create mode 100644 filters/chalk/png/chalk_png.desktop create mode 100644 filters/chalk/png/chalk_png_export.desktop create mode 100644 filters/chalk/png/chalk_png_import.desktop create mode 100644 filters/chalk/png/configure.in.bot create mode 100644 filters/chalk/png/kis_png_converter.cc create mode 100644 filters/chalk/png/kis_png_converter.h create mode 100644 filters/chalk/png/kis_png_export.cc create mode 100644 filters/chalk/png/kis_png_export.h create mode 100644 filters/chalk/png/kis_png_import.cc create mode 100644 filters/chalk/png/kis_png_import.h create mode 100644 filters/chalk/png/kis_wdg_options_png.ui create mode 100644 filters/chalk/raw/Makefile.am create mode 100644 filters/chalk/raw/chalk_raw.desktop create mode 100644 filters/chalk/raw/chalk_raw_import.desktop create mode 100644 filters/chalk/raw/dcraw.1 create mode 100644 filters/chalk/raw/dcraw.c create mode 100644 filters/chalk/raw/kis_raw_import.cpp create mode 100644 filters/chalk/raw/kis_raw_import.h create mode 100644 filters/chalk/raw/wdgrawimport.ui create mode 100644 filters/chalk/tiff/Makefile.am create mode 100644 filters/chalk/tiff/chalk_tiff.desktop create mode 100644 filters/chalk/tiff/chalk_tiff_export.desktop create mode 100644 filters/chalk/tiff/chalk_tiff_import.desktop create mode 100644 filters/chalk/tiff/configure.in.bot create mode 100644 filters/chalk/tiff/kis_dlg_options_tiff.cpp create mode 100644 filters/chalk/tiff/kis_dlg_options_tiff.h create mode 100644 filters/chalk/tiff/kis_tiff_converter.cc create mode 100644 filters/chalk/tiff/kis_tiff_converter.h create mode 100644 filters/chalk/tiff/kis_tiff_export.cc create mode 100644 filters/chalk/tiff/kis_tiff_export.h create mode 100644 filters/chalk/tiff/kis_tiff_import.cc create mode 100644 filters/chalk/tiff/kis_tiff_import.h create mode 100644 filters/chalk/tiff/kis_tiff_reader.cc create mode 100644 filters/chalk/tiff/kis_tiff_reader.h create mode 100644 filters/chalk/tiff/kis_tiff_stream.cc create mode 100644 filters/chalk/tiff/kis_tiff_stream.h create mode 100644 filters/chalk/tiff/kis_tiff_writer_visitor.cpp create mode 100644 filters/chalk/tiff/kis_tiff_writer_visitor.h create mode 100644 filters/chalk/tiff/kis_tiff_ycbcr_reader.cc create mode 100644 filters/chalk/tiff/kis_tiff_ycbcr_reader.h create mode 100644 filters/chalk/tiff/kis_wdg_options_tiff.ui create mode 100644 filters/chalk/tiff/kis_ycbcr_colorspace.h create mode 100644 filters/chalk/xcf/Makefile.am create mode 100644 filters/chalk/xcf/chalk_xcf_export.desktop create mode 100644 filters/chalk/xcf/chalk_xcf_import.desktop create mode 100644 filters/chalk/xcf/xcf/README create mode 100644 filters/chalk/xcf/xcf/xcf-load.cc create mode 100644 filters/chalk/xcf/xcf/xcf-load.h create mode 100644 filters/chalk/xcf/xcf/xcf-private.h create mode 100644 filters/chalk/xcf/xcf/xcf-read.cc create mode 100644 filters/chalk/xcf/xcf/xcf-read.h create mode 100644 filters/chalk/xcf/xcf/xcf-save.cc create mode 100644 filters/chalk/xcf/xcf/xcf-save.h create mode 100644 filters/chalk/xcf/xcf/xcf-seek.cc create mode 100644 filters/chalk/xcf/xcf/xcf-seek.h create mode 100644 filters/chalk/xcf/xcf/xcf-write.cc create mode 100644 filters/chalk/xcf/xcf/xcf-write.h create mode 100644 filters/chalk/xcf/xcfexport.cpp create mode 100644 filters/chalk/xcf/xcfexport.h create mode 100644 filters/chalk/xcf/xcfimport.cpp create mode 100644 filters/chalk/xcf/xcfimport.h create mode 100644 plugins/scan/scan-chalk.rc create mode 100644 tools/quickprint/chalk_konqi.desktop diff --git a/Doxyfile.temp b/Doxyfile.temp index 6f60392b..bb8dc58b 100644 --- a/Doxyfile.temp +++ b/Doxyfile.temp @@ -61,7 +61,7 @@ INPUT = example \ koshell \ kplato \ kpresenter \ - krita \ + chalk \ kspread kugar kword lib FILE_PATTERNS = *.h RECURSIVE = YES diff --git a/README b/README index e979baed..67fa6158 100644 --- a/README +++ b/README @@ -25,7 +25,7 @@ The applications currently included in KOffice are: Flowcharting program - Kexi Integrated data management -- Krita +- Chalk A pixel graphics tool - KFormula A mathematical formula editor diff --git a/README.APPS b/README.APPS index 6e76e0b2..ebdafae4 100644 --- a/README.APPS +++ b/README.APPS @@ -18,7 +18,7 @@ in the 1.6 cycle: - lib/kross - kchart - kexi -- krita +- chalk - kdgantt - kplato - doc diff --git a/README.PACKAGERS b/README.PACKAGERS index af384990..98791fa9 100644 --- a/README.PACKAGERS +++ b/README.PACKAGERS @@ -18,7 +18,7 @@ Table Of Contents 1. Database drivers (MySQL, PostgreSQL) 2. Development files 2.1. KexiDB development files - 2.2. Krita development files + 2.2. Chalk development files 3. Scripting support 4. Microsoft Access Import (optional, recommended) 5. Quick command-line tests of Kexi installation @@ -78,13 +78,13 @@ The files are: The installation can be tested by building the MS Access import plugin as described in the Microsoft Access import plugin section below. -2.2. Krita development files +2.2. Chalk development files -Location: koffice/krita/core, koffice/krita/sdk, -koffice/krita/kritacolor, koffice/krita/ui +Location: koffice/chalk/core, koffice/chalk/sdk, +koffice/chalk/chalkcolor, koffice/chalk/ui These directories contain header files that are installed and can be -used by plugin developers to extend Krita with new tools, colorspaces, +used by plugin developers to extend Chalk with new tools, colorspaces, paint-ops and more. If your distribution packages development files separately, it may be a good idea to make a package with these headers. @@ -93,7 +93,7 @@ separately, it may be a good idea to make a package with these headers. -------------------- Preliminary support for Ruby and Python scripting is available for -Krita and Kexi. +Chalk and Kexi. It can be disabled by passing the '--disable-scripting' option to 'configure'. @@ -131,15 +131,15 @@ For example, the Python scripting package may contain: share/apps/kexi/scripts/importxhtml/ImportXHTML.rc share/apps/kexi/scripts/projectdocumentor/ProjectDocumentor.py share/apps/kexi/scripts/projectdocumentor/ProjectDocumentor.rc - share/apps/krita/scripts/invert.py - share/apps/krita/scripts/reshapehisto.py + share/apps/chalk/scripts/invert.py + share/apps/chalk/scripts/reshapehisto.py and the Ruby scripting package may contain: lib/kde3/krossruby.so lib/kde3/krossruby.la - share/apps/krita/scripts/ruby/invert.rb - share/apps/krita/scripts/ruby/changecs.rb - share/apps/krita/scripts/ruby/randompaint.rb + share/apps/chalk/scripts/ruby/invert.rb + share/apps/chalk/scripts/ruby/changecs.rb + share/apps/chalk/scripts/ruby/randompaint.rb 4. Microsoft Access Import (optional, recommended) diff --git a/chalk/AUTHORS b/chalk/AUTHORS new file mode 100644 index 00000000..3ef41cde --- /dev/null +++ b/chalk/AUTHORS @@ -0,0 +1,20 @@ +Adrian Page +Andrew Richards +Bart Coppens +Boudewijn Rempt +Carsten Pfeiffer +Casper Boemann +Cyrille Berger +Danny Allen +Dirk Schoenberger +Gábor Lehel +John Califf +Matthias Elter +Melchior Franz +Michael Koch +Michael Thaler +Patrick Julien +Roger Larsson +Sven Langkamp + +Current maintainer: Boudewijn Rempt diff --git a/chalk/ChangeLog b/chalk/ChangeLog new file mode 100644 index 00000000..15793398 --- /dev/null +++ b/chalk/ChangeLog @@ -0,0 +1 @@ +We really should use cvs2changelog or something like that... diff --git a/chalk/HACKING b/chalk/HACKING new file mode 100644 index 00000000..c6f4ba66 --- /dev/null +++ b/chalk/HACKING @@ -0,0 +1,93 @@ +Since 1999, people have been hacking on Chalk. Everyone brought their +own coding style, their own code conventions, their own likes and +dislikes. Me, (Boudewijn that is), I like indents of four spaces, and +no scope prefixes for variables. However, in the interests of +consistency, these are the rules new code should adhere to: + + +Indentation + + With four spaces. Use the default Java indentation + style of (X)Emacs or KDevelop -- also for brace placement. + +Includes + + Avoid as much as possible #includes in header files; use forward declarations + of classes. + +Initializers + + Avoid as much as possible initializers in the body of the constructor. Use + initializer lists instead. + +Scope prefixes + + Use only m_ for class-level variables. No other scope prefixes; no g_, l_, + no 'p' for pointer variables. + +Shared pointers + + Use shared pointers wherever possible. + +Getter/setter + + Chalk doesn't use Qt's properties -- yet. If you want to introduce use of + properties, convert any and all classes in Chalk before committing. + + Getter/setters are named 'x() for getters and setX(int x) for setters. If you + come across violations of this rule, change the code. + +Class naming + + If you use a well-known design pattern, name the class according to the design + pattern. All files should start with 'kis_', all classes with the 'Kis' prefix. + In filenames, separate words with an underscore; in classnames use capital letters. + Example: kis_new_class.h/KisNewClass. + + The only exception to this rule are interfaces. + Example: kis_tool.h/KisToolInterface. + +Function naming + + Functions should be named in camelBackedFashion, to conform to Qt's standards. + If you encounter functions in c_style_like_this, feel free to rename. Also: + verbNoun -- i.e., rotateLayer, not layer_rotate. The latter is a true c-ism, + introduced by a language that needs to prefix the 'class' name to every function + in order to have something that not quite OO. + +Variable/Parameter names + + Variable/parameter names start with an undercast letter. A name composed of different + words is done in camelBackedStyle. + +Designer + + Chalk has started to use designer. All dialogs and all widgets that have a tqlayout + manager must be done in designer. We don't add code nor add signal/slot connections + in designer + +Enums + + All enums should be prefixed with 'enum'. + +Namespaces + + Currently, we only use anonymous (right term?) namespaces for things like undo + commands. For the rest, some classes have a 'Kis' prefix, others don't. This should + be made consistent, and we might want to use namespaces to keep all of Chalk + inside. + +Files and classes + + It's preferred (and strongly preferred) to have only one class per .h/.cpp file. + (Which is logical, because otherwise you won't be able to keep to the naming scheme.) + +Spaces + + Keep the source airy and open. (However, maybe I was wrong in wanting spaces around ->...) + +Slots and Q_SIGNALS + + Prefix Q_SLOTS with slot and Q_SIGNALS with sig: slotUpdateSelection, sigSelectionUpdated. + +Boudewijn Rempt \ No newline at end of file diff --git a/chalk/IMAGE_LIBRARIES b/chalk/IMAGE_LIBRARIES new file mode 100644 index 00000000..f2f0c1dc --- /dev/null +++ b/chalk/IMAGE_LIBRARIES @@ -0,0 +1,259 @@ +WARNING: OBSOLETE (Chalk's internal code has become much better by now) + +From time to time, people come up with the suggestion to use an +existing imaging library with Chalk, to replace our own core. This +file contains a list of all libraries known to me, and a short +evaluation. + +Perhaps, one day, we will decide to either use an existing library, or +remodel our core after one of those. Of the libraries present, except +for our own Chalk, Vigra look like it's the best bet from a technical +point of view, with Vips a good runner-up. + + +* Chalk (http://koffice.kde.org/chalk) + +Chalk contains its own 2D image library, consisting of the tile +manager, the layer classes and KisPainter. We really should separate +this 2d lib from the interface code, and put it in a real lib with +a well-defined interface. + +Advantages: + + - Already works + - Optimized for interactive work + - Allows different colour models + - Uses GraphicsMagick or ImageMagick for loading and saving. + +Disadvantages: + + - Does not work well with different channel depths + - Not integrated with CMS + - TileManager complicated and slow for pixel reading and + writing. + +* Gimp (http://www.gimp.org) + +The Gimp contains a complex core that allows interactive painting of +images with a channel depth of 8 bits. + +Advantages: + + - Well tested, very complete + - Optimized for interactive usage + +Disadvantages: + + - Written in C. + - Not readily available as a library. + - Depends on glib and gtk + - 8-bit only + - No colour models + - Has problems handling really large images + +* Vigra (http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/) + +Vigra is a C++ imaging library written by Ullrich Koetthe to +demonstrate his Phd thesis on flexible image algorithms. + +Advantages: + + - Supports very large images + - Supports colour models + - Supports different bit depths through templating + - C++ + - Relatively small + - Relatively well-documented + +Disadvantages: + + - License incompatible with GPL? + - Not optimized for interactive use + - Unsure about future development since this was a research + project. + +* Vips (http://www.vips.ecs.soton.ac.uk/) + +Vips is a C library with a C++ layer. It has been designed for +handling very large images, mainly in the context of research into +paintings in museums like the National Gallery. It comes with a gtk2 +gui. + +Advantages: + + - Handles very large images + - Handles colour models + - Handles different bit depths + - C++ interface + +Disadvantages: + + - Not optimized for paintbox type apps (even though it is + possible). + - Very large. + +* VXL (http://vxl.sourceforge.net/) + +VXL is a collection of small libraries that are used for compution +vision and imaging purposes in an academic setting. + +Advantages: + + - Handles very large images + - C++ + +Disadvantages: + + - Not recently updated + - Comes with its own core libraries that replace standard C++ + - Optimized for simple rgb images. + - No license at all + - Badly documented + +* CImg (http://cimg.sourceforge.net/) + +CImg is a very cool, very small library that offers some extremely +innovative image effects, like inpainting of damaged or noise images. + +Advantages: + + - Small + - GPL + - Cool stuff + +Disadvantages: + + - Everything, including GUI stuff, in one header file. + - badly documented. + + +* Gegl (http://www.gegl.org/) + +Gegl was intended to become the Gimp 2.0 core, but development had +stalled so much that the move to Gegl didn't happen before Gimp 2.0. +However, the Thawte millionaire whose name has escaped me, has +promised to support gegl development financially, freeing the +developer to work full-time on it. It is, more or less, an attempt to +write a templated library in C++ with the help of a custom language to +describe image operations. + +Advantages: + + - It's got money behind it + - Small + - Optimized for interactive use + +Disadvantages: + + - Not finished yet + - C + - Complex hack around the fact that C is a low-level language + +* libart_lgpl (http://www.levien.com/libart/) + +Libart isn't really an image library, but rather a canvas that can be +used to paint images on. It is optimized for vector graphics, and is +used by Karbon to render tqshapes before display. + +Advantages: + + - Raph Levien is really good at this stuff, so libart is + quality + +Disadvantages: + + - C + - It isn't an image library, really + + +* java2D (http://java.sun.com/j2se/1.4.2/docs/guide/2d/index.html) + + +Java2D is more or less complete library to write a paint app around. +It offers image types, colour spaces, kernel convolutions and text. +It's in Java, of course, and the free re-implementation is not done +yet, and besides, is based around Cairo. + +Advantages: + + - Neat OO design + - Complete + +Disadvantages: + + - Java + - Not free + - Has some legacy cruft. + +* ImageMagick/GraphicsMagick (http://imagemagick.org/, http://www.graphicsmagick.org/) + +GraphicsMagick is ImageMagick with a different license, and a +focus on API stability. GM and IM now also differ slightly in terms of +features offered. Chalk used to be based around IM (which can still be +seen in many places in the code). The IM core was dropped in favour of +the present core because it turned out that IM was not re-entrant, +making it hard to use in an interactive application. + +Advantages: + + - Mature + - C++ interface + - Full-featured + - RGB and CMYK (but not more) + - License compatible with Chalk + - Under active development + +Disadvantages: + + - Bit-depth a compile-time option + - Not re-entrant: not optimized for interactive use. + +* Paintlib2 (http://www.paintlib.de/paintlib/) + +A portable (windows/Linux) library for image loading, manipulation and +saving. The same kind of thing as IM/GM, but not quite as mature. + +Advantages: + +Disadvantages: + + - No support for larger bit depths per channel + - Windows (bmp) centric + - Development seems to have stopped in 2000 + + +* Antigrain (http://www.antigrain.com/) + +Antigrain is a graphics lib that specializes in high-quality anti-aliasing. It can be +useful to mine for algorithms, but is mainly a library to render vector data to bitmaps, +just like libart or cairo. + +Advantages: + + - High quality algorithms + - Completely free license. + - Colour-space agnostic + +Disadvantages: + + - Not a complete 2D library + - self-admittedly complex and hard to use. + - No support for greater bit-depths. + +* The Visualization Toolkit (VTK, http://public.kitware.com/VTK/) + +A very big C++ library for 2d and 3d image processing and visualisation. It's +too big to easily evaluate for me. + +Advantages + + - It is used in other Qt applications, like Julius + - Probably very good + +Disadvantages + + - The book is very expensive + - Uses its own make equivalent, CMake + - Very large + +* Java Advanced Imaging diff --git a/chalk/Makefile.am b/chalk/Makefile.am new file mode 100644 index 00000000..246c5bb1 --- /dev/null +++ b/chalk/Makefile.am @@ -0,0 +1,47 @@ +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + +## The common lib, shared between the part, the plugins, and the filters +lib_LTLIBRARIES = libchalkcommon.la +libchalkcommon_la_SOURCES = dummy.cc +libchalkcommon_la_LDFLAGS = $(all_libraries) $(LIB_QT) -version-info 1:0 -no-undefined +libchalkcommon_la_LIBADD = sdk/libchalksdk.la core/libchalkimage.la ui/libchalkui.la chalkcolor/libchalkcolor.la $(LCMS_LIBS) $(LIB_KOFFICEUI) $(LIB_KOPAINTER) $(LIB_KOPALETTE) $(LIB_XINPUTEXT) + +## The part +kde_module_LTLIBRARIES = libchalkpart.la +libchalkpart_la_SOURCES = chalk_part_init.cc +libchalkpart_la_LDFLAGS = $(all_libraries) $(LIB_QT) -L../lib/kofficecore/.libs/ -lkofficecore -L../lib/kofficeui/.libs/ -lkofficeui -L../lib/store/.libs/ -lkstore -L../chalk/ui/.libs -lchalkui -module $(KDE_PLUGIN) +libchalkpart_la_LIBADD = libchalkcommon.la + +METASOURCES = AUTO + +## The kdeinit loadable module and executable +kdeinit_LTLIBRARIES = chalk.la +bin_PROGRAMS = +chalk_la_SOURCES = main.cc +chalk_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) +chalk_la_LIBADD = $(LIB_KOFFICECORE) + +xdg_apps_DATA = chalk.desktop +kdemimedir = $(kde_mimedir)/application + +rcdir = $(kde_datadir)/chalk +rc_DATA = chalk.rc chalk_readonly.rc + +SUBDIRS = sdk chalkcolor core ui . dtd colorspaces plugins data pics +# Needed to compile libchalkcommon.la, which has no source files to itself +# but everything in static libs. +dummy.cc: + echo > dummy.cc + +messages: rc.cpp + $(EXTRACTRC) `find . -name \*.ui` >> rc.cpp + $(EXTRACTRC) `find . -name \*.rc` >> rc.cpp + perl extracti18n.pl > i18ndata + $(XGETTEXT) i18ndata rc.cpp `find . -name \*.cc -o -name \*.h -o -name \*.cpp` ui/kis_aboutdata.h -o $(podir)/chalk.pot + rm -f i18ndata + +DOXYGEN_EXCLUDE = CImg.h colorspaces plugins chalkcolor/colorspaces core/tiles +include $(top_srcdir)/admin/Doxyfile.am + +kde_services_DATA = chalkpart.desktop + diff --git a/chalk/README b/chalk/README new file mode 100644 index 00000000..6155f277 --- /dev/null +++ b/chalk/README @@ -0,0 +1,13 @@ +Chalk + +Chalk is a paint application for bitmap images. It's also, according to +the Dictionary of Phrase and Fable: + +The first of four Hindu periods contained in the great Yuga, when the +genius of Truth and Right, in the form of bull, stood firm on his four +feet, and man gained nothing by iniquity. + +In the Mahabharata, the name 'chalk' is used in a context where this +can be translated with 'perfect' - the perfect age. + +Chalk is Swedish for chalk (or pencil?) and rita means "to write". diff --git a/chalk/TODO b/chalk/TODO new file mode 100644 index 00000000..7cd95e6b --- /dev/null +++ b/chalk/TODO @@ -0,0 +1,181 @@ +After 1.5 cleanups + +* Move core/ui class private members to d-pointers +* Selections, adj. masks, wetness, heigh masks (all 8-bit mask ideas) + as sublayers to paint layers, and make them movable between layers + and x,y, toggle on/off. +* Fix KisFilter::colorSpaceIndependence/worksWith overlap +* Add api & gui to exclude channels from compositing +* Add a mechanism for cspaces to start long-running filters when a paintdev + is created -- and a gui to turn that on and off, perhaps something analogous + to a channels box +* Make set of filter categories extensible +* BUG 121975: selections and group layers. +* Add end poly entry to the popup menu when the poly tool is active (note: + make this more generically useful for tools. Great idea by David Herman +* Paint direct should be paint directly + +UI stuff: + +* color picker: top combo should be as wide as the whole widget; the widget is a bit too big, + we should try to make the listview a lot smaller. Maybe just use labels here? +* The edit palette dialog two-step should be changed into a single dialog + +Code organization + +Transform tool (CBR) + + * Implement native integer versions for bell, bspline, lanczos3 and mitchell filters + * The option widget should be connected + * Figure out why scaling down produces sum of weights <255 (Hermite filter) + * Implement gui, create cursors and update visitor for shearing + +Integration + + * A chalk document embedded in KWord has the wrong scaling and transparency + * A chalk document embedded in another document prints at the wrong place + * Embedded KOffice objects don't paint themselves correctly + * There is currently no kimgio module for Chalk images: implement one by + saving a rendered png image into the chalk file and extracting that from + kimgio. (Saving of a png image in .kra files is done; now we just need to + add the kimgio file) + * There is no easy way to get back from editing an embedded document (if the image is larger + than the window) + +Colorspace independence (found with the test colorstrategy) + + * Check and double check the cms capabilities: especially the use of + profiles in the render/convert/edit paths. + * Merge grayscale layers back into one color image. + +Core + + * The fill painter (and perhaps other paitners, too) should call addDirtyRect, and the floodfill + tool should use that rect to blit and notify the image, instead of notifying the complete image.s + * Fix image resolution handling (zooming, pixel-for-pixel, 100% == zoomed to dpi/xdpi etc.) + * Loading and saving of selections + * Anti-aliased filling (requires some simple colorspace function to merge 2 Pixels) + * Load/save configuration of everything user-settable. + * Long painter operations (e.g., convolution painter) should use the + progressbar and be cancelable. + * Color adjustment filters seem to have a problem with partially selected pixels + +File Format: + + * Save & load all annotations in .kra files + * Save & load more information, like PNG comments, gamma information, etc + + +Import/Export + + * Fix gimp XCF PSD and import/export (ImageMagick hacking...) + * Fix imports to import metadata. + +User Interface + * Add an explanatory textframe to the scaling filter combobox. + * Add a good crosshair cursor and a crosshair cursor that extends to the rulers. + * Add a cheatsheet widget that integrates with knewstuff to have tutorials that people + can download and follow from Chalk. + * Add opacity widget (One that grows more white or transparent (showing those gray blocks) based on the + input) + * Add out-of-gamut selection + * Fix layout problems in tool option widgets. + * Disable dragging the toolbox from dock position to dock position (see Karbon) + * Disable all relevant actions when a layer is locked or invisible. See bug #90456. Show locked status of current layer in statusbar. + * Add link check to new image dialog to sync width and height + * The description field in color settings is empty + * Implement the following dialogs / widgets: + - Variations (#Boudewijn) + - Gradient: remove the autogradient dialog and make into a proper + gradient dialog, and allow saving gradients. + + * Show which tool is associated with which pointer (mouse, stylus, eraser, other stylusses) In the statusbar. + * Allow guides to be disabled. Allow diagonal guides (useful for perspective drawings) Bug #108398 + * Allow snapping to guides. + * Create templates for often-used image formats. Add save-as-template + * Add deselect with rmb -- maybe also selectable actions with other tools on rmb? + * Fix crop tool: when pressing shift, keep aspect ratio, implement gray mask. + (Michael Thaler) + * Allow shape tools to be filled with gradients + + Dockers + * Tabs in dockers drag-and-droppable (vector of docker + windows, create new docker if tab dropped outside existing + docker window) + * Add bird's eye view tab to dockers. + * Add action (macro) docker + * Add navigation/zoom docker + * Add history docker + + * Doing a copy of a selection, but having the wrong layer selected gives + me an empty selection (all transparent). Pressing paste should say so + (popup) instead of creating a new useless layer. + * the selection tools should allow pressing shift to go to 'substract' + mode without adjusting the combobox for the current tool. (a different + pointer would be nice as well) + + * Pressing save for the first time gives me the 'save document as' dialog + which is set to 'png' as default file format. + I suggest to set the default format (in the "save as" dialog) to the chalk + format for any image that has more then 1 layer. + + +Selections + + * On shearing, the whole image is mirrored, not the selected + bits. + * Add opacity slider to selection painting tools so you can + select something 50%. + +Profiles + + * Add an input profile combobox to the import image & scan dialogs + * Add an export profile combobox to the export image/print dialogs + * Add loading and saving of profiles associated with images in .chalk + files. + * Export profiles in tiff, png and jpg (this and the previous item + depend on ImageMagick or GraphicsMagick supporting this in some way.) + * Support out-of-gamut warning indications for parts of an image + containing unprintable colours (no idea how to implement this). -> this + is pretty easy with lcms + * preferences dialog can show non-existent profile for the monitor profile -> confusing + + +Tools + + * Zoom tool should zoom out when alt is pressed. Show zoom-minus cursor in that case + * Implement the following tools or paintops: + - fix airbrush tool (add rate option, add increase + of brush size if kept in one place) + - color changer, smudge tool,sharpen tool, blur + tool, dodge tool, burn tool, sponge tool (These + last are perhaps more generally: painting with + filters tool) + - stamp tool (paint with patttern/image selection) (#Cyrille) + - Text tool (use kotext with a transparent background here?) + - Measure tool + - calligraphic pen tool + + * Pressure sensivitize all relevant tools (e.g. line tool) + * Add resize slider to freehand tools that resizes the mean brush size. + * Implement path tools (Michael Thaler?) + * Sumi-e brush tool + * Natural media tools (chalk, ink, oil, watercolour -- fun!) + +Plugins + + * As many filters as possible :-) + +Modules + + * Add color models for HSV, YUV etc. + * Add Wet & Sticky model (in progress already) + * Implement Curtiss et. al. for watercolour (Levien, wet dreams. In progress) + * The composite ops in RGB -> composite.h do not take mask into account + - this goes for COPY and CLEAR in grayscale also + +Printing + + * No use of the resolution parameter (but the resolution dialog is still only a .ui file and not implemented at all) + * Use gutenprint or something better for image printing. + diff --git a/chalk/UIcomments b/chalk/UIcomments new file mode 100644 index 00000000..1b924240 --- /dev/null +++ b/chalk/UIcomments @@ -0,0 +1,59 @@ +Color palettes ; + +You can drag a color from the preview swatches but it is changing the +selected one at click and since dropping drops on the selected one, the +concept of duplicating the foreground to the background by dragging is +impossible. I suggest to do selecting of foreground/background color on +mouse release instead. + + + +Selections + +When you did a 'select all' and then create a selection nothing happens +since you can't select more then you already did. For that reason I +suggest to make select all and deselect lead to a similar situation where +adding a selection or substracting one will be smart and do make the +result of that select or deselect visible. In either case selecting a +part in both a fully selected and fully deselected image should lead to +the same result. + + + + +Thomas Zander + + +Missing tooltips (Carsten N.) + +LEGEND: NTAA No Tooltip At All + +Missing tooltips: + +KComboBox in the toolbar (the with 'Pixel Brush' for example) + +Overview-widget: NTAA + +Histogram: No Tooltip. Well, there is nothing but the histogram, there should be at least something... + +Context-Widgets of the tools: + +Star: NTAA + +Brush: NTAA + +Line: NTAA + +Rectangle: NTAA + +Ellispse: NTAA + +Polygone: NTAA + +Polyline: NTAA + +Duplicate Brush: NTAA diff --git a/chalk/chalk.desktop b/chalk/chalk.desktop new file mode 100644 index 00000000..e711f75b --- /dev/null +++ b/chalk/chalk.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %U +DocPath=chalk/index.html +Comment=Edit and paint images +Comment[bg]=Редактиране и оцветяване на изображения +Comment[ca]=Edita i pinta imatges +Comment[da]=Redigér og mal billeder +Comment[de]=Bilder zeichnen und bearbeiten +Comment[el]=Επεξεργασία και ζωγραφική εικόνων +Comment[eo]=Redakti kaj pentri bildojn +Comment[es]=Editar y pintar imágenes +Comment[et]=Piltide töötlemine ja joonistamine +Comment[fa]=ویرایش و رنگ‌آمیزی تصاویر +Comment[fi]=Muokkaa ja maalaa kuvia +Comment[fr]=Création et retouche d'images +Comment[fy]=Ofbyldings bewurkje en skilderje +Comment[gl]=Edita e pinta imaxes +Comment[he]=עריכה וצביעת תמונות +Comment[hu]=Képek szerkesztése +Comment[it]=Modifica e disegna immagini +Comment[ja]=描画と画像の編集 +Comment[km]=កែសម្រួល និង​គូរ​រូបភាព +Comment[lv]=Labot un zīmēt attēlus +Comment[nb]=Rediger og mal bilder +Comment[nds]=Biller malen un bewerken +Comment[ne]=छविहरू सम्पादन र पेन्ट गर्नुहोस् +Comment[nl]=Afbeeldingen bewerken en schilderen +Comment[pl]=Edycja i tworzenie obrazków +Comment[pt]=Editar e pintar as imagens +Comment[pt_BR]=Editar e pintar as imagens +Comment[ru]=Растровые рисунки +Comment[se]=Doaimmat ja mále govaid +Comment[sk]=Editivať a maľovať obrázky +Comment[sl]=Urejajte in ustvarjajte slike +Comment[sr]=Уређујте и правите слике +Comment[sr@Latn]=Uređujte i pravite slike +Comment[sv]=Redigera och måla bilder +Comment[uk]=Створення і редагування зображень +Comment[uz]=Rasm bilan ishlash dasturi +Comment[uz@cyrillic]=Расм билан ишлаш дастури +Comment[zh_TW]=編輯與畫圖片 +GenericName=Painting and Image Editing +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa d'edició d'imatges +GenericName[da]=Maling & billedredigering +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Επεξεργασία και ζωγραφική εικόνων +GenericName[eo]=Pentrado kaj Bildredaktado +GenericName[es]=Pintura y edición de imágenes +GenericName[et]=Joonistamine ja pilditöötlus +GenericName[fa]=رنگ‌آمیزی و ویرایش تصویر +GenericName[fi]=Maalaus ja kuvankäsittely +GenericName[fr]=Peinture et retouche d'images +GenericName[fy]=Ofbyldingsmanupilaasje +GenericName[ga]=Péinteáil agus Eagarthóireacht Íomhánna +GenericName[gl]=Debuxo e Edición de Imaxes +GenericName[he]=טיפול ועריכת תמונות +GenericName[hu]=Rajzoló és képszerkesztő +GenericName[is]=Málun og myndsýsl +GenericName[it]=Disegno e modifica di immagini +GenericName[ja]=描画と画像編集 +GenericName[km]=គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšana un attēlu apstrāde +GenericName[nb]=Program for maling og bilderedigering +GenericName[nds]=Malen un Biller bewerken +GenericName[ne]=पेन्टिङ्ग र छवि सम्पादन +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Edycja zdjęć oraz rysunków +GenericName[pt]=Pintura e Manipulação de Imagens +GenericName[pt_BR]=Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđaheapmi +GenericName[sk]=Program pre úpravu a maľovanie obrázkov +GenericName[sl]=Slikanje in urejanje slik +GenericName[sr]=Цртање и уређивање слика +GenericName[sr@Latn]=Crtanje i uređivanje slika +GenericName[sv]=Målning och bildredigering +GenericName[uk]=Малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑 +GenericName[zh_TW]=繪圖與影像編輯 +MimeType=application/x-chalk +Type=Application +Icon=chalk +Categories=Qt;KDE;Graphics; +X-KDE-NativeMimeType=application/x-chalk +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +X-Chalk-Version=2 diff --git a/chalk/chalk.rc b/chalk/chalk.rc new file mode 100644 index 00000000..323ef2f5 --- /dev/null +++ b/chalk/chalk.rc @@ -0,0 +1,199 @@ + + + + &Edit + + + + + + + + + + + + + + + + &Resources + + + + + + &View + + + + + + + + + + + + + + + + + Grid Spacing + + + + + + + + + + + + + + + + + +&Image + + + + + +&Layer + New + + + + + + + + + + + + + Mask + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Sele&ct + + + + + + + + + + + + +Filte&r + + + + + + + + + + + + + + + +&Tools + + + +Settings + + + + + + +Edit + + + + + + + + + + +Navigation + + + + + + + Chalk + + + + Brushes and Stuff + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/chalk_part_init.cc b/chalk/chalk_part_init.cc new file mode 100644 index 00000000..b5691974 --- /dev/null +++ b/chalk/chalk_part_init.cc @@ -0,0 +1,23 @@ +/* + * kis_part_init.cc - part of Krayon + * + * Copyright (c) 1999 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "ui/kis_factory.h" + + +K_EXPORT_COMPONENT_FACTORY( libchalkpart, KisFactory ) diff --git a/chalk/chalk_readonly.rc b/chalk/chalk_readonly.rc new file mode 100644 index 00000000..bfe8a233 --- /dev/null +++ b/chalk/chalk_readonly.rc @@ -0,0 +1,35 @@ + + + + Edit + + + + + + + + + View + + + + +Layer + + + + + + + +Edit + + + +Navigation + + + + + diff --git a/chalk/chalkcolor/Makefile.am b/chalk/chalkcolor/Makefile.am new file mode 100644 index 00000000..9ec16a40 --- /dev/null +++ b/chalk/chalkcolor/Makefile.am @@ -0,0 +1,45 @@ +# all_includes must remain last! +INCLUDES = $(KOFFICE_INCLUDES) \ + -I$(srcdir) \ + -I$(srcdir)/../sdk \ + -I$(srcdir)/colorspaces \ + $(OPENEXR_CFLAGS) \ + $(all_includes) + +lib_LTLIBRARIES = libchalkcolor.la + +if have_openexr +OPENEXR_SOURCES=kis_f16half_base_colorspace.cc +endif + +libchalkcolor_la_SOURCES = kis_color.cc kis_colorspace.cc \ + kis_colorspace_iface.cc kis_colorspace_iface.skel kis_composite_op.cc kis_profile.cc \ + kis_histogram_producer.cc kis_basic_histogram_producers.cc kis_abstract_colorspace.cc \ + kis_colorspace_factory_registry.cc kis_color_conversions.cc kis_u8_base_colorspace.cc \ + kis_u16_base_colorspace.cc kis_f32_base_colorspace.cc $(OPENEXR_SOURCES) + +libchalkcolor_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libchalkcolor_la_LIBADD = colorspaces/libchalkcolorspaces.la $(LCMS_LIBS) $(LIB_KPARTS) $(LIB_KDECORE) $(LIB_QT) $(OPENEXR_LIBS) + +include_HEADERS = \ + kis_channelinfo.h \ + kis_color.h \ + kis_colorspace.h \ + kis_composite_op.h \ + kis_profile.h \ + kis_histogram_producer.h \ + kis_basic_histogram_producers.h kis_u8_base_colorspace.h kis_u16_base_colorspace.h kis_f16half_base_colorspace.h kis_f32_base_colorspace.h \ + kis_colorspace_factory_registry.h kis_abstract_colorspace.h + + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = colorspaces . $(TESTSDIR) + +kde_servicetypes_DATA = chalk_colorspace.desktop + +METASOURCES = AUTO + + diff --git a/chalk/chalkcolor/README b/chalk/chalkcolor/README new file mode 100644 index 00000000..f80e0520 --- /dev/null +++ b/chalk/chalkcolor/README @@ -0,0 +1,4 @@ +The color library is a wrapper around lcms and provides colorspaces +that can do things to arrays of bytes that represent pixels. The +number of colorspaces is extensible with plugins. The colorspace +registry is responsible for loading the colorspace plugins. diff --git a/chalk/chalkcolor/TODO b/chalk/chalkcolor/TODO new file mode 100644 index 00000000..81bc56c1 --- /dev/null +++ b/chalk/chalkcolor/TODO @@ -0,0 +1,11 @@ +This library is still dependent upon chalk/sdk for some headers. This +should be changed. The headers concerned are: + +kis_id.h +kis_global.h +kis_annotation.h +kis_integer_maths.h + +Additionally, there is a problem with the histogram producers: those are +tied to the individual base colorspaces, but also need iterators, so they +are in core for the moment. diff --git a/chalk/chalkcolor/chalk_colorspace.desktop b/chalk/chalkcolor/chalk_colorspace.desktop new file mode 100644 index 00000000..7379a273 --- /dev/null +++ b/chalk/chalkcolor/chalk_colorspace.desktop @@ -0,0 +1,38 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Chalk/ColorSpace +Comment=A module implementing a complete colorspace for use with libchalkcolor +Comment[bg]=Модул, реализиращ пълна цветова гама за употреба с libchalkcolor +Comment[ca]=Un mòdul que implementa un complet espai de colors per a usar-lo amb libchalkcolor +Comment[cy]=Modiwl sy'n gweithredoli gofod lliw cyflawn i'w ddefnyddio efo libchalkcolor +Comment[da]=Et modul som implementerer et fuldstændigt farverum til brug med libchalkcolor +Comment[de]=Ein Modul, das einen kompletten Farbraum zur Benutzung mit libchalkcolor implementiert +Comment[el]=Ένα άρθρωμα που υλοποιεί έναν πλήρη χρωματικό χώρο για χρήση με το libchalkcolor +Comment[en_GB]=A module implementing a complete colourspace for use with libchalkcolor +Comment[es]=Un módulo que implementa un espacio de color completo para usar con libchalkcolor +Comment[et]=Täielikku värviruumi teostav moodul (teegile libchalkcolor) +Comment[fa]=پیمانه‌ای که فضای رنگ کاملی برای استفاده با libchalkcolor پیاده می‌کند +Comment[fr]=Un module implantant un espace de couleurs complet à utiliser avec libchalkcolor +Comment[fy]=In module dy in folslein kleurgebiet ymplementearret dat brûkt wurde kin mei libchalkcolor +Comment[gl]=Un módulo que implemente un espazo de cor completo para usar con libchalkcolor +Comment[hu]=Teljes színteret megvalósító modul a libchalkcolor programkönyvtárhoz +Comment[is]=Eining með fullu litasvæði til notkunar með libchalkcolor +Comment[it]=Un modulo che implementa uno spazio dei colori completo per usarlo con libchalkcolor +Comment[km]=ម៉ូឌុល​ដែល​អនុវត្ត​ប្រភេទ​ពណ៌​ពេញលេញ ដើម្បី​ប្រើ​ជាមួយ libchalkcolor +Comment[nb]=En modul som implementerer et komplett fargerom til bruk med libchalkcolor +Comment[nds]=En Moduul, dat en helen Klörenruum för den Bruuk mit libchalkcolor inbuut +Comment[ne]=लिबक्रितारङसँग प्रयोग गर्नका लागि सम्पूर्ण रङ खालीस्थानलाई मोड्युललाई औजार बनाइदै +Comment[nl]=Een module die een volledig kleurgebied implementeert dat gebruikt kan worden met libchalkcolor +Comment[pl]=Moduł implementujący kompletną przestrzeń barw do użytku z libchalkcolor +Comment[pt]=Um módulo que implementa um espaço de cores completo para usar com a 'libchalkcolor' +Comment[pt_BR]=Um módulo que implementa um espaço de cores completo para usar com a 'libchalkcolor' +Comment[ru]=Полная поддержка цветовых пространств в libchalkcolor +Comment[sk]=Modul ktorý poskytuje úplný farebný priestor pre použitie s libchalkcolor +Comment[sl]=Modul, v katerem je izveden celoten barvni prostor za uporabo z libchalkcolor +Comment[sr]=Модул који имплементира потпун простор боја за употребу са libchalkcolor +Comment[sr@Latn]=Modul koji implementira potpun prostor boja za upotrebu sa libchalkcolor +Comment[sv]=En modul som implementerar en fullständig färgrymd för användning med libchalkcolor +Comment[uk]=Модуль впровадження повного простору кольорів для вжитку з libchalkcolor +Comment[zh_TW]=實作完整色彩空間以使用 libchalkcolor 的模組 +[PropertyDef::X-Chalk-Version] +Type=int diff --git a/chalk/chalkcolor/colorspaces/Makefile.am b/chalk/chalkcolor/colorspaces/Makefile.am new file mode 100644 index 00000000..90f75d29 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = -I$(srcdir)/.. \ + -I$(srcdir)/../../sdk \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +noinst_LTLIBRARIES = libchalkcolorspaces.la + +libchalkcolorspaces_la_SOURCES = \ + kis_alpha_colorspace.cc \ + kis_lab_colorspace.cc + +noinst_HEADERS = \ + kis_alpha_colorspace.h \ + kis_lab_colorspace.h + +libchalkcolorspaces_la_LIBADD = $(OPENEXR_LIBS) + +libchalkcolorspaces_la_METASOURCES = AUTO + + diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc new file mode 100644 index 00000000..4b54556f --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#include +#include + +#include + +#include LCMS_HEADER + +#include "kis_alpha_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_channelinfo.h" +#include "kis_id.h" +#include "kis_integer_maths.h" + +namespace { + const TQ_UINT8 PIXEL_MASK = 0; +} + +KisAlphaColorSpace::KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) : + KisU8BaseColorSpace(KisID("ALPHA", i18n("Alpha tqmask")), TYPE_GRAY_8, icSigGrayData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 0, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + m_alphaPos = 0; +} + +KisAlphaColorSpace::~KisAlphaColorSpace() +{ +} + +void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = OPACITY_OPAQUE; +} + +void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + dst[PIXEL_MASK] = opacity; +} + +void KisAlphaColorSpace::getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const +{ + *alpha = *pixel; +} + +void KisAlphaColorSpace::toTQColor(const TQ_UINT8 */*src*/, TQColor *c, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); +} + +void KisAlphaColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/) +{ + c->setRgb(255, 255, 255); + *opacity = src[PIXEL_MASK]; +} + +TQ_UINT8 KisAlphaColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2) +{ + // Arithmetic operands smaller than int are converted to int automatically + return TQABS(src2[PIXEL_MASK] - src1[PIXEL_MASK]); +} + +void KisAlphaColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + if (nColors > 0) { + TQ_UINT32 total = 0; + + while(nColors) + { + nColors--; + total += *colors[nColors] * weights[nColors]; + } + *dst = total / 255; + } +} + +TQValueVector KisAlphaColorSpace::channels() const +{ + return m_channels; +} + +bool KisAlphaColorSpace::convertPixelsTo(const TQ_UINT8 *src, + TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 /*renderingIntent*/) +{ + // No lcms trickery here, we are only a opacity channel + TQ_INT32 size = dstColorSpace->pixelSize(); + + TQ_UINT32 j = 0; + TQ_UINT32 i = 0; + + while ( i < numPixels ) { + + dstColorSpace->fromTQColor(TQt::red, OPACITY_OPAQUE - *(src + i), (dst + j)); + + i += 1; + j += size; + + } + return true; + +} + + +//XXX bitblt of ColorSpaceAlpha does not take tqmask into consideration as this is probably not +// used ever +void KisAlphaColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + + TQ_UINT8 *d; + const TQ_UINT8 *s; + TQ_INT32 i; + TQ_INT32 linesize; + + if (rows <= 0 || cols <= 0) + return; + switch (op.op()) { + case COMPOSITE_COPY: + compositeCopy(dst, dststride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + return; + case COMPOSITE_CLEAR: + linesize = sizeof(TQ_UINT8) * cols; + d = dst; + while (rows-- > 0) { + memset(d, OPACITY_TRANSPARENT, linesize); + d += dststride; + } + return; + case COMPOSITE_ERASE: + while (rows-- > 0) { + d = dst; + s = src; + + for (i = cols; i > 0; i--, d ++, s ++) { + if (d[PIXEL_MASK] < s[PIXEL_MASK]) { + continue; + } + else { + d[PIXEL_MASK] = s[PIXEL_MASK]; + } + + } + + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_SUBTRACT: + while (rows-- > 0) { + d = dst; + s = src; + + for (i = cols; i > 0; i--, d++, s++) { + if (d[PIXEL_MASK] <= s[PIXEL_MASK]) { + d[PIXEL_MASK] = MIN_SELECTED; + } else { + d[PIXEL_MASK] -= s[PIXEL_MASK]; + } + } + + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_ALPHA_DARKEN: + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX; + if (srcAlpha > d[PIXEL_MASK]) + d[PIXEL_MASK] = srcAlpha; + } + dst += dststride; + src += srcRowStride; + } + return; + case COMPOSITE_OVER: + default: + if (opacity == OPACITY_TRANSPARENT) + return; + if (opacity != OPACITY_OPAQUE) { + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX; + d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX; + } + dst += dststride; + src += srcRowStride; + } + } + else { + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d++, s++) { + if (s[PIXEL_MASK] == OPACITY_TRANSPARENT) + continue; + if (d[PIXEL_MASK] == OPACITY_TRANSPARENT || s[PIXEL_MASK] == OPACITY_OPAQUE) { + memcpy(d, s, 1); + continue; + } + int srcAlpha = s[PIXEL_MASK]; + d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX; + } + dst += dststride; + src += srcRowStride; + } + } + + } +} + +KisCompositeOpList KisAlphaColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + + return list; +} + +TQString KisAlphaColorSpace::channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisAlphaColorSpace::normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(static_cast(pixel[channelPosition]) / UINT8_MAX); +} + + +void KisAlphaColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalAlpha = 0; + + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalAlpha += (*colors)[PIXEL_MASK] * weight; + } + colors++; + kernelValues++; + } + + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_MASK] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } +} diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h new file mode 100644 index 00000000..dd4f3916 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLORSPACE_ALPHA_H_ +#define KIS_COLORSPACE_ALPHA_H_ + +#include + +#include "kis_global.h" +#include "kis_u8_base_colorspace.h" + +/** + * The alpha tqmask is a special color strategy that treats all pixels as + * alpha value with a colour common to the tqmask. The default color is white. + */ +class KisAlphaColorSpace : public KisU8BaseColorSpace { +public: + KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p); + virtual ~KisAlphaColorSpace(); + +public: + virtual bool willDegrade(ColorSpaceIndependence) + { + return false; + }; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const; + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const { return 1; }; + virtual TQ_UINT32 nColorChannels() const { return 0; }; + virtual TQ_UINT32 pixelSize() const { return 1; }; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + +protected: + + /** + * Convert a byte array of srcLen pixels *src to the specified color space + * and put the converted bytes into the prepared byte array *dst. + * + * Returns false if the conversion failed, true if it succeeded + */ + virtual bool convertPixelsTo(const TQ_UINT8 *src, + TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +}; + +#endif // KIS_COLORSPACE_ALPHA_H_ diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc new file mode 100644 index 00000000..829b4f27 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc @@ -0,0 +1,571 @@ + /* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Adrian Page + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_lab_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" + +KisLabColorSpace::KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) + : KisU16BaseColorSpace(KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")), + COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1), + icSigLabData, tqparent, p) + +{ + m_channels.push_back(new KisChannelInfo(i18n("Lightness"), i18n("L"), CHANNEL_L * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(100,100,100))); + m_channels.push_back(new KisChannelInfo(i18n("a*"), i18n("a"), CHANNEL_A * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(150,150,150))); + m_channels.push_back(new KisChannelInfo(i18n("b*"), i18n("b"), CHANNEL_B * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(200,200,200))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), CHANNEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + + m_alphaPos = CHANNEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + +KisLabColorSpace::~KisLabColorSpace() +{ +} + +TQ_UINT8 * KisLabColorSpace::toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const +{ + TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()]; + memcpy( pixels, data, nPixels * pixelSize() ); + return pixels; +} + +TQ_UINT8 * KisLabColorSpace::fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const +{ + TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()]; + memcpy( pixels, labData, nPixels * pixelSize() ); + return pixels; +} + +TQ_UINT8 KisLabColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2) +{ + cmsCIELab labF1, labF2; + + if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT) + return (getAlpha(src1) == getAlpha(src2) ? 0 : 255); + + cmsLabEncoded2Float(&labF1, (WORD *)src1); + cmsLabEncoded2Float(&labF2, (WORD *)src2); + double diff = cmsDeltaE(&labF1, &labF2); + if(diff>255) + return 255; + else + return TQ_INT8(diff); +} + +void KisLabColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalLightness = 0, totalAlpha = 0; + TQ_UINT32 totala = 0, totalb = 0; + + while (nColors--) + { + const Pixel *color = reinterpret_cast( *colors ); + TQ_UINT32 alphaTimesWeight = UINT8_MULT(color->alpha, *weights); + + totalLightness += color->lightness * alphaTimesWeight; + totala += color->a * alphaTimesWeight; + totalb += color->b * alphaTimesWeight; + totalAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + if (totalAlpha > UINT16_MAX) { + totalAlpha = UINT16_MAX; + } + + ((Pixel *)dst)->alpha = totalAlpha; + + if (totalAlpha > 0) { + totalLightness /= totalAlpha; + totala /= totalAlpha; + totalb /= totalAlpha; + } // else the values are already 0 too + + if (totalLightness > MAX_CHANNEL_L) { + totalLightness = MAX_CHANNEL_L; + } + + ((Pixel *)dst)->lightness = totalLightness; + + if (totala > MAX_CHANNEL_AB) { + totala = MAX_CHANNEL_AB; + } + + ((Pixel *)dst)->a = totala; + + if (totalb > MAX_CHANNEL_AB) { + totalb = MAX_CHANNEL_AB; + } + + ((Pixel *)dst)->b = totalb; +} + +void KisLabColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * s = reinterpret_cast( src ); + + s->lightness = MAX_CHANNEL_L - s->lightness; + s->a = MAX_CHANNEL_AB - s->a; + s->b = MAX_CHANNEL_AB - s->b; + + src += psize; + } +} + +void KisLabColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, + TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalL = 0, totalA = 0, totalB = 0, totalAlpha = 0; + + while ( nColors -- ) + { + const Pixel * pixel = reinterpret_cast( *colors ); + TQ_INT32 weight = *kernelValues; + if ( weight != 0 ) { + totalL += pixel->lightness * weight; + totalA += pixel->a * weight; + totalB += pixel->b * weight; + totalAlpha += pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->lightness = CLAMP( ( totalL / factor) + offset, 0, TQ_UINT16_MAX); + p->a = CLAMP( ( totalA / factor) + offset, 0, TQ_UINT16_MAX); + p->b = CLAMP( ( totalB / factor) + offset, 0, TQ_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX); + } + +} + +void KisLabColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ + // XXX: Is the 255 right for u16 colorspaces? + TQ_UINT32 pSize = pixelSize(); + while ( nPixels-- ) { + const Pixel * s = reinterpret_cast( src ); + Pixel * d = reinterpret_cast( dst ); + + if ( compensate ) { + d->lightness = static_cast( ( s->lightness * shade ) / ( compensation * 255 ) ); + } + else { + d->lightness = static_cast( s->lightness * shade / 255 ); + } + d->a = s->a; + d->b = s->b; + d->alpha = s->alpha; + + src += pSize; + dst += pSize; + } +} + + +TQValueVector KisLabColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisLabColorSpace::nChannels() const +{ + return NUM_CHANNELS; +} + +TQ_UINT32 KisLabColorSpace::nColorChannels() const +{ + return NUM_COLOR_CHANNELS; +} + +TQ_UINT32 KisLabColorSpace::pixelSize() const +{ + return sizeof(Pixel); +} + +void KisLabColorSpace::getSingleChannelPixel(TQ_UINT8 *dst, const TQ_UINT8 *src, TQ_UINT32 channelIndex) +{ + if (channelIndex < NUM_CHANNELS) { + + const Pixel *srcPixel = reinterpret_cast(src); + Pixel *dstPixel = reinterpret_cast(dst); + + switch (channelIndex) { + case CHANNEL_L: + dstPixel->lightness = srcPixel->lightness; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_A: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = srcPixel->a; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_B: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = srcPixel->b; + dstPixel->alpha = U16_OPACITY_TRANSPARENT; + break; + case CHANNEL_ALPHA: + dstPixel->lightness = MAX_CHANNEL_L / 2; + dstPixel->a = CHANNEL_AB_ZERO_OFFSET; + dstPixel->b = CHANNEL_AB_ZERO_OFFSET; + dstPixel->alpha = srcPixel->alpha; + break; + } + } +} + +void KisLabColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + const Pixel *src = reinterpret_cast(srcRowStart); + Pixel *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + if (*tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, *tqmask); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, sizeof(Pixel)); + } else { + TQ_UINT16 dstAlpha = dst->alpha; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst->alpha = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, sizeof(Pixel)); + } else { +/*printf("blend is %d\n", srcBlend); +printf("%d %d %d\n", src->lightness, src->a, src->b); +printf("%d %d %d\n", dst->lightness, dst->a, dst->b); +*/ + dst->lightness = UINT16_BLEND(src->lightness, dst->lightness, srcBlend); + dst->a = UINT16_BLEND(src->a, dst->a, srcBlend); + dst->b = UINT16_BLEND(src->b, dst->b, srcBlend); +//printf("%d %d %d\n", dst->lightness, dst->a, dst->b); + } + } + } + + columns--; + src++; + dst++; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +void KisLabColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisLabColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + //compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + //compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + //compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + //compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + //compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + //compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + //compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + //compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisLabColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + + return list; +} + +TQString KisLabColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + const Pixel *pix = reinterpret_cast(U8_pixel); + Q_ASSERT(channelIndex < nChannels()); + switch(channelIndex) + { + case CHANNEL_L: + return TQString().setNum(pix->lightness); + case CHANNEL_A: + return TQString().setNum(pix->a); + case CHANNEL_B: + return TQString().setNum(pix->b); + case CHANNEL_ALPHA: + return TQString().setNum(pix->alpha); + default: + return TQString("Error"); + } +} + +TQString KisLabColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + const Pixel *pix = reinterpret_cast(U8_pixel); + Q_ASSERT(channelIndex < nChannels()); + + // These convert from lcms encoded format to standard ranges. + + switch(channelIndex) + { + case CHANNEL_L: + return TQString().setNum(100.0 * static_cast(pix->lightness) / MAX_CHANNEL_L); + case CHANNEL_A: + return TQString().setNum(100.0 * ((static_cast(pix->a) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_B: + return TQString().setNum(100.0 * ((static_cast(pix->b) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB)); + case CHANNEL_ALPHA: + return TQString().setNum(100.0 * static_cast(pix->alpha) / UINT16_MAX); + default: + return TQString("Error"); + } +} + diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h new file mode 100644 index 00000000..eeab55cf --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_LAB_H_ +#define KIS_STRATEGY_COLORSPACE_LAB_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_integer_maths.h" +#include "kis_u16_base_colorspace.h" + +class KisLabColorSpace : public KisU16BaseColorSpace { +public: + KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisLabColorSpace(); + +public: + + /** + * Return a COPY of the provided data. This method is provided to provide consistency, + * but you really don't want to be calling it. + */ + virtual TQ_UINT8 * toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const; + + /** + * Return a COPY of the provided data. This method is provided for consistency, + * but you really don't want to call it. + */ + virtual TQ_UINT8 * fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const; + + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); +/* + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); +*/ + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + struct Pixel { + TQ_UINT16 lightness; + TQ_UINT16 a; + TQ_UINT16 b; + TQ_UINT16 alpha; + }; + static const TQ_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX; + static const TQ_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN; + + static const TQ_UINT32 NUM_CHANNELS = 4; + static const TQ_UINT32 NUM_COLOR_CHANNELS = 3; + + static const TQ_UINT32 CHANNEL_L = 0; + static const TQ_UINT32 CHANNEL_A = 1; + static const TQ_UINT32 CHANNEL_B = 2; + static const TQ_UINT32 CHANNEL_ALPHA = 3; + + static const TQ_UINT32 MAX_CHANNEL_L = 0xff00; + static const TQ_UINT32 MAX_CHANNEL_AB = 0xffff; + static const TQ_UINT32 CHANNEL_AB_ZERO_OFFSET = 0x8000; + + friend class KisLabColorSpaceTester; +}; + +class KisLabColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)); }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigLabData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisLabColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "Lab built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_LAB_H_ diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc new file mode 100644 index 00000000..98ccead0 --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include + +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_abstract_colorspace.h" +#include "kis_u16_base_colorspace.h" +#include "kis_xyz_colorspace.h" +#include "kis_integer_maths.h" + +#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL)) +#define upscale(value) (value) // ((TQ_UINT8) (257UL*(value))) + +// XXX: Maybe use TYPE_XYZ_DBL for an extra stimulating performance hit? People shouldn't depend +// on this fallback... + +KisXyzColorSpace::KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) : + KisU16BaseColorSpace(KisID("XYZA", i18n("XYZ/Alpha")), (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)), icSigCmykData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("X"), i18n("X"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Y"), i18n("Y"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Z"), i18n("Z"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + + +KisXyzColorSpace::~KisXyzColorSpace() +{ +} + + +TQValueVector KisXyzColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisXyzColorSpace::nChannels() const +{ + return xyz::MAX_CHANNEL_XYZA; +} + +TQ_UINT32 KisXyzColorSpace::nColorChannels() const +{ + return xyz::MAX_CHANNEL_XYZ; +} + +TQ_UINT32 KisXyzColorSpace::pixelSize() const +{ + return xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16); +} + +KisColorAdjustment * KisXyzColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues) +{ + return 0; +} + +void KisXyzColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels) +{ +} + +void KisXyzColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_INT32 pSize = pixelSize(); + + while (nPixels--) + { + TQ_UINT16 * p = reinterpret_cast(src); + p[PIXEL_X] = UINT16_MAX - p[PIXEL_X]; + p[PIXEL_Y] = UINT16_MAX - p[PIXEL_Y]; + p[PIXEL_Z] = UINT16_MAX - p[PIXEL_Z]; + src += pSize; + } +} + +void KisXyzColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ +} + +void KisXyzColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const +{ +} + +void KisXyzColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ +} + +TQ_UINT8 KisXyzColorSpace::intensity8(const TQ_UINT8 * src) const +{ + return 0; +} + +void KisXyzColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, xyz::MAX_CHANNEL_XYZ * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_X] = UINT16_BLEND(src[PIXEL_X], dst[PIXEL_X], srcBlend); + dst[PIXEL_Y] = UINT16_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend); + dst[PIXEL_Z] = UINT16_BLEND(src[PIXEL_Z], dst[PIXEL_Z], srcBlend); + } + } + } + + columns--; + src += xyz::MAX_CHANNEL_XYZA; + dst += xyz::MAX_CHANNEL_XYZA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); \ + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + TQ_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += xyz::MAX_CHANNEL_XYZA; \ + dst += xyz::MAX_CHANNEL_XYZA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisXyzColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = CLAMP(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisXyzColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + + + +void KisXyzColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s -> alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d -> alpha = UINT16_MULT(srcAlpha, d -> alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisXyzColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisXyzColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} + + diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h new file mode 100644 index 00000000..2f7c3efd --- /dev/null +++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS__COLORSPACE_XYZ_H_ +#define KIS__COLORSPACE_XYZ_H_ + +#include + +#include "kis_global.h" +#include "kis_integer_maths.h" +#include "kis_u16_base_colorspace.h" + +namespace xyz { + const TQ_INT32 MAX_CHANNEL_XYZ = 3; + const TQ_INT32 MAX_CHANNEL_XYZA = 4; +} + + + +class KisXyzColorSpace : public KisU16BaseColorSpace { + +public: + + struct Pixel { + TQ_UINT16 X; + TQ_UINT16 Y; + TQ_UINT16 Z; + TQ_UINT16 alpha; + }; + +public: + KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p); + virtual ~KisXyzColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; +public: + // Pixel manipulation + virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues); + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels); + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const; + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + // Information about the colorstrategy + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + + // Composition + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +protected: + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + + static const TQ_UINT8 PIXEL_X = 0; + static const TQ_UINT8 PIXEL_Y = 1; + static const TQ_UINT8 PIXEL_Z = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor. + +}; + +#endif // KIS__COLORSPACE_XYZ_H_ diff --git a/chalk/chalkcolor/kis_abstract_colorspace.cc b/chalk/chalkcolor/kis_abstract_colorspace.cc new file mode 100644 index 00000000..a19b9d69 --- /dev/null +++ b/chalk/chalkcolor/kis_abstract_colorspace.cc @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include + +#include "kis_abstract_colorspace.h" +#include "kis_global.h" +#include "kis_profile.h" +#include "kis_id.h" +#include "kis_integer_maths.h" +#include "kis_color_conversions.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_channelinfo.h" + +class KisColorAdjustmentImpl : public KisColorAdjustment +{ + public: + + KisColorAdjustmentImpl() : KisColorAdjustment() + { + csProfile = 0; + transform = 0; + profiles[0] = 0; + profiles[1] = 0; + profiles[2] = 0; + }; + + ~KisColorAdjustmentImpl() { + + if (transform) + cmsDeleteTransform(transform); + if (profiles[0] && profiles[0] != csProfile) + cmsCloseProfile(profiles[0]); + if(profiles[1] && profiles[1] != csProfile) + cmsCloseProfile(profiles[1]); + if(profiles[2] && profiles[2] != csProfile) + cmsCloseProfile(profiles[2]); + } + + cmsHPROFILE csProfile; + cmsHPROFILE profiles[3]; + cmsHTRANSFORM transform; +}; + +KisAbstractColorSpace::KisAbstractColorSpace(const KisID& id, + DWORD cmType, + icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) + : m_parent( tqparent ) + , m_profile( p ) + , m_id( id ) + , m_cmType( cmType ) + , m_colorSpaceSignature( colorSpaceSignature ) +{ + m_alphaPos = -1; + m_alphaSize = -1; + m_qcolordata = 0; + m_lastUsedDstColorSpace = 0; + m_lastUsedTransform = 0; + m_lastRGBProfile = 0; + m_lastToRGB = 0; + m_lastFromRGB = 0; + m_defaultFromRGB = 0; + m_defaultToRGB = 0; + m_defaultFromLab = 0; + m_defaultToLab = 0; +} + +void KisAbstractColorSpace::init() +{ + // Default pixel buffer for TQColor conversion + m_qcolordata = new TQ_UINT8[3]; + Q_CHECK_PTR(m_qcolordata); + + if (m_profile == 0) return; + + // For conversions from default rgb + m_lastFromRGB = cmsCreate_sRGBProfile(); + + m_defaultFromRGB = cmsCreateTransform(m_lastFromRGB, TYPE_BGR_8, + m_profile->profile(), m_cmType, + INTENT_PERCEPTUAL, 0); + + m_defaultToRGB = cmsCreateTransform(m_profile->profile(), m_cmType, + m_lastFromRGB, TYPE_BGR_8, + INTENT_PERCEPTUAL, 0); + + cmsHPROFILE hLab = cmsCreateLabProfile(NULL); + + m_defaultFromLab = cmsCreateTransform(hLab, TYPE_Lab_16, m_profile->profile(), m_cmType, + INTENT_PERCEPTUAL, 0); + + m_defaultToLab = cmsCreateTransform(m_profile->profile(), m_cmType, hLab, TYPE_Lab_16, + INTENT_PERCEPTUAL, 0); +} + +KisAbstractColorSpace::~KisAbstractColorSpace() +{ +} + + + +void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 *dst, KisProfile * profile) +{ + m_qcolordata[2] = color.red(); + m_qcolordata[1] = color.green(); + m_qcolordata[0] = color.blue(); + + + if (profile == 0) { + // Default sRGB + if (!m_defaultFromRGB) return; + + cmsDoTransform(m_defaultFromRGB, m_qcolordata, dst, 1); + } + else { + if (m_lastFromRGB == 0 || (m_lastFromRGB != 0 && m_lastRGBProfile != profile->profile())) { + m_lastFromRGB = cmsCreateTransform(profile->profile(), TYPE_BGR_8, + m_profile->profile(), m_cmType, + INTENT_PERCEPTUAL, 0); + m_lastRGBProfile = profile->profile(); + + } + cmsDoTransform(m_lastFromRGB, m_qcolordata, dst, 1); + } + + setAlpha(dst, OPACITY_OPAQUE, 1); +} + +void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile) +{ + fromTQColor(color, dst, profile); + setAlpha(dst, opacity, 1); +} + +void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile) +{ + if (profile == 0) { + // Default sRGB transform + if (!m_defaultToRGB) return; + cmsDoTransform(m_defaultToRGB, const_cast (src), m_qcolordata, 1); + } + else { + if (m_lastToRGB == 0 || (m_lastToRGB != 0 && m_lastRGBProfile != profile->profile())) { + m_lastToRGB = cmsCreateTransform(m_profile->profile(), m_cmType, + profile->profile(), TYPE_BGR_8, + INTENT_PERCEPTUAL, 0); + m_lastRGBProfile = profile->profile(); + } + cmsDoTransform(m_lastToRGB, const_cast (src), m_qcolordata, 1); + } + c->setRgb(m_qcolordata[2], m_qcolordata[1], m_qcolordata[0]); +} + +void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile) +{ + toTQColor(src, c, profile); + *opacity = getAlpha(src); +} + +void KisAbstractColorSpace::toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const +{ + if ( m_defaultToLab == 0 ) return; + + cmsDoTransform( m_defaultToLab, const_cast( src ), dst, nPixels ); +} + +void KisAbstractColorSpace::fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const +{ + if ( m_defaultFromLab == 0 ) return; + + cmsDoTransform( m_defaultFromLab, const_cast( src ), dst, nPixels ); +} + + +void KisAbstractColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex) +{ + if (channelIndex < m_channels.count()) { + + fromTQColor(TQt::black, OPACITY_TRANSPARENT, dstPixel); + + const KisChannelInfo *channelInfo = m_channels[channelIndex]; + memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size()); + } +} + +bool KisAbstractColorSpace::convertPixelsTo(const TQ_UINT8 * src, + TQ_UINT8 * dst, + KisColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent) +{ + if (dstColorSpace->colorSpaceType() == colorSpaceType() + && dstColorSpace->getProfile() == getProfile()) + { + if (src!= dst) + memcpy (dst, src, numPixels * pixelSize()); + + return true; + } + + cmsHTRANSFORM tf = 0; + + TQ_INT32 srcPixelSize = pixelSize(); + TQ_INT32 dstPixelSize = dstColorSpace->pixelSize(); + + if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) { + if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() && + dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) { + tf = m_lastUsedTransform; + } + } + + if (!tf && m_profile && dstColorSpace->getProfile()) { + + if (!m_transforms.tqcontains(dstColorSpace)) { + tf = createTransform(dstColorSpace, + m_profile, + dstColorSpace->getProfile(), + renderingIntent); + if (tf) { + // XXX: Should we clear the transform cache if it gets too big? + m_transforms[dstColorSpace] = tf; + } + } + else { + tf = m_transforms[dstColorSpace]; + } + + if ( tf ) { + m_lastUsedTransform = tf; + m_lastUsedDstColorSpace = dstColorSpace; + } + } + + if (tf) { + + cmsDoTransform(tf, const_cast(src), dst, numPixels); + + // Lcms does nothing to the destination alpha channel so we must convert that manually. + while (numPixels > 0) { + TQ_UINT8 alpha = getAlpha(src); + dstColorSpace->setAlpha(dst, alpha, 1); + + src += srcPixelSize; + dst += dstPixelSize; + numPixels--; + } + + return true; + } + + // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5. + while (numPixels > 0) { + TQColor color; + TQ_UINT8 opacity; + + toTQColor(src, &color, &opacity); + dstColorSpace->fromTQColor(color, opacity, dst); + + src += srcPixelSize; + dst += dstPixelSize; + numPixels--; + } + + return true; +} + + +KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues) +{ + if (!m_profile) return 0; + + LPGAMMATABLE transferFunctions[3]; + transferFunctions[0] = cmsBuildGamma(256, 1.0); + transferFunctions[1] = cmsBuildGamma(256, 1.0); + transferFunctions[2] = cmsBuildGamma(256, 1.0); + + for(int i =0; i < 256; i++) + transferFunctions[0]->GammaTable[i] = transferValues[i]; + + KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl; + adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions); + cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass); + + adj->profiles[0] = m_profile->profile(); + adj->profiles[2] = m_profile->profile(); + adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0); + adj->csProfile = m_profile->profile(); + return adj; +} + +typedef struct { + double Saturation; + +} BCHSWADJUSTS, *LPBCHSWADJUSTS; + + +static int desaturateSampler(register WORD In[], register WORD Out[], register LPVOID /*Cargo*/) +{ + cmsCIELab LabIn, LabOut; + cmsCIELCh LChIn, LChOut; + //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo; + + cmsLabEncoded2Float(&LabIn, In); + + cmsLab2LCh(&LChIn, &LabIn); + + // Do some adjusts on LCh + LChOut.L = LChIn.L; + LChOut.C = 0;//LChIn.C + bchsw->Saturation; + LChOut.h = LChIn.h; + + cmsLCh2Lab(&LabOut, &LChOut); + + // Back to encoded + cmsFloat2LabEncoded(Out, &LabOut); + + return TRUE; +} + +KisColorAdjustment *KisAbstractColorSpace::createDesaturateAdjustment() +{ + if (!m_profile) return 0; + + KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl; + + adj->profiles[0] = m_profile->profile(); + adj->profiles[2] = m_profile->profile(); + adj->csProfile = m_profile->profile(); + + LPLUT Lut; + BCHSWADJUSTS bchsw; + + bchsw.Saturation = -25; + + adj->profiles[1] = _cmsCreateProfilePlaceholder(); + if (!adj->profiles[1]) // can't allocate + return NULL; + + cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass); + cmsSetColorSpace(adj->profiles[1], icSigLabData); + cmsSetPCS(adj->profiles[1], icSigLabData); + + cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL); + + // Creates a LUT with 3D grid only + Lut = cmsAllocLUT(); + + cmsAlloc3DGrid(Lut, 32, 3, 3); + + if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast(&bchsw), 0)) { + // Shouldn't reach here + cmsFreeLUT(Lut); + cmsCloseProfile(adj->profiles[1]); + return NULL; + } + + // Create tags + + cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag, (LPVOID) "(chalk internal)"); + cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "chalk saturation abstract profile"); + cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag, (LPVOID) "saturation built-in"); + + cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ()); + + cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut); + + // LUT is already on virtual profile + cmsFreeLUT(Lut); + + adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0); + + return adj; +} + +KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(TQ_UINT16 **transferValues) +{ + if (!m_profile) return 0; + + LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1]; + + for(uint ch=0; ch < nColorChannels(); ch++) { + transferFunctions[ch] = cmsBuildGamma(256, 1.0); + for(uint i =0; i < 256; i++) { + transferFunctions[ch]->GammaTable[i] = transferValues[ch][i]; + } + } + + KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl; + adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions); + adj->profiles[1] = NULL; + adj->profiles[2] = NULL; + adj->csProfile = m_profile->profile(); + adj->transform = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0); + + delete [] transferFunctions; + + return adj; +} + + +void KisAbstractColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adjustment, TQ_INT32 nPixels) +{ + KisColorAdjustmentImpl * adj = dynamic_cast(adjustment); + if (adj) + cmsDoTransform(adj->transform, const_cast(src), dst, nPixels); +} + + +void KisAbstractColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQColor c; + TQ_UINT8 opacity; + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + toTQColor(src, &c, &opacity); + c.setRgb(TQ_UINT8_MAX - c.red(), TQ_UINT8_MAX - c.green(), TQ_UINT8_MAX - c.blue()); + fromTQColor( c, opacity, src); + + src += psize; + } +} + +TQ_UINT8 KisAbstractColorSpace::difference(const TQ_UINT8* src1, const TQ_UINT8* src2) +{ + if (m_defaultToLab) { + + TQ_UINT8 lab1[8], lab2[8]; + cmsCIELab labF1, labF2; + + if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT) + return (getAlpha(src1) == getAlpha(src2) ? 0 : 255); + + cmsDoTransform( m_defaultToLab, const_cast( src1 ), lab1, 1); + cmsDoTransform( m_defaultToLab, const_cast( src2 ), lab2, 1); + cmsLabEncoded2Float(&labF1, (WORD *)lab1); + cmsLabEncoded2Float(&labF2, (WORD *)lab2); + double diff = cmsDeltaE(&labF1, &labF2); + if(diff>255) + return 255; + else + return TQ_INT8(diff); + } + else { + TQColor c1; + TQ_UINT8 opacity1; + toTQColor(src1, &c1, &opacity1); + + TQColor c2; + TQ_UINT8 opacity2; + toTQColor(src2, &c2, &opacity2); + + TQ_UINT8 red = abs(c1.red() - c2.red()); + TQ_UINT8 green = abs(c1.green() - c2.green()); + TQ_UINT8 blue = abs(c1.blue() - c2.blue()); + return TQMAX(red, TQMAX(green, blue)); + } +} + +void KisAbstractColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + TQColor c; + TQ_UINT8 opacity; + + while (nColors--) + { + // Ugly hack to get around the current constness mess of the colour strategy... + const_cast(this)->toTQColor(*colors, &c, &opacity); + + TQ_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights); + + totalRed += c.red() * alphaTimesWeight; + totalGreen += c.green() * alphaTimesWeight; + totalBlue += c.blue() * alphaTimesWeight; + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= 255); + + if (newAlpha > 0) { + totalRed = UINT8_DIVIDE(totalRed, newAlpha); + totalGreen = UINT8_DIVIDE(totalGreen, newAlpha); + totalBlue = UINT8_DIVIDE(totalBlue, newAlpha); + } + + // Divide by 255. + totalRed += 0x80; + + TQ_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8; + Q_ASSERT(dstRed <= 255); + + totalGreen += 0x80; + TQ_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8; + Q_ASSERT(dstGreen <= 255); + + totalBlue += 0x80; + TQ_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8; + Q_ASSERT(dstBlue <= 255); + + const_cast(this)->fromTQColor(TQColor(dstRed, dstGreen, dstBlue), newAlpha, dst); +} + +void KisAbstractColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, + TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + TQColor dstColor; + TQ_UINT8 dstOpacity; + + const_cast(this)->toTQColor(dst, &dstColor, &dstOpacity); + + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + TQColor c; + TQ_UINT8 opacity; + const_cast(this)->toTQColor( *colors, &c, &opacity ); + totalRed += c.red() * weight; + totalGreen += c.green() * weight; + totalBlue += c.blue() * weight; + totalAlpha += opacity * weight; + } + colors++; + kernelValues++; + } + + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + const_cast(this)->fromTQColor(TQColor(CLAMP((totalRed / factor) + offset, 0, TQ_UINT8_MAX), + CLAMP((totalGreen / factor) + offset, 0, TQ_UINT8_MAX), + CLAMP((totalBlue / factor) + offset, 0, TQ_UINT8_MAX)), + dstOpacity, + dst); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + const_cast(this)->fromTQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX), dst); + } + +} + +void KisAbstractColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ + if (m_defaultToLab) { + TQ_UINT16 * labcache = new TQ_UINT16[nPixels * 4]; + cmsDoTransform( m_defaultToLab, const_cast( src ), reinterpret_cast( labcache ), nPixels ); + for ( int i = 0; i < nPixels * 4; ++i ) { + if ( compensate ) { + labcache[i] = static_cast( ( labcache[i] * shade ) / ( compensation * 255 ) ); + } + else { + labcache[i] = static_cast( labcache[i] * shade / 255 ); + } + } + cmsDoTransform( m_defaultFromLab, reinterpret_cast( labcache ), dst, nPixels ); + + // Copy alpha + for ( int i = 0; i < nPixels; ++i ) { + TQ_UINT8 alpha = getAlpha( src ); + setAlpha( dst, alpha, 1 ); + } + delete [] labcache; + } + else { + + TQColor c; + TQ_INT32 psize = pixelSize(); + + for (int i = 0; i < nPixels; ++i) { + + const_cast(this)->toTQColor(src + (i * psize), &c); + TQ_INT32 r, g, b; + + if (compensate) { + r = static_cast( TQMIN(255, (c.red() * shade) / (compensation * 255))); + g = static_cast( TQMIN(255, (c.green() * shade) / (compensation * 255))); + b = static_cast( TQMIN(255, (c.blue() * shade) / (compensation * 255))); + } + else { + r = static_cast( TQMIN(255, (c.red() * shade / 255))); + g = static_cast( TQMIN(255, (c.green() * shade / 255))); + b = static_cast( TQMIN(255, (c.blue() * shade / 255))); + } + c.setRgb(r, g, b); + + const_cast(this)->fromTQColor( c, dst + (i * psize)); + } + } +} + +TQ_UINT8 KisAbstractColorSpace::intensity8(const TQ_UINT8 * src) const +{ + TQColor c; + TQ_UINT8 opacity; + const_cast(this)->toTQColor(src, &c, &opacity); + return static_cast((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5); + +} + + +KisID KisAbstractColorSpace::mathToolboxID() const +{ + return KisID("Basic"); +} + +void KisAbstractColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + KisColorSpace * srcSpace, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + if (rows <= 0 || cols <= 0) + return; + + if (this != srcSpace) { + TQ_UINT32 len = pixelSize() * rows * cols; + + // If our conversion cache is too small, extend it. + if (!m_conversionCache.resize( len, TQGArray::SpeedOptim )) { + kdWarning() << "Could not allocate enough memory for the conversion!\n"; + // XXX: We should do a slow, pixel by pixel bitblt here... + abort(); + } + + for (TQ_INT32 row = 0; row < rows; row++) { + srcSpace->convertPixelsTo(src + row * srcRowStride, + m_conversionCache.data() + row * cols * pixelSize(), this, + cols); + } + + // The old srcRowStride is no longer valid because we converted to the current cs + srcRowStride = cols * pixelSize(); + + bitBlt(dst, + dststride, + m_conversionCache.data(), + srcRowStride, + srcAlphaMask, + tqmaskRowStride, + opacity, + rows, + cols, + op); + + } + else { + bitBlt(dst, + dststride, + src, + srcRowStride, + srcAlphaMask, + tqmaskRowStride, + opacity, + rows, + cols, + op); + } +} + +TQImage KisAbstractColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile *dstProfile, + TQ_INT32 renderingIntent, float /*exposure*/) + +{ + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer( true ); + + KisColorSpace * dstCS; + + if (dstProfile) + dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName()); + else + dstCS = m_parent->getRGB8(); + + if (data) + convertPixelsTo(const_cast(data), img.bits(), dstCS, width * height, renderingIntent); + + return img; +} + + +cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace, + KisProfile * srcProfile, + KisProfile * dstProfile, + TQ_INT32 renderingIntent) +{ + KConfig * cfg = KGlobal::config(); + bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false); + + int flags = 0; + + if (bpCompensation) { + flags = cmsFLAGS_BLACKPOINTCOMPENSATION; + } + + if (dstColorSpace && dstProfile && srcProfile ) { + cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(), + colorSpaceType(), + dstProfile->profile(), + dstColorSpace->colorSpaceType(), + renderingIntent, + flags); + + return tf; + } + return 0; +} + +void KisAbstractColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 * /*tqmaskRowStart*/, TQ_INT32 /*tqmaskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *src = srcRowStart; + TQ_INT32 bytesPerPixel = pixelSize(); + + while (rows > 0) { + memcpy(dst, src, numColumns * bytesPerPixel); + + if (opacity != OPACITY_OPAQUE) { + multiplyAlpha(dst, opacity, numColumns); + } + + dst += dstRowStride; + src += srcRowStride; + --rows; + } +} + diff --git a/chalk/chalkcolor/kis_abstract_colorspace.h b/chalk/chalkcolor/kis_abstract_colorspace.h new file mode 100644 index 00000000..75dfd1ef --- /dev/null +++ b/chalk/chalkcolor/kis_abstract_colorspace.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_ABSTRACT_COLORSPACE_H_ +#define KIS_ABSTRACT_COLORSPACE_H_ + +#include + +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_channelinfo.h" +#include "kis_profile.h" +#include "kis_id.h" +#include "kis_composite_op.h" +#include "kis_colorspace.h" +#include "koffice_export.h" + + +class TQPainter; +class KisPixelRO; +class KisColorSpaceFactoryRegistry; + + +/** + * A colorspace strategy is the definition of a certain color model + * in Chalk. + */ +class KRITA_EXPORT KisAbstractColorSpace : public KisColorSpace { + + +public: + + /** + * @param id The unique human and machine readable identifiation of this colorspace + * @param cmType the lcms type indentification for this colorspace, may be 0 + * @param colorSpaceSignature the icc identification for this colorspace, may be 0 + * @param tqparent the registry that owns this instance + * @param profile the profile this colorspace uses for transforms + */ + KisAbstractColorSpace(const KisID & id, + DWORD cmType, + icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * tqparent, + KisProfile *profile); + + void init(); + + virtual ~KisAbstractColorSpace(); + + virtual bool operator==(const KisAbstractColorSpace& rhs) const { + return (m_id == rhs.m_id && m_profile == rhs.m_profile); + } + + +//================== Information about this color strategy ========================// + +public: + + + //========== Channels =====================================================// + + // Return a vector describing all the channels this color model has. + virtual TQValueVector channels() const = 0; + + virtual TQ_UINT32 nChannels() const = 0; + + virtual TQ_UINT32 nColorChannels() const = 0; + + virtual TQ_UINT32 nSubstanceChannels() const { return 0; }; + + virtual TQ_UINT32 pixelSize() const = 0; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0; + + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0; + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0; + + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0; + + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex); + + //========== Identification ===============================================// + + virtual KisID id() const { return m_id; } + + void setColorSpaceType(TQ_UINT32 type) { m_cmType = type; } + TQ_UINT32 colorSpaceType() { return m_cmType; } + + virtual icColorSpaceSignature colorSpaceSignature() { return m_colorSpaceSignature; } + + //========== Capabilities =================================================// + + virtual KisCompositeOpList userVisiblecompositeOps() const = 0; + + /** + * Returns true if the colorspace supports channel values outside the + * (normalised) range 0 to 1. + */ + virtual bool hasHighDynamicRange() const { return false; } + + //========== Display profiles =============================================// + + virtual KisProfile * getProfile() const { return m_profile; }; + + +//================= Conversion functions ==================================// + + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + + virtual void toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const; + virtual void fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual bool convertPixelsTo(const TQ_UINT8 * src, + TQ_UINT8 * dst, KisColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + +//============================== Manipulation fucntions ==========================// + + +// +// The manipulation functions have default implementations that _convert_ the pixel +// to a TQColor and back. Reimplement these methods in your color strategy! +// + virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues); + + virtual KisColorAdjustment *createDesaturateAdjustment(); + + virtual KisColorAdjustment *createPerChannelAdjustment(TQ_UINT16 **transferValues); + + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels); + + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + + virtual TQ_UINT8 difference(const TQ_UINT8* src1, const TQ_UINT8* src2); + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const; + + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual KisID mathToolboxID() const; + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + KisColorSpace * srcSpace, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + +//========================== END of Public API ========================================// + +protected: + + + /** + * Compose two byte arrays containing pixels in the same color + * model together. + */ + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) = 0; + + virtual cmsHTRANSFORM createTransform(KisColorSpace * dstColorSpace, + KisProfile * srcProfile, + KisProfile * dstProfile, + TQ_INT32 renderingIntent); + + virtual void compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity); + + + // So I don't need to re-implement it everywhere. + template + void abstractCompositeAlphaDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, + const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity, + NativeMult nativeMult, Uint8ToNative uint8ToNative, + NativeOpacityTest nativeOpacityTest) { + while (rows > 0) { + + const ColorType *src = reinterpret_cast(srcRowStart); + ColorType *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + ColorType srcAlpha = src[AlphaPos]; + ColorType dstAlpha = dst[AlphaPos]; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = nativeMult(srcAlpha, uint8ToNative(*tqmask)); + tqmask++; + } + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = nativeMult(srcAlpha, uint8ToNative(opacity)); + } + + // not transparent + if (nativeOpacityTest(srcAlpha) && srcAlpha >= dstAlpha) { + dst[AlphaPos] = srcAlpha; + memcpy(dst, src, NonAlphaSize * sizeof(ColorType)); + } + + columns--; + src += TotalSize; + dst += TotalSize; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } + } + +protected: + + TQStringList m_profileFilenames; + TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor. + TQ_INT32 m_alphaPos; // The position in _bytes_ of the alpha channel + TQ_INT32 m_alphaSize; // The width in _bytes_ of the alpha channel + + TQValueVector m_channels; + + KisColorSpaceFactoryRegistry * m_parent; + +private: + + cmsHTRANSFORM m_defaultToRGB; // Default transform to 8 bit sRGB + cmsHTRANSFORM m_defaultFromRGB; // Default transform from 8 bit sRGB + + cmsHPROFILE m_lastRGBProfile; // Last used profile to transform to/from RGB + cmsHTRANSFORM m_lastToRGB; // Last used transform to transform to RGB + cmsHTRANSFORM m_lastFromRGB; // Last used transform to transform from RGB + + cmsHTRANSFORM m_defaultToLab; + cmsHTRANSFORM m_defaultFromLab; + + KisProfile * m_profile; + KisColorSpace *m_lastUsedDstColorSpace; + cmsHTRANSFORM m_lastUsedTransform; + + KisID m_id; + DWORD m_cmType; // The colorspace type as defined by littlecms + icColorSpaceSignature m_colorSpaceSignature; // The colorspace signature as defined in icm/icc files + + // cmsHTRANSFORM is a void *, so this should work. + typedef TQMap TransformMap; + TransformMap m_transforms; // Cache for existing transforms + + KisAbstractColorSpace(const KisAbstractColorSpace&); + KisAbstractColorSpace& operator=(const KisAbstractColorSpace&); + + TQMemArray m_conversionCache; // XXX: This will be a bad problem when we have threading. +}; + +#endif // KIS_STRATEGY_COLORSPACE_H_ diff --git a/chalk/chalkcolor/kis_basic_histogram_producers.cc b/chalk/chalkcolor/kis_basic_histogram_producers.cc new file mode 100644 index 00000000..b769a3d3 --- /dev/null +++ b/chalk/chalkcolor/kis_basic_histogram_producers.cc @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "config.h" + +#ifdef HAVE_OPENEXR +#include +#endif + +#include "kis_global.h" +#include "kis_basic_histogram_producers.h" +#include "kis_integer_maths.h" +#include "kis_channelinfo.h" +#include "kis_colorspace.h" +#include "kis_lab_colorspace.h" + +KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0; + + +KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs) + : m_channels(channels), + m_nrOfBins(nrOfBins), + m_colorSpace(cs), + m_id(id) +{ + m_bins.resize(m_channels); + for (int i = 0; i < m_channels; i++) + m_bins.at(i).resize(m_nrOfBins); + m_outLeft.resize(m_channels); + m_outRight.resize(m_channels); + m_count = 0; + m_from = 0.0; + m_width = 1.0; +} + +void KisBasicHistogramProducer::clear() { + m_count = 0; + for (int i = 0; i < m_channels; i++) { + for (int j = 0; j < m_nrOfBins; j++) { + m_bins.at(i).at(j) = 0; + } + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } +} + +void KisBasicHistogramProducer::makeExternalToInternal() { + // This function assumes that the pixel is has no 'gaps'. That is to say: if we start + // at byte 0, we can get to the end of the pixel by adding consecutive size()s of + // the channels + TQValueVector c = channels(); + uint count = c.count(); + int currentPos = 0; + + for (uint i = 0; i < count; i++) { + for (uint j = 0; j < count; j++) { + if (c.at(j)->pos() == currentPos) { + m_external.append(j); + break; + } + } + currentPos += c.at(m_external.at(m_external.count() - 1))->size(); + } +} + +// ------------ U8 --------------------- + +KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicU8HistogramProducer::positionToString(double pos) const { + return TQString("%1").tqarg(static_cast(pos * UINT8_MAX)); +} + +void KisBasicU8HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + if (!pixels) return; + if (!cs) return; + if (nPixels == 0) return; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + while (nPixels > 0) { + if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) { + + for (int i = 0; i < m_channels; i++) { + m_bins.at(i).at(pixels[i])++; + } + m_count++; + + } + + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) { + + for (int i = 0; i < m_channels; i++) { + m_bins.at(i).at(pixels[i])++; + } + m_count++; + + } + + pixels += pSize; + nPixels--; + } + } +} + +// ------------ U16 --------------------- + +KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicU16HistogramProducer::positionToString(double pos) const +{ + return TQString("%1").tqarg(static_cast(pos * UINT8_MAX)); +} + +double KisBasicU16HistogramProducer::maximalZoom() const +{ + return 1.0 / 255.0; +} + +void KisBasicU16HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + // The view + TQ_UINT16 from = static_cast(m_from * UINT16_MAX); + TQ_UINT16 width = static_cast(m_width * UINT16_MAX + 0.5); // We include the end + TQ_UINT16 to = from + width; + double factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + TQ_UINT16* pixel = reinterpret_cast(pixels); + while (nPixels > 0) { + if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + TQ_UINT16 value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + TQ_UINT16* pixel = reinterpret_cast(pixels); + + if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + TQ_UINT16 value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + nPixels--; + + } + } +} + +// ------------ Float32 --------------------- +KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) +{ +} + +TQString KisBasicF32HistogramProducer::positionToString(double pos) const { + return TQString("%1").tqarg(static_cast(pos)); // XXX I doubt this is correct! +} + +double KisBasicF32HistogramProducer::maximalZoom() const { + // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment + return 1.0 / 255.0; +} + +void KisBasicF32HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) { + // The view + float from = static_cast(m_from); + float width = static_cast(m_width); + float to = from + width; + float factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + + if ( selectionMask ) { + while (nPixels > 0) { + + float* pixel = reinterpret_cast(pixels); + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + + pixels += pSize; + selectionMask++; + nPixels--; + + } + } + else { + while (nPixels > 0) { + + float* pixel = reinterpret_cast(pixels); + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + + pixels += pSize; + nPixels--; + + } + } +} + +#ifdef HAVE_OPENEXR +// ------------ Float16 Half --------------------- +KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id, + KisColorSpace *cs) + : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) { +} + +TQString KisBasicF16HalfHistogramProducer::positionToString(double pos) const { + return TQString("%1").tqarg(static_cast(pos)); // XXX I doubt this is correct! +} + +double KisBasicF16HalfHistogramProducer::maximalZoom() const { + // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment + return 1.0 / 255.0; +} + +void KisBasicF16HalfHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) { + // The view + float from = static_cast(m_from); + float width = static_cast(m_width); + float to = from + width; + float factor = 255.0 / width; + + TQ_INT32 pSize = cs->pixelSize(); + if ( selectionMask ) { + while (nPixels > 0) { + half* pixel = reinterpret_cast(pixels); + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + half* pixel = reinterpret_cast(pixels); + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + for (int i = 0; i < m_channels; i++) { + float value = pixel[i]; + if (value > to) + m_outRight.at(i)++; + else if (value < from) + m_outLeft.at(i)++; + else + m_bins.at(i).at(static_cast((value - from) * factor))++; + } + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} +#endif + +// ------------ Generic RGB --------------------- +KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer() + : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")), + 3, 256, 0) { + /* we set 0 as colorspece, because we are not based on a specific colorspace. This + is no problem for the superclass since we override channels() */ + m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(255,0,0))); + m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,255,0))); + m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,0,255))); +} + +TQValueVector KisGenericRGBHistogramProducer::channels() { + return m_channelsList; +} + +TQString KisGenericRGBHistogramProducer::positionToString(double pos) const { + return TQString("%1").tqarg(static_cast(pos * UINT8_MAX)); +} + +double KisGenericRGBHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericRGBHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + TQColor c; + TQ_INT32 pSize = cs->pixelSize(); + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; + m_bins.at(1).at(c.green())++; + m_bins.at(2).at(c.blue())++; + + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + + } + else { + while (nPixels > 0) { + + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; + m_bins.at(1).at(c.green())++; + m_bins.at(2).at(c.blue())++; + + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} + +// ------------ Generic L*a*b* --------------------- +KisGenericLabHistogramProducer::KisGenericLabHistogramProducer() + : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) { + /* we set 0 as colorspace, because we are not based on a specific colorspace. This + is no problem for the superclass since we override channels() */ + m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + + if (!m_labCs) { + KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL)); + m_labCs = new KisLabColorSpace(0, labProfile); + } + m_colorSpace = m_labCs; +} +KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer() +{ + delete m_channelsList[0]; + delete m_channelsList[1]; + delete m_channelsList[2]; +} + +TQValueVector KisGenericLabHistogramProducer::channels() { + return m_channelsList; +} + +TQString KisGenericLabHistogramProducer::positionToString(double pos) const { + return TQString("%1").tqarg(static_cast(pos * UINT16_MAX)); +} + +double KisGenericLabHistogramProducer::maximalZoom() const { + return 1.0; +} + + +void KisGenericLabHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) +{ + for (int i = 0; i < m_channels; i++) { + m_outRight.at(i) = 0; + m_outLeft.at(i) = 0; + } + + TQ_UINT8 dst[8]; + TQ_INT32 pSize = cs->pixelSize(); + + if (selectionMask) { + while (nPixels > 0) { + if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) { +/* + cs->toTQColor(pixels, &c); + m_bins.at(0).at(c.red())++; +*/ + m_count++; + } + pixels += pSize; + selectionMask++; + nPixels--; + } + } + else { + while (nPixels > 0) { + if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) { + + cs->convertPixelsTo(pixels, dst, m_colorSpace, 1); + m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++; + m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++; + m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++; + + m_count++; + } + pixels += pSize; + nPixels--; + } + } +} + diff --git a/chalk/chalkcolor/kis_basic_histogram_producers.h b/chalk/chalkcolor/kis_basic_histogram_producers.h new file mode 100644 index 00000000..8b913ece --- /dev/null +++ b/chalk/chalkcolor/kis_basic_histogram_producers.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_BASIC_HISTOGRAM_PRODUCERS_ +#define _KIS_BASIC_HISTOGRAM_PRODUCERS_ + +#include +#include + +#include "config.h" + +#include "kis_histogram_producer.h" +#include "kis_colorspace.h" +#include "kis_id.h" + +class KisLabColorSpace; + +class KisBasicHistogramProducer : public KisHistogramProducer { +public: + KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *colorSpace); + virtual ~KisBasicHistogramProducer() {} + + virtual void clear(); + + virtual void setView(double from, double size) { m_from = from; m_width = size; } + + virtual const KisID& id() const { return m_id; } + virtual TQValueVector channels() { return m_colorSpace->channels(); } + virtual TQ_INT32 numberOfBins() { return m_nrOfBins; } + virtual double viewFrom() const { return m_from; } + virtual double viewWidth() const { return m_width; } + + virtual TQ_INT32 count() { return m_count; } + + virtual TQ_INT32 getBinAt(int channel, int position) + { return m_bins.at(externalToInternal(channel)).at(position); } + + virtual TQ_INT32 outOfViewLeft(int channel) + { return m_outLeft.at(externalToInternal(channel)); } + + virtual TQ_INT32 outOfViewRight(int channel) + { return m_outRight.at(externalToInternal(channel)); } + +protected: + /** + * The order in which channels() returns is not the same as the internal representation, + * that of the pixel internally. This method converts external usage to internal usage. + * This method uses some basic assumtpions about the tqlayout of the pixel, so _extremely_ + * exotic spaces might want to override this (see makeExternalToInternal source for + * those assumptions) + **/ + virtual int externalToInternal(int ext) { + if (channels().count() > 0 && m_external.count() == 0) // Set up the translation table + makeExternalToInternal(); + return m_external.at(ext); + } + // not virtual since that is useless: we call it from constructor + void makeExternalToInternal(); + typedef TQValueVector vBins; + TQValueVector m_bins; + vBins m_outLeft, m_outRight; + double m_from, m_width; + TQ_INT32 m_count; + int m_channels, m_nrOfBins; + KisColorSpace *m_colorSpace; + KisID m_id; + TQValueVector m_external; +}; + +class KisBasicU8HistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const { return 1.0; } +}; + +class KisBasicU16HistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const; +}; + +class KisBasicF32HistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const; +}; + +#ifdef HAVE_OPENEXR +class KisBasicF16HalfHistogramProducer : public KisBasicHistogramProducer { +public: + KisBasicF16HalfHistogramProducer(const KisID& id, KisColorSpace *colorSpace); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const; +}; +#endif + +/** + * Parametrized on a specific KisHistogramProducer. Its generated producers + * will have the same KisID as the factory's. This is acceptable because we can't mix + * Factories with Producers in the code because they are incompatible types, and + * in the GUI we actually only need a producer's name, not a factory's. + */ +template class KisBasicHistogramProducerFactory : public KisHistogramProducerFactory { +public: + KisBasicHistogramProducerFactory(const KisID& id, KisColorSpace *colorSpace) + : KisHistogramProducerFactory(id), m_cs(colorSpace) {} + virtual ~KisBasicHistogramProducerFactory() {} + virtual KisHistogramProducerSP generate() { return new T(id(), m_cs); } + virtual bool isCompatibleWith(KisColorSpace* colorSpace) const { return colorSpace->id() == m_cs->id(); } + virtual float preferrednessLevelWith(KisColorSpace* /*colorSpace*/) const { return 1.0; } +protected: + KisColorSpace *m_cs; +}; + +/** + * This is a Producer (with associated factory) that converts the pixels of the colorspace + * to RGB8 with toTQColor, and then does its counting on RGB. This is NOT registered with the + * Registry, because it isCompatibleWith all colorspaces, and should only be used in extreme + * cases (like no other producer being available + **/ +class KisGenericRGBHistogramProducer : public KisBasicHistogramProducer { +public: + KisGenericRGBHistogramProducer(); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const; + virtual TQValueVector channels(); +protected: + TQValueVector m_channelsList; +}; + +/** KisGenericRGBHistogramProducer his special Factory that isCompatibleWith everything. */ +class KisGenericRGBHistogramProducerFactory : public KisHistogramProducerFactory { +public: + KisGenericRGBHistogramProducerFactory() + : KisHistogramProducerFactory(KisID("GENRGBHISTO", i18n("Generic RGB"))) {} + virtual ~KisGenericRGBHistogramProducerFactory() {} + virtual KisHistogramProducerSP generate() { return new KisGenericRGBHistogramProducer(); } + virtual bool isCompatibleWith(KisColorSpace*) const { return true; } + virtual float preferrednessLevelWith(KisColorSpace*) const { return 0.0; } +}; + + +/** + * This is a Producer (with associated factory) that converts the pixels of the colorspace + * to L*a*b*, and then does its counting. + * It isCompatibleWith all colorspaces + **/ +class KisGenericLabHistogramProducer : public KisBasicHistogramProducer { + public: + KisGenericLabHistogramProducer(); + virtual ~KisGenericLabHistogramProducer(); + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace); + virtual TQString positionToString(double pos) const; + virtual double maximalZoom() const; + virtual TQValueVector channels(); + protected: + TQValueVector m_channelsList; + private: + static KisLabColorSpace* m_labCs; +}; + +/** KisGenericLabHistogramProducer his special Factory that isCompatibleWith everything. */ +class KisGenericLabHistogramProducerFactory : public KisHistogramProducerFactory { + public: + KisGenericLabHistogramProducerFactory() + : KisHistogramProducerFactory(KisID("GENLABHISTO", i18n("Generic L*a*b*"))) {} + virtual ~KisGenericLabHistogramProducerFactory() {} + virtual KisHistogramProducerSP generate() { return new KisGenericLabHistogramProducer(); } + virtual bool isCompatibleWith(KisColorSpace*) const { return true; } + virtual float preferrednessLevelWith(KisColorSpace*) const { return 0.0; } +}; + + +#endif // _KIS_BASIC_HISTOGRAM_PRODUCERS_ diff --git a/chalk/chalkcolor/kis_channelinfo.h b/chalk/chalkcolor/kis_channelinfo.h new file mode 100644 index 00000000..f8ec8301 --- /dev/null +++ b/chalk/chalkcolor/kis_channelinfo.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_CHANNELINFO_H_ +#define KIS_CHANNELINFO_H_ + +#include +#include "tqstring.h" +#include "ksharedptr.h" + +/** + * This class gives some basic information about a channel, + * that is, one of the components that makes up a particular + * pixel. + */ +class KisChannelInfo : public KShared { +public: + enum enumChannelType { + COLOR, // The channel represents a color + ALPHA, // The channel represents the opacity of a pixel + SUBSTANCE, // The channel represents a real-world substance like pigments or medium + SUBSTRATE // The channel represents a real-world painting substrate like a canvas + }; + + enum enumChannelValueType { + UINT8, + UINT16, + FLOAT16, + FLOAT32, + INT8, + INT16, + OTHER // Use this if the channel is neither an integer or a float + }; + enum enumChannelFlags { + FLAG_COLOR = 1, + FLAG_ALPHA = (1 << 1), + FLAG_SUBSTANCE = (1 << 2), + FLAG_SUBSTRATE = (1 << 3), + FLAG_COLOR_AND_ALPHA = FLAG_ALPHA | FLAG_COLOR // HACK to be able to use convolution of color and alpha at the same time + }; + +public: + KisChannelInfo() { }; + /** + * @param name The i18n'ed name of this channel ("Red") + * @param abbrev A one or two letter abbreviation of the name of this channel ("R") + * @param npos the position of the first byte of this channel value in the pixel + * @param channelType the type of this channel (color, alpha, etc) + * @param channelValueType the datatype of this channel + * @param size the size in bytes of this channel + * @param color a color to visually represent this channel by in the gui + */ + KisChannelInfo( const TQString & name, const TQString & abbrev, TQ_INT32 npos, enumChannelType channelType, enumChannelValueType channelValueType, TQ_INT32 size = 1, TQColor color = TQColor(0,0,0)) + : m_name (name), m_abbrev(abbrev), m_pos (npos), m_channelType(channelType), m_channelValueType(channelValueType), m_size(size), m_color(color) { }; +public: + /** + * User-friendly name for this channel for presentation purposes in the gui + */ + inline TQString name() const { return m_name; }; + + /** + * Return the single-letter abbreviation for this channel + */ + inline TQString abbrev() const { return m_abbrev; }; + /** + * returns the position of the first byte of the channel in the pixel + */ + inline TQ_INT32 pos() const { return m_pos; }; + + /** + * returns the number of bytes this channel takes + */ + inline TQ_INT32 size() const { return m_size; }; + + /** + * returns the type of the channel + */ + inline enumChannelType channelType() const { return m_channelType; }; + /** + * return the type of the value of the channel (float, uint8 or uint16) + */ + inline enumChannelValueType channelValueType() const { return m_channelValueType; }; + /** + * This is a color that can be used to represent this channel in histograms and so. + * By default this is black, so keep in mind that many channels might look the same + */ + inline TQColor color() const { return m_color; } + +private: + + TQString m_name; + TQString m_abbrev; + TQ_INT32 m_pos; + enumChannelType m_channelType; + enumChannelValueType m_channelValueType; + TQ_INT32 m_size; + TQColor m_color; + +}; + +#endif // KIS_CHANNELINFO_H_ diff --git a/chalk/chalkcolor/kis_color.cc b/chalk/chalkcolor/kis_color.cc new file mode 100644 index 00000000..7d6acb89 --- /dev/null +++ b/chalk/chalkcolor/kis_color.cc @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "kdebug.h" +#include "kis_debug_areas.h" +#include "kis_color.h" +#include "kis_profile.h" +#include "kis_colorspace.h" +#include "kis_colorspace_factory_registry.h" + +KisColor::KisColor() +{ + m_data = 0; + m_colorSpace = 0; +} + +KisColor::~KisColor() +{ + delete [] m_data; +} + +KisColor::KisColor(const TQColor & color, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + Q_ASSERT(color.isValid()); + Q_ASSERT(colorSpace); + + m_data = new TQ_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + + m_colorSpace->fromTQColor(color, OPACITY_OPAQUE, m_data); +} + + +KisColor::KisColor(const TQColor & color, TQ_UINT8 alpha, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + Q_ASSERT(color.isValid()); + Q_ASSERT(colorSpace); + m_data = new TQ_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + + m_colorSpace->fromTQColor(color, alpha, m_data); +} + +KisColor::KisColor(const TQ_UINT8 * data, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + + m_data = new TQ_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + memmove(m_data, data, colorSpace->pixelSize()); +} + + +KisColor::KisColor(const KisColor &src, KisColorSpace * colorSpace) + : m_colorSpace(colorSpace) +{ + m_data = new TQ_UINT8[colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + + src.colorSpace()->convertPixelsTo(src.data(), m_data, colorSpace, 1); +} + +KisColor::KisColor(const KisColor & rhs) +{ + if (this == &rhs) return; + + m_colorSpace = rhs.colorSpace(); + m_data = new TQ_UINT8[m_colorSpace->pixelSize()]; + memset(m_data, 0, m_colorSpace->pixelSize()); + memcpy(m_data, rhs.data(), m_colorSpace->pixelSize()); +} + +KisColor & KisColor::operator=(const KisColor & rhs) +{ + delete [] m_data; + m_data = 0; + m_colorSpace = rhs.colorSpace(); + + if (rhs.m_colorSpace && rhs.m_data) { + m_data = new TQ_UINT8[m_colorSpace->pixelSize()]; + memcpy(m_data, rhs.m_data, m_colorSpace->pixelSize()); + } + return * this; +} + +void KisColor::convertTo(KisColorSpace * cs) +{ + //kdDebug(DBG_AREA_CMS) << "Our colormodel: " << m_colorSpace->id().name() + // << ", new colormodel: " << cs->id().name() << "\n"; + + if (m_colorSpace == cs) + return; + + TQ_UINT8 * m_data2 = new TQ_UINT8[cs->pixelSize()]; + memset(m_data2, 0, cs->pixelSize()); + + m_colorSpace->convertPixelsTo(m_data, m_data2, cs, 1); + + delete [] m_data; + m_data = m_data2; + m_colorSpace = cs; +} + + +void KisColor::setColor(TQ_UINT8 * data, KisColorSpace * colorSpace) +{ + delete [] m_data; + m_data = new TQ_UINT8[colorSpace->pixelSize()]; + memcpy(m_data, data, colorSpace->pixelSize()); + m_colorSpace = colorSpace; +} + +// To save the user the trouble of doing color->colorSpace()->toTQColor(color->data(), &c, &a, profile +void KisColor::toTQColor(TQColor *c) const +{ + if (m_colorSpace && m_data) { + // XXX (bsar): There must be a better way, but I'm getting hopelessly confused about constness by now + KisColorSpace * cs(const_cast(m_colorSpace)); + + cs->toTQColor(m_data, c); + } +} + +void KisColor::toTQColor(TQColor *c, TQ_UINT8 *opacity) const +{ + if (m_colorSpace && m_data) { + // XXX (bsar): There must be a better way, but I'm getting hopelessly confused about constness by now + KisColorSpace * cs(const_cast(m_colorSpace)); + cs->toTQColor(m_data, c, opacity); + } +} + +TQColor KisColor::toTQColor() const +{ + TQColor c; + toTQColor(&c); + return c; +} + +void KisColor::dump() const +{ + + //kdDebug(DBG_AREA_CMS) << "KisColor (" << this << "), " << m_colorSpace->id().name() << "\n"; + TQValueVector channels = m_colorSpace->channels(); + + TQValueVector::const_iterator begin = channels.begin(); + TQValueVector::const_iterator end = channels.end(); + + for (TQValueVector::const_iterator it = begin; it != end; ++it) + { + KisChannelInfo * ch = (*it); + // XXX: setNum always takes a byte. + if (ch->size() == sizeof(TQ_UINT8)) { + // Byte + //kdDebug(DBG_AREA_CMS) << "Channel (byte): " << ch->name() << ": " << TQString().setNum(m_data[ch->pos()]) << "\n"; + } + else if (ch->size() == sizeof(TQ_UINT16)) { + // Short (may also by an nvidia half) + //kdDebug(DBG_AREA_CMS) << "Channel (short): " << ch->name() << ": " << TQString().setNum(*((const TQ_UINT16 *)(m_data+ch->pos()))) << "\n"; + } + else if (ch->size() == sizeof(TQ_UINT32)) { + // Integer (may also be float... Find out how to distinguish these!) + //kdDebug(DBG_AREA_CMS) << "Channel (int): " << ch->name() << ": " << TQString().setNum(*((const TQ_UINT32 *)(m_data+ch->pos()))) << "\n"; + } + } + +} diff --git a/chalk/chalkcolor/kis_color.h b/chalk/chalkcolor/kis_color.h new file mode 100644 index 00000000..b7646586 --- /dev/null +++ b/chalk/chalkcolor/kis_color.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_COLOR_H_ +#define _KIS_COLOR_H_ + +#include +#include "ksharedptr.h" + +#include "kis_global.h" +#include "kis_profile.h" +#include "kis_colorspace.h" + + +/** + * A KisColor describes a color in a certain colorspace. + * + */ +class KisColor { + +public: + /// Create an empty KisColor. It will be valid, but also black and transparent + KisColor(); + + virtual ~KisColor(); + + /// Create a KisColor from a TQColor. The TQColor is immediately converted to native. The TQColor + /// is assumed to have the current monitor profile. + KisColor(const TQColor & color, KisColorSpace * colorSpace); + + /// Create a KisColor from a TQColor. The TQColor is immediately converted to native. The TQColor + /// is assumed to have the current monitor profile. + KisColor(const TQColor & color, TQ_UINT8 alpha, KisColorSpace * colorSpace); + + /// Create a KisColor using a native color strategy. The data is copied. + KisColor(const TQ_UINT8 * data, KisColorSpace * colorSpace); + + /// Create a KisColor by converting src into another colorspace + KisColor(const KisColor &src, KisColorSpace * colorSpace); + + /// Copy constructor -- deep copies the colors. + KisColor(const KisColor & rhs); + + /// Effective C++, item 11 + KisColor &operator=(const KisColor &); + + /// For easy memcpy'ing etc. + TQ_UINT8 * data() const { return m_data; } + + KisColorSpace * colorSpace() const { return m_colorSpace; } + + KisProfile * profile() const { return m_colorSpace->getProfile(); } + + /// Convert this KisColor to the specified colorspace. If the specified colorspace is the + /// same as the original colorspace, do nothing. Returns the converted KisColor. + void convertTo(KisColorSpace * cs); + + /// Replace the existing color data, and colorspace with the specified data. + void setColor(TQ_UINT8 * data, KisColorSpace * colorSpace = 0); + + /// To save the user the trouble of doing color->colorSpace()->toTQColor(color->data(), &c, &a + void toTQColor(TQColor *c) const; + void toTQColor(TQColor *c, TQ_UINT8 *opacity) const; + + TQColor toTQColor() const; + + void dump() const; + +private: + + TQ_UINT8 * m_data; + + KisColorSpace * m_colorSpace; +}; + +#endif diff --git a/chalk/chalkcolor/kis_color_conversions.cc b/chalk/chalkcolor/kis_color_conversions.cc new file mode 100644 index 00000000..e517c9f7 --- /dev/null +++ b/chalk/chalkcolor/kis_color_conversions.cc @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_color_conversions.h" + +/** + * A number of often-used conversions between color models + */ + +void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V) +{ + unsigned int max = R; + unsigned int min = R; + unsigned char maxValue = 0; // r = 0, g = 1, b = 2 + + // find maximum and minimum RGB values + if(static_cast(G) > max) { + max = G; + maxValue = 1; + } + + if (static_cast(B) > max) + { + max = B; + maxValue = 2; + } + + if(static_cast(G) < min) + min = G; + + if(static_cast(B) < min ) + min = B; + + int delta = max - min; + + // To prevent division by zero later on. + if (delta == 0) delta = 1; + + *V = max; // value + *S = max ? (510 * delta + max) / ( 2 * max) : 0; // saturation + + // calc hue + if(*S == 0) + *H = -1; // undefined hue + else + { + switch(maxValue) + { + case 0: // red + if(G >= B) + *H = (120 * (G - B) + delta) / (2 * delta); + else + *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300; + break; + case 1: // green + if(B > R) + *H = 120 + (120 * (B - R) + delta) / (2 * delta); + else + *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta); + break; + case 2: // blue + if(R > G) + *H = 240 + (120 * (R - G) + delta) / (2 * delta); + else + *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta); + break; + } + } +} + +void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B) +{ + *R = *G = *B = V; + + if (S != 0 && H != -1) { // chromatic + + if (H >= 360) { + // angle > 360 + H %= 360; + } + + unsigned int f = H % 60; + H /= 60; + unsigned int p = static_cast(2*V*(255-S)+255)/510; + unsigned int q, t; + + if (H & 1) { + q = static_cast(2 * V * (15300 - S * f) + 15300) / 30600; + switch (H) { + case 1: + *R = static_cast(q); + *G = static_cast(V); + *B = static_cast(p); + break; + case 3: + *R = static_cast(p); + *G = static_cast(q); + *B = static_cast(V); + break; + case 5: + *R = static_cast(V); + *G = static_cast(p); + *B = static_cast(q); + break; + } + } else { + t = static_cast(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600; + switch (H) { + case 0: + *R = static_cast(V); + *G = static_cast(t); + *B = static_cast(p); + break; + case 2: + *R = static_cast(p); + *G = static_cast(V); + *B = static_cast(t); + break; + case 4: + *R = static_cast(t); + *G = static_cast(p); + *B = static_cast(V); + break; + } + } + } +} + +#define EPSILON 1e-6 +#define UNDEFINED_HUE -1 + +void RGBToHSV(float r, float g, float b, float *h, float *s, float *v) +{ + float max = TQMAX(r, TQMAX(g, b)); + float min = TQMIN(r, TQMIN(g, b)); + + *v = max; + + if (max > EPSILON) { + *s = (max - min) / max; + } else { + *s = 0; + } + + if (*s < EPSILON) { + *h = UNDEFINED_HUE; + } else { + float delta = max - min; + + if (r == max) { + *h = (g - b) / delta; + } else if (g == max) { + *h = 2 + (b - r) / delta; + } else { + *h = 4 + (r - g) / delta; + } + + *h *= 60; + if (*h < 0) { + *h += 360; + } + } +} + +void HSVToRGB(float h, float s, float v, float *r, float *g, float *b) +{ + if (s < EPSILON || h == UNDEFINED_HUE) { + // Achromatic case + + *r = v; + *g = v; + *b = v; + } else { + float f, p, q, t; + int i; + + if (h > 360 - EPSILON) { + h -= 360; + } + + h /= 60; + i = static_cast(floor(h)); + f = h - i; + p = v * (1 - s); + q = v * (1 - (s * f)); + t = v * (1 - (s * (1 - f))); + + switch (i) { + case 0: + *r = v; + *g = t; + *b = p; + break; + case 1: + *r = q; + *g = v; + *b = p; + break; + case 2: + *r = p; + *g = v; + *b = t; + break; + case 3: + *r = p; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = p; + *b = v; + break; + case 5: + *r = v; + *g = p; + *b = q; + break; + } + } +} + +void rgb_to_hls(TQ_UINT8 red, TQ_UINT8 green, TQ_UINT8 blue, float * hue, float * lightness, float * saturation) +{ + float r = red / 255.0; + float g = green / 255.0; + float b = blue / 255.0; + float h = 0; + float l = 0; + float s = 0; + + float max, min, delta; + + max = TQMAX(r, g); + max = TQMAX(max, b); + + min = TQMIN(r, g); + min = TQMIN(min, b); + + delta = max - min; + + l = (max + min) / 2; + + if (delta == 0) { + // This is a gray, no chroma... + h = 0; + s = 0; + } + else { + if ( l < 0.5) + s = delta / ( max + min ); + else + s = delta / ( 2 - max - min ); + + float delta_r, delta_g, delta_b; + + delta_r = (( max - r ) / 6 ) / delta; + delta_g = (( max - g ) / 6 ) / delta; + delta_b = (( max - b ) / 6 ) / delta; + + if ( r == max ) + h = delta_b - delta_g; + else if ( g == max) + h = ( 1.0 / 3 ) + delta_r - delta_b; + else if ( b == max) + h = ( 2.0 / 3 ) + delta_g - delta_r; + + if (h < 0) h += 1; + if (h > 1) h += 1; + + } + + *hue = h * 360; + *saturation = s; + *lightness = l; +} + +float hue_value(float n1, float n2, float hue) +{ + if (hue > 360 ) + hue = hue -360; + else if (hue < 0 ) + hue = hue +360; + if (hue < 60 ) + return n1 + (((n2 - n1) * hue) / 60); + else if (hue < 180 ) + return n2; + else if (hue < 240 ) + return n1 + (((n2 - n1) * (240 - hue)) / 60); + else return n1; +} + + +void hls_to_rgb(float h, float l, float s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b) +{ + float m1, m2; + + if (l <= 0.5 ) + m2 = l * ( 1 + s ); + else + m2 = l + s - l * s; + + m1 = 2 * l - m2; + + *r = (TQ_UINT8)(hue_value(m1, m2, h + 120) * 255 + 0.5); + *g = (TQ_UINT8)(hue_value(m1, m2, h) * 255 + 0.5); + *b = (TQ_UINT8)(hue_value(m1, m2, h - 120) * 255 + 0.5); + +} + +void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, int * h, int * l, int * s) +{ + float hue, saturation, lightness; + + rgb_to_hls(r, g, b, &hue, &lightness, &saturation); + *h = (int)(hue + 0.5); + *l = (int)(lightness * 255 + 0.5); + *s = (int)(saturation * 255 + 0.5); +} + +void hls_to_rgb(int h, int l, int s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b) +{ + float hue = h; + float lightness = l / 255.0; + float saturation = s / 255.0; + + hls_to_rgb(hue, lightness, saturation, r, g, b); +} + +/* +A Fast HSL-to-RGB Transform +by Ken Fishkin +from "Graphics Gems", Academic Press, 1990 +*/ + +void RGBToHSL(float r, float g, float b, float *h, float *s, float *l) +{ + float v; + float m; + float vm; + float r2, g2, b2; + + v = TQMAX(r,g); + v = TQMAX(v,b); + m = TQMIN(r,g); + m = TQMIN(m,b); + + if ((*l = (m + v) / 2.0) <= 0.0) { + *h = UNDEFINED_HUE; + *s = 0; + return; + } + if ((*s = vm = v - m) > 0.0) { + *s /= (*l <= 0.5) ? (v + m ) : + (2.0 - v - m) ; + } else { + *h = UNDEFINED_HUE; + return; + } + + + r2 = (v - r) / vm; + g2 = (v - g) / vm; + b2 = (v - b) / vm; + + if (r == v) + *h = (g == m ? 5.0 + b2 : 1.0 - g2); + else if (g == v) + *h = (b == m ? 1.0 + r2 : 3.0 - b2); + else + *h = (r == m ? 3.0 + g2 : 5.0 - r2); + + *h *= 60; +} + +void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b) + +{ + float v; + + v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl); + if (v <= 0) { + *r = *g = *b = 0.0; + } else { + float m; + float sv; + int sextant; + float fract, vsf, mid1, mid2; + + m = l + l - v; + sv = (v - m ) / v; + h /= 60.0; + sextant = static_cast(h); + fract = h - sextant; + vsf = v * sv * fract; + mid1 = m + vsf; + mid2 = v - vsf; + switch (sextant) { + case 0: *r = v; *g = mid1; *b = m; break; + case 1: *r = mid2; *g = v; *b = m; break; + case 2: *r = m; *g = v; *b = mid1; break; + case 3: *r = m; *g = mid2; *b = v; break; + case 4: *r = mid1; *g = m; *b = v; break; + case 5: *r = v; *g = m; *b = mid2; break; + } + } +} + diff --git a/chalk/chalkcolor/kis_color_conversions.h b/chalk/chalkcolor/kis_color_conversions.h new file mode 100644 index 00000000..53a476e0 --- /dev/null +++ b/chalk/chalkcolor/kis_color_conversions.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CONVERSIONS_H_ +#define _KIS_CONVERSIONS_H_ + +#include + +/** + * A number of often-used conversions between color models + */ + +// 8-bit integer versions. RGBSL are 0-255, H is 0-360. + void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V); + void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B); + +// Floating point versions. RGBSL are 0-1, H is 0-360. + void RGBToHSV(float r, float g, float b, float *h, float *s, float *v); + void HSVToRGB(float h, float s, float v, float *r, float *g, float *b); + + void RGBToHSL(float r, float g, float b, float *h, float *s, float *l); + void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b); + + void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, float * h, float * l, float * s); + + float hue_value(float n1, float n2, float hue); + + void hls_to_rgb(float h, float l, float s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b); + + void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, int * h, int * l, int * s); + void hls_to_rgb(int h, int l, int s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b); + +#endif // _KIS_CONVERSIONS_H_ + diff --git a/chalk/chalkcolor/kis_colorspace.cc b/chalk/chalkcolor/kis_colorspace.cc new file mode 100644 index 00000000..de0c44cf --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_colorspace.h" +#include "kis_colorspace_iface.h" + +KisColorSpace::KisColorSpace() +{ + m_dcop = 0; +} + +KisColorSpace::~KisColorSpace() +{ + delete m_dcop; +} + +DCOPObject * KisColorSpace::dcopObject() +{ + if (!m_dcop) { + m_dcop = new KisColorSpaceIface(this); + Q_CHECK_PTR(m_dcop); + } + return m_dcop; +} diff --git a/chalk/chalkcolor/kis_colorspace.h b/chalk/chalkcolor/kis_colorspace.h new file mode 100644 index 00000000..6071909c --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace.h @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLORSPACE_H_ +#define KIS_COLORSPACE_H_ + +#include +#include LCMS_HEADER + +#include +#include + +#include "kis_composite_op.h" +#include "kis_channelinfo.h" + +class DCOPObject; + +class KisProfile; +class KisColorSpaceFactoryRegistry; +class KisMathToolbox; +class KisFilter; + +class KisColorAdjustment +{ +public: + + KisColorAdjustment() {}; + virtual ~KisColorAdjustment() {}; +}; + + +enum ColorSpaceIndependence { + FULLY_INDEPENDENT, + TO_LAB16, + TO_RGBA8, + TO_RGBA16 +}; + +/** + * A colorspace is the definition of a certain color model + * in Chalk. This is the definition of the public API for + * colormodels. + */ +class KisColorSpace { + + +public: + + KisColorSpace(); + virtual ~KisColorSpace(); + + virtual DCOPObject * dcopObject(); + + virtual bool operator==(const KisColorSpace& rhs) const { + return id().id() == rhs.id().id(); + } + + +public: + + //========== Channels =====================================================// + + /// Return a vector describing all the channels this color model has. + virtual TQValueVector channels() const = 0; + + /** + * The total number of channels for a single pixel in this color model + */ + virtual TQ_UINT32 nChannels() const = 0; + + /** + * The total number of color channels (excludes alpha and substance) for a single + * pixel in this color model. + */ + virtual TQ_UINT32 nColorChannels() const = 0; + + /** + * The total number of substance channels for a single pixel + * in this color model + */ + virtual TQ_UINT32 nSubstanceChannels() const { return 0; }; + + /** + * The size in bytes of a single pixel in this color model + */ + virtual TQ_UINT32 pixelSize() const = 0; + + /** + * Return a string with the channel's value suitable for display in the gui. + */ + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0; + + /** + * Return a string with the channel's value with integer + * channels normalised to the floating point range 0 to 1, if appropriate. + */ + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0; + + /** + * Convert the value of the channel at the specified position into + * an 8-bit value. The position is not the number of bytes, but + * the position of the channel as defined in the channel info list. + */ + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0; + + /** + * Convert the value of the channel at the specified position into + * a 16-bit value. This may be upscaling or downscaling, depending + * on the defined value of the channel + */ + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0; + + /** + * Set dstPixel to the pixel containing only the given channel of srcPixel. The remaining channels + * should be set to whatever makes sense for 'empty' channels of this colour space, + * with the intent being that the pixel should look like it only has the given channel. + */ + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex) = 0; + + //========== Identification ===============================================// + + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const = 0; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() = 0; + + virtual icColorSpaceSignature colorSpaceSignature() = 0; + + /** + * If false, images in this colorspace will degrade considerably by + * functions, tools and filters that have the given measure of colorspace + * independence. + * + * @param independence the measure to which this colorspace will suffer + * from the manipulations of the tool or filter asking + * @return false if no degradation will take place, true if degradation will + * take place + */ + virtual bool willDegrade(ColorSpaceIndependence independence) = 0; + + //========== Capabilities =================================================// + + /** + * Returns the list of user-visible composite ops supported by this colourspace. Internal + * ops such as COPY, CLEAR, and ERASE, are not included as these make no sense + * for layers in the full image model. + */ + virtual KisCompositeOpList userVisiblecompositeOps() const = 0; + + /** + * Returns true if the colorspace supports channel values outside the + * (normalised) range 0 to 1. + */ + virtual bool hasHighDynamicRange() const = 0; + + + //========== Display profiles =============================================// + + /** + * Return the profile of this color space. This may be 0 + */ + virtual KisProfile * getProfile() const = 0; + +//================= Conversion functions ==================================// + + + /** + * The fromTQColor methods take a given color defined as an RGB TQColor + * and fills a byte array with the corresponding color in the + * the colorspace managed by this strategy. + * + * @param c the TQColor that will be used to fill dst + * @param dst a pointer to a pixel + * @param profile the optional profile that describes the color values of TQColor + */ + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0) = 0; + + /** + * The fromTQColor methods take a given color defined as an RGB TQColor + * and fills a byte array with the corresponding color in the + * the colorspace managed by this strategy. + * + * @param c the TQColor that will be used to fill dst + * @param opacity the opacity of the color + * @param dst a pointer to a pixel + * @param profile the optional profile that describes the color values of TQColor + */ + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0) = 0; + + + /** + * The toTQColor methods take a byte array that is at least pixelSize() long + * and converts the contents to a TQColor, using the given profile as a source + * profile and the optional profile as a destination profile. + * + * @param src a pointer to the source pixel + * @param c the TQColor that will be filled with the color at src + * @param profile the optional profile that describes the color in c, for instance the monitor profile + */ + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0) = 0; + + /** + * The toTQColor methods take a byte array that is at least pixelSize() long + * and converts the contents to a TQColor, using the given profile as a source + * profile and the option profile as a destination profile. + * + * @param src a pointer to the source pixel + * @param c the TQColor that will be filled with the color at src + * @param opacity a pointer to a byte that will be filled with the opacity a src + * @param profile the optional profile that describes the color in c, for instance the monitor profile + */ + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0) = 0; + + /** + * Convert the pixels in data to (8-bit BGRA) TQImage using the specified profiles. + * The pixels are supposed to be encoded in this color model. The default implementation + * will convert the pixels using either the profiles or the default profiles for the + * current colorstrategy and the RGBA colorstrategy. If that is not what you want, + * or if you think you can do better than lcms, reimplement this methods. + * + * @param data A pointer to a contiguous memory region containing width * height pixels + * @param width in pixels + * @param height in pixels + * @param dstProfile destination profile + * @param renderingIntent the rendering intent + * @param exposure The exposure setting for rendering a preview of a high dynamic range image. + */ + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f) = 0; + + + /** + * Convert the specified data to Lab. All colorspaces are guaranteed to support this + * + * @param src the source data + * @param dst the destination data + * @param nPixels the number of source pixels + */ + virtual void toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const = 0; + + /** + * Convert the specified data from Lab. to this colorspace. All colorspaces are + * guaranteed to support this. + * + * @param src the pixels in 16 bit lab format + * @param dst the destination data + * @param nPixels the number of pixels in the array + */ + virtual void fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const = 0; + + /** + * Convert a byte array of srcLen pixels *src to the specified color space + * and put the converted bytes into the prepared byte array *dst. + * + * Returns false if the conversion failed, true if it succeeded + */ + virtual bool convertPixelsTo(const TQ_UINT8 * src, + TQ_UINT8 * dst, KisColorSpace * dstColorSpace, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL) = 0; + +//============================== Manipulation functions ==========================// + + +// +// The manipulation functions have default implementations that _convert_ the pixel +// to a TQColor and back. Reimplement these methods in your color strategy! +// + + /** + * Get the alpha value of the given pixel, downscaled to an 8-bit value. + */ + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const = 0; + + /** + * Set the alpha channel of the given run of pixels to the given value. + * + * pixels -- a pointer to the pixels that will have their alpha set to this value + * alpha -- a downscaled 8-bit value for opacity + * nPixels -- the number of pixels + * + */ + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const = 0; + + /** + * Multiply the alpha channel of the given run of pixels by the given value. + * + * pixels -- a pointer to the pixels that will have their alpha set to this value + * alpha -- a downscaled 8-bit value for opacity + * nPixels -- the number of pixels + * + */ + virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) = 0; + + /** + * Applies the specified 8-bit alpha tqmask to the pixels. We assume that there are just + * as many alpha values as pixels but we do not check this; the alpha values + * are assumed to be 8-bits. + */ + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) = 0; + + /** + * Applies the inverted 8-bit alpha tqmask to the pixels. We assume that there are just + * as many alpha values as pixels but we do not check this; the alpha values + * are assumed to be 8-bits. + */ + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) = 0; + + /** + * Create an adjustment object for adjusting the brightness and contrast + * transferValues is a 256 bins array with values from 0 to 0xFFFF + */ + virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues) = 0; + + /** + * Create an adjustment object for desaturating + */ + virtual KisColorAdjustment *createDesaturateAdjustment() = 0; + + /** + * Create an adjustment object for adjusting individual channels + * transferValues is an array of nColorChannels number of 256 bins array with values from 0 to 0xFFFF + */ + virtual KisColorAdjustment *createPerChannelAdjustment(TQ_UINT16 **transferValues) = 0; + + /** + * Apply the adjustment created with onr of the other functions + */ + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels) = 0; + + /** + * Invert color channels of the given pixels + */ + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) = 0; + + // XXX: What with alpha channels? YYY: Add an overloaded function that takes alpha into account? + /** + * Get the difference between 2 colors, normalized in the range (0,255) + */ + virtual TQ_UINT8 difference(const TQ_UINT8* src1, const TQ_UINT8* src2) = 0; + + + /** + * Mix the colors given their weights and return in dst + * The sum of weights is assumed 255 */ + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const = 0; + + /** + * Convolve the given array of pointers to pixels and return the result + * in dst. The kernel values are clamped between -128 and 128 + */ + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const = 0; + + /** + * Darken all color channels with the given amount. If compensate is true, + * the compensation factor will be used to limit the darkening. + * + * (See the bumpmap filter) + */ + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const = 0; + + /** + * Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible + */ + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const = 0; + + /** + * Create a mathematical toolbox compatible with this colorspace + */ + virtual KisID mathToolboxID() const =0; + + /** + * Compose two arrays of pixels together. If source and target + * are not the same colour model, the source pixels will be + * converted to the target model. + */ + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + KisColorSpace * srcSpace, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) = 0; + + /** + * The backgroundfilters will be run periodically on the newly + * created paint device. XXX: Currently this uses times and not + * threads. + */ + virtual TQValueList createBackgroundFilters() + { return TQValueList(); }; + +private: + + DCOPObject * m_dcop; + +}; + +class KisColorSpaceFactory { +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const = 0; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() = 0; + + virtual icColorSpaceSignature colorSpaceSignature() = 0; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *) = 0; + + /** + * Returns the default icc profile for use with this colorspace. This may be "" + * + & @return the default icc profile name + */ + virtual TQString defaultProfile() = 0; + +}; + +#endif // KIS_COLORSPACE_H_ diff --git a/chalk/chalkcolor/kis_colorspace_factory_registry.cc b/chalk/chalkcolor/kis_colorspace_factory_registry.cc new file mode 100644 index 00000000..6758f7d5 --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace_factory_registry.cc @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdebug.h" +#include +#include +#include +#include +#include +#include +#include "kis_debug_areas.h" +#include "kis_colorspace.h" +#include "kis_profile.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_alpha_colorspace.h" +#include "kis_lab_colorspace.h" + + +KisColorSpaceFactoryRegistry::KisColorSpaceFactoryRegistry(TQStringList profileFilenames) +{ + // Create the built-in colorspaces + + m_alphaCs = new KisAlphaColorSpace(this, 0); + + // Load the profiles + if (!profileFilenames.empty()) { + KisProfile * profile = 0; + for ( TQStringList::Iterator it = profileFilenames.begin(); it != profileFilenames.end(); ++it ) { + profile = new KisProfile(*it); + Q_CHECK_PTR(profile); + + profile->load(); + if (profile->valid()) { + m_profileMap[profile->productName()] = profile; + } + } + } + + KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL)); + addProfile(labProfile); + add(new KisLabColorSpaceFactory()); +/* XXX where to put this + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("LABAHISTO", i18n("L*a*b* Histogram")), new KisLabColorSpace(this, 0);) ); +*/ + + // Load all colorspace modules + KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/ColorSpace"), + TQString::tqfromLatin1("(Type == 'Service') and " + "([X-Chalk-Version] == 2)")); + + if (offers.empty()) { + KMessageBox::sorry(0, i18n("Cannot start Chalk: no colorspaces available.")); + abort(); + } + + KTrader::OfferList::ConstIterator iter; + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService ( service, this, 0, TQStringList(), &errCode); + if ( plugin ) + kdDebug(DBG_AREA_PLUGINS) << "found colorspace " << service->property("Name").toString() << "\n"; + else { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n"; + if( errCode == KParts::ComponentFactory::ErrNoLibrary) + { + kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl; + } + } + } +} + +KisColorSpaceFactoryRegistry::KisColorSpaceFactoryRegistry() +{ +} + +KisColorSpaceFactoryRegistry::~KisColorSpaceFactoryRegistry() +{ +} + +KisProfile * KisColorSpaceFactoryRegistry::getProfileByName(const TQString & name) +{ + if (m_profileMap.tqfind(name) == m_profileMap.end()) { + return 0; + } + + return m_profileMap[name]; +} + +TQValueVector KisColorSpaceFactoryRegistry::profilesFor(KisID id) +{ + return profilesFor(get(id)); +} + +TQValueVector KisColorSpaceFactoryRegistry::profilesFor(KisColorSpaceFactory * csf) +{ + + TQValueVector profiles; + + TQMap::Iterator it; + for (it = m_profileMap.begin(); it != m_profileMap.end(); ++it) { + KisProfile * profile = it.data(); + if (profile->colorSpaceSignature() == csf->colorSpaceSignature()) { + profiles.push_back(profile); + } + } + return profiles; +} + +void KisColorSpaceFactoryRegistry::addProfile(KisProfile *p) +{ + if (p->valid()) { + m_profileMap[p->productName()] = p; + } +} + +void KisColorSpaceFactoryRegistry::addPaintDeviceAction(KisColorSpace* cs, + KisPaintDeviceAction* action) { + m_paintDevActionMap[cs->id()].append(action); +} + +TQValueVector +KisColorSpaceFactoryRegistry::paintDeviceActionsFor(KisColorSpace* cs) { + return m_paintDevActionMap[cs->id()]; +} + +KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const TQString & pName) +{ + TQString profileName = pName; + + if(profileName.isEmpty()) + { + KisColorSpaceFactory *csf = get(csID); + + if(!csf) + return 0; + + profileName = csf->defaultProfile(); + } + + TQString name = csID.id() + "" + profileName; + + if (m_csMap.tqfind(name) == m_csMap.end()) { + KisColorSpaceFactory *csf = get(csID); + if(!csf) + return 0; + + KisProfile *p = getProfileByName(profileName); + if(!p && profileName != "") + return 0; + KisColorSpace *cs = csf->createColorSpace(this, p); + if(!cs) + return 0; + + m_csMap[name] = cs; + } + + if(m_csMap.tqcontains(name)) + return m_csMap[name]; + else + return 0; +} + + +KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const KisProfile * profile) +{ + if( profile ) + { + KisColorSpace *cs = getColorSpace( csID, profile->productName()); + + if(!cs) + { + // The profile was not stored and thus not the combination either + KisColorSpaceFactory *csf = get(csID); + if(!csf) + return 0; + + cs = csf->createColorSpace(this, const_cast(profile)); + if(!cs ) + return 0; + + TQString name = csID.id() + "" + profile->productName(); + m_csMap[name] = cs; + } + + return cs; + } else { + return getColorSpace( csID, ""); + } +} + +KisColorSpace * KisColorSpaceFactoryRegistry::getAlpha8() +{ + return m_alphaCs; +} + +KisColorSpace * KisColorSpaceFactoryRegistry::getRGB8() +{ + return getColorSpace(KisID("RGBA", ""), ""); +} + +#include "kis_colorspace_factory_registry.moc" diff --git a/chalk/chalkcolor/kis_colorspace_factory_registry.h b/chalk/chalkcolor/kis_colorspace_factory_registry.h new file mode 100644 index 00000000..104c99aa --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace_factory_registry.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_COLORSPACE_FACTORY_REGISTRY_H_ +#define KIS_COLORSPACE_FACTORY_REGISTRY_H_ +#include "tqobject.h" +#include "kis_generic_registry.h" +#include "kis_colorspace.h" + +class TQStringList; +class KisPaintDeviceAction; + +/** + * This class tqcontains: + * - a registry of colorspace instantiated with specific profiles. + * - a registry of singleton colorspace factories. + * - a registry of icc profiles + */ +class KisColorSpaceFactoryRegistry : public TQObject, public KisGenericRegistry { + + + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Create a new colorspacefactory registry. The registry will + * load all colorspace modules that have the right version and + * all profiles given in the list. It is always possible + * to add more profiles with addProfile() + * + * @param profileFileNames a list of all filenames of all profiles that need to be loaded initially + */ + KisColorSpaceFactoryRegistry(TQStringList profileFileNames); + + virtual ~KisColorSpaceFactoryRegistry(); + + /** + * Add the profile to the list. + */ + void addProfile(KisProfile * p); + + /** + * Return the profile associated with the given product name, + * or 0. + */ + KisProfile * getProfileByName(const TQString & name); + + /** + * Return the vector of profiles for this colorspacefactory + */ + TQValueVector profilesFor(KisColorSpaceFactory * cs); + + TQValueVector profilesFor(KisID id); + + /** + * Return the colorspace + profile as named, or NULL if impossible combination. + */ + KisColorSpace * getColorSpace(const KisID & csID, const TQString & profileName); + + /** + * Return the colorspace + profile -- where the profile is matched on the name of the specified profile + */ + KisColorSpace * getColorSpace(const KisID & csID, const KisProfile * profile); + + /** + * Convenience method to get the often used alpha colorspace + */ + KisColorSpace * getAlpha8(); + + /** + * Convenience method to get an RGB colorspace with the default lcms profile + */ + KisColorSpace * getRGB8(); + + /** + * add a KisConstructPaintDeviceAction to the registry for a colorspace + * + * These actions are exectued when an image is created on the first layer + * in the image, on the image width and height rect. + */ + void addPaintDeviceAction(KisColorSpace* cs, KisPaintDeviceAction* action); + + /** + * Get a list of KisConstructPaintDeviceAction for a colorspace + */ + TQValueVector paintDeviceActionsFor(KisColorSpace* cs); + +private: + KisColorSpaceFactoryRegistry(); + KisColorSpaceFactoryRegistry(const KisColorSpaceFactoryRegistry&); + KisColorSpaceFactoryRegistry operator=(const KisColorSpaceFactoryRegistry&); + +private: + + TQMap m_profileMap; + TQMap m_csMap; + typedef TQValueVector PaintActionVector; + TQMap m_paintDevActionMap; + KisColorSpace *m_alphaCs; +}; + +#endif // KIS_COLORSPACE_FACTORY_REGISTRY_H_ + diff --git a/chalk/chalkcolor/kis_colorspace_iface.cc b/chalk/chalkcolor/kis_colorspace_iface.cc new file mode 100644 index 00000000..6e6b3cb8 --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace_iface.cc @@ -0,0 +1,39 @@ +/* + * This file is part of the KDE project + * + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_colorspace_iface.h" +#include "kis_colorspace.h" + +#include + +KisColorSpaceIface::KisColorSpaceIface( KisColorSpace * tqparent ) + : DCOPObject(tqparent->id().id().latin1()) +{ + m_parent = tqparent; +} + +TQByteArray KisColorSpaceIface::invertColor(TQByteArray src, TQ_INT32 nPixels) +{ + m_parent->invertColor((TQ_UINT8*)src.data(), nPixels); + return src; + +} + diff --git a/chalk/chalkcolor/kis_colorspace_iface.h b/chalk/chalkcolor/kis_colorspace_iface.h new file mode 100644 index 00000000..ce52e846 --- /dev/null +++ b/chalk/chalkcolor/kis_colorspace_iface.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_COLORSPACE_IFACE_H +#define _KIS_COLORSPACE_IFACE_H + +#include +#include + +#include + +class KisColorSpace; + +class KisColorSpaceIface : public DCOPObject +{ + K_DCOP +public: + KisColorSpaceIface( KisColorSpace * tqparent ); +k_dcop: + + TQByteArray invertColor(TQByteArray src, TQ_INT32 nPixels); + +private: + + KisColorSpace *m_parent; +}; + +#endif diff --git a/chalk/chalkcolor/kis_composite_op.cc b/chalk/chalkcolor/kis_composite_op.cc new file mode 100644 index 00000000..ddce271b --- /dev/null +++ b/chalk/chalkcolor/kis_composite_op.cc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "kis_composite_op.h" + +//KisIDCompositeOpMap +std::map KisCompositeOp::s_idOpMap; + +KisCompositeOp::KisCompositeOp() +{ + m_valid = false; +} + +KisCompositeOp::KisCompositeOp(const TQString& id) +{ + if (s_idOpMap.empty()) { + fillMap(); + } + + KisIDCompositeOpMap::const_iterator it; + m_valid = false; + + for (it = s_idOpMap.begin(); it != s_idOpMap.end(); ++it) { + + const KisID& kisId = (*it).first; + + if (kisId.id() == id) { + + m_id = (*it).first; + m_op = (*it).second; + m_valid = true; + break; + } + } +} + +KisCompositeOp::KisCompositeOp(CompositeOp compositeOp) +{ + if (s_idOpMap.empty()) { + fillMap(); + } + + KisIDCompositeOpMap::const_iterator it; + m_valid = false; + + for (it = s_idOpMap.begin(); it != s_idOpMap.end(); ++it) { + + CompositeOp compOp = (*it).second; + + if (compOp == compositeOp) { + + m_id = (*it).first; + m_op = compositeOp; + m_valid = true; + break; + } + } +} + +bool KisCompositeOp::operator==(const KisCompositeOp& other) const +{ + if (isValid() && other.isValid()) { + return op() == other.op(); + } + return false; +} + +bool KisCompositeOp::operator!=(const KisCompositeOp& other) const +{ + return !(*this == other); +} + +void KisCompositeOp::fillMap() +{ + s_idOpMap[KisID("normal", i18n("Normal"))] = COMPOSITE_OVER; + s_idOpMap[KisID("alphadarken", i18n("Alpha Darken"))] = COMPOSITE_ALPHA_DARKEN; + s_idOpMap[KisID("in", i18n("In"))] = COMPOSITE_IN; + s_idOpMap[KisID("out", i18n("Out"))] = COMPOSITE_OUT; + s_idOpMap[KisID("atop", i18n("Atop"))] = COMPOSITE_ATOP; + s_idOpMap[KisID("xor", i18n("Xor"))] = COMPOSITE_XOR; + s_idOpMap[KisID("plus", i18n("Plus"))] = COMPOSITE_PLUS; + s_idOpMap[KisID("minus", i18n("Minus"))] = COMPOSITE_MINUS; + s_idOpMap[KisID("add", i18n("Add"))] = COMPOSITE_ADD; + s_idOpMap[KisID("subtract", i18n("Subtract"))] = COMPOSITE_SUBTRACT; + s_idOpMap[KisID("diff", i18n("Diff"))] = COMPOSITE_DIFF; + s_idOpMap[KisID("multiply", i18n("Multiply"))] = COMPOSITE_MULT; + s_idOpMap[KisID("divide", i18n("Divide"))] = COMPOSITE_DIVIDE; + s_idOpMap[KisID("dodge", i18n("Dodge"))] = COMPOSITE_DODGE; + s_idOpMap[KisID("burn", i18n("Burn"))] = COMPOSITE_BURN; + s_idOpMap[KisID("bumpmap", i18n("Bumpmap"))] = COMPOSITE_BUMPMAP; + s_idOpMap[KisID("copy", i18n("Copy"))] = COMPOSITE_COPY; + s_idOpMap[KisID("copyred", i18n("Copy Red"))] = COMPOSITE_COPY_RED; + s_idOpMap[KisID("copygreen", i18n("Copy Green"))] = COMPOSITE_COPY_GREEN; + s_idOpMap[KisID("copyblue", i18n("Copy Blue"))] = COMPOSITE_COPY_BLUE; + s_idOpMap[KisID("copyopacity", i18n("Copy Opacity"))] = COMPOSITE_COPY_OPACITY; + s_idOpMap[KisID("clear", i18n("Clear"))] = COMPOSITE_CLEAR; + s_idOpMap[KisID("dissolve", i18n("Dissolve"))] = COMPOSITE_DISSOLVE; + s_idOpMap[KisID("displace", i18n("Displace"))] = COMPOSITE_DISPLACE; +#if 0 + s_idOpMap[KisID("modulate", i18n("Modulate"))] = COMPOSITE_MODULATE; + s_idOpMap[KisID("threshold", i18n("Threshold"))] = COMPOSITE_THRESHOLD; +#endif + s_idOpMap[KisID("nocomposition",i18n("No Composition"))] = COMPOSITE_NO; + s_idOpMap[KisID("darken", i18n("Darken"))] = COMPOSITE_DARKEN; + s_idOpMap[KisID("lighten", i18n("Lighten"))] = COMPOSITE_LIGHTEN; + s_idOpMap[KisID("hue", i18n("Hue"))] = COMPOSITE_HUE; + s_idOpMap[KisID("saturation", i18n("Saturation"))] = COMPOSITE_SATURATION; + s_idOpMap[KisID("value", i18n("Value"))] = COMPOSITE_VALUE; + s_idOpMap[KisID("color", i18n("Color"))] = COMPOSITE_COLOR; + s_idOpMap[KisID("colorize", i18n("Colorize"))] = COMPOSITE_COLORIZE; + s_idOpMap[KisID("luminize", i18n("Luminize"))] = COMPOSITE_LUMINIZE; + s_idOpMap[KisID("screen", i18n("Screen"))] = COMPOSITE_SCREEN; + s_idOpMap[KisID("overlay", i18n("Overlay"))] = COMPOSITE_OVERLAY; + s_idOpMap[KisID("copycyan", i18n("Copy Cyan"))] = COMPOSITE_COPY_CYAN; + s_idOpMap[KisID("copymagenta", i18n("Copy Magenta"))] = COMPOSITE_COPY_MAGENTA; + s_idOpMap[KisID("copyyellow", i18n("Copy Yellow"))] = COMPOSITE_COPY_YELLOW; + s_idOpMap[KisID("copyblack", i18n("Copy Black"))] = COMPOSITE_COPY_BLACK; + s_idOpMap[KisID("erase", i18n("Erase"))] = COMPOSITE_ERASE; + s_idOpMap[KisID("undefined", i18n("Undefined"))] = COMPOSITE_UNDEF; +} + diff --git a/chalk/chalkcolor/kis_composite_op.h b/chalk/chalkcolor/kis_composite_op.h new file mode 100644 index 00000000..bd4f10a2 --- /dev/null +++ b/chalk/chalkcolor/kis_composite_op.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COMPOSITE_OP_H_ +#define KIS_COMPOSITE_OP_H_ + +#include +#include + +//#include "kis_global.h" +#include "kis_id.h" + +enum CompositeOp { + COMPOSITE_OVER, + COMPOSITE_IN, + COMPOSITE_OUT, + COMPOSITE_ATOP, + COMPOSITE_XOR, + COMPOSITE_PLUS, + COMPOSITE_MINUS, + COMPOSITE_ADD, + COMPOSITE_SUBTRACT, + COMPOSITE_DIFF, + COMPOSITE_MULT, + COMPOSITE_DIVIDE, + COMPOSITE_DODGE, + COMPOSITE_BURN, + COMPOSITE_BUMPMAP, + COMPOSITE_COPY, + COMPOSITE_COPY_RED, + COMPOSITE_COPY_GREEN, + COMPOSITE_COPY_BLUE, + COMPOSITE_COPY_OPACITY, + COMPOSITE_CLEAR, + COMPOSITE_DISSOLVE, + COMPOSITE_DISPLACE, +#if 0 + COMPOSITE_MODULATE, + COMPOSITE_THRESHOLD, +#endif + COMPOSITE_NO, + COMPOSITE_DARKEN, + COMPOSITE_LIGHTEN, + COMPOSITE_HUE, + COMPOSITE_SATURATION, + COMPOSITE_VALUE, + COMPOSITE_COLOR, + COMPOSITE_COLORIZE, + COMPOSITE_LUMINIZE, + COMPOSITE_SCREEN, + COMPOSITE_OVERLAY, + COMPOSITE_COPY_CYAN, + COMPOSITE_COPY_MAGENTA, + COMPOSITE_COPY_YELLOW, + COMPOSITE_COPY_BLACK, + COMPOSITE_ERASE, + COMPOSITE_ALPHA_DARKEN, + COMPOSITE_UNDEF +}; + +class KisCompositeOp { +public: + KisCompositeOp(); + KisCompositeOp(const TQString& id); + KisCompositeOp(CompositeOp compositeOp); + + KisID id() const { return m_id; } + CompositeOp op() const { return m_op; } + + bool isValid() const { return m_valid; } + + bool operator==(const KisCompositeOp& other) const; + bool operator!=(const KisCompositeOp& other) const; + +private: + void fillMap(); + +private: + CompositeOp m_op; + KisID m_id; + bool m_valid; + + typedef std::map KisIDCompositeOpMap; + static KisIDCompositeOpMap s_idOpMap; +}; + +typedef TQValueList KisCompositeOpList; + +#endif // KIS_COMPOSITE_OP_H diff --git a/chalk/chalkcolor/kis_f16half_base_colorspace.cc b/chalk/chalkcolor/kis_f16half_base_colorspace.cc new file mode 100644 index 00000000..d4886c5f --- /dev/null +++ b/chalk/chalkcolor/kis_f16half_base_colorspace.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kdebug.h" + +#include "kis_global.h" +#include "kis_f16half_base_colorspace.h" + +TQ_UINT8 KisF16HalfBaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const +{ + if (m_alphaPos < 0) return OPACITY_OPAQUE; + + U8_pixel += m_alphaPos; + + const half *pixel = reinterpret_cast(U8_pixel); + return HALF_TO_UINT8(*pixel); +} + +void KisF16HalfBaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + + while (nPixels > 0) { + + half *pixel = reinterpret_cast(U8_pixel + m_alphaPos); + *pixel = UINT8_TO_HALF(alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisF16HalfBaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + half alpha = UINT8_TO_HALF(U8_alpha); + + while (nPixels > 0) { + + half *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha *= alpha; + + --nPixels; + U8_pixel += psize; + } +} + +void KisF16HalfBaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + half *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha *= UINT8_TO_HALF(*alpha8); + + ++alpha8; + U8_pixel += psize; + } +} + +void KisF16HalfBaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + half *pixelAlpha = reinterpret_cast(U8_pixels + m_alphaPos); + *pixelAlpha *= UINT8_TO_HALF(MAX_SELECTED - *alpha8); + + U8_pixels += psize; + ++alpha8; + } +} + +TQString KisF16HalfBaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const half *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisF16HalfBaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const half *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half); + + return TQString().setNum(100.0 * pixel[channelPosition]); +} + +TQ_UINT8 KisF16HalfBaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const half *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return HALF_TO_UINT8(*pixelChannel); +} + +TQ_UINT16 KisF16HalfBaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const half *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return HALF_TO_UINT16(*pixelChannel); +} + diff --git a/chalk/chalkcolor/kis_f16half_base_colorspace.h b/chalk/chalkcolor/kis_f16half_base_colorspace.h new file mode 100644 index 00000000..ff1dbf8c --- /dev/null +++ b/chalk/chalkcolor/kis_f16half_base_colorspace.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_F16HALF_BASE_COLORSPACE_H_ +#define KIS_F16HALF_BASE_COLORSPACE_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_integer_maths.h" + +/** + * This class is the base for all 16-bit float colorspaces using the + * OpenEXR half format. This format can be used with the OpenGL + * extensions GL_NV_half_float and GL_ARB_half_float_pixel. + */ + +inline half UINT8_TO_HALF(uint c) +{ + return static_cast(c) / UINT8_MAX; +} + +inline uint HALF_TO_UINT8(half c) +{ + return static_cast(CLAMP(static_cast(c * static_cast(UINT8_MAX) + 0.5), + static_cast(UINT8_MIN), static_cast(UINT8_MAX))); +} + + +inline uint HALF_TO_UINT16(half c) +{ + return static_cast(CLAMP(static_cast(c * static_cast(UINT16_MAX) + 0.5), + static_cast(UINT16_MIN), static_cast(UINT16_MAX))); +} + +inline half HALF_BLEND(half a, half b, half alpha) +{ + return (a - b) * alpha + b; +} + +#define F16HALF_OPACITY_OPAQUE ((half)1.0f) +#define F16HALF_OPACITY_TRANSPARENT ((half)0.0f) + +class KisF16HalfBaseColorSpace : public KisAbstractColorSpace { + +public: + + KisF16HalfBaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p) + { + m_alphaSize = sizeof(half); + }; + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels); + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + + virtual bool hasHighDynamicRange() const { return true; } + +protected: + // For Alpha Composite + struct F16HalfMult { + inline half operator()(const half& a, const half& b) const { + return a * b; + } + }; + struct Uint8ToF16Half { + inline half operator()(const TQ_UINT8 src) const { + return UINT8_TO_HALF(src); + } + }; + struct F16HalfOpacityTest { + inline bool operator()(const half& opacity) const { + return opacity > F16HALF_OPACITY_TRANSPARENT + HALF_EPSILON; + } + }; +}; + +#endif // KIS_F16HALF_BASE_COLORSPACE_H_ diff --git a/chalk/chalkcolor/kis_f32_base_colorspace.cc b/chalk/chalkcolor/kis_f32_base_colorspace.cc new file mode 100644 index 00000000..27a6a312 --- /dev/null +++ b/chalk/chalkcolor/kis_f32_base_colorspace.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kdebug.h" + +#include "kis_global.h" +#include "kis_f32_base_colorspace.h" + +TQ_UINT8 KisF32BaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const +{ + if (m_alphaPos < 0) return OPACITY_OPAQUE; + + U8_pixel += m_alphaPos; + + const float *pixel = reinterpret_cast(U8_pixel); + return FLOAT_TO_UINT8(*pixel); +} + +void KisF32BaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + + while (nPixels > 0) { + + float *pixel = reinterpret_cast(U8_pixel + m_alphaPos); + *pixel = UINT8_TO_FLOAT(alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisF32BaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + float alpha = UINT8_TO_FLOAT(U8_alpha); + + while (nPixels > 0) { + + float *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha *= alpha; + + --nPixels; + U8_pixel += psize; + } +} + +void KisF32BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + float *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha *= UINT8_TO_FLOAT(*alpha8); + + ++alpha8; + U8_pixel += psize; + } +} + +void KisF32BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + float *pixelAlpha = reinterpret_cast(U8_pixels + m_alphaPos); + *pixelAlpha *= UINT8_TO_FLOAT(MAX_SELECTED - *alpha8); + + U8_pixels += psize; + ++alpha8; + } +} + +TQString KisF32BaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const float *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisF32BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const float *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float); + + return TQString().setNum(100.0 * pixel[channelPosition]); +} + +TQ_UINT8 KisF32BaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const float *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return FLOAT_TO_UINT8(*pixelChannel); +} + +TQ_UINT16 KisF32BaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const float *pixelChannel = reinterpret_cast(U8_pixel + channelPos); + return FLOAT_TO_UINT16(*pixelChannel); +} + diff --git a/chalk/chalkcolor/kis_f32_base_colorspace.h b/chalk/chalkcolor/kis_f32_base_colorspace.h new file mode 100644 index 00000000..60ecb9aa --- /dev/null +++ b/chalk/chalkcolor/kis_f32_base_colorspace.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_F32_BASE_COLORSPACE_H_ +#define KIS_F32_BASE_COLORSPACE_H_ + +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_integer_maths.h" + +/** + * This class is the base for all 32-bit float colorspaces. + */ + +inline float UINT8_TO_FLOAT(uint c) +{ + return static_cast(c) / UINT8_MAX; +} + +inline uint FLOAT_TO_UINT8(float c) +{ + return static_cast(CLAMP(static_cast(c * static_cast(UINT8_MAX) + 0.5), + static_cast(UINT8_MIN), static_cast(UINT8_MAX))); +} + + +inline uint FLOAT_TO_UINT16(float c) +{ + return static_cast(CLAMP(static_cast(c * static_cast(UINT16_MAX) + 0.5), + static_cast(UINT16_MIN), static_cast(UINT16_MAX))); +} + +inline float FLOAT_BLEND(float a, float b, float alpha) +{ + return (a - b) * alpha + b; +} + +#define F32_OPACITY_OPAQUE 1.0f +#define F32_OPACITY_TRANSPARENT 0.0f + +class KisF32BaseColorSpace : public KisAbstractColorSpace { + +public: + + KisF32BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p) + { + m_alphaSize = sizeof(float); + }; + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels); + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + + virtual bool hasHighDynamicRange() const { return true; } +}; + +#endif // KIS_F32_BASE_COLORSPACE_H_ diff --git a/chalk/chalkcolor/kis_histogram_producer.cc b/chalk/chalkcolor/kis_histogram_producer.cc new file mode 100644 index 00000000..bbea95ba --- /dev/null +++ b/chalk/chalkcolor/kis_histogram_producer.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_histogram_producer.h" +#include "kis_basic_histogram_producers.h" + +KisHistogramProducerFactoryRegistry* KisHistogramProducerFactoryRegistry::m_singleton = 0; + +KisHistogramProducerFactoryRegistry::KisHistogramProducerFactoryRegistry() { + Q_ASSERT(KisHistogramProducerFactoryRegistry::m_singleton == 0); +} + +KisHistogramProducerFactoryRegistry::~KisHistogramProducerFactoryRegistry() { +} + +KisHistogramProducerFactoryRegistry* KisHistogramProducerFactoryRegistry::instance() { + if(KisHistogramProducerFactoryRegistry::m_singleton == 0) { + KisHistogramProducerFactoryRegistry::m_singleton + = new KisHistogramProducerFactoryRegistry(); + m_singleton->add( new KisGenericLabHistogramProducerFactory() ); + } + return KisHistogramProducerFactoryRegistry::m_singleton; +} + +KisIDList KisHistogramProducerFactoryRegistry::listKeysCompatibleWith( + KisColorSpace* colorSpace) const +{ + KisIDList list; + TQValueList preferredList; + storageMap::const_iterator it = m_storage.begin(); + storageMap::const_iterator endit = m_storage.end(); + // O(n^2), can't this be done better? (But preferrably not by looking up the preferredness + // during the sorting... + while( it != endit ) { + if (it->second->isCompatibleWith(colorSpace)) { + float preferred = it->second->preferrednessLevelWith(colorSpace); + TQValueList::iterator pit = preferredList.begin(); + TQValueList::iterator pend = preferredList.end(); + KisIDList::iterator lit = list.begin(); + + while (pit != pend && preferred <= *pit) { + ++pit; + ++lit; + } + + list.insert(lit, it->first); + preferredList.insert(pit, preferred); + } + ++it; + } + return list; +} diff --git a/chalk/chalkcolor/kis_histogram_producer.h b/chalk/chalkcolor/kis_histogram_producer.h new file mode 100644 index 00000000..2d25b354 --- /dev/null +++ b/chalk/chalkcolor/kis_histogram_producer.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_HISTOGRAM_PRODUCER_ +#define _KIS_HISTOGRAM_PRODUCER_ + +#include +#include + +#include + +#include "kis_generic_registry.h" + +class KisRectIteratorPixel; +class TQString; +class KisChannelInfo; + +/** + * This class is an interface used in the generation of a histogram. It is a container of + * data, all mathematically interesting things will calculated by a KisHistogram. + * + * The default view will be the entire range each color can be in. And don't let the + * numberOfBins return anything else then 256 unless you have a very good reason for it. + * + * About the views: a view is a zoom combined with a start level: the entire + * range of a channel is 0.0 - 1.0: this is the position. Combined with a zoom, we can + * calculate what part of a channel will fall in a bin. This gives us an interface to + * that the views that is not dependent of the actual colorspace of the histogram. + * The 'size' value is the size, again from 0.0 to 1.0 of the displayed range. + * + * For comfort of the GUI, and because it is logical, channels are accessed in the order + * in which they are found in the channels() method. This is potentially different from + * the order in which they are internally ordered! + **/ +class KisHistogramProducer : public KShared { +public: + KisHistogramProducer() : m_skipTransparent(true), m_skipUnselected(true) {} + virtual ~KisHistogramProducer() {} + + // Methods to change the bins + + /** Clears the data in this producer, but keeps its other settings */ + virtual void clear() = 0; + + /** + * Adds the values from the specified array of pixels to the bins -- does not + * reset anything. + * + * @param pixels A pointer an array of pixeldata in the given colorspace + * @param selectionMask a pointer to an array of bytes, where 0 is unselected and 1-255 is degree of selectedness. The array + * must be just as long as the array of pixels. + * @param nPixels The number of pixels + * @param colorSpace the colorspace that can decode the pixel data. + */ + virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace* colorSpace) = 0; + + // Methods to set what exactly is being added to the bins + virtual void setView(double from, double width) = 0; + virtual void setSkipTransparent(bool set) { m_skipTransparent = set; } + virtual void setSkipUnselected(bool set) { m_skipUnselected = set; } + + // Methods with general information about this specific producer + virtual const KisID& id() const = 0; + virtual TQValueVector channels() = 0; + virtual TQ_INT32 numberOfBins() = 0; + virtual TQString positionToString(double pos) const = 0; + virtual double viewFrom() const = 0; + virtual double viewWidth() const = 0; + virtual double maximalZoom() const = 0; + + // Methods to get information on the data we have seen + virtual TQ_INT32 count() = 0; + virtual TQ_INT32 getBinAt(TQ_INT32 channel, TQ_INT32 position) = 0; + virtual TQ_INT32 outOfViewLeft(TQ_INT32 channel) = 0; + virtual TQ_INT32 outOfViewRight(TQ_INT32 channel) = 0; +protected: + bool m_skipTransparent; + bool m_skipUnselected; +}; + +typedef KSharedPtr KisHistogramProducerSP; + +class KisHistogramProducerFactory { +public: + KisHistogramProducerFactory(const KisID& id) : m_id(id) {} + virtual ~KisHistogramProducerFactory() {} + /// Factory method, generates a new KisHistogramProducer + virtual KisHistogramProducerSP generate() = 0; + /// Returns if a colorspace can be used with this producer + virtual bool isCompatibleWith(KisColorSpace* colorSpace) const = 0; + /// Returns a float in the [0.0, 1.0] range, 0.0 means this is a very generic method + virtual float preferrednessLevelWith(KisColorSpace* colorSpace) const = 0; + virtual const KisID& id() const { return m_id; } +protected: + KisID m_id; +}; + +class KisHistogramProducerFactoryRegistry + : public KisGenericRegistry { +public: + virtual ~KisHistogramProducerFactoryRegistry(); + static KisHistogramProducerFactoryRegistry* instance(); + /// returns a list, sorted by preferrence: higher preferance comes first + KisIDList listKeysCompatibleWith(KisColorSpace* colorSpace) const; + +private: + KisHistogramProducerFactoryRegistry(); + KisHistogramProducerFactoryRegistry(const KisHistogramProducerFactoryRegistry&); + KisHistogramProducerFactoryRegistry operator=(const KisHistogramProducerFactoryRegistry&); + + static KisHistogramProducerFactoryRegistry* m_singleton; +}; + +#endif // _KIS_HISTOGRAM_PRODUCER diff --git a/chalk/chalkcolor/kis_profile.cc b/chalk/chalkcolor/kis_profile.cc new file mode 100644 index 00000000..2d0ad98f --- /dev/null +++ b/chalk/chalkcolor/kis_profile.cc @@ -0,0 +1,208 @@ +/* + * kis_profile.cc - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * 2001 John Califf + * 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include LCMS_HEADER + +#include +#include +#include + +#include + +#include "kis_profile.h" +#include "kis_global.h" + +#include "ksharedptr.h" + +#include +#include +#include + +KisProfile::KisProfile(TQByteArray rawData) + : m_rawData(rawData), + m_filename( TQString() ), + m_valid( false ), + m_suitableForOutput(false) +{ + m_profile = cmsOpenProfileFromMem(rawData.data(), (DWORD)rawData.size()); + init(); +} + +KisProfile::KisProfile(const TQString& file) + : m_filename(file), + m_valid( false ), + m_suitableForOutput( false ) +{ +} + +KisProfile::KisProfile(const cmsHPROFILE profile) + : m_profile(profile), + m_filename( TQString() ), + m_valid( true ) +{ + size_t bytesNeeded=0; + + // Make a raw data image ready for saving + _cmsSaveProfileToMem(m_profile, 0, &bytesNeeded); // calc size + if(m_rawData.tqresize(bytesNeeded)) + { + _cmsSaveProfileToMem(m_profile, m_rawData.data(), &bytesNeeded); // fill buffer + cmsHPROFILE newprofile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD) bytesNeeded); + cmsCloseProfile(m_profile); + m_profile = newprofile; + } + else + m_rawData.resize(0); + + init(); +} + +KisProfile::~KisProfile() +{ + cmsCloseProfile(m_profile); +} + + +bool KisProfile::load() +{ + TQFile file(m_filename); + file.open(IO_ReadOnly); + m_rawData = file.readAll(); + m_profile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD)m_rawData.size()); + file.close(); + + if (m_profile == 0) { + kdWarning() << "Failed to load profile from " << m_filename << endl; + } + + return init(); + +} + +bool KisProfile::init() +{ + if (m_profile) { + m_colorSpaceSignature = cmsGetColorSpace(m_profile); + m_deviceClass = cmsGetDeviceClass(m_profile); + m_productName = cmsTakeProductName(m_profile); + m_productDescription = cmsTakeProductDesc(m_profile); + m_productInfo = cmsTakeProductInfo(m_profile); + m_valid = true; + + // Check if the profile can convert (something->this) +// LPMATSHAPER OutMatShaper = cmsBuildOutputMatrixShaper(m_profile); +// if( OutMatShaper ) +// { +// m_suitableForOutput = true; +// } + cmsCIEXYZTRIPLE Primaries; + + if (cmsTakeColorants(&Primaries, m_profile)) + { + m_suitableForOutput = true; + } + +#if 0 + // XXX: It wasn't that easy to save a little memory: thsi gives an lcms error + // Okay, we know enough. Free the memory; we'll load it again if needed. + + cmsCloseProfile(m_profile); + m_profile = 0; + +#endif + return true; + } + return false; +} + +cmsHPROFILE KisProfile::profile() +{ +#if 0 + if (m_profile = 0) { + TQFile file(m_filename); + file.open(IO_ReadOnly); + m_rawData = file.readAll(); + m_profile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD)m_rawData.size()); + file.close(); + } +#endif + return m_profile; +} + +bool KisProfile::save() +{ + return false; +} + +KisAnnotationSP KisProfile::annotation() const +{ + // XXX we hardcode icc, this is correct for lcms? + // XXX productName(), or just "ICC Profile"? + if (!m_rawData.isEmpty()) + return new KisAnnotation("icc", productName(), m_rawData); + else + return 0; +} + +KisProfile * KisProfile::getScreenProfile (int screen) +{ + +#ifdef Q_WS_X11 + + Atom type; + int format; + unsigned long nitems; + unsigned long bytes_after; + TQ_UINT8 * str; + + static Atom icc_atom = XInternAtom( qt_xdisplay(), "_ICC_PROFILE", False ); + + if ( XGetWindowProperty ( qt_xdisplay(), + qt_xrootwin( screen ), + icc_atom, + 0, + INT_MAX, + False, + XA_CARDINAL, + &type, + &format, + &nitems, + &bytes_after, + (unsigned char **) &str) + ) { + + TQByteArray bytes (nitems); + bytes.assign((char*)str, (TQ_UINT32)nitems); + + return new KisProfile(bytes); + } else { + return NULL; + } +#else + return NULL; + +#endif +} + + diff --git a/chalk/chalkcolor/kis_profile.h b/chalk/chalkcolor/kis_profile.h new file mode 100644 index 00000000..5f732188 --- /dev/null +++ b/chalk/chalkcolor/kis_profile.h @@ -0,0 +1,98 @@ +/* + * kis_profile.h - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PROFILE_H +#define KIS_PROFILE_H + +#include + +#include LCMS_HEADER + +#include +#include + +#include + +#include + +//XXX: Profiles should be loaded by the color strategies +// and be available only through the color strategy +// that matches the profile's color model +class KisProfile { + +public: + KisProfile(TQByteArray rawData); + KisProfile(const TQString& file); + KisProfile(const cmsHPROFILE profile); + + virtual ~KisProfile(); + + virtual bool load(); + virtual bool save(); + + inline icColorSpaceSignature colorSpaceSignature() const { return m_colorSpaceSignature; } + inline icProfileClassSignature deviceClass() const { return m_deviceClass; } + inline TQString productName() const { return m_productName; } + inline TQString productDescription() const { return m_productDescription; } + inline TQString productInfo() const { return m_productInfo; } + inline TQString manufacturer() const { return m_manufacturer; } + cmsHPROFILE profile(); + + KisAnnotationSP annotation() const; + + friend inline bool operator==( const KisProfile &, const KisProfile & ); + + inline bool valid() const { return m_valid; }; + + inline bool isSuitableForOutput() { return m_suitableForOutput; }; + + inline TQString filename() const { return m_filename; } + +public: + + static KisProfile * getScreenProfile(int screen = -1); + +private: + bool init(); + + cmsHPROFILE m_profile; + icColorSpaceSignature m_colorSpaceSignature; + icProfileClassSignature m_deviceClass; + TQString m_productName; + TQString m_productDescription; + TQString m_productInfo; + TQString m_manufacturer; + + TQByteArray m_rawData; + + TQString m_filename; + bool m_valid; + bool m_suitableForOutput; + +}; + +inline bool operator==( const KisProfile & p1, const KisProfile & p2 ) +{ + return p1.m_profile == p2.m_profile; +} + +#endif // KIS_PROFILE_H + diff --git a/chalk/chalkcolor/kis_u16_base_colorspace.cc b/chalk/chalkcolor/kis_u16_base_colorspace.cc new file mode 100644 index 00000000..a735e35c --- /dev/null +++ b/chalk/chalkcolor/kis_u16_base_colorspace.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kdebug.h" + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_u16_base_colorspace.h" + + +TQ_UINT8 KisU16BaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const +{ + if (m_alphaPos < 0) return OPACITY_OPAQUE; + + U8_pixel+= m_alphaPos; + + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + return UINT16_TO_UINT8(*pixel); +} + + +void KisU16BaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + + + while (nPixels > 0) { + + TQ_UINT16 *pixel = reinterpret_cast(U8_pixel + m_alphaPos); + pixel[0] = UINT8_TO_UINT16(alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisU16BaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + TQ_UINT16 alpha = UINT8_TO_UINT16(U8_alpha); + + while (nPixels > 0) { + + TQ_UINT16 *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha = UINT16_MULT(*pixelAlpha, alpha); + + --nPixels; + U8_pixel += psize; + } +} + +void KisU16BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + // Go to the alpha position (which is given in bytes from the start of the pixel, + // and cast to short. + + TQ_UINT16 *pixelAlpha = reinterpret_cast(U8_pixel + m_alphaPos); + *pixelAlpha = UINT8_MULT(*pixelAlpha, *alpha8); + + ++alpha8; + U8_pixel += psize; + + } +} + +void KisU16BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels) +{ + + if (m_alphaPos < 0) return; + + TQ_INT32 psize = pixelSize(); + + + while(nPixels--) { + + TQ_UINT16 s_alpha8; + TQ_UINT32 p_alpha, s_alpha16; + + TQ_UINT16 *alpha = reinterpret_cast(U8_pixels + m_alphaPos); + + p_alpha = *(alpha); + s_alpha8 = MAX_SELECTED - *alpha8; + s_alpha16 = UINT8_TO_UINT16(s_alpha8); + + // Go to the alpha position (which is given in bytes from the start of the pixel, + // and cast to short. + + alpha[0] = UINT16_MULT(p_alpha, s_alpha16); + + U8_pixels += psize; + ++alpha8; + } +} + +TQString KisU16BaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(TQ_UINT16); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisU16BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos() / sizeof(TQ_UINT16); + + return TQString().setNum(100.0 * static_cast(pixel[channelPosition]) / UINT16_MAX); +} + +TQ_UINT8 KisU16BaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + return UINT16_TO_UINT8(pixel[channelPos]); +} + +TQ_UINT16 KisU16BaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos) +{ + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + return pixel[channelPos]; +} + diff --git a/chalk/chalkcolor/kis_u16_base_colorspace.h b/chalk/chalkcolor/kis_u16_base_colorspace.h new file mode 100644 index 00000000..756ab9b5 --- /dev/null +++ b/chalk/chalkcolor/kis_u16_base_colorspace.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_U16_BASE_COLORSPACE_H_ +#define KIS_U16_BASE_COLORSPACE_H_ + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_integer_maths.h" + +/** + * This is the base class for 16-bit/channel colorspaces with 16-bit alpha + * channels. It defines a number of common methods, like handling 16-bit alpha + * and up- and down-scaling of channels. + */ +class KisU16BaseColorSpace : public KisAbstractColorSpace { + +public: + + static const TQ_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX; + static const TQ_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN; + +public: + + KisU16BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, + tqparent, + p) + { + m_alphaSize = sizeof(TQ_UINT16); + }; + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels); + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + +protected: + // For Alpha Composite + struct U16Mult { + inline TQ_UINT16 operator()(const TQ_UINT16& a, const TQ_UINT16& b) const { + return UINT16_MULT(a, b); + } + }; + struct Uint8ToU16 { + inline TQ_UINT16 operator()(const TQ_UINT8 src) const { + return UINT8_TO_UINT16(src); + } + }; + struct U16OpacityTest { + inline bool operator()(const TQ_UINT16& opacity) const { + return opacity != U16_OPACITY_TRANSPARENT; + } + }; +}; +#endif // KIS_U16_BASE_COLORSPACE_H_ diff --git a/chalk/chalkcolor/kis_u8_base_colorspace.cc b/chalk/chalkcolor/kis_u8_base_colorspace.cc new file mode 100644 index 00000000..338d95d6 --- /dev/null +++ b/chalk/chalkcolor/kis_u8_base_colorspace.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_abstract_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_integer_maths.h" + +TQ_UINT8 KisU8BaseColorSpace::getAlpha(const TQ_UINT8 * pixel) const +{ + return pixel[m_alphaPos]; +} + + + +void KisU8BaseColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + + pixels += m_alphaPos; + while (nPixels > 0) { + *pixels = alpha; + --nPixels; + pixels += psize; + } + +} + +void KisU8BaseColorSpace::multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) +{ + if (m_alphaPos < 0) return; + TQ_INT32 psize = pixelSize(); + + while (nPixels > 0) { + pixels[m_alphaPos] = UINT8_MULT(pixels[m_alphaPos], alpha); + --nPixels; + pixels += psize; + } +} + +void KisU8BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ + TQ_INT32 psize = pixelSize(); + + while (nPixels--) { + + pixels[m_alphaPos] = UINT8_MULT(*(pixels + m_alphaPos) , *alpha); + + alpha++; + pixels += psize; + + } +} + +void KisU8BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ + TQ_INT32 psize = pixelSize(); + + while(nPixels--) { + + TQ_UINT16 p_alpha, s_alpha; + + p_alpha = getAlpha(pixels); + s_alpha = MAX_SELECTED - *alpha; + + setAlpha(pixels, UINT8_MULT(p_alpha, s_alpha), 1); + + pixels += psize; + ++alpha; + } +} + +TQString KisU8BaseColorSpace::channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisU8BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < (TQ_UINT32)nChannels()); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(100.0 * static_cast(pixel[channelPosition]) / UINT8_MAX); +} + + +TQ_UINT8 KisU8BaseColorSpace::scaleToU8(const TQ_UINT8 * pixel, TQ_INT32 channelPos) +{ + return pixel[channelPos]; +} + +TQ_UINT16 KisU8BaseColorSpace::scaleToU16(const TQ_UINT8 * pixel, TQ_INT32 channelPos) +{ + return UINT8_TO_UINT16(pixel[channelPos]); +} + diff --git a/chalk/chalkcolor/kis_u8_base_colorspace.h b/chalk/chalkcolor/kis_u8_base_colorspace.h new file mode 100644 index 00000000..098a1f59 --- /dev/null +++ b/chalk/chalkcolor/kis_u8_base_colorspace.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_U8_BASE_COLORSPACE_H_ +#define KIS_U8_BASE_COLORSPACE_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_integer_maths.h" + +/** + * This class is the base for all homogenous 8-bit/channel colorspaces with 8-bit alpha channels + */ +class KisU8BaseColorSpace : public KisAbstractColorSpace { + +public: + + KisU8BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, + KisColorSpaceFactoryRegistry * tqparent, + KisProfile *p) + : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p) + { + m_alphaSize = sizeof(TQ_UINT8); + }; + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels); + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + +protected: + // For Alpha Composite + struct U8Mult { + inline TQ_UINT8 operator()(const TQ_UINT8& a, const TQ_UINT8& b) const { + return UINT8_MULT(a, b); + } + }; + struct Uint8ToU8 { + inline TQ_UINT8 operator()(const TQ_UINT8 src) const { + return src; + } + }; + struct U8OpacityTest { + inline bool operator()(const TQ_UINT8& opacity) const { + return opacity != OPACITY_TRANSPARENT; + } + }; +}; + + +#endif // KIS_U8_BASE_COLORSPACE_H_ diff --git a/chalk/chalkcolor/tests/Makefile.am b/chalk/chalkcolor/tests/Makefile.am new file mode 100644 index 00000000..e78141e7 --- /dev/null +++ b/chalk/chalkcolor/tests/Makefile.am @@ -0,0 +1,16 @@ +AM_CPPFLAGS = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../ \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_color_conversions_tester.la + +kunittest_kis_color_conversions_tester_la_SOURCES = kis_color_conversions_tester.cpp +kunittest_kis_color_conversions_tester_la_LIBADD = -lkunittest ../libchalkcolor.la ../../libchalkcommon.la +kunittest_kis_color_conversions_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_color_conversions_tester.la + kunittestmodrunner + diff --git a/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp b/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp new file mode 100644 index 00000000..d244b5dd --- /dev/null +++ b/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_color_conversions_tester.h" +#include "kis_color_conversions.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE(kunittest_kis_color_conversions_tester, "Color Conversions Tester"); +KUNITTEST_MODULE_REGISTER_TESTER(KisColorConversionsTester); + +void KisColorConversionsTester::allTests() +{ + testRGBHSV(); + testRGBHSL(); +} + +#define EPSILON 1e-6 + +void KisColorConversionsTester::testRGBHSV() +{ + float r, g, b, h, s, v; + + RGBToHSV(1, 0, 0, &h, &s, &v); + CHECK(h, 0.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(1, 1, 0, &h, &s, &v); + CHECK(h, 60.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(0, 1, 0, &h, &s, &v); + CHECK(h, 120.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(0, 1, 1, &h, &s, &v); + CHECK(h, 180.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(0, 0, 1, &h, &s, &v); + CHECK(h, 240.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(1, 0, 1, &h, &s, &v); + CHECK(h, 300.0f); + CHECK(s, 1.0f); + CHECK(v, 1.0f); + + RGBToHSV(0, 0, 0, &h, &s, &v); + CHECK(h, -1.0f); + CHECK(s, 0.0f); + CHECK(v, 0.0f); + + RGBToHSV(1, 1, 1, &h, &s, &v); + CHECK(h, -1.0f); + CHECK(s, 0.0f); + CHECK(v, 1.0f); + + RGBToHSV(0.5, 0.25, 0.75, &h, &s, &v); + CHECK_TOLERANCE(h, 270.0f, EPSILON); + CHECK_TOLERANCE(s, 0.666667f, EPSILON); + CHECK_TOLERANCE(v, 0.75f, EPSILON); + + HSVToRGB(0, 1, 1, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 0.0f); + CHECK(b, 0.0f); + + HSVToRGB(60, 1, 1, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 1.0f); + CHECK(b, 0.0f); + + HSVToRGB(120, 1, 1, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 1.0f); + CHECK(b, 0.0f); + + HSVToRGB(180, 1, 1, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 1.0f); + CHECK(b, 1.0f); + + HSVToRGB(240, 1, 1, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 0.0f); + CHECK(b, 1.0f); + + HSVToRGB(300, 1, 1, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 0.0f); + CHECK(b, 1.0f); + + HSVToRGB(-1, 0, 0, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 0.0f); + CHECK(b, 0.0f); + + HSVToRGB(-1, 0, 1, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 1.0f); + CHECK(b, 1.0f); + + HSVToRGB(270, 0.666667, 0.75, &r, &g, &b); + CHECK_TOLERANCE(r, 0.5f, EPSILON); + CHECK_TOLERANCE(g, 0.25f, EPSILON); + CHECK_TOLERANCE(b, 0.75f, EPSILON); +} + +void KisColorConversionsTester::testRGBHSL() +{ + float r, g, b, h, s, l; + + RGBToHSL(1, 0, 0, &h, &s, &l); + CHECK(h, 360.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(1, 1, 0, &h, &s, &l); + CHECK(h, 60.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(0, 1, 0, &h, &s, &l); + CHECK(h, 120.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(0, 1, 1, &h, &s, &l); + CHECK(h, 180.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(0, 0, 1, &h, &s, &l); + CHECK(h, 240.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(1, 0, 1, &h, &s, &l); + CHECK(h, 300.0f); + CHECK(s, 1.0f); + CHECK(l, 0.5f); + + RGBToHSL(0, 0, 0, &h, &s, &l); + CHECK(h, -1.0f); + CHECK(s, 0.0f); + CHECK(l, 0.0f); + + RGBToHSL(1, 1, 1, &h, &s, &l); + CHECK(h, -1.0f); + CHECK(s, 0.0f); + CHECK(l, 1.0f); + + RGBToHSL(0.5, 0.25, 0.75, &h, &s, &l); + CHECK_TOLERANCE(h, 270.0f, EPSILON); + CHECK_TOLERANCE(s, 0.5f, EPSILON); + CHECK_TOLERANCE(l, 0.5f, EPSILON); + + HSLToRGB(0, 1, 0.5, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 0.0f); + CHECK(b, 0.0f); + + HSLToRGB(60, 1, 0.5, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 1.0f); + CHECK(b, 0.0f); + + HSLToRGB(120, 1, 0.5, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 1.0f); + CHECK(b, 0.0f); + + HSLToRGB(180, 1, 0.5, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 1.0f); + CHECK(b, 1.0f); + + HSLToRGB(240, 1, 0.5, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 0.0f); + CHECK(b, 1.0f); + + HSLToRGB(300, 1, 0.5, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 0.0f); + CHECK(b, 1.0f); + + HSLToRGB(-1, 0, 0, &r, &g, &b); + CHECK(r, 0.0f); + CHECK(g, 0.0f); + CHECK(b, 0.0f); + + HSLToRGB(-1, 0, 1, &r, &g, &b); + CHECK(r, 1.0f); + CHECK(g, 1.0f); + CHECK(b, 1.0f); + + HSLToRGB(270, 0.5, 0.5, &r, &g, &b); + CHECK_TOLERANCE(r, 0.5f, EPSILON); + CHECK_TOLERANCE(g, 0.25f, EPSILON); + CHECK_TOLERANCE(b, 0.75f, EPSILON); +} + diff --git a/chalk/chalkcolor/tests/kis_color_conversions_tester.h b/chalk/chalkcolor/tests/kis_color_conversions_tester.h new file mode 100644 index 00000000..1223abbb --- /dev/null +++ b/chalk/chalkcolor/tests/kis_color_conversions_tester.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_COLOR_CONVERSIONS_TESTER_H +#define KIS_COLOR_CONVERSIONS_TESTER_H + +#include + +#define CHECK_TOLERANCE( x, y, tolerance ) \ +if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \ +{ \ + success(TQString(__FILE__) + "[" + TQString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(TQString(__FILE__) + "[" + TQString::number(__LINE__) + TQString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + TQString::number(x)); \ +} \ + + +class KisColorConversionsTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testRGBHSV(); + void testRGBHSL(); +}; + +#endif + diff --git a/chalk/chalkpart.desktop b/chalk/chalkpart.desktop new file mode 100644 index 00000000..92aa2304 --- /dev/null +++ b/chalk/chalkpart.desktop @@ -0,0 +1,91 @@ +[Desktop Entry] +Name=KOffice Painting and Image Editor Component +Name[bg]=Компонент за рисуване и редактиране на изображения в KOffice +Name[ca]=Component de manipulació d'imatges de KOffice +Name[cy]=Cydran Peintio a Golygu Delweddau KOffice +Name[da]=Koffice male- og billedredigeringskomponent +Name[de]=KOffice-Komponente für Malen und Bildbearbeitung +Name[el]=Συστατικό επεξεργασίας και ζωγραφικής εικόνων του KOffice +Name[eo]=KOffice Pentrad- kaj Bildredaktad-komponanto +Name[es]=Componente de pintura y de edición de imágenes de KOffice +Name[et]=KOffice'i joonistamise ja pilditöötluse komponent +Name[fa]=مؤلفۀ ویرایشگر تصویر و رنگ‌آمیزی KOffice +Name[fi]=KOfficen maalaus- ja kuvankäsittelykomponentti +Name[fr]=Composant manipulation d'images et dessin de KOffice +Name[fy]=KOffice-komponint foar ôfbyldingsmanupilaasje +Name[gl]=Componente de Debuxo e Edición de Imaxes de KOffice +Name[he]=רכיב של KOffice לצביעה ועריכת תמונות +Name[hu]=KOffice rajzoló és képszerkesztő komponens +Name[is]=KOffice málunar og myndritils eining +Name[it]=Componente per il disegno e la manipolazione di immagini di KOffice +Name[ja]=KOffice 描画と画像編集コンポーネント +Name[km]=សមាសភាគ​កម្មវិធី​កែ​សម្រួល​រូបភាព និង​គំនូរ​KOffice +Name[lv]=KOffice zīmēšanas un attelu apstrādes komponente +Name[nb]=KOffice-komponent for maling og bildemanipulasjon +Name[nds]=KOffice-Komponent för't Malen un Bildbewerken +Name[ne]=केडीई कार्यालय पेन्टिङ्ग र छवि सम्पादक अवयव +Name[nl]=KOffice-component voor afbeeldingsmanipulatie +Name[pl]=Komponent edycji zdjęć oraz rysunków dla KOffice +Name[pt]=Componente de Edição e Pintura de Imagens do KOffice +Name[pt_BR]=Componente de Edição e Pintura de Imagens do KOffice +Name[ru]=Компонент рисования и редактирования изображений KOffice +Name[sk]=KOffice modul na úpravu a maľovanie obrázkov +Name[sl]=Komponenta za slikanje in urejanje slik za KOffice +Name[sr]=KOffice-ова компонента за цртање и уређивање слика +Name[sr@Latn]=KOffice-ova komponenta za crtanje i uređivanje slika +Name[sv]=Koffice målnings- och bildredigeringskomponent +Name[uk]=Компонент KOffice для малювання і редагування зображень +Name[uz]=KOffice rasm bilan ishlash komponenti +Name[uz@cyrillic]=KOffice расм билан ишлаш компоненти +Name[zh_CN]=KOffice 绘图和图像编辑器组件 +Name[zh_TW]=KOffice 繪圖與影像編輯元件 +X-KDE-Library=libchalkpart +MimeType=application/x-chalk +Type=Service +ServiceTypes=KOfficePart,KParts/ReadOnlyPart,KParts/ReadWritePart +X-KDE-NativeMimeType=application/x-chalk +GenericName=Image Object +GenericName[bg]=Графично изображение +GenericName[br]=Tra skeudenn +GenericName[ca]=Objecte d'imatge +GenericName[cy]=Gwrthrych Delwedd +GenericName[da]=Billedobjekt +GenericName[de]=Bildobjekt +GenericName[el]=Αντικείμενο εικόνας +GenericName[eo]=Bildobjekto +GenericName[es]=Objeto de imagen +GenericName[et]=Pildiobjekt +GenericName[fa]=شیء تصویر +GenericName[fi]=Kuvaobjekti +GenericName[fr]=Objet image +GenericName[fy]=Ofbylding +GenericName[ga]=Réad Íomhá +GenericName[gl]=Imaxe +GenericName[he]=אובייקט תמונה +GenericName[hu]=Képobjektum +GenericName[is]=Myndhluti +GenericName[it]=Oggetto immagine +GenericName[ja]=画像オブジェクト +GenericName[km]=វត្ថុ​រូបភាព +GenericName[lv]=Attēla objekts +GenericName[nb]=Bildeobjekt +GenericName[nds]=Bildobjekt +GenericName[ne]=छवि वस्तु +GenericName[nl]=Afbeelding +GenericName[pl]=Obrazek +GenericName[pt]=Objecto de Imagem +GenericName[pt_BR]=Imagem +GenericName[ru]=Рисунок +GenericName[se]=Govvaobjeakta +GenericName[sk]=Objekt obrázok +GenericName[sl]=Slika +GenericName[sr]=Објект слике +GenericName[sr@Latn]=Objekt slike +GenericName[sv]=Bildobjekt +GenericName[uk]=Об'єкт зображення +GenericName[uz]=Rasm obʼekti +GenericName[uz@cyrillic]=Расм объекти +GenericName[zh_CN]=图像对象 +GenericName[zh_TW]=圖片物件 +Icon=chalk +X-Chalk-Version=2 diff --git a/chalk/colorspaces/Makefile.am b/chalk/colorspaces/Makefile.am new file mode 100644 index 00000000..8f975e96 --- /dev/null +++ b/chalk/colorspaces/Makefile.am @@ -0,0 +1,15 @@ +# Definition of the service type + +if have_openexr +HALF_SUBDIRS=rgb_f16half +endif + +SUBDIRS = rgb_u8 rgb_u16 rgb_f32 \ + gray_u8 gray_u16 \ + cmyk_u8 cmyk_u16 \ + lms_f32 \ + ycbcr_u8 ycbcr_u16 \ + $(HALF_SUBDIRS) \ + wet +#wet wetsticky + diff --git a/chalk/colorspaces/README b/chalk/colorspaces/README new file mode 100644 index 00000000..dfb25f70 --- /dev/null +++ b/chalk/colorspaces/README @@ -0,0 +1,11 @@ +About Modules + +Modules are plug-ins that implement exchangable core functionality +for Chalk, such as colour strategies. Modules are loaded at startup +and shared among all Chalk documents and views. That means that making +modules stateful is iffy, and that you need to be careful about +re-entrancy. + +Modules are named modules because the plugins, which are kpartgui's +are already called plugins. Capito? Good. + diff --git a/chalk/colorspaces/cmyk_u16/Makefile.am b/chalk/colorspaces/cmyk_u16/Makefile.am new file mode 100644 index 00000000..a43d685f --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/Makefile.am @@ -0,0 +1,30 @@ +kde_services_DATA = chalk_cmyk_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalk_cmyk_u16.la +libchalk_cmyk_u16_la_SOURCES = kis_cmyk_u16_colorspace.cc +libchalk_cmyk_u16_la_LDFLAGS = $(all_libraries) +libchalk_cmyk_u16_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_cmyk_u16_plugin.la + +# Srcs for the plugin +chalk_cmyk_u16_plugin_la_SOURCES = cmyk_u16_plugin.cc +noinst_HEADERS = cmyk_u16_plugin.h kis_cmyk_u16_colorspace.h + +chalk_cmyk_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_cmyk_u16_plugin_la_LIBADD = libchalk_cmyk_u16.la ../../chalkcolor/libchalkcolor.la + +chalk_cmyk_u16_plugin_la_METASOURCES = AUTO +#METASOURCES = AUTO # XXX: which of the two? + + +SUBDIRS = . +#$(TESTSDIR) + diff --git a/chalk/colorspaces/cmyk_u16/chalk_cmyk_u16_plugin.desktop b/chalk/colorspaces/cmyk_u16/chalk_cmyk_u16_plugin.desktop new file mode 100644 index 00000000..661662b0 --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/chalk_cmyk_u16_plugin.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Name=CMYK Color Model (16-bit integer) +Name[bg]=Цветови модел CMYK (16 бита) +Name[ca]=Model de color CMYK (enters de 16 bits) +Name[cy]=Model Lliw CMYK (cyfanrif 16-did) +Name[da]=CMYK-farvemodel (16-bit heltal) +Name[de]=CMYK-Farbmodell (16-bit Ganzzahl) +Name[el]=Χρωματικό μοντέλο CMYK (16-bit ακέραιοι) +Name[en_GB]=CMYK Colour Model (16-bit integer) +Name[eo]=CMYK-kolormodelo (16-bita entjero) +Name[es]=Modelo de color CMYK (entero de 16 bits) +Name[et]=CMYK värvimudel (16-bitine täisarv) +Name[fa]=مدل رنگ CMYK )عدد صحیح ۱۶ بیتی( +Name[fi]=CMYK-värimalli +Name[fr]=Modèle de couleurs CMYK (entiers 16 bits) +Name[fy]=CMYK-kleurmodel (16-bit ynteger) +Name[gl]=Modelo de Cores CMYK (inteiro de 16-bit) +Name[he]=מודל צבעים CMYK (16 סיביות) +Name[hu]=CMYK színmodell (16 bites egész) +Name[is]=CMYK litategund (16-bita) +Name[it]=Modello di colore CMYK (intero a 16 bit) +Name[ja]=CMYK カラーモデル (16 ビット整数) +Name[km]=គំរូ​ពណ៌ CMYK (ចំនួនគត់ ១៦ ប៊ីត) +Name[lt]=CMYK spalvų modelis (16-bitų sveikasis) +Name[nb]=CMYK-fargemodell (16-bit heltall) +Name[nds]=CMYK-Klöörmodell (16-Bit Heeltall) +Name[ne]=CMYK रङ मोडेल (१६-बिट इन्टिजर) +Name[nl]=CMYK-kleurmodel (16-bit integer) +Name[pl]=Przestrzeń barw CMYK (16-bitowa liczbowa całkowita) +Name[pt]=Modelo de Cor CMYK (inteiros de 16 bits) +Name[pt_BR]=Modelo de Cor CMYK (inteiros de 16 bits) +Name[ru]=CMYK (целое 16-бит) +Name[se]=CMYK-ivdnemálle (16-bihttá lohku) +Name[sk]=CMYK model farieb (16-bitové čísla) +Name[sl]=Barvni model CMYK (16-bitno celo število) +Name[sr]=CMYK модел боја (16-битно целобројно) +Name[sr@Latn]=CMYK model boja (16-bitno celobrojno) +Name[sv]=CMYK-färgmodell (16-bitars heltal) +Name[uk]=Модель кольору CMYK (16-бітне ціле число) +Name[uz]=CMYK rang usuli (16-bit butun) +Name[uz@cyrillic]=CMYK ранг усули (16-бит бутун) +Name[zh_CN]=CMYK 色彩模型(16 位整数) +Name[zh_TW]=CMYK 色彩模型 (16-bit 整數) +Comment=Color model for 16-bit integer per channel CMYK images +Comment[bg]=Цветови модел за 16 битови изображения CMYK +Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges CMYK +Comment[cy]=Model lliw ar gyfer delweddau CMYK â chyfanrif 16-did/sianel +Comment[da]=Farvemodel for 16-bit heltal pr kanal CMYK-billeder +Comment[de]=Farbmodell für 16-bit pro Kanal CMYK-Bilder +Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι CMYK εικόνες +Comment[en_GB]=Colour model for 16-bit integer per channel CMYK images +Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes CMYK +Comment[et]=16-bitiste täisarvuliste kanalitega CMYK-piltide värvimudel +Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی در هر مجرای تصاویر CMYK +Comment[fi]=Värimalli 8-bittisille/kanavaisille CMYK-kuville +Comment[fr]=Modèle de couleurs pour des images CMYK à 16 bits/plage +Comment[fy]=Kleurmodel foar 16-bit/kanaal fan CMYK-ôfbeeldings +Comment[gl]=Modelo de Cores para imaxes CMYK de 16-bit por canal +Comment[he]=מודל צבעים עבור תמונות CMYK של 16 סיביות/ערוצים +Comment[hu]=Színmodell 16 bit/csatorna CMYK képekhez +Comment[is]=Litategund fyrir 16-bita/rásir CMYK myndir +Comment[it]=Modello di colore per immagini CMYK a canale di 16 bit +Comment[ja]=16 ビット整数/チャンネル CMYK 画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព CMYK ចំនួនគត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល +Comment[nb]=Fargemodell for CMYK-bilder med 16 bit per kanal +Comment[nds]=Klöörmodell för CMYK-Biller mit 16-Bit Heeltall per Kanaal +Comment[ne]=प्रति च्यानल CMYK छविहरूको १६ बिट इन्टिजरका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 16-bit/kanaal van CMYK-afbeeldingen +Comment[pl]=Przestrzeń barw dla obrazków CMYK z 16-bitowymi liczbami całkowitymi na kanał +Comment[pt]=Modelo de cor para imagens CMYK com 16 bits por canal +Comment[pt_BR]=Modelo de cor para imagens CMYK com 16 bits por canal +Comment[ru]=Цветовое пространство CMYK (целое 16-бит/канал) +Comment[se]=CMYK-ivdnemálle mas lea 16 bihttá kanálas +Comment[sk]=Model farieb pre CMYK obrázky so 16 bitmi na kanál +Comment[sl]=Barvni model za slike CMYK z 16 biti/kanal +Comment[sr]=Модел боја за CMYK слике, 16-битно целобројно по каналу +Comment[sr@Latn]=Model boja za CMYK slike, 16-bitno celobrojno po kanalu +Comment[sv]=Färgmodell för 16-bitars heltal per kanal CMYK-bilder +Comment[uk]=Модель кольору з 16-бітним цілим числом для кожного каналу зображень CMYK +Comment[zh_CN]=16 位整数每通道 CYMK 图像的色彩模型 +Comment[zh_TW]=每色頻為 16-bit 的 CMYK 圖片色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_cmyk_u16_plugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.cc b/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.cc new file mode 100644 index 00000000..d694133e --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.cc @@ -0,0 +1,61 @@ +/* +* cmyk_u16_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include "cmyk_u16_plugin.h" +#include "kis_cmyk_u16_colorspace.h" + +typedef KGenericFactory CMYKU16PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_cmyk_u16_plugin, CMYKU16PluginFactory( "chalk" ) ) + + +CMYKU16Plugin::CMYKU16Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(CMYKU16PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceCMYKU16 = new KisCmykU16ColorSpace(f, 0); + KisColorSpaceFactory * csf = new KisCmykU16ColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceCMYKU16); + f->add(csf); + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("CMYK16HISTO", i18n("CMYK16")), colorSpaceCMYKU16) ); + } + +} + +CMYKU16Plugin::~CMYKU16Plugin() +{ +} + +#include "cmyk_u16_plugin.moc" diff --git a/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.h b/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.h new file mode 100644 index 00000000..07224a14 --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/cmyk_u16_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CMYK_U16_PLUGIN_H_ +#define CMYK_U16_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the CMYK U16 colour space strategy. + */ +class CMYKU16Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + CMYKU16Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~CMYKU16Plugin(); + +}; + + +#endif // CMYK_U16_PLUGIN_H_ diff --git a/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc b/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc new file mode 100644 index 00000000..3f2ccc80 --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include LCMS_HEADER + +#include + +#include +#include + +#include +#include "kis_cmyk_u16_colorspace.h" +#include "kis_u16_base_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" +#include "kis_colorspace_factory_registry.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_CMYK = 4; + const TQ_INT32 MAX_CHANNEL_CMYKA = 5; +} + +KisCmykU16ColorSpace::KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU16BaseColorSpace(KisID("CMYKA16", i18n("CMYK (16-bit integer/channel)")), TYPE_CMYK5_16, icSigCmykData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0 * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQt::cyan)); + m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1 * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQt::magenta)); + m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2 * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQt::yellow)); + m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3 * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQt::black)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4 * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + +KisCmykU16ColorSpace::~KisCmykU16ColorSpace() +{ +} + +void KisCmykU16ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalBlack = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + TQ_UINT32 alpha = pixel->alpha; + TQ_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights)); + + totalCyan += UINT16_MULT(pixel->cyan, alphaTimesWeight); + totalMagenta += UINT16_MULT(pixel->magenta, alphaTimesWeight); + totalYellow += UINT16_MULT(pixel->yellow, alphaTimesWeight); + totalBlack += UINT16_MULT(pixel->black, alphaTimesWeight); + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > 0) { + totalCyan = UINT16_DIVIDE(totalCyan, newAlpha); + totalMagenta = UINT16_DIVIDE(totalMagenta, newAlpha); + totalYellow = UINT16_DIVIDE(totalYellow, newAlpha); + totalBlack = UINT16_DIVIDE(totalBlack, newAlpha); + } + + dstPixel->cyan = totalCyan; + dstPixel->magenta = totalMagenta; + dstPixel->yellow = totalYellow; + dstPixel->black = totalBlack; +} + +void KisCmykU16ColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalCyan += pixel->cyan * weight; + totalMagenta += pixel->magenta * weight; + totalYellow += pixel->yellow * weight; + totalK += pixel->black * weight; + totalAlpha += pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->cyan = CLAMP( ( totalCyan / factor) + offset, 0, TQ_UINT16_MAX); + p->magenta = CLAMP( ( totalMagenta / factor) + offset, 0, TQ_UINT16_MAX); + p->yellow = CLAMP( ( totalYellow / factor) + offset, 0, TQ_UINT16_MAX); + p->black = CLAMP( ( totalK / factor) + offset, 0, TQ_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX); + } +} + + +void KisCmykU16ColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->cyan = TQ_UINT16_MAX - p->cyan; + p->magenta = TQ_UINT16_MAX - p->magenta; + p->yellow = TQ_UINT16_MAX - p->yellow; + p->black = TQ_UINT16_MAX - p->black; + src += psize; + } +} + + + +void KisCmykU16ColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adj, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + TQ_UINT8 * tmp = new TQ_UINT8[nPixels * psize]; + TQ_UINT8 * tmpPtr = tmp; + memcpy(tmp, dst, nPixels * psize); + + KisAbstractColorSpace::applyAdjustment(src, dst, adj, nPixels); + + // Copy the alpha, which lcms doesn't do for us, grumble. + + while (nPixels--) + { + TQ_UINT16 *pixelAlphaSrc = reinterpret_cast(tmpPtr + m_alphaPos); + TQ_UINT16 *pixelAlphaDst = reinterpret_cast(dst + m_alphaPos); + + *pixelAlphaDst= *pixelAlphaSrc; + + tmpPtr += psize; + dst += psize; + } + + delete [] tmp; +} + +TQValueVector KisCmykU16ColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisCmykU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_CMYKA; +} + +TQ_UINT32 KisCmykU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_CMYK; +} + +TQ_UINT32 KisCmykU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_CMYKA * sizeof(TQ_UINT16); +} + +void KisCmykU16ColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex) +{ + if (channelIndex < (TQ_UINT32)MAX_CHANNEL_CMYKA) { + + memset(dstPixel, 0, MAX_CHANNEL_CMYKA * sizeof(TQ_UINT16)); + + if (U16_OPACITY_TRANSPARENT != 0) { + dstPixel[PIXEL_ALPHA] = U16_OPACITY_TRANSPARENT; + } + + memcpy(dstPixel + (channelIndex * sizeof(TQ_UINT16)), srcPixel + (channelIndex * sizeof(TQ_UINT16)), sizeof(TQ_UINT16)); + } +} + +void KisCmykU16ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_CMYKA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_CMYK * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_CYAN] = UINT16_BLEND(src[PIXEL_CYAN], dst[PIXEL_CYAN], srcBlend); + dst[PIXEL_MAGENTA] = UINT16_BLEND(src[PIXEL_MAGENTA], dst[PIXEL_MAGENTA], srcBlend); + dst[PIXEL_YELLOW] = UINT16_BLEND(src[PIXEL_YELLOW], dst[PIXEL_YELLOW], srcBlend); + dst[PIXEL_BLACK] = UINT16_BLEND(src[PIXEL_BLACK], dst[PIXEL_BLACK], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_CMYKA; + dst += MAX_CHANNEL_CMYKA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); \ + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + TQ_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += MAX_CHANNEL_CMYKA; \ + dst += MAX_CHANNEL_CMYKA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisCmykU16ColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + } + + + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + if (srcColor > UINT16_MAX - srcColor) srcColor = UINT16_MAX; + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykU16ColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + + +void KisCmykU16ColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_CYAN: + //compositeCopyCyan(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_MAGENTA: + //compositeCopyMagenta(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_YELLOW: + //compositeCopyYellow(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisCmykU16ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} diff --git a/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h b/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h new file mode 100644 index 00000000..8e43cd1c --- /dev/null +++ b/chalk/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_CMYK_U16_H_ +#define KIS_STRATEGY_COLORSPACE_CMYK_U16_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_u16_base_colorspace.h" +#include "kis_integer_maths.h" + + +class KRITATOOL_EXPORT KisCmykU16ColorSpace : public KisU16BaseColorSpace { +public: + + struct Pixel { + TQ_UINT16 cyan; + TQ_UINT16 magenta; + TQ_UINT16 yellow; + TQ_UINT16 black; + TQ_UINT16 alpha; + }; + +public: + KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisCmykU16ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + +public: + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adj, TQ_INT32 nPixels); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + friend class KisCmykU16ColorSpaceTester; + + static const TQ_UINT8 PIXEL_CYAN = 0; + static const TQ_UINT8 PIXEL_MAGENTA = 1; + static const TQ_UINT8 PIXEL_YELLOW = 2; + static const TQ_UINT8 PIXEL_BLACK = 3; + static const TQ_UINT8 PIXEL_ALPHA = 4; +}; + +class KisCmykU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("CMYKA16", i18n("CMYK (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_CMYK5_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisCmykU16ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "Offset printing, according to ISO/DIS 12647-2:2004, OFCOM, paper type 1 or 2 = coated art, 115 g/m2, screen ruling 60 cm-1, positive-acting plates"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_CMYK_U16_H_ diff --git a/chalk/colorspaces/cmyk_u8/Makefile.am b/chalk/colorspaces/cmyk_u8/Makefile.am new file mode 100644 index 00000000..623add37 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/Makefile.am @@ -0,0 +1,20 @@ +kde_services_DATA = chalkcmykplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy \ + -I$(srcdir)/../../chalkcolor \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkcmykplugin.la + +chalkcmykplugin_la_SOURCES = cmyk_plugin.cc kis_cmyk_colorspace.cc +noinst_HEADERS = cmyk_plugin.h kis_cmyk_colorspace.h + +chalkcmykplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalkcmykplugin_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +chalkcmykplugin_la_METASOURCES = AUTO + + +SUBDIRS=templates diff --git a/chalk/colorspaces/cmyk_u8/chalkcmykplugin.desktop b/chalk/colorspaces/cmyk_u8/chalkcmykplugin.desktop new file mode 100644 index 00000000..d01baeb3 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/chalkcmykplugin.desktop @@ -0,0 +1,99 @@ +[Desktop Entry] +Name=CMYK Color Model +Name[bg]=Цветови модел CMYK +Name[br]=Gobari al livioù CMYK +Name[ca]=Model de color CMYK +Name[cy]=Model Lliw CMYK +Name[da]=CMYK-farvemodel +Name[de]=CMYK-Farbmodell +Name[el]=Χρωματικό μοντέλο CMYK +Name[en_GB]=CMYK Colour Model +Name[eo]=CMYK-kolormodelo +Name[es]=Modelo de color CMYK +Name[et]=CMYK värvimudel +Name[eu]=CMYK kolore-eredua +Name[fa]=مدل رنگ CMYK +Name[fi]=CMYK-värimalli +Name[fr]=Modèle de couleurs CMYK +Name[fy]=CMYK kleur-model +Name[gl]=Modelo de Cores CMYK +Name[he]=מודל צבעים CMYK +Name[hi]=सीएमवायके रंग नमूना +Name[hu]=CMYK színmodell +Name[is]=CMYK litategund +Name[it]=Modello di colore CMYK +Name[ja]=CMYK カラーモデル +Name[km]=គំរូពណ៌ CMYK +Name[lt]=CMYK spalvų modelis +Name[ms]=Model Warna CMYK +Name[nb]=CMYK-fargemodell +Name[nds]=CMYK-Klöörmodell +Name[ne]=CMYK रङ मोडेलल +Name[nl]=CMYK-kleurmodel +Name[nn]=CMYK-fargemodell +Name[pl]=Przestrzeń barw CMYK +Name[pt]=Modelo de Cor CMYK +Name[pt_BR]=Modelo de Cor CMYK +Name[ru]=CMYK +Name[se]=CMYK-ivdnemálle +Name[sk]=Model farieb CMYK +Name[sl]=Barvni model CMYK +Name[sr]=CMYK модел боја +Name[sr@Latn]=CMYK model boja +Name[sv]=CMYK-färgmodell +Name[ta]=CMYK வண்ண முறை +Name[tr]=CMYK Renk Modeli +Name[uk]=Модель кольору CMYK +Name[uz]=CMYK rang usuli +Name[uz@cyrillic]=CMYK ранг усули +Name[zh_CN]=CMYK 色彩模型 +Name[zh_TW]=CMYK 色彩模型 +Comment=Color model for 8-bit/channel CMYK images +Comment[bg]=Цветови модел за 8 битови изображения CMYK +Comment[ca]=Model de color d'enters de 8 bits per a canal d'imatges CMYK +Comment[cy]=Model lliw ar gyfer delweddau CMYK 8-did/sianel +Comment[da]=Farvemodel for 8-bit/kanal CMYK-billeder +Comment[de]=Farbmodell für 8-bit pro Kanal CMYK-Bilder +Comment[el]=Χρωματικό μοντέλο για 8-bit/κανάλι CMYK εικόνες +Comment[en_GB]=Colour model for 8-bit/channel CMYK images +Comment[es]=Modelo de color para imágenes de 8 bits/canal CMYK +Comment[et]=8-bitiste kanalitega CMYK-piltide värvimudel +Comment[eu]=8 bit/kanaleko CMYK irudien kolore-eredua +Comment[fa]=مدل رنگ برای تصاویر CMYK مجرا/۸ بیتی +Comment[fi]=Värimalli 8-bittisille/kanavaisille CMYK-kuville +Comment[fr]=Modèle de couleurs pour des images CMYK à 8 bits/plage +Comment[fy]=Kleurmodel foar 8-bit/kanaal CMYK-ôfbeeldings +Comment[gl]=Modelo de Cores para imaxer CMYK de 8-bit/canal +Comment[he]=מודל צבעים עבור תמונות CMYK של 8 סיביות/ערוצים +Comment[hi]=8-बिट/चैनल सीएमवायके छवियों के लिए रंग नमूना +Comment[hu]=Színmodell 8 bit/csatorna CMYK képekhez +Comment[is]=Litategund fyrir 8-bita/rásir CMYK myndir +Comment[it]=Modello di colore per immagini CMYK a canale di 8 bit +Comment[ja]=8 ビット/チャンネル CMYK 画像のためのカラーモデル +Comment[km]=គំរូពណ៌សម្រាប់​រូបភាព CMYK ៨ ប៊ីត​ក្នុង​មួយ​ឆានែល +Comment[ms]=Model warna bagi imej CMYK 8-bit/saluran +Comment[nb]=Fargemodell for CMYK-bilder med 8 bit per kanal +Comment[nds]=Klöörmodell för CMYK-Biller mit 8-Bit Heeltall per Kanaal +Comment[ne]=८-बिट/च्यानल CMYK छविहरूका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 8-bit/kanaal CMYK-afbeeldingen +Comment[nn]=Fargemodell for CMYK-bilete med 8 bit per kanal +Comment[pl]=Przestrzeń barw dla obrazków CMYK 8 bitów/kanał +Comment[pt]=Modelo de cor para imagens CMYK com 8 bits por canal +Comment[pt_BR]=Modelo de cor para imagens com 8-bits de canal CMYK +Comment[ru]=Цветовое пространство CMYK (8-бит/канал) +Comment[se]=CMYK-ivdnemálle mas lea 8 bihttá kanálas +Comment[sk]=Model farieb pre CMYK obrázky s 8 bitmi na kanál +Comment[sl]=Barvni model za slike CMYK z 8 biti/kanal +Comment[sr]=Модел боја за CMYK слике са 8 битова по каналу +Comment[sr@Latn]=Model boja za CMYK slike sa 8 bitova po kanalu +Comment[sv]=Färgmodell för 8 bitar/kanal CMYK-bilder +Comment[ta]=8/பிட்/வழி CMYK பிம்பங்களுக்கான வண்ண முறை +Comment[tr]=8-bit/kanal CMYK görüntüler için renk modeli +Comment[uk]=Модель кольору CMYK для зображень 8-біт/каналів +Comment[zh_CN]=八位/通道 CMYK 图像的色彩模型 +Comment[zh_TW]=8-bit/色頻的 CMYK 圖片色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkcmykplugin +X-Chalk-Version=2 + diff --git a/chalk/colorspaces/cmyk_u8/cmyk_plugin.cc b/chalk/colorspaces/cmyk_u8/cmyk_plugin.cc new file mode 100644 index 00000000..686a22bf --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/cmyk_plugin.cc @@ -0,0 +1,66 @@ +/* + * cmyk_plugin.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cmyk_plugin.h" + +#include "kis_cmyk_colorspace.h" + +typedef KGenericFactory CMYKPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcmykplugin, CMYKPluginFactory( "chalk" ) ) + + +CMYKPlugin::CMYKPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(CMYKPluginFactory::instance()); + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceCMYK = new KisCmykColorSpace(f, 0); + KisColorSpaceFactory * csf = new KisCmykColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceCMYK); + f->add(csf); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("CMYKHISTO", i18n("CMYK")), colorSpaceCMYK) ); + } + +} + +CMYKPlugin::~CMYKPlugin() +{ +} + +#include "cmyk_plugin.moc" diff --git a/chalk/colorspaces/cmyk_u8/cmyk_plugin.h b/chalk/colorspaces/cmyk_u8/cmyk_plugin.h new file mode 100644 index 00000000..073a5e61 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/cmyk_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CMYK_PLUGIN_H_ +#define CMYK_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the CMYK colour space strategy. + */ +class CMYKPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + CMYKPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~CMYKPlugin(); + + +}; + +#endif // CMYK_PLUGIN_H_ diff --git a/chalk/colorspaces/cmyk_u8/cmykplugin.rc b/chalk/colorspaces/cmyk_u8/cmykplugin.rc new file mode 100644 index 00000000..bb7f6316 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/cmykplugin.rc @@ -0,0 +1,7 @@ + + +&Image + &Mode + + + diff --git a/chalk/colorspaces/cmyk_u8/composite.h b/chalk/colorspaces/cmyk_u8/composite.h new file mode 100644 index 00000000..4914a7df --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/composite.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COMPOSITE_CMYK +#define COMPOSITE_CMYK + +void compositeCopyCyan(TQ_INT32 stride, + TQ_UINT8 *dst, + TQ_INT32 dststride, + TQ_UINT8 *src, + TQ_INT32 srcstride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_CYAN, stride, dst, dststride, src, srcstride, rows, cols, opacity); +} + + +void compositeCopyMagenta(TQ_INT32 stride, + TQ_UINT8 *dst, + TQ_INT32 dststride, + TQ_UINT8 *src, + TQ_INT32 srcstride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_MAGENTA, stride, dst, dststride, src, srcstride, rows, cols, opacity); + +} + + +void compositeCopyYellow(TQ_INT32 stride, + TQ_UINT8 *dst, + TQ_INT32 dststride, + TQ_UINT8 *src, + TQ_INT32 srcstride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_YELLOW, stride, dst, dststride, src, srcstride, rows, cols, opacity); + +} + + +void compositeCopyBlack(TQ_INT32 stride, + TQ_UINT8 *dst, + TQ_INT32 dststride, + TQ_UINT8 *src, + TQ_INT32 srcstride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_BLACK, stride, dst, dststride, src, srcstride, rows, cols, opacity); +} + + +#endif \ No newline at end of file diff --git a/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc b/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc new file mode 100644 index 00000000..49256c26 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can CYANistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_cmyk_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_colorspace_factory_registry.h" + +#include "kis_profile.h" +#include "kis_integer_maths.h" + +namespace cmyk { + const TQ_INT32 MAX_CHANNEL_CMYK = 4; + const TQ_INT32 MAX_CHANNEL_CMYKA = 5; +} + +KisCmykColorSpace::KisCmykColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU8BaseColorSpace(KisID("CMYK", i18n("CMYK")), TYPE_CMYK5_8, icSigCmykData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQt::cyan)); + m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQt::magenta)); + m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQt::yellow)); + m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQt::black)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8, 1, TQt::white)); + + m_alphaPos = PIXEL_CMYK_ALPHA; + + init(); +} + +KisCmykColorSpace::~KisCmykColorSpace() +{ +} + +void KisCmykColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + TQ_UINT32 alpha = (*colors)[4]; + TQ_UINT32 alphaTimesWeight = alpha * *weights; + + totalCyan += (*colors)[0] * alphaTimesWeight; + totalMagenta += (*colors)[1] * alphaTimesWeight; + totalYellow += (*colors)[2] * alphaTimesWeight; + totalK += (*colors)[3] * alphaTimesWeight; + totalAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + //Q_ASSERT(newAlpha <= 255*255); + if (totalAlpha > 255*255) totalAlpha = 255*255; + + // Divide by 255. + dst[4] =(((totalAlpha + 0x80)>>8)+totalAlpha) >>8; + + if (totalAlpha > 0) { + totalCyan = totalCyan / totalAlpha; + totalMagenta = totalMagenta / totalAlpha; + totalYellow = totalYellow / totalAlpha; + totalK = totalK / totalAlpha; + } // else the values are already 0 too + + TQ_UINT32 dstCyan = totalCyan; + if (dstCyan > 255) dstCyan = 255; + dst[0] = dstCyan; + + TQ_UINT32 dstMagenta = totalMagenta; + if (dstMagenta > 255) dstMagenta = 255; + dst[1] = dstMagenta; + + TQ_UINT32 dstYellow = totalYellow; + if (dstYellow > 255) dstYellow = 255; + dst[2] = dstYellow; + + TQ_UINT32 dstK = totalK; + if (dstK > 255) dstK = 255; + dst[3] = dstK; +} + + +void KisCmykColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0; + + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalCyan += (*colors)[PIXEL_CYAN] * weight; + totalMagenta += (*colors)[PIXEL_MAGENTA] * weight; + totalYellow += (*colors)[PIXEL_YELLOW] * weight; + totalK += (*colors)[PIXEL_BLACK] * weight; + totalAlpha += (*colors)[PIXEL_CMYK_ALPHA] * weight; + } + colors++; + kernelValues++; + } + + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + dst[PIXEL_CYAN] = CLAMP((totalCyan / factor) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_MAGENTA] = CLAMP((totalMagenta / factor) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_YELLOW] = CLAMP((totalYellow / factor) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_BLACK] = CLAMP((totalK / factor) + offset, 0, TQ_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_CMYK_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } +} + + +void KisCmykColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_CYAN] = TQ_UINT8_MAX - src[PIXEL_CYAN]; + src[PIXEL_MAGENTA] = TQ_UINT8_MAX - src[PIXEL_MAGENTA]; + src[PIXEL_YELLOW] = TQ_UINT8_MAX - src[PIXEL_YELLOW]; + src[PIXEL_BLACK] = TQ_UINT8_MAX - src[PIXEL_BLACK]; + src += psize; + } +} + +void KisCmykColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adj, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + TQ_UINT8 * tmp = new TQ_UINT8[nPixels * psize]; + TQ_UINT8 * tmpPtr = tmp; + memcpy(tmp, dst, nPixels * psize); + + KisAbstractColorSpace::applyAdjustment(src, dst, adj, nPixels); + + // Copy the alpha, which lcms doesn't do for us, grumble. + + while (nPixels--) + { + dst[4] = tmpPtr[4]; + + tmpPtr += psize; + dst += psize; + } + + delete [] tmp; +} + +TQValueVector KisCmykColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisCmykColorSpace::nChannels() const +{ + return cmyk::MAX_CHANNEL_CMYKA; +} + +TQ_UINT32 KisCmykColorSpace::nColorChannels() const +{ + return cmyk::MAX_CHANNEL_CMYK; +} + +TQ_UINT32 KisCmykColorSpace::pixelSize() const +{ + return cmyk::MAX_CHANNEL_CMYKA; +} + +void KisCmykColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex) +{ + if (channelIndex < (TQ_UINT32)cmyk::MAX_CHANNEL_CMYKA) { + + memset(dstPixel, 0, cmyk::MAX_CHANNEL_CMYKA * sizeof(TQ_UINT8)); + + if (OPACITY_TRANSPARENT != 0) { + dstPixel[PIXEL_CMYK_ALPHA] = OPACITY_TRANSPARENT; + } + + memcpy(dstPixel + (channelIndex * sizeof(TQ_UINT8)), srcPixel + (channelIndex * sizeof(TQ_UINT8)), sizeof(TQ_UINT8)); + } +} + +void KisCmykColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, U8_tqmask); + } + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, cmyk::MAX_CHANNEL_CMYKA * sizeof(TQ_UINT8)); + } else { + TQ_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA]; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_CMYK_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, cmyk::MAX_CHANNEL_CMYK * sizeof(TQ_UINT8)); + } else { + dst[PIXEL_CYAN] = UINT8_BLEND(src[PIXEL_CYAN], dst[PIXEL_CYAN], srcBlend); + dst[PIXEL_MAGENTA] = UINT8_BLEND(src[PIXEL_MAGENTA], dst[PIXEL_MAGENTA], srcBlend); + dst[PIXEL_YELLOW] = UINT8_BLEND(src[PIXEL_YELLOW], dst[PIXEL_YELLOW], srcBlend); + dst[PIXEL_BLACK] = UINT8_BLEND(src[PIXEL_BLACK], dst[PIXEL_BLACK], srcBlend); + } + } + } + + columns--; + src += cmyk::MAX_CHANNEL_CMYKA; + dst += cmyk::MAX_CHANNEL_CMYKA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT8 *src = srcRowStart; \ + TQ_UINT8 *dst = dstRowStart; \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA]; \ + TQ_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT8_MULT(srcAlpha, U8_tqmask); \ +} \ + tqmask++; \ +} \ + \ + if (srcAlpha != OPACITY_TRANSPARENT) { \ + \ + if (opacity != OPACITY_OPAQUE) { \ + srcAlpha = UINT8_MULT(srcAlpha, opacity); \ +} \ + \ + TQ_UINT8 srcBlend; \ + \ + if (dstAlpha == OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ +} else { \ + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_CMYK_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); \ +} else { \ + srcBlend = srcAlpha; \ +} \ +} + +#define COMMON_COMPOSITE_OP_EPILOG() \ +} \ + \ + columns--; \ + src += cmyk::MAX_CHANNEL_CMYKA; \ + dst += cmyk::MAX_CHANNEL_CMYKA; \ +} \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ +} \ +} + +void KisCmykColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[channel] = UINT8_BLEND(srcColor, dstColor, srcBlend); + } + + + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + 2u * UINT8_MULT(srcColor, UINT8_MAX - dstColor)); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1u)) / (UINT8_MAX + 1u - srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1u)) / (srcColor + 1u), UINT8_MAX); + if (srcColor > UINT8_MAX - srcColor) srcColor = UINT8_MAX; + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisCmykColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT8 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, U8_tqmask); + } + tqmask++; + } + d->alpha = UINT8_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisCmykColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_CYAN: + //compositeCopyCyan(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_MAGENTA: + //compositeCopyMagenta(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_YELLOW: + //compositeCopyYellow(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U8Mult(), Uint8ToU8(), U8OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisCmykColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} diff --git a/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.h b/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.h new file mode 100644 index 00000000..69ef80e4 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/kis_cmyk_colorspace.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_CMYK_H_ +#define KIS_STRATEGY_COLORSPACE_CMYK_H_ + +#include +#include +#include +#include "kis_global.h" +#include "kis_u8_base_colorspace.h" + +class KRITACORE_EXPORT KisCmykColorSpace : public KisU8BaseColorSpace { + +public: + + + struct Pixel { + TQ_UINT16 cyan; + TQ_UINT16 magenta; + TQ_UINT16 yellow; + TQ_UINT16 black; + TQ_UINT16 alpha; + }; +public: + KisCmykColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisCmykColorSpace(); + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + + +public: + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adj, TQ_INT32 nPixels); + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + // XXX: darken & intensity8? + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + +private: + + TQ_UINT8 * m_qcolordata; + + static const TQ_UINT8 PIXEL_CYAN = 0; + static const TQ_UINT8 PIXEL_MAGENTA = 1; + static const TQ_UINT8 PIXEL_YELLOW = 2; + static const TQ_UINT8 PIXEL_BLACK = 3; + static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4; +}; + +class KisCmykColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("CMYK", i18n("CMYK (8-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_CMYK5_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisCmykColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "Offset printing, according to ISO/DIS 12647-2:2004, OFCOM, paper type 1 or 2 = coated art, 115 g/m2, screen ruling 60 cm-1, positive-acting plates"; }; // Do not i18n -- this is from a data file +}; + +#endif // KIS_STRATEGY_COLORSPACE_CMYK_H_ diff --git a/chalk/colorspaces/cmyk_u8/templates/.directory b/chalk/colorspaces/cmyk_u8/templates/.directory new file mode 100644 index 00000000..f69b12ea --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/templates/.directory @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=CMYK +Name[fr]=CMJN +Name[hi]=सीएमवायके +X-KDE-DefaultTab=true diff --git a/chalk/colorspaces/cmyk_u8/templates/Makefile.am b/chalk/colorspaces/cmyk_u8/templates/Makefile.am new file mode 100644 index 00000000..fdd99b60 --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/templates/Makefile.am @@ -0,0 +1,8 @@ +templates_DATA = .directory white_2000x800.desktop +templatesdir = $(kde_datadir)/chalk/templates/cmyk + +templatesrc_DATA = white_2000x800.kra +templatesrcdir = $(kde_datadir)/chalk/templates/cmyk/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/chalk/icons diff --git a/chalk/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png b/chalk/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png new file mode 100644 index 00000000..4e237472 Binary files /dev/null and b/chalk/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png differ diff --git a/chalk/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz b/chalk/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz new file mode 100644 index 00000000..a1ad0ae5 Binary files /dev/null and b/chalk/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz differ diff --git a/chalk/colorspaces/cmyk_u8/templates/white_2000x800.desktop b/chalk/colorspaces/cmyk_u8/templates/white_2000x800.desktop new file mode 100644 index 00000000..81119e3a --- /dev/null +++ b/chalk/colorspaces/cmyk_u8/templates/white_2000x800.desktop @@ -0,0 +1,100 @@ +[Desktop Entry] +Type=Link +URL=.source/white_2000x800.kra +Icon=template_cmyk_empty +Name=White 2000 x 800 +Name[bg]=Бяло 2000x800 +Name[br]=Gwenn 2000 x 800 +Name[ca]=Blanc 2000 x 800 +Name[cy]=Gwyn 2000 x 800 +Name[da]=Hvidt 2000 x 800 +Name[de]=Weiß 2000 x 800 +Name[el]=Λευκό 2000 x 800 +Name[es]=2000 x 800 blanco +Name[et]=Valge 2000 x 800 +Name[eu]=Zuria 2000 x 800 +Name[fa]=سفید ۸۰۰ × ۲۰۰۰ +Name[fi]=Valkoinen 2000 x 800 +Name[fr]=Image blanche 2000 x 800 +Name[fy]=Wyt 2000 x 800 +Name[ga]=Bán 2000×800 +Name[gl]=Branco 2000 x 800 +Name[he]=לבן ‎2000 x 800 +Name[hi]=सफेद 2000 x 800 +Name[hu]=fehér 2000 x 800 +Name[is]=Hvít 2000 x 800 +Name[it]=Bianco 2000 × 800 +Name[ja]=白 2000 x 800 +Name[km]=ពណ៌​ស 2000 x 800 +Name[lt]=Baltas 2000 x 800 +Name[lv]=Balts 2000 x 800 +Name[ms]=Putih 2000 x 800 +Name[nb]=Hvit 2000 x 800 +Name[nds]=Witt 2000 x 800 +Name[ne]=सेतो २००० x ८०० +Name[nl]=Wit 2000 x 800 +Name[nn]=Kvitt 2000 × 800 +Name[pl]=Biały 2000 x 800 +Name[pt]=Branca 2000 x 800 +Name[pt_BR]=2000 x 800 em Branco +Name[ru]=Белый 2000x800 +Name[se]=Vilges 2000 × 800 +Name[sk]=Biely 2000 x 800 +Name[sl]=Bela 2000 x 800 +Name[sr]=Бела 2000 x 800 +Name[sr@Latn]=Bela 2000 x 800 +Name[sv]=Vit 2000 x 800 +Name[ta]=வெள்ளை 2000 x 800 +Name[tr]=Beyaz 2000 x 800 +Name[uk]=Біле 2000 x 800 +Name[uz]=Oq 2000 x 800 +Name[uz@cyrillic]=Оқ 2000 x 800 +Name[zh_CN]=白色 2000 x 800 +Name[zh_TW]=白色 2000 x 800 +Comment=Creates a white CMYK image of 2000 x 800 pixels. +Comment[bg]=Създаване на бяло изображения CMYK с размери 2000x800 пиксела. +Comment[ca]=Crea una imatge blanca CMYK de 2000 x 800 píxels. +Comment[cy]=Creu delwedd CMYK wen o 2000 x 800 picsel. +Comment[da]=Laver et hvidt CMYK-billede på 2000 x 800 biledpunkter. +Comment[de]=Erstellt ein weißes CMYK-Bild mit 2000 x 800 Pixeln. +Comment[el]=Δημιουργεί μία λευκή CMYK εικόνα μεγέθους 2000 x 800 εικονοστοιχείων. +Comment[es]=Crea una imagen CMYK blanca de 2000 x 800 píxeles. +Comment[et]=Loob valge CMYK-pildi mõõtmetega 2000 x 800 pikslit. +Comment[eu]=2000 x 800 pixeleko CMYK irudi zuri bat sortzen du. +Comment[fa]=یک تصویر سفید CMYK ۲۰۰۰ × ۸۰۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo valkoisen 2000 x 800 pikselin CMYK-kuvan. +Comment[fr]=Crée une image CMYK blanche de 2000 x 800 pixels. +Comment[fy]=Makket in wite CMYK-ôfbeelding oan fan 2000 x 2000 byldpunten. +Comment[gl]=Cria unha imaxe CMYK branca de 2000 x 800 pixels. +Comment[he]=יצירת תמונת CMYK לבנה בגודל ‎2000 x 800 פיקסלים +Comment[hi]=2000 x 800 पिक्सेल की सफेद सीएमवायके छवि बनाता है. +Comment[hu]=Létrehoz egy fehér, 2000 x 800 képpontos CMYK képet. +Comment[is]=Býr til hvíta CMYK mynd með 2000 x 800 punktum. +Comment[it]=Crea un'immagine CMYK bianca di 2000 × 800 pixel. +Comment[ja]=2000 x 800 ピクセルの CMYK 画像を作成 +Comment[km]=បង្កើត​រូបភាព CMYK ពណ៌​ស​មួយ ដែល​មាន​ទំហំ ២០០០ x ៨០០ ភីកសែល ។ +Comment[ms]=Cipta imej CMYK putih 2000 x 800 piksel. +Comment[nb]=Lager et hvitt CMYK-bilde på 2000 x 800 piksler. +Comment[nds]=Stellt en wittet CMYK-Bild mit 2000 x 800 Pixels op. +Comment[ne]=२००० x ८०० पिक्सेलको सेतो CMYK छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een witte CMYK-afbeelding aan van 2000 x 2000 pixels. +Comment[nn]=Lagar eit kvitt CMYK-bilete på 2000 × 800 pikslar. +Comment[pl]=Tworzy biały obrazek CMYK o rozmiarach 2000 na 800 pikseli. +Comment[pt]=Cria uma imagem CMYK branca com 2000 x 800 pontos. +Comment[pt_BR]=Cria uma imagem CMYK em branco de 2000 x 800 pixéis. +Comment[ru]=Рисунок CMYK, 2000x800, белый фон +Comment[se]=Ráhkada CMYK-gova mas leat 2000 × 800 govvačuoggá. +Comment[sk]=Vytvorí biely obrázok CMYK s rozmermi 2000 x 800 pixelov. +Comment[sl]=Ustvari belo sliko CMYK velikosti 2000 x 800 pik. +Comment[sr]=Прави белу CMYK слику са 2000 x 800 пиксела. +Comment[sr@Latn]=Pravi belu CMYK sliku sa 2000 x 800 piksela. +Comment[sv]=Skapar en vit CMYK-bild med 2000 x 800 bildpunkter. +Comment[ta]=2000 x 800 படத்துணுக்குகளில் ஒரு வெள்ளை CMYK பிம்பத்தை உருவாக்குகிறது. +Comment[tr]=2000 x 800 piksel ebadında beyaz bir CMYK görüntü oluşturur. +Comment[uk]=Створює біле зображення CMYK 2000 x 800 пікселів. +Comment[uz]=Oʻlchami 2000 x 800 nuqta boʻlgan oq CMYK rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 2000 x 800 нуқта бўлган оқ CMYK расмни яратиш. +Comment[zh_CN]=创建 2000 x 800 像素的白色 CMYK 图像。 +Comment[zh_TW]=建立一個白色,2000 x 800 像素的 CMYK 圖片。 +X-Chalk-Version=2 + diff --git a/chalk/colorspaces/cmyk_u8/templates/white_2000x800.kra b/chalk/colorspaces/cmyk_u8/templates/white_2000x800.kra new file mode 100644 index 00000000..b6833a24 Binary files /dev/null and b/chalk/colorspaces/cmyk_u8/templates/white_2000x800.kra differ diff --git a/chalk/colorspaces/gray_u16/Makefile.am b/chalk/colorspaces/gray_u16/Makefile.am new file mode 100644 index 00000000..5b756bce --- /dev/null +++ b/chalk/colorspaces/gray_u16/Makefile.am @@ -0,0 +1,29 @@ +# location for the rc file +kde_services_DATA = chalk_gray_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalk_gray_u16.la +libchalk_gray_u16_la_SOURCES = kis_gray_u16_colorspace.cc +libchalk_gray_u16_la_LDFLAGS = $(all_libraries) +libchalk_gray_u16_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_gray_u16_plugin.la + +# Srcs for the plugin +chalk_gray_u16_plugin_la_SOURCES = gray_u16_plugin.cc +noinst_HEADERS = gray_u16_plugin.h kis_gray_u16_colorspace.h + +chalk_gray_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_gray_u16_plugin_la_LIBADD = libchalk_gray_u16.la ../../chalkcolor/libchalkcolor.la + +chalk_gray_u16_plugin_la_METASOURCES = AUTO + + +SUBDIRS = . + diff --git a/chalk/colorspaces/gray_u16/chalk_gray_u16_plugin.desktop b/chalk/colorspaces/gray_u16/chalk_gray_u16_plugin.desktop new file mode 100644 index 00000000..893557c5 --- /dev/null +++ b/chalk/colorspaces/gray_u16/chalk_gray_u16_plugin.desktop @@ -0,0 +1,83 @@ +[Desktop Entry] +Name=Grayscale Color Model (16-bit integer) +Name[bg]=Цветови модел сива гама (16 бита) +Name[ca]=Model de color d'escala de grisos (enters de 16 bits) +Name[cy]=Model Lliw Graddlwyd (cyfanrif 16-did) +Name[da]=Farvemodel med gråskala (16-bit heltal) +Name[de]=Graustufen-Farbmodell (16-bit Ganzzahl) +Name[el]=Χρωματικό μοντέλο διαβαθμίσεων του γκρι (16 bit ακέραιοι) +Name[en_GB]=Greyscale Colour Model (16-bit integer) +Name[eo]=Grizoskala kolormodelo (16-bita entjero) +Name[es]=Modelo de color de escala de grises (entero de 16 bits) +Name[et]=Halltooni värvimudel (16-bitine) +Name[fa]=مدل رنگ مقیاس خاکستری )عدد صحیح ۱۶ بیتی( +Name[fi]=Harmaasävyvärimalli (16-bittinen) +Name[fr]=Modèle de couleurs en nivaux de gris (entiers 16 bits) +Name[fy]=Kleurmodel foar griiswearden (16-bit yntegers) +Name[gl]=Modelo de Cores en Escala de Gris (inteiro de 16-bit) +Name[he]=מודל צבעים של גווני אפור )16 סיביות( +Name[hu]=Szürkeárnyalatos színmodell (16 bites egész) +Name[is]=Gráskala litategund (16-bita heiltala) +Name[it]=Modello di colore a scala di grigio (intero a 16 bit) +Name[ja]=グレースケール カラーモデル (16 ビット整数) +Name[km]=គំរូ​ពណ៌​មាត្រដ្ឋានប្រផេះ (ចំនួនគត់ ១៦ ប៊ីត) +Name[nb]=Fargemodell med gråtoner (16-bit heltall) +Name[nds]=Griestöön-Klöörmodell (16-Bit Heeltall) +Name[ne]=ग्रेस्केल रङ मोडेल (१६-बिट इन्टिजर) +Name[nl]=Kleurmodel voor grijswaarden (16-bit integers) +Name[pl]=Skala szarości (16-bitowa liczba całkowita) +Name[pt]=Modelo de Cor de Tons de Cinzento (inteiros de 16 bits) +Name[pt_BR]=Modelo de Cor de Tons de Cinza (inteiros de 16 bits) +Name[ru]=Градации серого (целое 16-бит) +Name[se]=Ránesivdnemálle (16-bihttá lohku) +Name[sk]=Čiernobiely/šedý model farieb (16-bitové čísla) +Name[sl]=Sivinski barvni model (16-bitno celo število) +Name[sr]=Модел боја у сивим нијансама (16-битно целобројно) +Name[sr@Latn]=Model boja u sivim nijansama (16-bitno celobrojno) +Name[sv]=Färgmodell med gråskala (16-bitars heltal) +Name[uk]=Модель кольору відтінків сірого (16-бітне ціле число) +Name[uz]=Kul rang usuli (16-bit butun) +Name[uz@cyrillic]=Кул ранг усули (16-бит бутун) +Name[zh_CN]=灰度色彩模型(16 位整数) +Name[zh_TW]=灰階色彩模型 (16-bit 整數) +Comment=Color model for 16-bit integer per channel Grayscale images +Comment[bg]=Цветови модел за 16 битови изображения в сива гама +Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges d'escala de grisos +Comment[cy]=Model lliw ar gyfer delweddau Graddlwyd â chyfanrif 16-did/sianel +Comment[da]=Farvemodel for 16-bit heltal pr kanal Gråskala-billeder +Comment[de]=Farbmodell für 16-bit Ganzzahl pro Kanal Graustufen-Bilder +Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι με διαβαθμίσεις του γκρι εικόνες +Comment[en_GB]=Colour model for 16-bit integer per channel Greyscale images +Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes de escala de grises +Comment[et]=16-bitiste täisarvuliste kanalitega halltoonis piltide värvimudel +Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی در هر تصویر مقیاس خاکستری مجرا +Comment[fi]=Värimalli 16-bittisille harmaasävykuville +Comment[fr]=Modèle de couleurs pour des images en nivaux de gris à 16 bits/plage +Comment[fy]=Kleurmodel foar16-bit/kanaal griiswearde-ôfbeeldings +Comment[gl]=Modelo de cor para imaxes en escala de grises de 16-bit por canal +Comment[he]=מודל צבעים עבור תמונות של 16 סיביות בגווני אפור +Comment[hu]=Színmodell 16 bit/csatorna szürkeárnyalatos képekhez +Comment[is]=Litategund fyrir 16-bita heiltölu á rás gráskala myndir +Comment[it]=Modello di colore per immagini in scala di grigio a canale di 16 bit +Comment[ja]=16 ビット整数/チャンネル グレースケール画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព​មាត្រដ្ឋាន​ប្រផេះ​ចំនួន​គត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល +Comment[nb]=Fargemodell for gråtonebilde med 16 bit per kanal +Comment[nds]=Klöörmodell för Griestöön-Biller mit 16-Bit Heeltall per Kanaal +Comment[ne]=प्रति च्यानल ग्रेस्केल छविहरूका १६-बिट च्यानलका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 16-bit/kanaal grijswaarde-afbeeldingen +Comment[pl]=Przestrzeń barw dla obrazków w skali szarości z 16-bitową liczbą całkowitą na kanał +Comment[pt]=Modelo de cor para imagens de tons de cinzento com 16 bits por canal +Comment[pt_BR]=Modelo de cor para imagens de tons de cinza com 16 bits por canal +Comment[ru]=Цветовое пространство градаций серого (целое 16-бит/канал) +Comment[sk]=Model farieb pre ČB/šedé obrázky so 16 bitmi na kanál +Comment[sl]=Barvni model za 16-bitna cela števila/kanal sivinske slike +Comment[sr]=Модел боја за слике у сивим нијансама, 16-битно целобројно по каналу +Comment[sr@Latn]=Model boja za slike u sivim nijansama, 16-bitno celobrojno po kanalu +Comment[sv]=Färgmodell för 16-bitars heltal per kanal gråskalebilder +Comment[uk]=Модель кольору для зображень відтінків сірого, 16-біт/канал +Comment[zh_CN]=每通道 16 位整数的灰度图像色彩模型 +Comment[zh_TW]=每色頻為 16-bit 的灰階圖片色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-Chalk-Version=2 +X-KDE-Library=chalk_gray_u16_plugin diff --git a/chalk/colorspaces/gray_u16/gray_u16_plugin.cc b/chalk/colorspaces/gray_u16/gray_u16_plugin.cc new file mode 100644 index 00000000..436caf5d --- /dev/null +++ b/chalk/colorspaces/gray_u16/gray_u16_plugin.cc @@ -0,0 +1,63 @@ +/* +* gray_u16_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* +* This program is free software; you can grayistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include + +#include +#include + +#include "gray_u16_plugin.h" +#include "kis_gray_u16_colorspace.h" + +typedef KGenericFactory GRAYU16PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_gray_u16_plugin, GRAYU16PluginFactory( "chalk" ) ) + + +GRAYU16Plugin::GRAYU16Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(GRAYU16PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceGRAYU16 = new KisGrayU16ColorSpace(f, 0); + KisColorSpaceFactory * csf = new KisGrayU16ColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceGRAYU16); + f->add(csf); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("GRAYA16HISTO", i18n("GRAY/Alpha16")), colorSpaceGRAYU16) ); + } + +} + +GRAYU16Plugin::~GRAYU16Plugin() +{ +} + +#include "gray_u16_plugin.moc" diff --git a/chalk/colorspaces/gray_u16/gray_u16_plugin.h b/chalk/colorspaces/gray_u16/gray_u16_plugin.h new file mode 100644 index 00000000..39ef6c2a --- /dev/null +++ b/chalk/colorspaces/gray_u16/gray_u16_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can grayistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GRAY_U16_PLUGIN_H_ +#define GRAY_U16_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the GRAY U16 colour space strategy. + */ +class GRAYU16Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + GRAYU16Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~GRAYU16Plugin(); + +}; + + +#endif // GRAY_U16_PLUGIN_H_ diff --git a/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.cc b/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.cc new file mode 100644 index 00000000..00f3440c --- /dev/null +++ b/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.cc @@ -0,0 +1,658 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include +#include + +#include "kis_gray_u16_colorspace.h" +#include "kis_u16_base_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" +#include "kis_colorspace_factory_registry.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_GRAY = 1; + const TQ_INT32 MAX_CHANNEL_GRAYA = 2; +} + +KisGrayU16ColorSpace::KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU16BaseColorSpace(KisID("GRAYA16", i18n("Grayscale (16-bit integer/channel)")), TYPE_GRAYA_16, icSigGrayData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Gray"), i18n("G"), PIXEL_GRAY * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + +/* LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); + cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); + cmsFreeGamma(Gamma); +*/ + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + +KisGrayU16ColorSpace::~KisGrayU16ColorSpace() +{ +} + +void KisGrayU16ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalGray = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + TQ_UINT32 alpha = pixel->alpha; + TQ_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights)); + + totalGray += UINT16_MULT(pixel->gray, alphaTimesWeight); + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > 0) { + totalGray = UINT16_DIVIDE(totalGray, newAlpha); + } + + dstPixel->gray = totalGray; +} + +void KisGrayU16ColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, + TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalGray = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalGray += pixel->gray * weight; + totalAlpha += pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->gray = CLAMP( ( totalGray / factor) + offset, 0, TQ_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX); + } +} + + +void KisGrayU16ColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->gray = TQ_UINT16_MAX - p->gray; + src += psize; + } +} + + + +TQ_UINT8 KisGrayU16ColorSpace::intensity8(const TQ_UINT8 * src) const +{ + const Pixel * p = reinterpret_cast( src ); + return UINT16_TO_UINT8(p->gray); +} + + +TQValueVector KisGrayU16ColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisGrayU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_GRAYA; +} + +TQ_UINT32 KisGrayU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_GRAY; +} + +TQ_UINT32 KisGrayU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_GRAYA * sizeof(TQ_UINT16); +} + +void KisGrayU16ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_GRAYA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_GRAY * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_GRAY] = UINT16_BLEND(src[PIXEL_GRAY], dst[PIXEL_GRAY], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_GRAYA; + dst += MAX_CHANNEL_GRAYA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); \ + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + TQ_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += MAX_CHANNEL_GRAYA; \ + dst += MAX_CHANNEL_GRAYA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisGrayU16ColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + TQ_UINT16 srcColor = src[PIXEL_GRAY]; + TQ_UINT16 dstColor = dst[PIXEL_GRAY]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[PIXEL_GRAY] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisGrayU16ColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + + +void KisGrayU16ColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisGrayU16ColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisGrayU16ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} diff --git a/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.h b/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.h new file mode 100644 index 00000000..5c2351da --- /dev/null +++ b/chalk/colorspaces/gray_u16/kis_gray_u16_colorspace.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can grayistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_GRAY_U16_H_ +#define KIS_STRATEGY_COLORSPACE_GRAY_U16_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_u16_base_colorspace.h" +#include "kis_integer_maths.h" + + +class KRITATOOL_EXPORT KisGrayU16ColorSpace : public KisU16BaseColorSpace { +public: + + struct Pixel { + TQ_UINT16 gray; + TQ_UINT16 alpha; + }; + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + +public: + KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisGrayU16ColorSpace(); + +public: + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + friend class KisGrayU16ColorSpaceTester; + + static const TQ_UINT8 PIXEL_GRAY = 0; + static const TQ_UINT8 PIXEL_ALPHA = 1; +}; + +class KisGrayU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("GRAYA16", i18n("Grayscale (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_GRAY_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisGrayU16ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "gray built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_GRAY_U16_H_ diff --git a/chalk/colorspaces/gray_u8/Makefile.am b/chalk/colorspaces/gray_u8/Makefile.am new file mode 100644 index 00000000..adce3031 --- /dev/null +++ b/chalk/colorspaces/gray_u8/Makefile.am @@ -0,0 +1,31 @@ +kde_services_DATA = chalkgrayplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + -I$(interfacedir) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libchalkgrayscale.la +libchalkgrayscale_la_SOURCES = kis_gray_colorspace.cc +libchalkgrayscale_la_LDFLAGS = $(all_libraries) +libchalkgrayscale_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +kde_module_LTLIBRARIES = chalkgrayplugin.la + +chalkgrayplugin_la_SOURCES = gray_plugin.cc +noinst_HEADERS = gray_plugin.h kis_gray_colorspace.h + +chalkgrayplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalkgrayplugin_la_LIBADD = libchalkgrayscale.la ../../chalkcolor/libchalkcolor.la + +chalkgrayplugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . templates $(TESTSDIR) + diff --git a/chalk/colorspaces/gray_u8/chalkgrayplugin.desktop b/chalk/colorspaces/gray_u8/chalkgrayplugin.desktop new file mode 100644 index 00000000..58a6d992 --- /dev/null +++ b/chalk/colorspaces/gray_u8/chalkgrayplugin.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Name=Grayscale Color Model +Name[bg]=Цветови модел със степени на сивото +Name[ca]=Model de color d'escala de grisos +Name[cy]=Model Lliw Graddlwyd +Name[da]=Farvemodel med gråskala +Name[de]=Graustufen-Farbmodell +Name[el]=Χρωματικό μοντέλο διαβαθμίσεων του γκρι +Name[en_GB]=Greyscale Colour Model +Name[eo]=Grizoskala kolormodelo +Name[es]=Modelo de color de escala de grises +Name[et]=Halltooni värvimudel +Name[eu]=Gris-eskala kolore-eredua +Name[fa]=مدل رنگ مقیاس خاکستری +Name[fi]=Harmaasävyvärimalli +Name[fr]=Modèle de couleurs en niveaux de gris +Name[fy]=Griiswearden kleurmodel +Name[gl]=Modelo de Cores en Escala de Gris +Name[he]=מודל צבעים של גווני אפור +Name[hi]=श्वेत-श्याम रंग नमूना +Name[hu]=Szürkeárnyalatos színmodell +Name[is]=Gráskala litategund +Name[it]=Modello di colore in scala di grigio +Name[ja]=グレースケール カラーモデル +Name[km]=គំរូ​ពណ៌​មាត្រដ្ឋាន​ប្រផេះ +Name[lv]=Pelēktoņu krāsu modelis +Name[ms]=Model Warna Skala Kelabu +Name[nb]=Fargemodell med gråtoner +Name[nds]=Griestöön-Klöörmodell +Name[ne]=ग्रेस्केल रङ मोडेल +Name[nl]=Grijswaarden kleurmodel +Name[nn]=Fargemodell med gråtonar +Name[pl]=Skala szarości +Name[pt]=Modelo de Cor de Tons de Cinzento +Name[pt_BR]=Modelo de Cor em Tons de Cinza +Name[ru]=Градации серого +Name[se]=Ránesivnniid ivdnemálle +Name[sk]=Model farieb ČB/šedý +Name[sl]=Sivinski barvni model +Name[sr]=Модел боја за сиве нијансе +Name[sr@Latn]=Model boja za sive nijanse +Name[sv]=Gråskalefärgmodell +Name[ta]=பழுப்புநிற வண்ண மாதிரி +Name[tr]=Griton Renk Modeli +Name[uk]=Модель кольору "відтінки сірого" +Name[uz]=Kul rang usuli +Name[uz@cyrillic]=Кул ранг усули +Name[zh_CN]=灰度色彩模型 +Name[zh_TW]=灰階色彩模型 +Comment=Color model for 8-bit grayscale images +Comment[bg]=Цветови модел за 8 битови сиви изображения +Comment[ca]=Model de color d'escala de grisos de 8 bits +Comment[cy]=Model lliw ar gyfer delweddau graddlwyd 8-did +Comment[da]=Farvemodel for 8-bit gråskala-billeder +Comment[de]=Farbmodell für 8-bit Graustufenbilder +Comment[el]=Χρωματικό μοντέλο για 8-bit με διαβαθμίσεις του γκρι εικόνες +Comment[en_GB]=Colour model for 8-bit greyscale images +Comment[eo]=Kolormodelo por 8-bitaj grizoskalaj bildoj +Comment[es]=Modelo de color de imágenes de escala de grises para 8 bits +Comment[et]=8-bitiste halltoonis piltide värvimudel +Comment[eu]=8 bit/kanaleko gris-eskalako irudien kolore-eredua +Comment[fa]=مدل رنگ برای تصاویر مقیاس خاکستری ۸ بیتی +Comment[fi]=Värimalli 8-bittisille harmaasävykuville +Comment[fr]=Modèle de couleurs pour des images en niveaux de gris 8 bits +Comment[fy]=Kleurmodel foar ôfbeeldings yn 8-bit griiswearden +Comment[gl]=Modelo de Cores de escala de gris de for 8-bit +Comment[he]=מודל צבעים עבור תמונות של 8 סיביות בגווני אפור +Comment[hi]=8-बिट श्वेत-श्याम छवियों के लिए रंग नमूना +Comment[hu]=Színmodell 8 bites szürkeárnyalatos képekhez +Comment[is]=Litategund fyrir 8-bita gráskala myndir +Comment[it]=Modello di colore per immagini a 8 bit in scala di grigio +Comment[ja]=8 ビット グレースケール画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព​មាត្រដ្ឋាន​ប្រផេះ ៨ ប៊ីត +Comment[ms]=Model warna bagi imej skala kelabu 8-bit +Comment[nb]=Fargemodell for 8-bits gråtonebilder +Comment[nds]=Klöörmodell för Griestöön-Biller mit 8-Bit Heeltall +Comment[ne]=८-बिट ग्रेस्केल छविहरूका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor afbeeldingen in 8-bit grijswaarden +Comment[nn]=Fargemodell for 8-bits gråtonebilete +Comment[pl]=Przestrzeń braw dla 8-bitowych obrazków w skali szarości +Comment[pt]=Modelo de cor para imagens de tons de cinzento com 8 bits +Comment[pt_BR]=Modelo de cor para imagens com 8-bits de tons de cinza +Comment[ru]=Цветовое пространство градаций серого (8-бит) +Comment[sk]=Model farieb pre ČB/šedé obrázky s 8 bitmi na kanál +Comment[sl]=Barvni model za 8 bitne sivinske slike +Comment[sr]=Модел боја за слике у 8-битним сивим нијансама +Comment[sr@Latn]=Model boja za slike u 8-bitnim sivim nijansama +Comment[sv]=Färgmodell för 8-bitars gråskalebilder +Comment[ta]=8-பிட் பழுப்புநிற பிம்பங்களுக்கு வண்ண மாதிரி +Comment[tr]=8-bit griton görüntüler için renk modeli. +Comment[uk]=Модель кольору зображень відтінків сірого (8-бітів) +Comment[zh_CN]=8 位灰度图像的色彩模型 +Comment[zh_TW]=8-bit 灰階圖片的色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkgrayplugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/gray_u8/gray_plugin.cc b/chalk/colorspaces/gray_u8/gray_plugin.cc new file mode 100644 index 00000000..0028c597 --- /dev/null +++ b/chalk/colorspaces/gray_u8/gray_plugin.cc @@ -0,0 +1,77 @@ +/* + * gray_plugin.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gray_plugin.h" +#include "kis_gray_colorspace.h" + +typedef KGenericFactory GrayPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkgrayplugin, GrayPluginFactory( "chalkcore" ) ) + + +GrayPlugin::GrayPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(GrayPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + // .22 gamma grayscale or something like that. Taken from the lcms tutorial... + LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2); + cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma); + cmsFreeGamma(Gamma); + KisProfile *defProfile = new KisProfile(hProfile); + + f->addProfile(defProfile); + + KisColorSpace * colorSpaceGrayA = new KisGrayColorSpace(f, 0); + + KisColorSpaceFactory * csf = new KisGrayColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceGrayA); + + f->add(csf); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("GRAYA8HISTO", i18n("GRAY/Alpha8")), colorSpaceGrayA) ); + } + +} + +GrayPlugin::~GrayPlugin() +{ +} + +#include "gray_plugin.moc" diff --git a/chalk/colorspaces/gray_u8/gray_plugin.h b/chalk/colorspaces/gray_u8/gray_plugin.h new file mode 100644 index 00000000..f18bf77c --- /dev/null +++ b/chalk/colorspaces/gray_u8/gray_plugin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef GRAY_PLUGIN_H_ +#define GRAY_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the GRAY colour space strategy. + */ +class GrayPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + GrayPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~GrayPlugin(); + +}; + +#endif // GRAY_PLUGIN_H_ diff --git a/chalk/colorspaces/gray_u8/grayplugin.rc b/chalk/colorspaces/gray_u8/grayplugin.rc new file mode 100644 index 00000000..8d4562cd --- /dev/null +++ b/chalk/colorspaces/gray_u8/grayplugin.rc @@ -0,0 +1,7 @@ + + +&Image + &Mode + + + diff --git a/chalk/colorspaces/gray_u8/kis_gray_colorspace.cc b/chalk/colorspaces/gray_u8/kis_gray_colorspace.cc new file mode 100644 index 00000000..dbd475df --- /dev/null +++ b/chalk/colorspaces/gray_u8/kis_gray_colorspace.cc @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include LCMS_HEADER + +#include + +#include +#include +#include + +#include "kis_abstract_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_gray_colorspace.h" +#include "kis_integer_maths.h" + +#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL)) +#define upscale(value) (value) // ((TQ_UINT8) (257UL*(value))) + +namespace { + const TQ_INT32 MAX_CHANNEL_GRAYSCALE = 1; + const TQ_INT32 MAX_CHANNEL_GRAYSCALEA = 2; +} + +KisGrayColorSpace::KisGrayColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU8BaseColorSpace(KisID("GRAYA", i18n("Grayscale")), TYPE_GRAYA_8, icSigGrayData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Gray"), i18n("G"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 1, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + + m_alphaPos = PIXEL_GRAY_ALPHA; + + init(); +} + + +KisGrayColorSpace::~KisGrayColorSpace() +{ +} + +void KisGrayColorSpace::setPixel(TQ_UINT8 *pixel, TQ_UINT8 gray, TQ_UINT8 alpha) const +{ + pixel[PIXEL_GRAY] = gray; + pixel[PIXEL_GRAY_ALPHA] = alpha; +} + +void KisGrayColorSpace::getPixel(const TQ_UINT8 *pixel, TQ_UINT8 *gray, TQ_UINT8 *alpha) const +{ + *gray = pixel[PIXEL_GRAY]; + *alpha = pixel[PIXEL_GRAY_ALPHA]; +} + +void KisGrayColorSpace::getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const +{ + *alpha = pixel[PIXEL_GRAY_ALPHA]; +} + +void KisGrayColorSpace::setAlpha(TQ_UINT8 *pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + while (nPixels > 0) { + pixels[PIXEL_GRAY_ALPHA] = alpha; + --nPixels; + pixels += MAX_CHANNEL_GRAYSCALEA; + } +} + +void KisGrayColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalGray = 0, newAlpha = 0; + + while (nColors--) + { + TQ_UINT32 alpha = (*colors)[PIXEL_GRAY_ALPHA]; + TQ_UINT32 alphaTimesWeight = UINT8_MULT(alpha, *weights); + + totalGray += (*colors)[PIXEL_GRAY] * alphaTimesWeight; + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= 255); + + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha > 0) { + totalGray = UINT8_DIVIDE(totalGray, newAlpha); + } + + // Divide by 255. + totalGray += 0x80; + TQ_UINT32 dstGray = ((totalGray >> 8) + totalGray) >> 8; + Q_ASSERT(dstGray <= 255); + dst[PIXEL_GRAY] = dstGray; +} + +void KisGrayColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalGray = 0, totalAlpha = 0; + + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalGray += (*colors)[PIXEL_GRAY] * weight; + totalAlpha += (*colors)[PIXEL_GRAY_ALPHA] * weight; + } + colors++; + kernelValues++; + } + + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + dst[PIXEL_GRAY] = CLAMP((totalGray / factor) + offset, 0, TQ_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_GRAY_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } + +} + + +void KisGrayColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_GRAY] = TQ_UINT8_MAX - src[PIXEL_GRAY]; + src += psize; + } +} + +void KisGrayColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ + TQ_UINT32 pSize = pixelSize(); + + while (nPixels--) { + if (compensate) { + dst[PIXEL_GRAY] = (TQ_INT8) TQMIN(255,((src[PIXEL_GRAY] * shade) / (compensation * 255))); + } + else { + dst[PIXEL_GRAY] = (TQ_INT8) TQMIN(255, (src[PIXEL_GRAY] * shade / 255)); + } + dst += pSize; + src += pSize; + } +} + +TQ_UINT8 KisGrayColorSpace::intensity8(const TQ_UINT8 * src) const +{ + return src[PIXEL_GRAY]; +} + +TQValueVector KisGrayColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisGrayColorSpace::nChannels() const +{ + return MAX_CHANNEL_GRAYSCALEA; +} + +TQ_UINT32 KisGrayColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_GRAYSCALE; +} + +TQ_UINT32 KisGrayColorSpace::pixelSize() const +{ + return MAX_CHANNEL_GRAYSCALEA; +} + +void KisGrayColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: { + TQ_UINT8 *d; + TQ_INT32 linesize; + + linesize = MAX_CHANNEL_GRAYSCALEA*sizeof(TQ_UINT8) * cols; + d = dst; + while (rows-- > 0) { + memset(d, 0, linesize); + d += dstRowStride; + } + } + break; + case COMPOSITE_ALPHA_DARKEN: + compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + + default: + break; + } +} + +KisCompositeOpList KisGrayColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + + return list; +} + +void KisGrayColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_GRAYSCALEA * sizeof(TQ_UINT8)); + } else { + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_GRAYSCALE * sizeof(TQ_UINT8)); + } else { + dst[PIXEL_GRAY] = UINT8_BLEND(src[PIXEL_GRAY], dst[PIXEL_GRAY], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + TQ_UINT8 srcColor = src[PIXEL_GRAY]; + TQ_UINT8 dstColor = dst[PIXEL_GRAY]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[PIXEL_GRAY] = UINT8_BLEND(srcColor, dstColor, srcBlend); + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1)) / (1 + srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor)); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = kMin(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX); + srcColor = kClamp(UINT8_MAX - srcColor, 0u, UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_GRAY_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisGrayColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/) +{ + TQ_INT32 i; + TQ_UINT8 srcAlpha; + + while (rows-- > 0) + { + const TQ_UINT8 *s = src; + TQ_UINT8 *d = dst; + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (i = cols; i > 0; i--, s+=MAX_CHANNEL_GRAYSCALEA, d+=MAX_CHANNEL_GRAYSCALEA) + { + srcAlpha = s[PIXEL_GRAY_ALPHA]; + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *tqmask); + tqmask++; + } + d[PIXEL_GRAY_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_GRAY_ALPHA]); + } + + dst += dstRowSize; + if(srcAlphaMask) + srcAlphaMask += tqmaskRowStride; + src += srcRowSize; + } +} + +void KisGrayColorSpace::compositeAlphaDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, + const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA]; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha != OPACITY_TRANSPARENT && srcAlpha >= dstAlpha) { + dst[PIXEL_GRAY_ALPHA] = srcAlpha; + memcpy(dst, src, MAX_CHANNEL_GRAYSCALE * sizeof(TQ_UINT8)); + } + + columns--; + src += MAX_CHANNEL_GRAYSCALEA; + dst += MAX_CHANNEL_GRAYSCALEA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} diff --git a/chalk/colorspaces/gray_u8/kis_gray_colorspace.h b/chalk/colorspaces/gray_u8/kis_gray_colorspace.h new file mode 100644 index 00000000..8a3bc34b --- /dev/null +++ b/chalk/colorspaces/gray_u8/kis_gray_colorspace.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_ +#define KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_ +#include + +#include + +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" +#include "kis_u8_base_colorspace.h" + +class KRITACORE_EXPORT KisGrayColorSpace : public KisU8BaseColorSpace { +public: + KisGrayColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisGrayColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence /*independence*/) + { + return false; + }; + +public: + + void setPixel(TQ_UINT8 *pixel, TQ_UINT8 gray, TQ_UINT8 alpha) const; + void getPixel(const TQ_UINT8 *pixel, TQ_UINT8 *gray, TQ_UINT8 *alpha) const; + + virtual void getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dststride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + KisCompositeOpList userVisiblecompositeOps() const; + +protected: + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeAlphaDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + + +private: + friend class KisGrayColorSpaceTester; + + static const TQ_UINT8 PIXEL_GRAY = 0; + static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1; +}; + +class KisGrayColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("GRAYA", i18n("Grayscale (8-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_GRAYA_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisGrayColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "gray built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_ diff --git a/chalk/colorspaces/gray_u8/templates/.directory b/chalk/colorspaces/gray_u8/templates/.directory new file mode 100644 index 00000000..e408f23f --- /dev/null +++ b/chalk/colorspaces/gray_u8/templates/.directory @@ -0,0 +1,48 @@ +[Desktop Entry] +Name=Grayscale +Name[bg]=Гама на сивото +Name[br]=SkeulLouet +Name[ca]=Escala de grisos +Name[cy]=Graddlwyd +Name[da]=Gråskala +Name[de]=Graustufen +Name[el]=Διαβαθμίσεις του γκρι +Name[eo]=Grizoskalo +Name[es]=Escala de grises +Name[et]=Halltoonid +Name[fa]=مقیاس خاکستری +Name[fi]=Harmaasävyinen +Name[fr]=Niveaux de gris +Name[fy]=Griiswearden +Name[ga]=Liathscála +Name[gl]=Escala de Gris +Name[he]=גווני אפור +Name[hi]=श्वेत-श्याम +Name[hu]=Szürkeárnyalatok +Name[is]=Gráskali +Name[it]=Scala di grigio +Name[ja]=グレースケール +Name[km]=មាត្រដ្ឋាន​ប្រផេះ​ +Name[lv]=Pelēktoņu +Name[nb]=Gråtoner +Name[nds]=Griestöön +Name[ne]=ग्रेस्केल +Name[nl]=Grijswaarden +Name[pl]=Skala szarości +Name[pt]=Tons de Cinzento +Name[pt_BR]=Tons de Cinza +Name[ru]=Градации серого +Name[se]=Ránesivnnit +Name[sk]=Čiernobiely +Name[sl]=Sivinska +Name[sr]=Сиве нијансе +Name[sr@Latn]=Sive nijanse +Name[sv]=Gråskala +Name[ta]=பழுப்புநிற வண்ணம் +Name[tr]=Griton +Name[uk]=Відтінки сірого +Name[uz]=Oq-qora +Name[uz@cyrillic]=Оқ-қора +Name[zh_CN]=灰度 +Name[zh_TW]=灰階 +X-KDE-DefaultTab=true diff --git a/chalk/colorspaces/gray_u8/templates/Makefile.am b/chalk/colorspaces/gray_u8/templates/Makefile.am new file mode 100644 index 00000000..ab5be17b --- /dev/null +++ b/chalk/colorspaces/gray_u8/templates/Makefile.am @@ -0,0 +1,8 @@ +templates_DATA = .directory white_640x480.desktop +templatesdir = $(kde_datadir)/chalk/templates/gray + +templatesrc_DATA =white_640x480.kra +templatesrcdir = $(kde_datadir)/chalk/templates/gray/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/chalk/icons diff --git a/chalk/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png b/chalk/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png new file mode 100644 index 00000000..73e064b6 Binary files /dev/null and b/chalk/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png differ diff --git a/chalk/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz b/chalk/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz new file mode 100644 index 00000000..93af227f Binary files /dev/null and b/chalk/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz differ diff --git a/chalk/colorspaces/gray_u8/templates/white_640x480.desktop b/chalk/colorspaces/gray_u8/templates/white_640x480.desktop new file mode 100644 index 00000000..1da17a33 --- /dev/null +++ b/chalk/colorspaces/gray_u8/templates/white_640x480.desktop @@ -0,0 +1,99 @@ +[Desktop Entry] +Type=Link +URL=.source/white_640x480.kra +Icon=template_gray_empty +Name=White Background, 640 x 480 +Name[bg]=Бял фон, 640x480 +Name[ca]=Fons blanc, 640 x 480 +Name[cy]=Cefndir Gwyn, 640 x 480 +Name[da]=Hvid baggrund, 640 x 480 +Name[de]=Weißer Hintergrund, 640 x 480 +Name[el]=Λευκό φόντο, 640 x 480 +Name[eo]=Blanka fono, 640 x 480 +Name[es]=Fondo blanco, 640 x 480 +Name[et]=Valge taust, 640 x 480 +Name[eu]=Atzeko plano zuria, 640 x 480 +Name[fa]=زمینۀ سفید، ۴۸۰ × ۶۴۰ +Name[fi]=Valkoinen tausta, 640 x 480 +Name[fr]=Fond blanc 640 x 480 +Name[fy]=Wite eftergrûn, 640 x 480 +Name[ga]=Cúlra Bán, 640×480 +Name[gl]=Fondo Branco, 640 x 480 +Name[he]=רקע לבן, ‎640 x 480 +Name[hi]=सफेद पृष्ठभूमि, 640 x 480 +Name[hu]=Fehér háttér, 640 x 480 +Name[is]=Hvítur bakgrunnur, 640 x 480 +Name[it]=Sfondo bianco, 640 × 480 +Name[ja]=白い背景 640 x 480 +Name[km]=ផ្ទៃខាងក្រោយ​ពណ៌​ស, 640 x 480 +Name[lt]=Baltas fonas, 640 x 480 +Name[lv]=Balts fons, 640x480 +Name[ms]=Latar Belakang Putih, 640 x 480 +Name[nb]=Hvit bakgrunn, 640 x 480 +Name[nds]=Witt Achtergrund, 640 x 480 +Name[ne]=सेतो पृष्ठभूमि, ६४० x ४८० +Name[nl]=Witte achtergrond, 640 x 480 +Name[nn]=Kvit bakgrunn, 640 × 480 +Name[pl]=Białe tło, 640 x 480 +Name[pt]=Fundo Branco, 640 x 480 +Name[pt_BR]=Fundo em branco, 640 x 480 +Name[ru]=Рисунок 640x480, белый фон +Name[se]=Vilges duogáš, 640 × 480 +Name[sk]=Biele pozadie, 640 x 480 +Name[sl]=Belo ozadje, 640 x 480 +Name[sr]=Бела позадина, 640 x 480 +Name[sr@Latn]=Bela pozadina, 640 x 480 +Name[sv]=Vit bakgrund, 640 x 480 +Name[ta]=வெள்ளை பின்னணி, 640 x 480 +Name[tr]=Beyaz Arkaplan, 640 x 480 +Name[uk]=Біле тло, 640 x 480 +Name[uz]=Oq orqa fon 640 x 480 +Name[uz@cyrillic]=Оқ орқа фон 640 x 480 +Name[zh_CN]=白色背景,640 x 480 +Name[zh_TW]=白色背景, 640 x 480 +Comment=Creates an image of 640 x 480 pixels with a white background. +Comment[bg]=Създаване на изображение с размери 640x480 пиксела и бял фон. +Comment[ca]=Crea una imatge de 640 x 480 píxels amb el fons blanc. +Comment[cy]=Creu delwedd o 640 x 480 o bicseli efo cefndir gwyn. +Comment[da]=Laver et billede på 640 x 480 billedpunkter med en hvid baggrund. +Comment[de]=Erstellt ein Bild mit 640 x 480 Pixeln mit einem weißen Hintergrund. +Comment[el]=Δημιουργεί μία εικόνα μεγέθους 640 x 480 εικονοστοιχείων με λευκό φόντο. +Comment[es]=Crea una imagen de 640 x 480 píxeles con un fondo blanco. +Comment[et]=Loob valge taustaga pildi mõõtmetega 640 x 800 pikslit. +Comment[eu]=640 x 480 pixeleko atzeko planoa zuria duen irudi bat sortzen du. +Comment[fa]=تصویری ۴۸۰ × ۶۴۰ تصویردانه‌ای با یک زمینۀ سفید ایجاد می‌کند. +Comment[fi]=Luo 640 x 480 pikselin kuvan valkoisella taustalla. +Comment[fr]=Crée une image de 640 x 480 pixels avec un fond blanc. +Comment[fy]=Makket in ôfbylding oan fan 640 x 480 byldpunten, mei in wite eftergrûn +Comment[gl]=Cria unha imaxe de 640 x 480 pixels cun fondo branco. +Comment[he]=יצירת תמונת בגודל ‎640 x 480 פיקסלים עם רקע לבן +Comment[hi]=640 x 480 पिक्सेल का, सफेद पृष्ठभूमि युक्त छवि बनाता है +Comment[hu]=Létrehoz egy 640 x 480 képpontos képet fehér háttérrel. +Comment[is]=Býr til hvíta mynd í 640 x 480 punkta upplausn með hvítum bakgrunni. +Comment[it]=Crea un'immagine di 640 × 480 pixel con uno sfondo bianco. +Comment[ja]=640 x 480 ピクセルの白い背景の画像を作成 +Comment[km]=បង្កើត​រូបភាព​ទំហំ 640 x 480 ភីកសែល ដែល​មាន​ផ្ទៃ​ខាង​ក្រោយ​ពណ៌​ស ។ +Comment[ms]=Cipta imej 640 x 480 piksel dengan latar belakang putih. +Comment[nb]=Lager et bilde på 640 x 480 piksler med hvit bakgrunn. +Comment[nds]=Stellt en Bild mit 640 x 480 Pixels mit witten Achtergrund op. +Comment[ne]=सेतो पृष्ठभूमि सहित ६४० x ४८० पिक्सेलको छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een afbeelding aan van 640 x 480 pixels, met een witte achtergrond. +Comment[nn]=Lagar eit bilete på 640 × 480 pikslar med ein kvit bakgrunn. +Comment[pl]=Tworzy obrazek z białym tłem o rozmiarach 640 x 480 pikseli. +Comment[pt]=Cria uma imagem de 640 x 480 pontos com um fundo branco. +Comment[pt_BR]=Cria uma imagem de 640 x 480 pixéis com um fundo branco. +Comment[ru]=Рисунок 640x480, белый фон +Comment[se]=Ráhkada vilges govva mas leat 640 × 480 govvačuogga. +Comment[sk]=Vytvorí obrázok s rozmermi 640 x 480 pixelov a bielym pozadím. +Comment[sl]=Ustvari sliko velikosti 640 x 480 pik z belim ozadjem. +Comment[sr]=Прави слику од 640 x 480 пиксела са белом позадином. +Comment[sr@Latn]=Pravi sliku od 640 x 480 piksela sa belom pozadinom. +Comment[sv]=Skapar en bild med 640 x 480 bildpunkter och en vit bakgrund. +Comment[ta]=640 x 480 படத்துணுக்குகளில் வெள்ளை பின்னணியுடன் ஒரு பிம்பத்தை உருவாக்குகிறது. +Comment[tr]=640 x 480 piksel ebadında beyaz arkaplana sahip bir görüntü oluşturur +Comment[uk]=Створює зображення 640 x 480 пікселів з білим тлом. +Comment[uz]=Oʻlchami 640 x 480 nuqta va foni oq boʻlgan rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта ва фони оқ бўлган расмни яратиш. +Comment[zh_CN]=创建白色背景的 640 x 480 像素的图像。 +Comment[zh_TW]=建立一個 640 x 480 像素,白色背景的圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/gray_u8/templates/white_640x480.kra b/chalk/colorspaces/gray_u8/templates/white_640x480.kra new file mode 100644 index 00000000..534368ef Binary files /dev/null and b/chalk/colorspaces/gray_u8/templates/white_640x480.kra differ diff --git a/chalk/colorspaces/gray_u8/tests/Makefile.am b/chalk/colorspaces/gray_u8/tests/Makefile.am new file mode 100644 index 00000000..35e83689 --- /dev/null +++ b/chalk/colorspaces/gray_u8/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_strategy_colorspace_grayscale_tester.la + +kunittest_kis_strategy_colorspace_grayscale_tester_la_SOURCES = kis_strategy_colorspace_grayscale_tester.cpp +kunittest_kis_strategy_colorspace_grayscale_tester_la_LIBADD = -lkunittest ../libchalkgrayscale.la +kunittest_kis_strategy_colorspace_grayscale_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_strategy_colorspace_grayscale_tester.la + kunittestmodrunner + diff --git a/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp b/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp new file mode 100644 index 00000000..0374c072 --- /dev/null +++ b/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_factory.h" +#include "kis_strategy_colorspace_grayscale_tester.h" +#include "kis_gray_colorspace.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_grayscale_tester, "Greyscale ColorSpace Tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisGrayColorSpaceTester ); + +void KisGrayColorSpaceTester::allTests() +{ + // We need this so that the colour profile loading can operate without crashing. + KisFactory *factory = new KisFactory(); + + testBasics(); + testMixColors(); + + delete factory; +} + +#define MAX_CHANNEL_GRAYSCALEA 2 + +#define GRAY_CHANNEL 0 +#define ALPHA_CHANNEL 1 + +void KisGrayColorSpaceTester::testBasics() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + KisGrayColorSpace *cs = new KisGrayColorSpace(profile); + + + TQ_UINT8 pixel[MAX_CHANNEL_GRAYSCALEA]; + + pixel[KisGrayColorSpace::PIXEL_GRAY] = 255; + pixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 128; + + TQString valueText = cs->channelValueText(pixel, GRAY_CHANNEL); + CHECK(valueText, TQString("255")); + + valueText = cs->channelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, TQString("128")); + + valueText = cs->normalisedChannelValueText(pixel, GRAY_CHANNEL); + CHECK(valueText, TQString().setNum(1.0)); + + valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(128.0 / 255.0)); + + cs->setPixel(pixel, 128, 192l); + CHECK((uint)pixel[KisGrayColorSpace::PIXEL_GRAY], 128u); + CHECK((uint)pixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 192u); + + TQ_UINT8 gray; + TQ_UINT8 alpha; + + cs->getPixel(pixel, &gray, &alpha); + CHECK((uint)gray, 128u); + CHECK((uint)alpha, 192u); + + delete cs; +} + +void KisGrayColorSpaceTester::testMixColors() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + KisAbstractColorSpace * cs = new KisGrayColorSpace(profile); + + TQ_UINT8 pixel1[MAX_CHANNEL_GRAYSCALEA]; + TQ_UINT8 pixel2[MAX_CHANNEL_GRAYSCALEA]; + TQ_UINT8 outputPixel[MAX_CHANNEL_GRAYSCALEA]; + + pixel1[KisGrayColorSpace::PIXEL_GRAY] = 255; + pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255; + + pixel2[KisGrayColorSpace::PIXEL_GRAY] = 0; + pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 0; + + const TQ_UINT8 *pixelPtrs[2]; + TQ_UINT8 weights[2]; + + pixelPtrs[0] = pixel1; + pixelPtrs[1] = pixel2; + + weights[0] = 255; + weights[1] = 0; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255); + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 255); + + weights[0] = 0; + weights[1] = 255; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 0); + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 0); + + weights[0] = 128; + weights[1] = 127; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255); + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 128); + + pixel1[KisGrayColorSpace::PIXEL_GRAY] = 200; + pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255; + + pixel2[KisGrayColorSpace::PIXEL_GRAY] = 100; + pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 150); + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 255); + + pixel1[KisGrayColorSpace::PIXEL_GRAY] = 0; + pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 0; + + pixel2[KisGrayColorSpace::PIXEL_GRAY] = 255; + pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 254; + + weights[0] = 89; + weights[1] = 166; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255); + CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 165); +} + + diff --git a/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h b/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h new file mode 100644 index 00000000..9b5f8d5e --- /dev/null +++ b/chalk/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_STRATEGY_COLORSPACE_GRAYSCALE_TESTER_H +#define KIS_STRATEGY_COLORSPACE_GRAYSCALE_TESTER_H + +#include + +class KisGrayColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testMixColors(); + void testBasics(); +}; + +#endif + diff --git a/chalk/colorspaces/lms_f32/Makefile.am b/chalk/colorspaces/lms_f32/Makefile.am new file mode 100644 index 00000000..537ba370 --- /dev/null +++ b/chalk/colorspaces/lms_f32/Makefile.am @@ -0,0 +1,28 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = chalk_lms_f32_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libchalk_lms_f32.la +libchalk_lms_f32_la_SOURCES = kis_lms_f32_colorspace.cc +libchalk_lms_f32_la_LDFLAGS = $(all_libraries) +libchalk_lms_f32_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_lms_f32_plugin.la + +# Srcs for the plugin +chalk_lms_f32_plugin_la_SOURCES = lms_f32_plugin.cc +noinst_HEADERS = lms_f32_plugin.h kis_lms_f32_colorspace.h + +chalk_lms_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_lms_f32_plugin_la_LIBADD = libchalk_lms_f32.la ../../chalkcolor/libchalkcolor.la + +chalk_lms_f32_plugin_la_METASOURCES = AUTO + diff --git a/chalk/colorspaces/lms_f32/chalk_lms_f32_plugin.desktop b/chalk/colorspaces/lms_f32/chalk_lms_f32_plugin.desktop new file mode 100644 index 00000000..9f4dab25 --- /dev/null +++ b/chalk/colorspaces/lms_f32/chalk_lms_f32_plugin.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Name=LMS Color Model (32-bit float) +Name[bg]=Цветови модел LMS (32 бита) +Name[ca]=Model de color LMS (paleta de 32 bits) +Name[cy]=Model Lliw LMS (arnawf 32-did) +Name[da]=LMS-farvemodel (32-bit float) +Name[de]=LMS-Farbmodell (32-bit Fließkomma) +Name[el]=Χρωματικό μοντέλο LMS (32 bit δεκαδικοί) +Name[en_GB]=LMS Colour Model (32-bit float) +Name[eo]=LMS-kolormodelo (32-bita flupunkto) +Name[es]=Modelo de color LMS (decimal de 32 bits) +Name[et]=LMS värvimudel (32-bitine murdarv) +Name[fa]=مدل رنگ LMS )شناور ۳۲ بیتی( +Name[fr]=Modèle de couleurs LMS (flottants 32 bits) +Name[fy]=LMS-kleurmodel (32-bit float) +Name[gl]=Modelo de Cores LMS (vírgula flutuante 32-bit) +Name[he]=מודל צבעים LMS (32 סיביות) +Name[hu]=LMS színmodell (32 bites lebegőpontos) +Name[is]=LMS litategund (32-bita fleytitala) +Name[it]=Modello di colore LMS (virgola mobile a 32 bit) +Name[ja]=LMS カラーモデル (32 ビット浮動小数) +Name[km]=គំរូ​ពណ៌ LMS (ចំនួន​ទស្សភាគ ៣២ ប៊ីត) +Name[nb]=LMS-fargemodell (32-bit flyttall) +Name[nds]=LMS-Klöörmodell (32-Bit Fleetkomma) +Name[ne]=LMS रङ मोडेल (३२-बिट उत्प्लावन) +Name[nl]=LMS-kleurmodel (32-bit float) +Name[pl]=Przestrzeń barw LMS (32-bitowa liczba zmiennoprzecinkowa) +Name[pt]=Modelo de Cor LMS (v. flutuante de 32-bits) +Name[pt_BR]=Modelo de Cor LMS (ponto flutuante de 32-bits) +Name[ru]=LMS (32-бит с плавающей точкой) +Name[sk]=Model farieb LMS (32-bitové reálne čísla) +Name[sl]=Barvni model LMS (32-bitna decimalno število) +Name[sr]=LMS модел боја (32-битно реално) +Name[sr@Latn]=LMS model boja (32-bitno realno) +Name[sv]=LMS-färgmodell (32-bitars flyttal) +Name[uk]=Модель кольору LMS (32-бітне дробове число) +Name[uz]=LMS rang usuli (32-bit kasr) +Name[uz@cyrillic]=LMS ранг усули (32-бит каср) +Name[zh_CN]=LMS 色彩模型(32 位浮点) +Name[zh_TW]=LMS 色彩模型 (32-bit 浮點數) +Comment=Color model for LMS cone space (Long Middle and Short wavelengths) +Comment[bg]=Цветови модел за интервали LMS (дълги, средни и къси вълни) +Comment[ca]=Model de color per a conus d'espai LMC (amples d'ona llargs, mitjos i curts) +Comment[cy]=Model lliw ar gyfer gofod côn LMS (tonfeddi Hir, Canolig a Byr) +Comment[da]=Farvemodel for LMS-keglerum (Lange, mellemliggende og korte bølgelængder) +Comment[de]=Farbmodell für LMS cone space (Lange, Mittelere und Kurze Wellenlängen) +Comment[el]=Χρωματικό μοντέλο για χώρο χρωμάτων LMS (Μακρά μεσαία και σύντομα μήκη κύματος) +Comment[en_GB]=Colour model for LMS cone space (Long Middle and Short wavelengths) +Comment[es]=Modelo de color para el espacio cónico LMS (con longitudes de onda larga, media y corta) +Comment[et]=LMS koonuse (pikad, keskmised ja lühikesed lainepikkused) värvimudel +Comment[fa]=مدل رنگ برای فضای مخروط LMS )طول موج بلند، متوسط و کوتاه( +Comment[fr]=Modèle de couleurs pour l'espace conique LMS (longueurs d'ondes longues, moyennes et courtes) +Comment[fy]=Kleurmodel Foar LMS-kegelromte (lange, middelt en koarte golflingten) +Comment[gl]=Modelo de Cores para o espazo do cone LMS (Long Middle and Short wavelengths) +Comment[hu]=Színmodell az LMS kúptérhez (hosszú, közepes és rövid hullámhosszak) +Comment[is]=Litategund fyrir LMS keilubil (löng miðlungs og stutt bylgjulengd) +Comment[it]=Modello di colore per lo spazio conico LMS (lunghezze d'onda lunghe, medie e corte) +Comment[km]=មូដែល​ពណ៌​សម្រាប់ LMS ដែល​មាន​ចន្លោះ​រាង​សាជី​មូល​ (ប្រវែង​រលក​ខ្លី និង​ពាក់​កណ្ដាល​វែង) +Comment[nb]=Fargemodell for LMS-kjeglerom (Long Middle og Short bølgelengder) +Comment[nds]=Klöörmodell för LMS-Kegelruum (Lang, middel un kort Bülgenlängden) +Comment[ne]=LMS शंकु खाली स्थान (लामो मध्य र छोटो तरङलम्बाइहरू) का लागि रङ मोडेल +Comment[nl]=Kleurmodel voor LMS-kegelruimte (lange, middel en korte golflengten) +Comment[pl]=Przestrzeń barw dla przestrzeni stożkowej LMS (średnie długie i krótkie długości fal) +Comment[pt]=Modelo de cor para o espaço cónico do LMS (comprimentos de onda longos, médios e curtos) +Comment[pt_BR]=Modelo de cor para o espaço cônico do LMS (comprimentos de onda longos, médios e curtos) +Comment[ru]=Цветовое пространство LMS (Long Middle and Short wavelengths) +Comment[sk]=Model farieb pre LMS kónický priestor (dlhé, stredné a krátke vlnové dĺžky) +Comment[sl]=Barvni model za prostor stožca LMS (dolge, srednje in kratke valovne dolžine) +Comment[sr]=Модел боја за LMS конусни простор (дуге средње и кратке таласне дужине) +Comment[sr@Latn]=Model boja za LMS konusni prostor (duge srednje i kratke talasne dužine) +Comment[sv]=Färgmodell för LMS-konrymd (Långa, mellanliggande och korta våglängder) +Comment[uk]=Модель кольорів для конусного простору LMS (довгі середні і короткі довжини кольорів) +Comment[zh_TW]=LMS cone space 顏色模式(Long Middle and Short 波長) +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_lms_f32_plugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.cc b/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.cc new file mode 100644 index 00000000..57475a03 --- /dev/null +++ b/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.cc @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Adrian Page + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_lms_f32_colorspace.h" +#include "kis_color_conversions.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_LMS = 3; + const TQ_INT32 MAX_CHANNEL_LMSA = 4; +} + +#include "kis_integer_maths.h" + +#define FLOAT_MAX 1.0f //temp + +#define EPSILON 1e-6 + +// FIXME: lcms doesn't support 32-bit float +#define F32_LCMS_TYPE TYPE_BGRA_16 + +// disable the lcms handling by setting profile=0 +KisLmsF32ColorSpace::KisLmsF32ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile */*p*/) : + KisF32BaseColorSpace(KisID("LMSAF32", i18n("LMS (32-bit float/channel)")), F32_LCMS_TYPE, icSig3colorData, tqparent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Long"), i18n("L"), PIXEL_LONGWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Middle"), i18n("M"), PIXEL_MIDDLEWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Short"), i18n("S"), PIXEL_SHORTWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(float), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT32, sizeof(float))); + + m_alphaPos = PIXEL_ALPHA * sizeof(float); +} + +KisLmsF32ColorSpace::~KisLmsF32ColorSpace() +{ +} + +void KisLmsF32ColorSpace::setPixel(TQ_UINT8 *dst, float longWave, float middleWave, float shortWave, float alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->longWave = longWave; + dstPixel->middleWave = middleWave; + dstPixel->shortWave = shortWave; + dstPixel->alpha = alpha; +} + +void KisLmsF32ColorSpace::getPixel(const TQ_UINT8 *src, float *longWave, float *middleWave, float *shortWave, float *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *longWave = srcPixel->longWave; + *middleWave = srcPixel->middleWave; + *shortWave = srcPixel->shortWave; + *alpha = srcPixel->alpha; +} + +void KisLmsF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile * /*profile*/) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->longWave = computeLong(c.red(),c.green(),c.blue()); + dst->middleWave = computeMiddle(c.red(),c.green(),c.blue()); + dst->shortWave = computeShort(c.red(),c.green(),c.blue()); +} + +void KisLmsF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile * /*profile*/) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->longWave = computeLong(c.red(),c.green(),c.blue()); + dst->middleWave = computeMiddle(c.red(),c.green(),c.blue()); + dst->shortWave = computeShort(c.red(),c.green(),c.blue()); + dst->alpha = UINT8_TO_FLOAT(opacity); +} + +void KisLmsF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile * /*profile*/) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave)); +} + +void KisLmsF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave)); + *opacity = FLOAT_TO_UINT8(src->alpha); +} + +TQ_UINT8 KisLmsF32ColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return FLOAT_TO_UINT8(TQMAX(TQABS(src2->longWave - src1->longWave), + TQMAX(TQABS(src2->middleWave - src1->middleWave), + TQABS(src2->shortWave - src1->shortWave)))); +} + +void KisLmsF32ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + float totalLong = 0, totalMiddle = 0, totalShort = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + float alpha = pixel->alpha; + float alphaTimesWeight = alpha * UINT8_TO_FLOAT(*weights); + + totalLong += pixel->longWave * alphaTimesWeight; + totalMiddle += pixel->middleWave * alphaTimesWeight; + totalShort += pixel->shortWave * alphaTimesWeight; + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= F32_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > EPSILON) { + totalLong = totalLong / newAlpha; + totalMiddle = totalMiddle / newAlpha; + totalShort = totalShort / newAlpha; + } + + dstPixel->longWave = totalLong; + dstPixel->middleWave = totalMiddle; + dstPixel->shortWave = totalShort; +} + +TQValueVector KisLmsF32ColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisLmsF32ColorSpace::nChannels() const +{ + return MAX_CHANNEL_LMSA; +} + +TQ_UINT32 KisLmsF32ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_LMS; +} + +TQ_UINT32 KisLmsF32ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_LMSA * sizeof(float); +} + +TQImage KisLmsF32ColorSpace::convertToTQImage(const TQ_UINT8 *dataU8, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float /*exposure*/) + +{ + const float *data = reinterpret_cast(dataU8); + + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + while ( i < width * height * MAX_CHANNEL_LMSA) { + double l = *( data + i + PIXEL_LONGWAVE ); + double m = *( data + i + PIXEL_MIDDLEWAVE ); + double s = *( data + i + PIXEL_SHORTWAVE ); + *( j + 3) = FLOAT_TO_UINT8(*( data + i + PIXEL_ALPHA )); + *( j + 2 ) = computeRed(l,m,s); + *( j + 1 ) = computeGreen(l,m,s); + *( j + 0 ) = computeBlue(l,m,s); + i += MAX_CHANNEL_LMSA; + j += MAX_CHANNEL_LMSA; + } + + /* + if (srcProfile != 0 && dstProfile != 0) { + convertPixelsTo(img.bits(), srcProfile, + img.bits(), this, dstProfile, + width * height, renderingIntent); + } + */ + return img; +} + + +void KisLmsF32ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + while (rows > 0) { + + const float *src = reinterpret_cast(srcRowStart); + float *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + float srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_FLOAT(U8_tqmask); + } + tqmask++; + } + + if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) { + + if (opacity < F32_OPACITY_OPAQUE - EPSILON) { + srcAlpha *= opacity; + } + + if (srcAlpha > F32_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_LMSA * sizeof(float)); + } else { + float dstAlpha = dst[PIXEL_ALPHA]; + + float srcBlend; + + if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) { + srcBlend = srcAlpha; + } else { + float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha; + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha > EPSILON) { + srcBlend = srcAlpha / newAlpha; + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend > F32_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_LMS * sizeof(float)); + } else { + dst[PIXEL_LONGWAVE] = FLOAT_BLEND(src[PIXEL_LONGWAVE], dst[PIXEL_LONGWAVE], srcBlend); + dst[PIXEL_MIDDLEWAVE] = FLOAT_BLEND(src[PIXEL_MIDDLEWAVE], dst[PIXEL_MIDDLEWAVE], srcBlend); + dst[PIXEL_SHORTWAVE] = FLOAT_BLEND(src[PIXEL_SHORTWAVE], dst[PIXEL_SHORTWAVE], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_LMSA; + dst += MAX_CHANNEL_LMSA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +void KisLmsF32ColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + float /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + float srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_tqmask)); + } + tqmask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisLmsF32ColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, + const TQ_UINT8 */*tqmaskRowStart*/, TQ_INT32 /*tqmaskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, float /*opacity*/) +{ + while (rows > 0) { + memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel)); + --rows; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + } +} + +void KisLmsF32ColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + float opacity = UINT8_TO_FLOAT(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +KisCompositeOpList KisLmsF32ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + return list; +} + diff --git a/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.h b/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.h new file mode 100644 index 00000000..36e9a01c --- /dev/null +++ b/chalk/colorspaces/lms_f32/kis_lms_f32_colorspace.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Adrian Page + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_LMS_F32_H_ +#define KIS_STRATEGY_COLORSPACE_LMS_F32_H_ + +#include + +#include + +#include + +#include "kis_global.h" +#include "kis_f32_base_colorspace.h" + +class KisColorSpaceFactoryRegistry; + +class KRITATOOL_EXPORT KisLmsF32ColorSpace : public KisF32BaseColorSpace { +public: + KisLmsF32ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisLmsF32ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + +public: + void setPixel(TQ_UINT8 *pixel, float longWave, float middleWave, float shortWave, float alpha) const; + void getPixel(const TQ_UINT8 *pixel, float *longWave, float *middleWave, float *shortWave, float *alpha) const; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual bool hasHighDynamicRange() const { return false; } + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + +private: + inline TQ_UINT8 computeRed(float l, float m, float s) const + { + return FLOAT_TO_UINT8(4.4679*l - 3.58738*m + 0.1193*s); + } + inline TQ_UINT8 computeGreen(float l, float m, float s) const + { + return FLOAT_TO_UINT8(-1.2186*l + 2.3809*m - 0.1624*s); + } + inline TQ_UINT8 computeBlue(float l, float m, float s) const + { + return FLOAT_TO_UINT8(0.0497*l - 0.2439*m + 1.2045*s); + } + inline float computeLong(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b) const + { + return 0.3811*UINT8_TO_FLOAT(r) + 0.5783*UINT8_TO_FLOAT(g) + 0.0402*UINT8_TO_FLOAT(b); + } + inline float computeMiddle(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b) const + { + return 0.1967*UINT8_TO_FLOAT(r) + 0.7244*UINT8_TO_FLOAT(g) + 0.0782*UINT8_TO_FLOAT(b); + } + inline float computeShort(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b) const + { + return 0.0241*UINT8_TO_FLOAT(r) + 0.1288*UINT8_TO_FLOAT(g) + 0.8444*UINT8_TO_FLOAT(b); + } + + friend class KisLmsF32ColorSpaceTester; + + static const TQ_UINT8 PIXEL_LONGWAVE = 0; + static const TQ_UINT8 PIXEL_MIDDLEWAVE = 1; + static const TQ_UINT8 PIXEL_SHORTWAVE = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + float longWave; + float middleWave; + float shortWave; + float alpha; + }; +}; + +class KisLmsF32ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("LMSAF32", i18n("LMS Cone Space (32-bit float/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return 0; }; // FIXME: lcms do not support LMS cone space + + virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisLmsF32ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_LMS_F32_H_ + diff --git a/chalk/colorspaces/lms_f32/lms_f32_plugin.cc b/chalk/colorspaces/lms_f32/lms_f32_plugin.cc new file mode 100644 index 00000000..d137c8e8 --- /dev/null +++ b/chalk/colorspaces/lms_f32/lms_f32_plugin.cc @@ -0,0 +1,64 @@ +/* +* lms_f32_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* Copyright (c) 2005 Cyrille Berger +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "lms_f32_plugin.h" +#include "kis_lms_f32_colorspace.h" + +typedef KGenericFactory LMSF32PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_lms_f32_plugin, LMSF32PluginFactory( "chalk" ) ) + + +LMSF32Plugin::LMSF32Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(LMSF32PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(tqparent); + + KisColorSpace * colorSpaceLMSF32 = new KisLmsF32ColorSpace(f, 0); + + KisColorSpaceFactory * csf = new KisLmsF32ColorSpaceFactory(); + f->add(csf); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("LMSF32HISTO", i18n("Float32")), colorSpaceLMSF32) ); + } + +} + +LMSF32Plugin::~LMSF32Plugin() +{ +} + +#include "lms_f32_plugin.moc" diff --git a/chalk/colorspaces/lms_f32/lms_f32_plugin.h b/chalk/colorspaces/lms_f32/lms_f32_plugin.h new file mode 100644 index 00000000..7d9229a6 --- /dev/null +++ b/chalk/colorspaces/lms_f32/lms_f32_plugin.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef LMS_F32_PLUGIN_H_ +#define LMS_F32_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the LMS F32 colour space strategy. + */ +class LMSF32Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + LMSF32Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~LMSF32Plugin(); + +}; + + +#endif // LMS_F32_PLUGIN_H_ diff --git a/chalk/colorspaces/lms_f32/lms_f32_plugin.rc b/chalk/colorspaces/lms_f32/lms_f32_plugin.rc new file mode 100644 index 00000000..ec36156c --- /dev/null +++ b/chalk/colorspaces/lms_f32/lms_f32_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/chalk/colorspaces/rgb_f16half/Makefile.am b/chalk/colorspaces/rgb_f16half/Makefile.am new file mode 100644 index 00000000..2c3bbfa1 --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/Makefile.am @@ -0,0 +1,35 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = chalk_rgb_f16half_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(OPENEXR_CFLAGS) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libchalk_rgb_f16half.la +libchalk_rgb_f16half_la_SOURCES = kis_rgb_f16half_colorspace.cc +libchalk_rgb_f16half_la_LDFLAGS = $(all_libraries) +libchalk_rgb_f16half_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_rgb_f16half_plugin.la + +# Srcs for the plugin +chalk_rgb_f16half_plugin_la_SOURCES = rgb_f16half_plugin.cc +noinst_HEADERS = rgb_f16half_plugin.h kis_rgb_f16half_colorspace.h + +chalk_rgb_f16half_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_rgb_f16half_plugin_la_LIBADD = libchalk_rgb_f16half.la ../../chalkcolor/libchalkcolor.la + +chalk_rgb_f16half_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/chalk/colorspaces/rgb_f16half/chalk_rgb_f16half_plugin.desktop b/chalk/colorspaces/rgb_f16half/chalk_rgb_f16half_plugin.desktop new file mode 100644 index 00000000..523903bf --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/chalk_rgb_f16half_plugin.desktop @@ -0,0 +1,76 @@ +[Desktop Entry] +Name=RGB Color Model (16-bit float 'half') +Name[bg]=Цветови модел RGB (16-bit float 'half') +Name[ca]=Model de color RGB (paleta 'mitja' de 16 bits) +Name[cy]=Model Lliw RGB (arnawf 16-did 'hanner') +Name[da]=RGB-farvemodel (16-bit heltal 'halv') +Name[de]=RGB-Farbmodell (16-bit Fließkomma 'Halb') +Name[el]=Χρωματικό μοντέλο RGB (16 bit μισοί δεκαδικοί) +Name[en_GB]=RGB Colour Model (16-bit float 'half') +Name[es]=Modelo de color RGB (decimal «medio» de 16 bits) +Name[et]=RGB värvimudel (16-bitine murdarv 'half') +Name[fa]=مدل رنگ RGB )»نیمه« شناور ۱۶ بیتی( +Name[fr]=Modèle de couleurs RVB (demi flottants 16 bits) +Name[fy]=RGB-kleurmodel (16-bit float 'heal') +Name[gl]=Modelo de Cores RGB (vírgula flutuante 16-bit 'half') +Name[he]=מודל צבעים RGB (16 סיביות) +Name[hu]=RGB színmodell (16 bites lebegőpontos - 'feles') +Name[is]=RGB litategund (16-bita fleytitala) +Name[it]=Modello di colore RGB (semi-virgola mobile a 16 bit) +Name[ja]=RGB カラーモデル (16-bit float 'half') +Name[km]=ម៉ូដែល​ពណ៌​RGB (ចំនួន​ទសភាគ 16 ប៊ីត​ 'ពាក់​កណ្ដាល') +Name[nb]=RGB-fargemodell (16-bit flytende 'halv') +Name[nds]=RGB-Klöörmodell (16-Bit Fleetkomma "half") +Name[ne]=RGB रङ मोडेल (१६-बिट उत्प्लावन 'आधा') +Name[nl]=RGB-kleurmodel (16-bit float 'half') +Name[pl]=Przestrzeń barw RGB ("połowa" 16-bitowej liczby zmiennoprzecinkowej) +Name[pt]=Modelo de Cor RGB (v. flutuante de 16-bits 'half') +Name[pt_BR]=Modelo de Cor RGB (ponto flutuante de 16-bits 'half') +Name[ru]=RGB (16-бит с плавающей точкой) +Name[sk]=Model farieb RGB (16-bitové reálne čísla 'half') +Name[sl]=Barvni model RGB (16-bitno celo število, »polovica«) +Name[sr]=RGB модел боја (16-битно реално „полу“) +Name[sr@Latn]=RGB model boja (16-bitno realno „polu“) +Name[sv]=RGB-färgmodell (16-bitars flyttal 'halva') +Name[uk]=Модель кольору RGB (16-бітне дробове число "half") +Name[uz]=RGB rang usuli (16-bit 'yarim' kasr) +Name[uz@cyrillic]=RGB ранг усули (16-бит 'ярим' каср) +Name[zh_TW]=RGB 色彩模型 (32-bit 浮點數「半」) +Comment=Color model for 16-bit floating point 'half' per channel RGB images +Comment[bg]=Цветови модел за 16 битови изображения RGB за полуканал +Comment[ca]=Model de color per a paleta 'mitja' de 16 bits-canal d'imatges RGB +Comment[da]=Farvemodel for 16-bit decimaltal 'halvdel' pr kanal RGB-billeder +Comment[de]=Farbmodell für 16-bit Fließkomma 'Halb' pro Kanal RGB-Bilder +Comment[el]=Χρωματικό μοντέλο για 16-bit μισούς δεκαδικούς ανά κανάλι RGB εικόνες +Comment[en_GB]=Colour model for 16-bit floating point 'half' per channel RGB images +Comment[es]=Modelo de color decimal «medio» de 16 bits por canal para imágenes RGB +Comment[et]=16-bitiste murdarvuliste ('half') kanalitega RGB-piltide värvimudel +Comment[fa]=مدل رنگ برای ممیز »نیمه« شناور برای هر تصویر RGB مجرا +Comment[fi]=Värimalli 16-bittisille/kanavaisille RGB-kuville +Comment[fr]=Modèle de couleurs pour des images RVB en 16 bits flottants (demi) par canal +Comment[fy]=Kleurmodel foar RGB-ôfbeeldings mei 16-bit driuwende komma 'heal' de kanaal +Comment[gl]=Espazo de cores para imaxes RGB de 16-bit de vírgula flutuante 'half' por canal +Comment[he]=מודל צבעים עבור תמונות RGB של 16 סיביות/ערוצים +Comment[hu]=Színmodell 16 bit (lebegőpontos, 'feles')/csatorna RGB képekhez +Comment[is]=Litategund fyrir 16-bita fleytitölu á rás RGB myndir +Comment[it]=Modello di colore per immagini RGB in semi-virgola mobile a canale di 16 bit +Comment[km]=ម៉ូលដែល​ពណ៌​ 16 ប៊ីត​ចំណុច​ដែល​អណ្ដែត​ 'ពាក្យ​កណ្ដាល' ក្នុង​ឆានែល​រូបភាព​ RGB +Comment[nb]=Fargemodell for RGB-bilde med 16 bit flyttall 'halv' per kanal +Comment[nds]=Klöörmodell för RGB-Biller mit 16-Bit Fleetkomma "half" per Kanaal +Comment[ne]='आधा' प्रति च्यानल RGB छविहरूको १६-बिट उत्प्लावन बिन्दुका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 16-bit drijvende komma 'half' per kanaal +Comment[pl]=Przestrzeń barw dla obrazków RGB z "połową" 16-bitowej liczby zmiennoprzecinkowej na kanał +Comment[pt]=Modelo de cor para imagens RGB com 16 bits de vírgula flutuante 'half' por canal +Comment[pt_BR]=Modelo de cor para imagens RGB com 16 bits de ponto flutuante 'half' por canal +Comment[ru]=Цветовое пространство RGB (16-бит/канал с плавающей точкой) +Comment[sk]=Model farieb pre RGB obrázky so 16-bitovými reálnymi číslami 'half' na kanál +Comment[sl]=Barvni model za slike RGB s 16-bitno plavajočo vejico na kanal +Comment[sr]=Модел боја за RGB слике, 16-битно реално „полу“ по каналу +Comment[sr@Latn]=Model boja za RGB slike, 16-bitno realno „polu“ po kanalu +Comment[sv]=Färgmodell för 16-bitars flyttal 'halva' per kanal RGB-bilder +Comment[uk]=Модель кольорів для 16-бітних зображень RGB, з плаваючою комою, "половина" на канал +Comment[zh_TW]=每色頻 16-bit 半浮點 RGB 圖片的色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_rgb_f16half_plugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc b/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc new file mode 100644 index 00000000..fb2df8c1 --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_rgb_f16half_colorspace.h" +#include "kis_f32_base_colorspace.h" +#include "kis_color_conversions.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_RGB = 3; + const TQ_INT32 MAX_CHANNEL_RGBA = 4; +} + +#include "kis_integer_maths.h" + +#ifndef HAVE_POWF +#undef powf +#define powf pow +#endif + +//#define HALF_MAX ((half)1.0f) //temp + +#define EPSILON HALF_EPSILON + +// FIXME: lcms doesn't support 16-bit float +#define RGBAF16HALF_LCMS_TYPE TYPE_BGRA_16 + +KisRgbF16HalfColorSpace::KisRgbF16HalfColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisF16HalfBaseColorSpace(KisID("RGBAF16HALF", i18n("RGB (16-bit float/channel)")), RGBAF16HALF_LCMS_TYPE, icSigRgbData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(half), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT16, sizeof(half))); + + //cmsHPROFILE hProfile = cmsCreate_sRGBProfile(); + //setDefaultProfile( new KisProfile(hProfile, RGBAF16HALF_LCMS_TYPE) ); + + m_alphaPos = PIXEL_ALPHA * sizeof(half); +} + +KisRgbF16HalfColorSpace::~KisRgbF16HalfColorSpace() +{ +} + +void KisRgbF16HalfColorSpace::setPixel(TQ_UINT8 *dst, half red, half green, half blue, half alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->red = red; + dstPixel->green = green; + dstPixel->blue = blue; + dstPixel->alpha = alpha; +} + +void KisRgbF16HalfColorSpace::getPixel(const TQ_UINT8 *src, half *red, half *green, half *blue, half *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *red = srcPixel->red; + *green = srcPixel->green; + *blue = srcPixel->blue; + *alpha = srcPixel->alpha; +} + +void KisRgbF16HalfColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile *) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->red = UINT8_TO_HALF(c.red()); + dst->green = UINT8_TO_HALF(c.green()); + dst->blue = UINT8_TO_HALF(c.blue()); +} + +void KisRgbF16HalfColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile *) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->red = UINT8_TO_HALF(c.red()); + dst->green = UINT8_TO_HALF(c.green()); + dst->blue = UINT8_TO_HALF(c.blue()); + dst->alpha = UINT8_TO_HALF(opacity); +} + +void KisRgbF16HalfColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile *) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(HALF_TO_UINT8(src->red), HALF_TO_UINT8(src->green), HALF_TO_UINT8(src->blue)); +} + +void KisRgbF16HalfColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile *) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(HALF_TO_UINT8(src->red), HALF_TO_UINT8(src->green), HALF_TO_UINT8(src->blue)); + *opacity = HALF_TO_UINT8(src->alpha); +} + +TQ_UINT8 KisRgbF16HalfColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return HALF_TO_UINT8(TQMAX(TQABS(src2->red - src1->red), + TQMAX(TQABS(src2->green - src1->green), + TQABS(src2->blue - src1->blue)))); +} + +void KisRgbF16HalfColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + half totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + half alpha = pixel->alpha; + half alphaTimesWeight = alpha * UINT8_TO_HALF(*weights); + + totalRed += pixel->red * alphaTimesWeight; + totalGreen += pixel->green * alphaTimesWeight; + totalBlue += pixel->blue * alphaTimesWeight; + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= F16HALF_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > EPSILON) { + totalRed = totalRed / newAlpha; + totalGreen = totalGreen / newAlpha; + totalBlue = totalBlue / newAlpha; + } + + dstPixel->red = totalRed; + dstPixel->green = totalGreen; + dstPixel->blue = totalBlue; +} + +void KisRgbF16HalfColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + half totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + half weight = *kernelValues; + + if (weight != 0) { + totalRed += pixel->red * UINT8_TO_HALF(weight); + totalGreen += pixel->green * UINT8_TO_HALF(weight); + totalBlue += pixel->blue * UINT8_TO_HALF(weight); + totalAlpha += pixel->alpha * UINT8_TO_HALF(weight); + } + colors++; + kernelValues++; + } + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->red = CLAMP( ( totalRed / factor) + offset, 0, HALF_MAX); + p->green = CLAMP( ( totalGreen / factor) + offset, 0, HALF_MAX); + p->blue = CLAMP( ( totalBlue / factor) + offset, 0, HALF_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, HALF_MAX); + } +} + + +void KisRgbF16HalfColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->red = 1.0 - p->red; + p->green = 1.0 - p->green; + p->blue = 1.0 - p->blue; + src += psize; + } + +} + + +TQ_UINT8 KisRgbF16HalfColorSpace::intensity8(const TQ_UINT8 * src) const +{ + const Pixel * p = reinterpret_cast( src ); + + return HALF_TO_UINT8((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5); +} + + +TQValueVector KisRgbF16HalfColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisRgbF16HalfColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +TQ_UINT32 KisRgbF16HalfColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +TQ_UINT32 KisRgbF16HalfColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(half); +} + +TQ_UINT8 convertToDisplay(float value, float exposureFactor, float gamma) +{ + //value *= pow(2, exposure + 2.47393); + value *= exposureFactor; + + value = powf(value, gamma); + + // scale middle gray to the target framebuffer value + + value *= 84.66f; + + int valueInt = (int)(value + 0.5); + + return CLAMP(valueInt, 0, 255); +} + +TQImage KisRgbF16HalfColorSpace::convertToTQImage(const TQ_UINT8 *dataU8, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float exposure) + +{ + const half *data = reinterpret_cast(dataU8); + + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + // XXX: For now assume gamma 2.2. + float gamma = 1 / 2.2; + float exposureFactor = powf(2, exposure + 2.47393); + + while ( i < width * height * MAX_CHANNEL_RGBA) { + *( j + 3) = HALF_TO_UINT8(*( data + i + PIXEL_ALPHA )); + *( j + 2 ) = convertToDisplay(*( data + i + PIXEL_RED ), exposureFactor, gamma); + *( j + 1 ) = convertToDisplay(*( data + i + PIXEL_GREEN ), exposureFactor, gamma); + *( j + 0 ) = convertToDisplay(*( data + i + PIXEL_BLUE ), exposureFactor, gamma); + i += MAX_CHANNEL_RGBA; + j += MAX_CHANNEL_RGBA; + } + + /* + if (srcProfile != 0 && dstProfile != 0) { + convertPixelsTo(img.bits(), srcProfile, + img.bits(), this, dstProfile, + width * height, renderingIntent); + } + */ + return img; +} + + +void KisRgbF16HalfColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + while (rows > 0) { + + const half *src = reinterpret_cast(srcRowStart); + half *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + half srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_HALF(U8_tqmask); + } + tqmask++; + } + + if (srcAlpha > F16HALF_OPACITY_TRANSPARENT + EPSILON) { + + if (opacity < F16HALF_OPACITY_OPAQUE - EPSILON) { + srcAlpha *= opacity; + } + + if (srcAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(half)); + } else { + half dstAlpha = dst[PIXEL_ALPHA]; + + half srcBlend; + + if (dstAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) { + srcBlend = srcAlpha; + } else { + half newAlpha = dstAlpha + (F16HALF_OPACITY_OPAQUE - dstAlpha) * srcAlpha; + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha > EPSILON) { + srcBlend = srcAlpha / newAlpha; + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend > F16HALF_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(half)); + } else { + dst[PIXEL_RED] = HALF_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend); + dst[PIXEL_GREEN] = HALF_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend); + dst[PIXEL_BLUE] = HALF_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const half *src = reinterpret_cast(srcRowStart); \ + half *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + half srcAlpha = src[PIXEL_ALPHA]; \ + half dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha *= UINT8_TO_HALF(U8_tqmask); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha > F16HALF_OPACITY_TRANSPARENT + EPSILON) { \ + \ + if (opacity < F16HALF_OPACITY_OPAQUE - EPSILON) { \ + srcAlpha *= opacity; \ + } \ + \ + half srcBlend; \ + \ + if (dstAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) { \ + srcBlend = srcAlpha; \ + } else { \ + half newAlpha = dstAlpha + (F16HALF_OPACITY_OPAQUE - dstAlpha) * srcAlpha; \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha > EPSILON) { \ + srcBlend = srcAlpha / newAlpha; \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += MAX_CHANNEL_RGBA; \ + dst += MAX_CHANNEL_RGBA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisRgbF16HalfColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + half srcColor = src[PIXEL_RED]; + half dstColor = dst[PIXEL_RED]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_RED] = HALF_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_GREEN]; + dstColor = dst[PIXEL_GREEN]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_GREEN] = HALF_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_BLUE]; + dstColor = dst[PIXEL_BLUE]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_BLUE] = HALF_BLEND(srcColor, dstColor, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = TQMIN(dstColor / (srcColor + EPSILON), HALF_MAX); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = HALF_MAX - ((HALF_MAX - dstColor) * (HALF_MAX - srcColor)); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = dstColor * (dstColor + 2 * (srcColor * (HALF_MAX - dstColor))); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = TQMIN(dstColor / (HALF_MAX + EPSILON - srcColor), HALF_MAX); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = TQMIN((HALF_MAX - dstColor) / (srcColor + EPSILON), HALF_MAX); + srcColor = CLAMP(HALF_MAX - srcColor, 0, HALF_MAX); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + half srcColor = src[channel]; + half dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + half newColor = HALF_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeHue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeSaturation(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeValue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeColor(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, half opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcLightness; + + float dstHue; + float dstSaturation; + float dstLightness; + + RGBToHSL(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcLightness); + RGBToHSL(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstLightness); + + HSLToRGB(srcHue, srcSaturation, dstLightness, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF16HalfColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + half /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + half srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = HALF_BLEND(srcAlpha, F16HALF_OPACITY_OPAQUE, UINT8_TO_HALF(U8_tqmask)); + } + tqmask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisRgbF16HalfColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + half opacity = UINT8_TO_HALF(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, + U8_opacity, F16HalfMult(), Uint8ToF16Half(), F16HalfOpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisRgbF16HalfColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + list.append(KisCompositeOp(COMPOSITE_HUE)); + list.append(KisCompositeOp(COMPOSITE_SATURATION)); + list.append(KisCompositeOp(COMPOSITE_VALUE)); + list.append(KisCompositeOp(COMPOSITE_COLOR)); + + return list; +} + diff --git a/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h b/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h new file mode 100644 index 00000000..a148a8f9 --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RGB_F16HALF_COLORSPACE_H_ +#define KIS_RGB_F16HALF_COLORSPACE_H_ + +#include + +#include + +#include + +#include "kis_global.h" +#include "kis_f16half_base_colorspace.h" + + +class KRITATOOL_EXPORT KisRgbF16HalfColorSpace : public KisF16HalfBaseColorSpace { +public: + KisRgbF16HalfColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisRgbF16HalfColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + +public: + void setPixel(TQ_UINT8 *pixel, half red, half green, half blue, half alpha) const; + void getPixel(const TQ_UINT8 *pixel, half *red, half *green, half *blue, half *alpha) const; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, half opacity); + +private: + friend class KisRgbF16HalfColorSpaceTester; + + static const TQ_UINT8 PIXEL_BLUE = 0; + static const TQ_UINT8 PIXEL_GREEN = 1; + static const TQ_UINT8 PIXEL_RED = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + half blue; + half green; + half red; + half alpha; + }; +}; + +// FIXME: lcms doesn't support 16-bit float +#define RGBAF16HALF_LCMS_TYPE TYPE_BGRA_16 + +class KisRgbF16HalfColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("RGBAF16HALF", i18n("RGB (16-bit float/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return RGBAF16HALF_LCMS_TYPE; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisRgbF16HalfColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_RGB_F16HALF_COLORSPACE_H_ + diff --git a/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.cc b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.cc new file mode 100644 index 00000000..f50672b9 --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.cc @@ -0,0 +1,63 @@ +/* +* rgb_f32_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "rgb_f16half_plugin.h" +#include "kis_rgb_f16half_colorspace.h" + +typedef KGenericFactory RGBF16HalfPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_rgb_f16half_plugin, RGBF16HalfPluginFactory( "chalk" ) ) + + +RGBF16HalfPlugin::RGBF16HalfPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(RGBF16HalfPluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceRGBF16Half = new KisRgbF16HalfColorSpace(f, 0); + KisColorSpaceFactory *csf = new KisRgbF16HalfColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceRGBF16Half); + f->add(csf); + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("RGBF16HALFHISTO", i18n("Float16 Half")), colorSpaceRGBF16Half) ); + } + +} + +RGBF16HalfPlugin::~RGBF16HalfPlugin() +{ +} + +#include "rgb_f16half_plugin.moc" + diff --git a/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.h b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.h new file mode 100644 index 00000000..a970247c --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef RGB_F16HALF_PLUGIN_H_ +#define RGB_F16HALF_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the RGB F16Half colour space strategy. + */ +class RGBF16HalfPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + RGBF16HalfPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~RGBF16HalfPlugin(); + +}; + + +#endif // RGB_F16HALF_PLUGIN_H_ diff --git a/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.rc b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.rc new file mode 100644 index 00000000..125060ae --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/rgb_f16half_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/chalk/colorspaces/rgb_f16half/tests/Makefile.am b/chalk/colorspaces/rgb_f16half/tests/Makefile.am new file mode 100644 index 00000000..284359ee --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/tests/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../../modules/rgb_f32 \ + $(OPENEXR_CFLAGS) \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_rgb_f16half_colorspace_tester.la + +kunittest_kis_rgb_f16half_colorspace_tester_la_SOURCES = kis_rgb_f16half_colorspace_tester.cc +kunittest_kis_rgb_f16half_colorspace_tester_la_LIBADD = -lkunittest ../libchalk_rgb_f16half.la +kunittest_kis_rgb_f16half_colorspace_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_rgb_f16half_colorspace_tester.la + kunittestmodrunner + diff --git a/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc b/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc new file mode 100644 index 00000000..59eb8e5f --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_factory.h" +#include "kis_rgb_f16half_colorspace.h" +#include "kis_rgb_f16half_colorspace_tester.h" +#include "kis_rgb_f32_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_paint_device.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_rgb_f16half_colorspace_tester, "RGBA 16-bit float half colorspace tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisRgbF16HalfColorSpaceTester ); + +#define PIXEL_BLUE 0 +#define PIXEL_GREEN 1 +#define PIXEL_RED 2 +#define PIXEL_ALPHA 3 + +#define NUM_CHANNELS 4 +#define NUM_COLOUR_CHANNELS 3 +#define CHANNEL_SIZE ((int)sizeof(half)) + +#define RED_CHANNEL 0 +#define GREEN_CHANNEL 1 +#define BLUE_CHANNEL 2 +#define ALPHA_CHANNEL 3 + +//#define MAX_CHANNEL_VALUE 1.0f +//#define MIN_CHANNEL_VALUE 0.0f + +#define CHANNEL_VALUE_ZERO ((half)0) +#define CHANNEL_VALUE_ONE ((half)1) + +void KisRgbF16HalfColorSpaceTester::allTests() +{ + // We need this so that the colour profile loading can operate without crashing. + KisFactory *factory = new KisFactory(); + + testBasics(); + testToTQImage(); + testCompositeOps(); + testMixColors(); + + delete factory; +} + +void KisRgbF16HalfColorSpaceTester::testBasics() +{ + + + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbF16HalfColorSpace *cs = new KisRgbF16HalfColorSpace(profile); + KisAbstractColorSpace * csSP = cs; + + CHECK(cs->hasAlpha(), true); + CHECK(cs->nChannels(), NUM_CHANNELS); + CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS); + CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE); + + TQValueVector channels = cs->channels(); + + // Red + CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE); + CHECK(channels[0]->size(), CHANNEL_SIZE); + CHECK(channels[0]->channelType(), COLOR); + + // Green + CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE); + CHECK(channels[1]->size(), CHANNEL_SIZE); + CHECK(channels[1]->channelType(), COLOR); + + // Blue + CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE); + CHECK(channels[2]->size(), CHANNEL_SIZE); + CHECK(channels[2]->channelType(), COLOR); + + // Alpha + CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE); + CHECK(channels[3]->size(), CHANNEL_SIZE); + CHECK(channels[3]->channelType(), ALPHA); + + KisPaintDeviceSP pd = new KisPaintDevice(cs, "test"); + + KisRgbF16HalfColorSpace::Pixel defaultPixel; + + memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel)); + + CHECK(defaultPixel.red, CHANNEL_VALUE_ZERO); + CHECK(defaultPixel.green, CHANNEL_VALUE_ZERO); + CHECK(defaultPixel.blue, CHANNEL_VALUE_ZERO); + CHECK(defaultPixel.alpha, F16HALF_OPACITY_TRANSPARENT); + + half pixel[NUM_CHANNELS]; + + cs->fromTQColor(tqRgb(255, 255, 255), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + + cs->fromTQColor(tqRgb(0, 0, 0), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ZERO); + CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ZERO); + CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ZERO); + + cs->fromTQColor(tqRgb(128, 64, 192), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], UINT8_TO_HALF(128)); + CHECK(pixel[PIXEL_GREEN], UINT8_TO_HALF(64)); + CHECK(pixel[PIXEL_BLUE], UINT8_TO_HALF(192)); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_ALPHA], F16HALF_OPACITY_TRANSPARENT); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK(pixel[PIXEL_ALPHA], UINT8_TO_HALF(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ONE; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE; + pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE; + + TQColor c; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ZERO; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ZERO; + pixel[PIXEL_BLUE] = CHANNEL_VALUE_ZERO; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ONE / 4; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2; + pixel[PIXEL_BLUE] = (3 * CHANNEL_VALUE_ONE) / 4; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + CHECK(c.green(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + CHECK(c.blue(), (int)HALF_TO_UINT8((3 * CHANNEL_VALUE_ONE) / 4)); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ONE; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE; + pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE; + pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ONE; + + TQ_UINT8 opacity; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_ALPHA] = F16HALF_OPACITY_OPAQUE; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ZERO; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ZERO; + pixel[PIXEL_BLUE] = CHANNEL_VALUE_ZERO; + pixel[PIXEL_ALPHA] = F16HALF_OPACITY_TRANSPARENT; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + CHECK(opacity, OPACITY_TRANSPARENT); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ONE / 4; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2; + pixel[PIXEL_BLUE] = (3 * CHANNEL_VALUE_ONE) / 4; + pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ONE / 2; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + CHECK(c.green(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + CHECK(c.blue(), (int)HALF_TO_UINT8((3 * CHANNEL_VALUE_ONE) / 4)); + CHECK((int)opacity, (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + + #define NUM_PIXELS 4 + + KisRgbF16HalfColorSpace::Pixel pixels[NUM_PIXELS] = { + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4}, + {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2}, + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO}, + {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE} + }; + + cs->setAlpha(reinterpret_cast(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS); + + CHECK(pixels[0].red, CHANNEL_VALUE_ONE); + CHECK(pixels[0].green, CHANNEL_VALUE_ONE); + CHECK(pixels[0].blue, CHANNEL_VALUE_ONE); + CHECK(pixels[0].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2)); + + CHECK(pixels[1].red, (half)(CHANNEL_VALUE_ONE / 3)); + CHECK(pixels[1].green, (half)(CHANNEL_VALUE_ONE / 2)); + CHECK(pixels[1].blue, (half)(CHANNEL_VALUE_ONE / 4)); + CHECK(pixels[1].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2)); + + CHECK(pixels[2].red, CHANNEL_VALUE_ONE); + CHECK(pixels[2].green, CHANNEL_VALUE_ONE); + CHECK(pixels[2].blue, CHANNEL_VALUE_ONE); + CHECK(pixels[2].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2)); + + CHECK(pixels[3].red, CHANNEL_VALUE_ZERO); + CHECK(pixels[3].green, CHANNEL_VALUE_ZERO); + CHECK(pixels[3].blue, CHANNEL_VALUE_ZERO); + CHECK(pixels[3].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = CHANNEL_VALUE_ONE; + pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2; + pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE / 4; + pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ZERO; + + TQString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ZERO)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE / 2)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ONE / 4)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(CHANNEL_VALUE_ZERO)); + + cs->setPixel(reinterpret_cast(pixel), 0.128, 0.192, 0.64, 0.99); + CHECK(pixel[PIXEL_RED], (half)0.128f); + CHECK(pixel[PIXEL_GREEN], (half)0.192f); + CHECK(pixel[PIXEL_BLUE], (half)0.64f); + CHECK(pixel[PIXEL_ALPHA], (half)0.99f); + + half red; + half green; + half blue; + half alpha; + + cs->getPixel(reinterpret_cast(pixel), &red, &green, &blue, &alpha); + CHECK(red, (half)0.128f); + CHECK(green, (half)0.192f); + CHECK(blue, (half)0.64f); + CHECK(alpha, (half)0.99f); + + CHECK(HALF_TO_UINT8(-0.5), 0u); + CHECK(HALF_TO_UINT8(0), 0u); + CHECK_TOLERANCE(HALF_TO_UINT8(0.5), UINT8_MAX / 2, 1u); + CHECK(HALF_TO_UINT8(1), UINT8_MAX); + CHECK(HALF_TO_UINT8(1.5), UINT8_MAX); + + CHECK(HALF_TO_UINT16(-0.5), 0u); + CHECK(HALF_TO_UINT16(0), 0u); + CHECK_TOLERANCE(HALF_TO_UINT16(0.5), UINT16_MAX / 2, 1u); + CHECK(HALF_TO_UINT16(1), UINT16_MAX); + CHECK(HALF_TO_UINT16(1.5), UINT16_MAX); +} + +void KisRgbF16HalfColorSpaceTester::testMixColors() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + KisAbstractColorSpace * cs = new KisRgbF16HalfColorSpace(profile); + + // Test mixColors. + half pixel1[NUM_CHANNELS]; + half pixel2[NUM_CHANNELS]; + half outputPixel[NUM_CHANNELS]; + + outputPixel[PIXEL_RED] = 0; + outputPixel[PIXEL_GREEN] = 0; + outputPixel[PIXEL_BLUE] = 0; + outputPixel[PIXEL_ALPHA] = 0; + + pixel1[PIXEL_RED] = CHANNEL_VALUE_ONE; + pixel1[PIXEL_GREEN] = CHANNEL_VALUE_ONE; + pixel1[PIXEL_BLUE] = CHANNEL_VALUE_ONE; + pixel1[PIXEL_ALPHA] = CHANNEL_VALUE_ONE; + + pixel2[PIXEL_RED] = 0; + pixel2[PIXEL_GREEN] = 0; + pixel2[PIXEL_BLUE] = 0; + pixel2[PIXEL_ALPHA] = 0; + + const TQ_UINT8 *pixelPtrs[2]; + TQ_UINT8 weights[2]; + + pixelPtrs[0] = reinterpret_cast(pixel1); + pixelPtrs[1] = reinterpret_cast(pixel2); + + weights[0] = 255; + weights[1] = 0; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE); + + weights[0] = 0; + weights[1] = 255; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], (half)0.0f); + CHECK(outputPixel[PIXEL_GREEN], (half)0.0f); + CHECK(outputPixel[PIXEL_BLUE], (half)0.0f); + CHECK(outputPixel[PIXEL_ALPHA], (half)0.0f); + + weights[0] = 128; + weights[1] = 127; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_ALPHA], (half)((128 * CHANNEL_VALUE_ONE) / 255)); + + pixel1[PIXEL_RED] = 20000; + pixel1[PIXEL_GREEN] = 10000; + pixel1[PIXEL_BLUE] = 5000; + pixel1[PIXEL_ALPHA] = CHANNEL_VALUE_ONE; + + pixel2[PIXEL_RED] = 10000; + pixel2[PIXEL_GREEN] = 20000; + pixel2[PIXEL_BLUE] = 2000; + pixel2[PIXEL_ALPHA] = CHANNEL_VALUE_ONE; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK_TOLERANCE(outputPixel[PIXEL_RED], (128 * 20000 + 127 * 10000) / 255, 5); + CHECK_TOLERANCE(outputPixel[PIXEL_GREEN], (128 * 10000 + 127 * 20000) / 255, 5); + CHECK_TOLERANCE(outputPixel[PIXEL_BLUE], (128 * 5000 + 127 * 2000) / 255, 5); + CHECK(outputPixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE); + + pixel1[PIXEL_RED] = 0; + pixel1[PIXEL_GREEN] = 0; + pixel1[PIXEL_BLUE] = 0; + pixel1[PIXEL_ALPHA] = 0; + + pixel2[PIXEL_RED] = CHANNEL_VALUE_ONE; + pixel2[PIXEL_GREEN] = CHANNEL_VALUE_ONE; + pixel2[PIXEL_BLUE] = CHANNEL_VALUE_ONE; + pixel2[PIXEL_ALPHA] = CHANNEL_VALUE_ONE; + + weights[0] = 89; + weights[1] = 166; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE); + CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE); + CHECK_TOLERANCE(outputPixel[PIXEL_ALPHA], (89 * 0 + 166 * CHANNEL_VALUE_ONE) / 255, 5); +} + +#define PIXELS_WIDTH 2 +#define PIXELS_HEIGHT 2 + +void KisRgbF16HalfColorSpaceTester::testToTQImage() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisAbstractColorSpace * cs = new KisRgbF16HalfColorSpace(profile); + + KisRgbF16HalfColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = { + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4}, + {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2}, + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO}, + {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE} + }; + + TQImage image = cs->convertToTQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + TQRgb c = image.pixel(0, 0); + + // Exposure comes into play here. + /* + CHECK(tqRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + + c = image.pixel(1, 0); + + CHECK(tqRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 3)); + CHECK(tqGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + CHECK(tqBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4)); + CHECK(tqAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2)); + + c = image.pixel(0, 1); + + CHECK(tqRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + CHECK(tqAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + + c = image.pixel(1, 1); + + CHECK(tqRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(tqGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(tqBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO)); + CHECK(tqAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE)); + */ +} + +#define NUM_ROWS 2 +#define NUM_COLUMNS 2 +#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define MASK_ROW_STRIDE NUM_COLUMNS + +/* +1 alpha 1 0 alpha 1 +1 alpha 0.5 0 alpha 1 +1 alpha 0.5 0 alpha 0.5 +1 alpha 0 0 alpha 0.5 + +*/ + +void KisRgbF16HalfColorSpaceTester::testCompositeOps() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbF16HalfColorSpace *cs = new KisRgbF16HalfColorSpace(profile); + + KisRgbF16HalfColorSpace::Pixel srcPixel; + KisRgbF16HalfColorSpace::Pixel dstPixel; + + srcPixel.red = UINT8_TO_HALF(102); + srcPixel.green = UINT8_TO_HALF(170); + srcPixel.blue = UINT8_TO_HALF(238); + srcPixel.alpha = F16HALF_OPACITY_OPAQUE; + + dstPixel = srcPixel; + + cs->compositeDivide(reinterpret_cast(&dstPixel), 1, reinterpret_cast(&srcPixel), + 1, 0, 0, 1, 1, F16HALF_OPACITY_OPAQUE); + /* + CHECK(dstPixel.red, (TQ_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbF16HalfColorSpace::F16HALF_OPACITY_OPAQUE); + + TQ_UINT16 srcColor = 43690; + TQ_UINT16 dstColor = 43690; + + srcColor = TQMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u); + + CHECK((int)newColor, 65534); + */ + + /* + KisRgbF16HalfColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = { + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4}, + {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2}, + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO}, + {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE} + }; + + KisRgbF16HalfColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = { + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4}, + {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2}, + {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO}, + {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE} + }; + + cs->compositeOver(reinterpret_cast(dstPixels), DST_ROW_STRIDE, reinterpret_cast(srcPixels), + SRC_ROW_STRIDE, tqmask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h b/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h new file mode 100644 index 00000000..6547e35b --- /dev/null +++ b/chalk/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_RGB_F16HALF_COLORSPACE_TESTER_H +#define KIS_RGB_F16HALF_COLORSPACE_TESTER_H + +#include + +#define CHECK_TOLERANCE( x, y, tolerance ) \ +if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \ +{ \ + success(TQString(__FILE__) + "[" + TQString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(TQString(__FILE__) + "[" + TQString::number(__LINE__) + TQString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + TQString::number(x)); \ +} \ + +class KisRgbF16HalfColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToTQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/chalk/colorspaces/rgb_f32/Makefile.am b/chalk/colorspaces/rgb_f32/Makefile.am new file mode 100644 index 00000000..edcf26a9 --- /dev/null +++ b/chalk/colorspaces/rgb_f32/Makefile.am @@ -0,0 +1,34 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = chalk_rgb_f32_plugin.desktop + +INCLUDES = \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libchalk_rgb_f32.la +libchalk_rgb_f32_la_SOURCES = kis_rgb_f32_colorspace.cc +libchalk_rgb_f32_la_LDFLAGS = $(all_libraries) +libchalk_rgb_f32_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_rgb_f32_plugin.la + +# Srcs for the plugin +chalk_rgb_f32_plugin_la_SOURCES = rgb_f32_plugin.cc +noinst_HEADERS = rgb_f32_plugin.h kis_rgb_f32_colorspace.h + +chalk_rgb_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_rgb_f32_plugin_la_LIBADD = libchalk_rgb_f32.la ../../chalkcolor/libchalkcolor.la + +chalk_rgb_f32_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/chalk/colorspaces/rgb_f32/chalk_rgb_f32_plugin.desktop b/chalk/colorspaces/rgb_f32/chalk_rgb_f32_plugin.desktop new file mode 100644 index 00000000..7f238a47 --- /dev/null +++ b/chalk/colorspaces/rgb_f32/chalk_rgb_f32_plugin.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Name=RGB Color Model (32-bit float) +Name[bg]=Цветови модел RGB (32 бита) +Name[ca]=Model de color RGB (paleta de 32 bits) +Name[cy]=Model Lliw RGB (arnawf 32-did) +Name[da]=RGB-farvemodel (32-bit float) +Name[de]=RGB-Farbmodell (32-bit Fließkomma) +Name[el]=Χρωματικό μοντέλο RGB (32 bit δεκαδικοί) +Name[en_GB]=RGB Colour Model (32-bit float) +Name[eo]=RGB-kolormodelo (32-bita flupunkto) +Name[es]=Modelo de color RGB (decimal de 32 bits) +Name[et]=RGB värvimudel (32-bitine murdarv) +Name[fa]=مدل رنگ RGB )شناور ۳۲ بیتی( +Name[fr]=Modèle de couleurs RVB (flottants 32 bits) +Name[fy]=RGB-kleurmodel (32-bit float) +Name[gl]=Espazo de Cores RGB (flutuante de 32-bit) +Name[he]=מודל צבעים RGB (32 סיביות) +Name[hu]=RGB színmodell (32 bites lebegőpontos) +Name[is]=RGB litategund (32-bita fleytitala) +Name[it]=Modello di colore RGB (virgola mobile a 32 bit) +Name[ja]=RGB カラーモデル (32 ビット浮動小数) +Name[km]=គំរូ​ពណ៌ RGB (ចំនួន​ទស្សភាគ 32 ប៊ីត) +Name[nb]=RGB-fargemodell (32-bit flyttall) +Name[nds]=RGB-Klöörmodell (32-Bit Fleetkomma) +Name[ne]=RGB रङ मोडेल (३२-बिट उत्प्लावन) +Name[nl]=RGB-kleurmodel (32-bit float) +Name[pl]=Przestrzeń barw RGB (32-bitowa zmiennoprzecinkowa) +Name[pt]=Modelo de Cor RGB (v. flutuante de 32-bits) +Name[pt_BR]=Modelo de Cor RGB (ponto flutuante de 32-bits) +Name[ru]=RGB (32-бит с плавающей точкой) +Name[sk]=Model farieb RGB (32-bitové reálne čísla) +Name[sl]=Barvni model RGB (32-bitno celo število) +Name[sr]=RGB модел боја (32-битно реално) +Name[sr@Latn]=RGB model boja (32-bitno realno) +Name[sv]=RGB-färgmodell (32-bitars heltal) +Name[uk]=Модель кольорів RGB (32-бітне дробове число) +Name[uz]=RGB rang usuli (32-bit kasr) +Name[uz@cyrillic]=RGB ранг усули (32-бит каср) +Name[zh_TW]=RGB 色彩模型 (32-bit 浮點數) +Comment=Color model for 32-bit floating point per channel RGB images +Comment[bg]=Цветови модел за 32 битови изображения RGB +Comment[ca]=Model de color per a punt flotant de 32 bits-canal d'imatges RGB +Comment[da]=Farvemodel for 32-bit decimaltal pr kanal RGB-billeder +Comment[de]=Farbmodell für 32-bit Fließkomma pro Kanal RGB-Bilder +Comment[el]=Χρωματικό μοντέλο για 32-bit δεκαδικούς ανά κανάλι RGB εικόνες +Comment[en_GB]=Colour model for 32-bit floating point per channel RGB images +Comment[es]=Modelo de color decimal de 32 bits por canal para imágenes RGB +Comment[et]=32-bitiste murdarvuliste kanalitega RGB-piltide värvimudel +Comment[fa]=مدل رنگ برای ممیز شناور ۳۲ بیتی برای هر تصویر RGB مجرا +Comment[fr]=Modèle de couleurs pour des images RVB en 32 bits flottants par canal +Comment[fy]=Kleurmodel foar RGB-ôfbyldings mei 32-bit Driuwende komma de kanaal +Comment[gl]=Espazo de cores para imaxes RGB de 32-bit vírgula flutuante por canal +Comment[he]=מודל צבעים עבור תמונות RGB של 32 סיביות/ערוצים +Comment[hu]=Színmodell 32 bit (lebegőpontos)/csatorna RGB képekhez +Comment[is]=Litategund fyrir 32-bita fleytitölu á rás RGB myndir +Comment[it]=Modello di colore per immagini RGB in virgola mobile a canale di 32 bit +Comment[ja]=32 ビット浮動小数/チャンネル RGB 画像のためのカラーモデル +Comment[km]=ម៉ូដែល​ពណ៌​សម្រាប់​ចំណុច​ចំនួន​ទស្សភាគ 32-bit ក្នុង​ឆានែល​រូបភាព RGB +Comment[nb]=Fargemodell for RGB-bilde med 32 bit flyttall per kanal +Comment[nds]=Klöörmodell för RGB-Biller mit 32-Bit Fleetkomma per Kanaal +Comment[ne]=प्रति च्यानल RGB छविहरूको ३२-बिट उत्प्लावन बिन्दुका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 32-bit drijvende komma per kanaal +Comment[pl]=Przestrzeń barw dla obrazków RGB z 32-bitową liczbą zmiennoprzecinkową na kanał +Comment[pt]=Modelo de cor para imagens RGB com 32 bits de vírgula flutuante por canal +Comment[pt_BR]=Modelo de cor para imagens RGB com 32 bits de ponto flutuante por canal +Comment[ru]=Цветовое пространство RGB (32-бит/канал с плавающей точкой) +Comment[sk]=Model farieb pre RGB obrázky s 32-bitovými reálnymi číslami na kanál +Comment[sl]=Barvni model za slike RGB z 32-bitno plavajočo vejico na kanal +Comment[sr]=Модел боја за RGB слике, 32-битно реално по каналу +Comment[sr@Latn]=Model boja za RGB slike, 32-bitno realno po kanalu +Comment[sv]=Färgmodell för 32-bitars flyttal per kanal RGB-bilder +Comment[uk]=Модель кольорів для зображень RGB 32-біт з плаваючою комою на канал +Comment[zh_TW]=每色頻 32-bit 浮點 RGB 圖片的色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-Chalk-Version=2 +X-KDE-Library=chalk_rgb_f32_plugin diff --git a/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc b/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc new file mode 100644 index 00000000..98e0b28b --- /dev/null +++ b/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_rgb_f32_colorspace.h" +#include "kis_color_conversions.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_RGB = 3; + const TQ_INT32 MAX_CHANNEL_RGBA = 4; +} + +#include "kis_integer_maths.h" + +#ifndef HAVE_POWF +#undef powf +#define powf pow +#endif + +#define FLOAT_MAX 1.0f //temp + +#define EPSILON 1e-6 + +// FIXME: lcms doesn't support 32-bit float +#define F32_LCMS_TYPE TYPE_BGRA_16 + +// disable the lcms handling by setting profile=0 +KisRgbF32ColorSpace::KisRgbF32ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile */*p*/) : + KisF32BaseColorSpace(KisID("RGBAF32", i18n("RGB (32-bit float/channel)")), F32_LCMS_TYPE, icSigRgbData, tqparent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(float), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT32, sizeof(float))); + + m_alphaPos = PIXEL_ALPHA * sizeof(float); +} + +KisRgbF32ColorSpace::~KisRgbF32ColorSpace() +{ +} + +void KisRgbF32ColorSpace::setPixel(TQ_UINT8 *dst, float red, float green, float blue, float alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->red = red; + dstPixel->green = green; + dstPixel->blue = blue; + dstPixel->alpha = alpha; +} + +void KisRgbF32ColorSpace::getPixel(const TQ_UINT8 *src, float *red, float *green, float *blue, float *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *red = srcPixel->red; + *green = srcPixel->green; + *blue = srcPixel->blue; + *alpha = srcPixel->alpha; +} + +void KisRgbF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile * /*profile*/) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->red = UINT8_TO_FLOAT(c.red()); + dst->green = UINT8_TO_FLOAT(c.green()); + dst->blue = UINT8_TO_FLOAT(c.blue()); +} + +void KisRgbF32ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile * /*profile*/) +{ + Pixel *dst = reinterpret_cast(dstU8); + + dst->red = UINT8_TO_FLOAT(c.red()); + dst->green = UINT8_TO_FLOAT(c.green()); + dst->blue = UINT8_TO_FLOAT(c.blue()); + dst->alpha = UINT8_TO_FLOAT(opacity); +} + +void KisRgbF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile * /*profile*/) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(FLOAT_TO_UINT8(src->red), FLOAT_TO_UINT8(src->green), FLOAT_TO_UINT8(src->blue)); +} + +void KisRgbF32ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/) +{ + const Pixel *src = reinterpret_cast(srcU8); + + c->setRgb(FLOAT_TO_UINT8(src->red), FLOAT_TO_UINT8(src->green), FLOAT_TO_UINT8(src->blue)); + *opacity = FLOAT_TO_UINT8(src->alpha); +} + +TQ_UINT8 KisRgbF32ColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8) +{ + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return FLOAT_TO_UINT8(TQMAX(TQABS(src2->red - src1->red), + TQMAX(TQABS(src2->green - src1->green), + TQABS(src2->blue - src1->blue)))); +} + +void KisRgbF32ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + float totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + float alpha = pixel->alpha; + float alphaTimesWeight = alpha * UINT8_TO_FLOAT(*weights); + + totalRed += pixel->red * alphaTimesWeight; + totalGreen += pixel->green * alphaTimesWeight; + totalBlue += pixel->blue * alphaTimesWeight; + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= F32_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > EPSILON) { + totalRed = totalRed / newAlpha; + totalGreen = totalGreen / newAlpha; + totalBlue = totalBlue / newAlpha; + } + + dstPixel->red = totalRed; + dstPixel->green = totalGreen; + dstPixel->blue = totalBlue; +} + +void KisRgbF32ColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + float totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + float weight = *kernelValues; + + if (weight != 0) { + totalRed += pixel->red * weight; + totalGreen += pixel->green * weight; + totalBlue += pixel->blue * weight; + totalAlpha += pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->red = CLAMP( ( totalRed / factor) + offset, 0, FLOAT_MAX); + p->green = CLAMP( ( totalGreen / factor) + offset, 0, FLOAT_MAX); + p->blue = CLAMP( ( totalBlue / factor) + offset, 0, FLOAT_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, FLOAT_MAX); + } +} + + +void KisRgbF32ColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->red = FLOAT_MAX - p->red; + p->green = FLOAT_MAX - p->green; + p->blue = FLOAT_MAX - p->blue; + src += psize; + } + +} + +TQ_UINT8 KisRgbF32ColorSpace::intensity8(const TQ_UINT8 * src) const +{ + const Pixel * p = reinterpret_cast( src ); + + return FLOAT_TO_UINT8((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5); +} + + + +TQValueVector KisRgbF32ColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisRgbF32ColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +TQ_UINT32 KisRgbF32ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +TQ_UINT32 KisRgbF32ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(float); +} + +TQ_UINT8 convertToDisplay(float value, float exposureFactor, float gamma) +{ + //value *= pow(2, exposure + 2.47393); + value *= exposureFactor; + + value = powf(value, gamma); + + // scale middle gray to the target framebuffer value + + value *= 84.66f; + + int valueInt = (int)(value + 0.5); + + return CLAMP(valueInt, 0, 255); +} + +TQImage KisRgbF32ColorSpace::convertToTQImage(const TQ_UINT8 *dataU8, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float exposure) + +{ + const float *data = reinterpret_cast(dataU8); + + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + // XXX: For now assume gamma 2.2. + float gamma = 1 / 2.2; + float exposureFactor = powf(2, exposure + 2.47393); + + while ( i < width * height * MAX_CHANNEL_RGBA) { + *( j + 3) = FLOAT_TO_UINT8(*( data + i + PIXEL_ALPHA )); + *( j + 2 ) = convertToDisplay(*( data + i + PIXEL_RED ), exposureFactor, gamma); + *( j + 1 ) = convertToDisplay(*( data + i + PIXEL_GREEN ), exposureFactor, gamma); + *( j + 0 ) = convertToDisplay(*( data + i + PIXEL_BLUE ), exposureFactor, gamma); + i += MAX_CHANNEL_RGBA; + j += MAX_CHANNEL_RGBA; + } + + /* + if (srcProfile != 0 && dstProfile != 0) { + convertPixelsTo(img.bits(), srcProfile, + img.bits(), this, dstProfile, + width * height, renderingIntent); + } + */ + return img; +} + + +void KisRgbF32ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + while (rows > 0) { + + const float *src = reinterpret_cast(srcRowStart); + float *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + float srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha *= UINT8_TO_FLOAT(U8_tqmask); + } + tqmask++; + } + + if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) { + + if (opacity < F32_OPACITY_OPAQUE - EPSILON) { + srcAlpha *= opacity; + } + + if (srcAlpha > F32_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(float)); + } else { + float dstAlpha = dst[PIXEL_ALPHA]; + + float srcBlend; + + if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) { + srcBlend = srcAlpha; + } else { + float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha; + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha > EPSILON) { + srcBlend = srcAlpha / newAlpha; + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend > F32_OPACITY_OPAQUE - EPSILON) { + memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(float)); + } else { + dst[PIXEL_RED] = FLOAT_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const float *src = reinterpret_cast(srcRowStart); \ + float *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + float srcAlpha = src[PIXEL_ALPHA]; \ + float dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha *= UINT8_TO_FLOAT(U8_tqmask); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) { \ + \ + if (opacity < F32_OPACITY_OPAQUE - EPSILON) { \ + srcAlpha *= opacity; \ + } \ + \ + float srcBlend; \ + \ + if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) { \ + srcBlend = srcAlpha; \ + } else { \ + float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha; \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha > EPSILON) { \ + srcBlend = srcAlpha / newAlpha; \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += MAX_CHANNEL_RGBA; \ + dst += MAX_CHANNEL_RGBA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisRgbF32ColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcColor = src[PIXEL_RED]; + float dstColor = dst[PIXEL_RED]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_RED] = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_GREEN]; + dstColor = dst[PIXEL_GREEN]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_GREEN] = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_BLUE]; + dstColor = dst[PIXEL_BLUE]; + + srcColor = srcColor * dstColor; + + dst[PIXEL_BLUE] = FLOAT_BLEND(srcColor, dstColor, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = TQMIN(dstColor / (srcColor + EPSILON), FLOAT_MAX); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = FLOAT_MAX - ((FLOAT_MAX - dstColor) * (FLOAT_MAX - srcColor)); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = dstColor * (dstColor + 2 * (srcColor * (FLOAT_MAX - dstColor))); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = TQMIN(dstColor / (FLOAT_MAX + EPSILON - srcColor), FLOAT_MAX); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = TQMIN((FLOAT_MAX - dstColor) / (srcColor + EPSILON), FLOAT_MAX); + srcColor = CLAMP(FLOAT_MAX - srcColor, 0, FLOAT_MAX); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + float srcColor = src[channel]; + float dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeHue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeSaturation(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeValue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeColor(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, float opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float srcRed = src[PIXEL_RED]; + float srcGreen = src[PIXEL_GREEN]; + float srcBlue = src[PIXEL_BLUE]; + + float dstRed = dst[PIXEL_RED]; + float dstGreen = dst[PIXEL_GREEN]; + float dstBlue = dst[PIXEL_BLUE]; + + float srcHue; + float srcSaturation; + float srcLightness; + + float dstHue; + float dstSaturation; + float dstLightness; + + RGBToHSL(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcLightness); + RGBToHSL(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstLightness); + + HSLToRGB(srcHue, srcSaturation, dstLightness, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbF32ColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + float /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + float srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_tqmask)); + } + tqmask++; + } + d->alpha = srcAlpha * d->alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisRgbF32ColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + float opacity = UINT8_TO_FLOAT(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, U8_opacity, F32Mult(), Uint8ToF32(), F32OpacityTest()); + default: + break; + } +} + +KisCompositeOpList KisRgbF32ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + list.append(KisCompositeOp(COMPOSITE_HUE)); + list.append(KisCompositeOp(COMPOSITE_SATURATION)); + list.append(KisCompositeOp(COMPOSITE_VALUE)); + list.append(KisCompositeOp(COMPOSITE_COLOR)); + + return list; +} + diff --git a/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h b/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h new file mode 100644 index 00000000..6f2ff3ae --- /dev/null +++ b/chalk/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_RGB_F32_H_ +#define KIS_STRATEGY_COLORSPACE_RGB_F32_H_ + +#include + +#include + +#include + +#include "kis_global.h" +#include "kis_f32_base_colorspace.h" + +class KisColorSpaceFactoryRegistry; + +class KRITATOOL_EXPORT KisRgbF32ColorSpace : public KisF32BaseColorSpace { +public: + KisRgbF32ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisRgbF32ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + + +public: + void setPixel(TQ_UINT8 *pixel, float red, float green, float blue, float alpha) const; + void getPixel(const TQ_UINT8 *pixel, float *red, float *green, float *blue, float *alpha) const; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, float opacity); + +private: + friend class KisRgbF32ColorSpaceTester; + + static const TQ_UINT8 PIXEL_BLUE = 0; + static const TQ_UINT8 PIXEL_GREEN = 1; + static const TQ_UINT8 PIXEL_RED = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + float blue; + float green; + float red; + float alpha; + }; + + // For Alpha Composite + struct F32Mult { + inline float operator()(const float& a, const float& b) const { + return a * b; + } + }; + struct Uint8ToF32 { + inline float operator()(const TQ_UINT8 src) const { + return UINT8_TO_FLOAT(src); + } + }; + struct F32OpacityTest { + inline bool operator()(const float& opacity) const { + return opacity > F32_OPACITY_TRANSPARENT + 1e-6; // #define EPSILON in the .cc + } + }; +}; + +// FIXME: lcms doesn't support 32-bit float +#define F32_LCMS_TYPE TYPE_BGRA_16 + +class KisRgbF32ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("RGBAF32", i18n("RGB (32-bit float/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return F32_LCMS_TYPE; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisRgbF32ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_F32_H_ + diff --git a/chalk/colorspaces/rgb_f32/rgb_f32_plugin.cc b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.cc new file mode 100644 index 00000000..4e11e36c --- /dev/null +++ b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.cc @@ -0,0 +1,63 @@ +/* +* rgb_f32_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include +#include + +#include "rgb_f32_plugin.h" +#include "kis_rgb_f32_colorspace.h" + +typedef KGenericFactory RGBF32PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_rgb_f32_plugin, RGBF32PluginFactory( "chalk" ) ) + + +RGBF32Plugin::RGBF32Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(RGBF32PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(tqparent); + + KisColorSpace * colorSpaceRGBF32 = new KisRgbF32ColorSpace(f, 0); + + KisColorSpaceFactory * csf = new KisRgbF32ColorSpaceFactory(); + f->add(csf); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("RGBF32HISTO", i18n("Float32")), colorSpaceRGBF32) ); + } + +} + +RGBF32Plugin::~RGBF32Plugin() +{ +} + +#include "rgb_f32_plugin.moc" diff --git a/chalk/colorspaces/rgb_f32/rgb_f32_plugin.h b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.h new file mode 100644 index 00000000..22ec674f --- /dev/null +++ b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef RGB_F32_PLUGIN_H_ +#define RGB_F32_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the RGB F32 colour space strategy. + */ +class RGBF32Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + RGBF32Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~RGBF32Plugin(); + +}; + + +#endif // RGB_F32_PLUGIN_H_ diff --git a/chalk/colorspaces/rgb_f32/rgb_f32_plugin.rc b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.rc new file mode 100644 index 00000000..88b13f85 --- /dev/null +++ b/chalk/colorspaces/rgb_f32/rgb_f32_plugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/chalk/colorspaces/rgb_f32/tests/Makefile.am b/chalk/colorspaces/rgb_f32/tests/Makefile.am new file mode 100644 index 00000000..5980c24e --- /dev/null +++ b/chalk/colorspaces/rgb_f32/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_strategy_colorspace_rgb_f32_tester.la + +kunittest_kis_strategy_colorspace_rgb_f32_tester_la_SOURCES = kis_strategy_colorspace_rgb_f32_tester.cc +kunittest_kis_strategy_colorspace_rgb_f32_tester_la_LIBADD = -lkunittest ../libchalk_rgb_f32.la +kunittest_kis_strategy_colorspace_rgb_f32_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_strategy_colorspace_rgb_f32_tester.la + kunittestmodrunner + diff --git a/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc b/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc new file mode 100644 index 00000000..b4ec34e9 --- /dev/null +++ b/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_factory.h" +#include "kis_strategy_colorspace_rgb_f32_tester.h" +#include "kis_rgb_f32_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_paint_device.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_f32_tester, "RGBA 32-bit float colorspace tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisRgbF32ColorSpaceTester ); + +#define PIXEL_BLUE 0 +#define PIXEL_GREEN 1 +#define PIXEL_RED 2 +#define PIXEL_ALPHA 3 + +#define NUM_CHANNELS 4 +#define NUM_COLOUR_CHANNELS 3 +#define CHANNEL_SIZE ((int)sizeof(float)) + +#define RED_CHANNEL 0 +#define GREEN_CHANNEL 1 +#define BLUE_CHANNEL 2 +#define ALPHA_CHANNEL 3 + +#define MAX_CHANNEL_VALUE 1.0f +#define MIN_CHANNEL_VALUE 0.0f + + +void KisRgbF32ColorSpaceTester::allTests() +{ + // We need this so that the colour profile loading can operate without crashing. + KisFactory *factory = new KisFactory(); + + testBasics(); + testToTQImage(); + testCompositeOps(); + testMixColors(); + + delete factory; +} + +void KisRgbF32ColorSpaceTester::testBasics() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbF32ColorSpace *cs = new KisRgbF32ColorSpace(profile); + KisAbstractColorSpace * csSP = cs; + + CHECK(cs->hasAlpha(), true); + CHECK(cs->nChannels(), NUM_CHANNELS); + CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS); + CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE); + + TQValueVector channels = cs->channels(); + + // Red + CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE); + CHECK(channels[0]->size(), CHANNEL_SIZE); + CHECK(channels[0]->channelType(), COLOR); + + // Green + CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE); + CHECK(channels[1]->size(), CHANNEL_SIZE); + CHECK(channels[1]->channelType(), COLOR); + + // Blue + CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE); + CHECK(channels[2]->size(), CHANNEL_SIZE); + CHECK(channels[2]->channelType(), COLOR); + + // Alpha + CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE); + CHECK(channels[3]->size(), CHANNEL_SIZE); + CHECK(channels[3]->channelType(), ALPHA); + + KisPaintDeviceSP pd = new KisPaintDevice(cs, "test"); + + KisRgbF32ColorSpace::Pixel defaultPixel; + + memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel)); + + CHECK(defaultPixel.red, 0.0f); + CHECK(defaultPixel.green, 0.0f); + CHECK(defaultPixel.blue, 0.0f); + CHECK(defaultPixel.alpha, F32_OPACITY_TRANSPARENT); + + float pixel[NUM_CHANNELS]; + + cs->fromTQColor(tqRgb(255, 255, 255), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(0, 0, 0), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], MIN_CHANNEL_VALUE); + CHECK(pixel[PIXEL_GREEN], MIN_CHANNEL_VALUE); + CHECK(pixel[PIXEL_BLUE], MIN_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(128, 64, 192), reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], UINT8_TO_FLOAT(128)); + CHECK(pixel[PIXEL_GREEN], UINT8_TO_FLOAT(64)); + CHECK(pixel[PIXEL_BLUE], UINT8_TO_FLOAT(192)); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_ALPHA], F32_OPACITY_TRANSPARENT); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast(pixel)); + + CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK(pixel[PIXEL_ALPHA], UINT8_TO_FLOAT(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + + TQColor c; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + + pixel[PIXEL_RED] = MIN_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(c.green(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(c.blue(), (int)FLOAT_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + TQ_UINT8 opacity; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_ALPHA] = F32_OPACITY_OPAQUE; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_RED] = MIN_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE; + pixel[PIXEL_ALPHA] = F32_OPACITY_TRANSPARENT; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + CHECK(opacity, OPACITY_TRANSPARENT); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4; + pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE / 2; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(c.green(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(c.blue(), (int)FLOAT_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4)); + CHECK((int)opacity, (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + #define NUM_PIXELS 4 + + KisRgbF32ColorSpace::Pixel pixels[NUM_PIXELS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + cs->setAlpha(reinterpret_cast(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS); + + CHECK(pixels[0].red, MAX_CHANNEL_VALUE); + CHECK(pixels[0].green, MAX_CHANNEL_VALUE); + CHECK(pixels[0].blue, MAX_CHANNEL_VALUE); + CHECK(pixels[0].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2)); + + CHECK(pixels[1].red, MAX_CHANNEL_VALUE / 3); + CHECK(pixels[1].green, MAX_CHANNEL_VALUE / 2); + CHECK(pixels[1].blue, MAX_CHANNEL_VALUE / 4); + CHECK(pixels[1].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2)); + + CHECK(pixels[2].red, MAX_CHANNEL_VALUE); + CHECK(pixels[2].green, MAX_CHANNEL_VALUE); + CHECK(pixels[2].blue, MAX_CHANNEL_VALUE); + CHECK(pixels[2].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2)); + + CHECK(pixels[3].red, MIN_CHANNEL_VALUE); + CHECK(pixels[3].green, MIN_CHANNEL_VALUE); + CHECK(pixels[3].blue, MIN_CHANNEL_VALUE); + CHECK(pixels[3].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE; + + TQString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(MIN_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(MIN_CHANNEL_VALUE)); + + cs->setPixel(reinterpret_cast(pixel), 0.128, 0.192, 0.64, 0.99); + CHECK(pixel[PIXEL_RED], 0.128f); + CHECK(pixel[PIXEL_GREEN], 0.192f); + CHECK(pixel[PIXEL_BLUE], 0.64f); + CHECK(pixel[PIXEL_ALPHA], 0.99f); + + float red; + float green; + float blue; + float alpha; + + cs->getPixel(reinterpret_cast(pixel), &red, &green, &blue, &alpha); + CHECK(red, 0.128f); + CHECK(green, 0.192f); + CHECK(blue, 0.64f); + CHECK(alpha, 0.99f); + + CHECK(FLOAT_TO_UINT8(-0.5), 0u); + CHECK(FLOAT_TO_UINT8(0), 0u); + CHECK_TOLERANCE(FLOAT_TO_UINT8(0.5), UINT8_MAX / 2, 1u); + CHECK(FLOAT_TO_UINT8(1), UINT8_MAX); + CHECK(FLOAT_TO_UINT8(1.5), UINT8_MAX); + + CHECK(FLOAT_TO_UINT16(-0.5), 0u); + CHECK(FLOAT_TO_UINT16(0), 0u); + CHECK_TOLERANCE(FLOAT_TO_UINT16(0.5), UINT16_MAX / 2, 1u); + CHECK(FLOAT_TO_UINT16(1), UINT16_MAX); + CHECK(FLOAT_TO_UINT16(1.5), UINT16_MAX); +} + +void KisRgbF32ColorSpaceTester::testMixColors() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisAbstractColorSpace * cs = new KisRgbF32ColorSpace(profile); + + // Test mixColors. + float pixel1[NUM_CHANNELS]; + float pixel2[NUM_CHANNELS]; + float outputPixel[NUM_CHANNELS]; + + outputPixel[PIXEL_RED] = 0; + outputPixel[PIXEL_GREEN] = 0; + outputPixel[PIXEL_BLUE] = 0; + outputPixel[PIXEL_ALPHA] = 0; + + pixel1[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel1[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel1[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + pixel1[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + pixel2[PIXEL_RED] = 0; + pixel2[PIXEL_GREEN] = 0; + pixel2[PIXEL_BLUE] = 0; + pixel2[PIXEL_ALPHA] = 0; + + const TQ_UINT8 *pixelPtrs[2]; + TQ_UINT8 weights[2]; + + pixelPtrs[0] = reinterpret_cast(pixel1); + pixelPtrs[1] = reinterpret_cast(pixel2); + + weights[0] = 255; + weights[1] = 0; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE); + + weights[0] = 0; + weights[1] = 255; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], 0.0f); + CHECK(outputPixel[PIXEL_GREEN], 0.0f); + CHECK(outputPixel[PIXEL_BLUE], 0.0f); + CHECK(outputPixel[PIXEL_ALPHA], 0.0f); + + weights[0] = 128; + weights[1] = 127; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_ALPHA], (128 * MAX_CHANNEL_VALUE) / 255); + + pixel1[PIXEL_RED] = 20000; + pixel1[PIXEL_GREEN] = 10000; + pixel1[PIXEL_BLUE] = 5000; + pixel1[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + pixel2[PIXEL_RED] = 10000; + pixel2[PIXEL_GREEN] = 20000; + pixel2[PIXEL_BLUE] = 2000; + pixel2[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK_TOLERANCE(outputPixel[PIXEL_RED], (128 * 20000 + 127 * 10000) / 255, 5); + CHECK_TOLERANCE(outputPixel[PIXEL_GREEN], (128 * 10000 + 127 * 20000) / 255, 5); + CHECK_TOLERANCE(outputPixel[PIXEL_BLUE], (128 * 5000 + 127 * 2000) / 255, 5); + CHECK(outputPixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE); + + pixel1[PIXEL_RED] = 0; + pixel1[PIXEL_GREEN] = 0; + pixel1[PIXEL_BLUE] = 0; + pixel1[PIXEL_ALPHA] = 0; + + pixel2[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel2[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel2[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + pixel2[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + weights[0] = 89; + weights[1] = 166; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK_TOLERANCE(outputPixel[PIXEL_ALPHA], (89 * 0 + 166 * MAX_CHANNEL_VALUE) / 255, 5); +} + +#define PIXELS_WIDTH 2 +#define PIXELS_HEIGHT 2 + +void KisRgbF32ColorSpaceTester::testToTQImage() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisAbstractColorSpace * cs = new KisRgbF32ColorSpace(profile); + + KisRgbF32ColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + TQImage image = cs->convertToTQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + TQRgb c = image.pixel(0, 0); + + // Exposure comes into play here. + /* + CHECK(tqRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + + c = image.pixel(1, 0); + + CHECK(tqRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 3)); + CHECK(tqGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(tqBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(tqAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + c = image.pixel(0, 1); + + CHECK(tqRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + + c = image.pixel(1, 1); + + CHECK(tqRed(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE)); + */ +} + +#define NUM_ROWS 2 +#define NUM_COLUMNS 2 +#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define MASK_ROW_STRIDE NUM_COLUMNS + +/* +1 alpha 1 0 alpha 1 +1 alpha 0.5 0 alpha 1 +1 alpha 0.5 0 alpha 0.5 +1 alpha 0 0 alpha 0.5 + +*/ + +void KisRgbF32ColorSpaceTester::testCompositeOps() +{ + KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbF32ColorSpace *cs = new KisRgbF32ColorSpace(profile); + + KisRgbF32ColorSpace::Pixel srcPixel; + KisRgbF32ColorSpace::Pixel dstPixel; + + srcPixel.red = UINT8_TO_FLOAT(102); + srcPixel.green = UINT8_TO_FLOAT(170); + srcPixel.blue = UINT8_TO_FLOAT(238); + srcPixel.alpha = F32_OPACITY_OPAQUE; + + dstPixel = srcPixel; + + cs->compositeDivide(reinterpret_cast(&dstPixel), 1, reinterpret_cast(&srcPixel), + 1, 0, 0, 1, 1, F32_OPACITY_OPAQUE); + /* + CHECK(dstPixel.red, (TQ_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbF32ColorSpace::F32_OPACITY_OPAQUE); + + TQ_UINT16 srcColor = 43690; + TQ_UINT16 dstColor = 43690; + + srcColor = TQMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u); + + CHECK((int)newColor, 65534); + */ + + /* + KisRgbF32ColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + KisRgbF32ColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + cs->compositeOver(reinterpret_cast(dstPixels), DST_ROW_STRIDE, reinterpret_cast(srcPixels), + SRC_ROW_STRIDE, tqmask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h b/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h new file mode 100644 index 00000000..1153f147 --- /dev/null +++ b/chalk/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_STRATEGY_COLORSPACE_RGB_F32_TESTER_H +#define KIS_STRATEGY_COLORSPACE_RGB_F32_TESTER_H + +#include + +#define CHECK_TOLERANCE( x, y, tolerance ) \ +if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \ +{ \ + success(TQString(__FILE__) + "[" + TQString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(TQString(__FILE__) + "[" + TQString::number(__LINE__) + TQString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + TQString::number(x)); \ +} \ + +class KisRgbF32ColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToTQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/chalk/colorspaces/rgb_u16/Makefile.am b/chalk/colorspaces/rgb_u16/Makefile.am new file mode 100644 index 00000000..28ef3e62 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/Makefile.am @@ -0,0 +1,32 @@ +# location for the rc file +kde_services_DATA = chalk_rgb_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalk_rgb_u16.la +libchalk_rgb_u16_la_SOURCES = kis_rgb_u16_colorspace.cc +libchalk_rgb_u16_la_LDFLAGS = $(all_libraries) +libchalk_rgb_u16_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_rgb_u16_plugin.la + +# Srcs for the plugin +chalk_rgb_u16_plugin_la_SOURCES = rgb_u16_plugin.cc +noinst_HEADERS = rgb_u16_plugin.h kis_rgb_u16_colorspace.h + +chalk_rgb_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_rgb_u16_plugin_la_LIBADD = libchalk_rgb_u16.la ../../chalkcolor/libchalkcolor.la + +chalk_rgb_u16_plugin_la_METASOURCES = AUTO + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + diff --git a/chalk/colorspaces/rgb_u16/chalk_rgb_u16_plugin.desktop b/chalk/colorspaces/rgb_u16/chalk_rgb_u16_plugin.desktop new file mode 100644 index 00000000..36ff2355 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/chalk_rgb_u16_plugin.desktop @@ -0,0 +1,80 @@ +[Desktop Entry] +Name=RGB Color Model (16-bit integer) +Name[bg]=Цветови модел RGB (16 бита) +Name[ca]=Model de color RGB (enter de 16 bits) +Name[cy]=Model Lliw RGB (cyfanrif 16-did) +Name[da]=RGB-farvemodel (16-bit heltal) +Name[de]=RGB-Farbmodell (16-bit Ganzzahl) +Name[el]=Χρωματικό μοντέλο RGB (16 bit ακέραιοι) +Name[en_GB]=RGB Colour Model (16-bit integer) +Name[eo]=RGB-kolormodelo (16-bita entjero) +Name[es]=Modelo de color RGB (entero de 16 bits) +Name[et]=RGB värvimudel (16-bitine täisarv) +Name[fa]=مدل رنگ RGB )عدد صحیح ۱۶ بیتی( +Name[fr]=Modèle de couleurs RVB (entiers 16 bits) +Name[fy]=RGB-kleurmodel (16-bit integer) +Name[gl]=Modelo de Cores RGB (inteiros de 16-bit) +Name[he]=מודל צבעים RGB (16 סיביות) +Name[hu]=RGB színmodell (16 bites egész) +Name[is]=RGB litategund (16-bita heiltala) +Name[it]=Modello di colore RGB (intero a 16 bit) +Name[ja]=RGB カラーモデル (16 ビット整数) +Name[km]=គំរូ​ពណ៌ RGB (ចំនួនគត់ 16 ប៊ីត) +Name[lt]=RGB spalvų modelis (16-bitų sveikasis) +Name[nb]=RGB-fargemodell (16-bit heltall) +Name[nds]=RGB-Klöörmodell (16-Bit Heeltall) +Name[ne]=RGB रङ मोडेल (१६-बिट इन्टिजर) +Name[nl]=RGB-kleurmodel (16-bit integer) +Name[pl]=Przestrzeń barw RGB (16-bitowa liczba całkowita) +Name[pt]=Modelo de Cor RGB (inteiro de 16-bits) +Name[pt_BR]=Modelo de Cor RGB (inteiro de 16-bits) +Name[ru]=RGB (целое 16-бит) +Name[sk]=Model farieb RGB (16-bitové čísla) +Name[sl]=Barvni model RGB (16-bitno celo število) +Name[sr]=RGB модел боја (16-битно целобројно) +Name[sr@Latn]=RGB model boja (16-bitno celobrojno) +Name[sv]=RGB-färgmodell (16-bitars heltal) +Name[uk]=Модель кольору RGB (16-бітне ціле число) +Name[uz]=RGB rang usuli (16-bit butun) +Name[uz@cyrillic]=RGB ранг усули (16-бит бутун) +Name[zh_TW]=RGB 色彩模型 (16-bit 整數) +Comment=Color model for 16-bit integer per channel RGB images +Comment[bg]=Цветови модел за 16 битови изображения RGB +Comment[ca]=Model de color enter de 16 bits per canal d'imatges RGB +Comment[cy]=Model lliw ar gyfer delweddau RGB â chyfanrif 16-did/sianel +Comment[da]=Farvemodel for 16-bit heltal pr kanal RGB-billeder +Comment[de]=Farbmodell für 16-bit Ganzzahl pro Kanal RGB-Bilder +Comment[el]=Χρωματικό μοντέλο για 16-bit ακέραιους ανά κανάλι RGB εικόνες +Comment[en_GB]=Colour model for 16-bit integer per channel RGB images +Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes RGB +Comment[et]=16-bitiste täisarvuliste kanalitega RGB-piltide värvimudel +Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی برای هر تصویر RGB مجرا +Comment[fr]=Modèle de couleurs pour des images RVB en 16 bits/plage +Comment[fy]=Kleurmodel foar RGB-ôfbyldings mei16-bit/kanaal +Comment[gl]=Modelo de cores para imaxes RGB de inteiro de 16-bit por canal +Comment[he]=מודל צבעים עבור תמונות RGB של 16 סיביות/ערוצים +Comment[hu]=Színmodell 16 bites egész/csatorna RGB képekhez +Comment[is]=Litategund fyrir 16-bita heiltölu á rás RGB myndir +Comment[it]=Modello di colore per immagini RGB in interi a canale di 16 bit +Comment[ja]=16 ビット整数/チャンネル RGB 画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព RGB ចំនួនគត់ 16 ប៊ីត​ក្នុង​មួយ​ឆានែល +Comment[nb]=Fargemodell for RGB-bilde med 16 bit heltall per kanal +Comment[nds]=Klöörmodell för RGB-Biller mit 16-Bit Heeltall per Kanaal +Comment[ne]=प्रति च्यानल RGB छविहरूको १६-बिट इन्टिजरका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 16-bit/kanaal +Comment[pl]=Przestrzeń barw dla obrazków RGB o 16-bitowych liczbach całkowitych na kanał +Comment[pt]=Modelo de cor para imagens RGB com 16 bits por canal +Comment[pt_BR]=Modelo de cor para imagens RGB com 16 bits por canal +Comment[ru]=Цветовое пространство RGB (целое 16-бит/канал) +Comment[sk]=Model farieb pre RGB obrázky so 16-bitovými číslami na kanál +Comment[sl]=Barvni model za slike RGB s 16-bitnim celim številom na kanal +Comment[sr]=Модел боја за RGB слике, 16-битно целобројно по каналу +Comment[sr@Latn]=Model boja za RGB slike, 16-bitno celobrojno po kanalu +Comment[sv]=Färgmodell för 16-bitars heltal/kanal RGB-bilder +Comment[uk]=Модель кольорів для зображень RGB 32-біт ціле число на канал +Comment[zh_TW]=每色頻 16-bit 整數 RGB 圖片的色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_rgb_u16_plugin +X-Chalk-Version=2 + diff --git a/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc b/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc new file mode 100644 index 00000000..c61433d2 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include +#include + +#include +#include +#include + +#include "kis_rgb_u16_colorspace.h" +#include "kis_u16_base_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" + +namespace { + const TQ_INT32 MAX_CHANNEL_RGB = 3; + const TQ_INT32 MAX_CHANNEL_RGBA = 4; +} + +// XXX: already defined is superclass? +//const TQ_UINT16 KisRgbU16ColorSpace::U16_OPACITY_OPAQUE; +//const TQ_UINT16 KisRgbU16ColorSpace::U16_OPACITY_TRANSPARENT; + +KisRgbU16ColorSpace::KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU16BaseColorSpace(KisID("RGBA16", i18n("RGB (16-bit integer/channel)")), TYPE_BGRA_16, icSigRgbData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(255,0,0))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(0,255,0))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(0,0,255))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + + init(); +} + +KisRgbU16ColorSpace::~KisRgbU16ColorSpace() +{ +} + +void KisRgbU16ColorSpace::setPixel(TQ_UINT8 *dst, TQ_UINT16 red, TQ_UINT16 green, TQ_UINT16 blue, TQ_UINT16 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->red = red; + dstPixel->green = green; + dstPixel->blue = blue; + dstPixel->alpha = alpha; +} + +void KisRgbU16ColorSpace::getPixel(const TQ_UINT8 *src, TQ_UINT16 *red, TQ_UINT16 *green, TQ_UINT16 *blue, TQ_UINT16 *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *red = srcPixel->red; + *green = srcPixel->green; + *blue = srcPixel->blue; + *alpha = srcPixel->alpha; +} + +void KisRgbU16ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + TQ_UINT32 alpha = pixel->alpha; + TQ_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights)); + + totalRed += UINT16_MULT(pixel->red, alphaTimesWeight); + totalGreen += UINT16_MULT(pixel->green, alphaTimesWeight); + totalBlue += UINT16_MULT(pixel->blue, alphaTimesWeight); + newAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE); + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > 0) { + totalRed = UINT16_DIVIDE(totalRed, newAlpha); + totalGreen = UINT16_DIVIDE(totalGreen, newAlpha); + totalBlue = UINT16_DIVIDE(totalBlue, newAlpha); + } + + dstPixel->red = totalRed; + dstPixel->green = totalGreen; + dstPixel->blue = totalBlue; +} + + +void KisRgbU16ColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, + TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + const Pixel * pixel = reinterpret_cast( *colors ); + + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + totalRed += pixel->red * weight; + totalGreen += pixel->green * weight; + totalBlue += pixel->blue * weight; + totalAlpha +=pixel->alpha * weight; + } + colors++; + kernelValues++; + } + + Pixel * p = reinterpret_cast< Pixel *>( dst ); + + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + p->red = CLAMP( ( totalRed / factor) + offset, 0, TQ_UINT16_MAX); + p->green = CLAMP( ( totalGreen / factor) + offset, 0, TQ_UINT16_MAX); + p->blue = CLAMP( ( totalBlue / factor) + offset, 0, TQ_UINT16_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX); + } +} + + +void KisRgbU16ColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + Pixel * p = reinterpret_cast< Pixel *>( src ); + p->red = TQ_UINT16_MAX - p->red; + p->green = TQ_UINT16_MAX - p->green; + p->blue = TQ_UINT16_MAX - p->blue; + src += psize; + } +} + +TQ_UINT8 KisRgbU16ColorSpace::intensity8(const TQ_UINT8 * src) const +{ + const Pixel * p = reinterpret_cast( src ); + + return UINT16_TO_UINT8(static_cast((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5)); +} + + +TQValueVector KisRgbU16ColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisRgbU16ColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +TQ_UINT32 KisRgbU16ColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +TQ_UINT32 KisRgbU16ColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA * sizeof(TQ_UINT16); +} + + +void KisRgbU16ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != U16_OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_RED] = UINT16_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend); + dst[PIXEL_GREEN] = UINT16_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend); + dst[PIXEL_BLUE] = UINT16_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +#define COMMON_COMPOSITE_OP_PROLOG() \ + while (rows > 0) { \ + \ + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); \ + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); \ + TQ_INT32 columns = numColumns; \ + const TQ_UINT8 *tqmask = tqmaskRowStart; \ + \ + while (columns > 0) { \ + \ + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \ + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \ + \ + srcAlpha = TQMIN(srcAlpha, dstAlpha); \ + \ + if (tqmask != 0) { \ + TQ_UINT8 U8_tqmask = *tqmask; \ + \ + if (U8_tqmask != OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \ + } \ + tqmask++; \ + } \ + \ + if (srcAlpha != U16_OPACITY_TRANSPARENT) { \ + \ + if (opacity != U16_OPACITY_OPAQUE) { \ + srcAlpha = UINT16_MULT(srcAlpha, opacity); \ + } \ + \ + TQ_UINT16 srcBlend; \ + \ + if (dstAlpha == U16_OPACITY_OPAQUE) { \ + srcBlend = srcAlpha; \ + } else { \ + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \ + dst[PIXEL_ALPHA] = newAlpha; \ + \ + if (newAlpha != 0) { \ + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \ + } else { \ + srcBlend = srcAlpha; \ + } \ + } + +#define COMMON_COMPOSITE_OP_EPILOG() \ + } \ + \ + columns--; \ + src += MAX_CHANNEL_RGBA; \ + dst += MAX_CHANNEL_RGBA; \ + } \ + \ + rows--; \ + srcRowStart += srcRowStride; \ + dstRowStart += dstRowStride; \ + if(tqmaskRowStart) { \ + tqmaskRowStart += tqmaskRowStride; \ + } \ + } + +void KisRgbU16ColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(srcColor, dstColor); + + dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend); + + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor)); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX); + srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT16 srcColor = src[channel]; + TQ_UINT16 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeHue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float FSrcRed = static_cast(src[PIXEL_RED]) / UINT16_MAX; + float FSrcGreen = static_cast(src[PIXEL_GREEN]) / UINT16_MAX; + float FSrcBlue = static_cast(src[PIXEL_BLUE]) / UINT16_MAX; + + TQ_UINT16 dstRed = dst[PIXEL_RED]; + TQ_UINT16 dstGreen = dst[PIXEL_GREEN]; + TQ_UINT16 dstBlue = dst[PIXEL_BLUE]; + + float FDstRed = static_cast(dstRed) / UINT16_MAX; + float FDstGreen = static_cast(dstGreen) / UINT16_MAX; + float FDstBlue = static_cast(dstBlue) / UINT16_MAX; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(srcHue, dstSaturation, dstValue, &FSrcRed, &FSrcGreen, &FSrcBlue); + + TQ_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + TQ_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + TQ_UINT16 srcBlue = static_cast(FSrcBlue * UINT16_MAX + 0.5); + + dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeSaturation(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float FSrcRed = static_cast(src[PIXEL_RED]) / UINT16_MAX; + float FSrcGreen = static_cast(src[PIXEL_GREEN]) / UINT16_MAX; + float FSrcBlue = static_cast(src[PIXEL_BLUE]) / UINT16_MAX; + + TQ_UINT16 dstRed = dst[PIXEL_RED]; + TQ_UINT16 dstGreen = dst[PIXEL_GREEN]; + TQ_UINT16 dstBlue = dst[PIXEL_BLUE]; + + float FDstRed = static_cast(dstRed) / UINT16_MAX; + float FDstGreen = static_cast(dstGreen) / UINT16_MAX; + float FDstBlue = static_cast(dstBlue) / UINT16_MAX; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, srcSaturation, dstValue, &FSrcRed, &FSrcGreen, &FSrcBlue); + + TQ_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + TQ_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + TQ_UINT16 srcBlue = static_cast(FSrcBlue * UINT16_MAX + 0.5); + + dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeValue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float FSrcRed = static_cast(src[PIXEL_RED]) / UINT16_MAX; + float FSrcGreen = static_cast(src[PIXEL_GREEN]) / UINT16_MAX; + float FSrcBlue = static_cast(src[PIXEL_BLUE]) / UINT16_MAX; + + TQ_UINT16 dstRed = dst[PIXEL_RED]; + TQ_UINT16 dstGreen = dst[PIXEL_GREEN]; + TQ_UINT16 dstBlue = dst[PIXEL_BLUE]; + + float FDstRed = static_cast(dstRed) / UINT16_MAX; + float FDstGreen = static_cast(dstGreen) / UINT16_MAX; + float FDstBlue = static_cast(dstBlue) / UINT16_MAX; + + float srcHue; + float srcSaturation; + float srcValue; + + float dstHue; + float dstSaturation; + float dstValue; + + RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue); + RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue); + + HSVToRGB(dstHue, dstSaturation, srcValue, &FSrcRed, &FSrcGreen, &FSrcBlue); + + TQ_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + TQ_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + TQ_UINT16 srcBlue = static_cast(FSrcBlue * UINT16_MAX + 0.5); + + dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeColor(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity) +{ + COMMON_COMPOSITE_OP_PROLOG(); + + { + float FSrcRed = static_cast(src[PIXEL_RED]) / UINT16_MAX; + float FSrcGreen = static_cast(src[PIXEL_GREEN]) / UINT16_MAX; + float FSrcBlue = static_cast(src[PIXEL_BLUE]) / UINT16_MAX; + + TQ_UINT16 dstRed = dst[PIXEL_RED]; + TQ_UINT16 dstGreen = dst[PIXEL_GREEN]; + TQ_UINT16 dstBlue = dst[PIXEL_BLUE]; + + float FDstRed = static_cast(dstRed) / UINT16_MAX; + float FDstGreen = static_cast(dstGreen) / UINT16_MAX; + float FDstBlue = static_cast(dstBlue) / UINT16_MAX; + + float srcHue; + float srcSaturation; + float srcLightness; + + float dstHue; + float dstSaturation; + float dstLightness; + + RGBToHSL(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcLightness); + RGBToHSL(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstLightness); + + HSLToRGB(srcHue, srcSaturation, dstLightness, &FSrcRed, &FSrcGreen, &FSrcBlue); + + TQ_UINT16 srcRed = static_cast(FSrcRed * UINT16_MAX + 0.5); + TQ_UINT16 srcGreen = static_cast(FSrcGreen * UINT16_MAX + 0.5); + TQ_UINT16 srcBlue = static_cast(FSrcBlue * UINT16_MAX + 0.5); + + dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend); + } + + COMMON_COMPOSITE_OP_EPILOG(); +} + +void KisRgbU16ColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT16 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisRgbU16ColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 U8_opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity); + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + case COMPOSITE_OUT: + //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity); + break; + case COMPOSITE_COPY_RED: + //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + abstractCompositeAlphaDarken( + dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, + rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest()); + break; + default: + break; + } +} + +KisCompositeOpList KisRgbU16ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + list.append(KisCompositeOp(COMPOSITE_HUE)); + list.append(KisCompositeOp(COMPOSITE_SATURATION)); + list.append(KisCompositeOp(COMPOSITE_VALUE)); + list.append(KisCompositeOp(COMPOSITE_COLOR)); + + return list; +} diff --git a/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h b/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h new file mode 100644 index 00000000..a4edbffa --- /dev/null +++ b/chalk/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_RGB_U16_H_ +#define KIS_STRATEGY_COLORSPACE_RGB_U16_H_ + +#include + +#include + +#include "kis_global.h" +#include "kis_u16_base_colorspace.h" +#include "kis_integer_maths.h" + + +class KRITATOOL_EXPORT KisRgbU16ColorSpace : public KisU16BaseColorSpace { +public: + + struct Pixel { + TQ_UINT16 blue; + TQ_UINT16 green; + TQ_UINT16 red; + TQ_UINT16 alpha; + }; +public: + KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisRgbU16ColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8) + return true; + else + return false; + }; + + + +public: + void setPixel(TQ_UINT8 *pixel, TQ_UINT16 red, TQ_UINT16 green, TQ_UINT16 blue, TQ_UINT16 alpha) const; + void getPixel(const TQ_UINT8 *pixel, TQ_UINT16 *red, TQ_UINT16 *green, TQ_UINT16 *blue, TQ_UINT16 *alpha) const; + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity); + +private: + friend class KisRgbU16ColorSpaceTester; + + static const TQ_UINT8 PIXEL_BLUE = 0; + static const TQ_UINT8 PIXEL_GREEN = 1; + static const TQ_UINT8 PIXEL_RED = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; +}; + +class KisRgbU16ColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("RGBA16", i18n("RGB (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_BGRA_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisRgbU16ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_U16_H_ diff --git a/chalk/colorspaces/rgb_u16/rgb_u16_plugin.cc b/chalk/colorspaces/rgb_u16/rgb_u16_plugin.cc new file mode 100644 index 00000000..828298c3 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/rgb_u16_plugin.cc @@ -0,0 +1,61 @@ +/* +* rgb_u16_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* Copyright (c) 2005 Adrian Page +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include + +#include +#include + +#include "rgb_u16_plugin.h" +#include "kis_rgb_u16_colorspace.h" +#include "kis_basic_histogram_producers.h" + +typedef KGenericFactory RGBU16PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_rgb_u16_plugin, RGBU16PluginFactory( "chalk" ) ) + + +RGBU16Plugin::RGBU16Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(RGBU16PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceRGBU16 = new KisRgbU16ColorSpace(f, 0); + KisColorSpaceFactory * csFactory = new KisRgbU16ColorSpaceFactory(); + f->add( csFactory ); + + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("RGB16HISTO", i18n("RGB16")), colorSpaceRGBU16) ); + } + +} + +RGBU16Plugin::~RGBU16Plugin() +{ +} + +#include "rgb_u16_plugin.moc" diff --git a/chalk/colorspaces/rgb_u16/rgb_u16_plugin.h b/chalk/colorspaces/rgb_u16/rgb_u16_plugin.h new file mode 100644 index 00000000..d5cf4d14 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/rgb_u16_plugin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RGB_U16_PLUGIN_H_ +#define RGB_U16_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the RGB U16 colour space strategy. + */ +class RGBU16Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + RGBU16Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~RGBU16Plugin(); +}; + + +#endif // RGB_U16_PLUGIN_H_ diff --git a/chalk/colorspaces/rgb_u16/tests/Makefile.am b/chalk/colorspaces/rgb_u16/tests/Makefile.am new file mode 100644 index 00000000..dcf23893 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_strategy_colorspace_rgb_u16_tester.la + +kunittest_kis_strategy_colorspace_rgb_u16_tester_la_SOURCES = kis_strategy_colorspace_rgb_u16_tester.cc +kunittest_kis_strategy_colorspace_rgb_u16_tester_la_LIBADD = -lkunittest ../libchalk_rgb_u16.la +kunittest_kis_strategy_colorspace_rgb_u16_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_strategy_colorspace_rgb_u16_tester.la + kunittestmodrunner + diff --git a/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc b/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc new file mode 100644 index 00000000..7861b8e1 --- /dev/null +++ b/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_factory.h" +#include "kis_strategy_colorspace_rgb_u16_tester.h" +#include "kis_rgb_u16_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_paint_device.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_u16_tester, "RGB 16-bit integer colorspace tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisRgbU16ColorSpaceTester ); + +#define PIXEL_BLUE 0 +#define PIXEL_GREEN 1 +#define PIXEL_RED 2 +#define PIXEL_ALPHA 3 + +#define NUM_CHANNELS 4 +#define NUM_COLOUR_CHANNELS 3 +#define CHANNEL_SIZE 2 + +#define RED_CHANNEL 0 +#define GREEN_CHANNEL 1 +#define BLUE_CHANNEL 2 +#define ALPHA_CHANNEL 3 + +#define MAX_CHANNEL_VALUE UINT16_MAX +#define MIN_CHANNEL_VALUE UINT16_MIN + +void KisRgbU16ColorSpaceTester::allTests() +{ + // We need this so that the colour profile loading can operate without crashing. + KisFactory *factory = new KisFactory(); + + testBasics(); + testToTQImage(); + testCompositeOps(); + testMixColors(); + + delete factory; +} + +void KisRgbU16ColorSpaceTester::testBasics() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbU16ColorSpace *cs = new KisRgbU16ColorSpace(defProfile); + KisAbstractColorSpace * csSP = cs; + + CHECK(cs->hasAlpha(), true); + CHECK(cs->nChannels(), NUM_CHANNELS); + CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS); + CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE); + + TQValueVector channels = cs->channels(); + + // Red + CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE); + CHECK(channels[0]->size(), CHANNEL_SIZE); + CHECK(channels[0]->channelType(), COLOR); + + // Green + CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE); + CHECK(channels[1]->size(), CHANNEL_SIZE); + CHECK(channels[1]->channelType(), COLOR); + + // Blue + CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE); + CHECK(channels[2]->size(), CHANNEL_SIZE); + CHECK(channels[2]->channelType(), COLOR); + + // Alpha + CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE); + CHECK(channels[3]->size(), CHANNEL_SIZE); + CHECK(channels[3]->channelType(), ALPHA); + + KisPaintDeviceSP pd = new KisPaintDevice(cs, "test"); + + KisRgbU16ColorSpace::Pixel defaultPixel; + + memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel)); + + CHECK((int)defaultPixel.red, 0); + CHECK((int)defaultPixel.green, 0); + CHECK((int)defaultPixel.blue, 0); + CHECK((int)defaultPixel.alpha, 0); + + TQ_UINT16 pixel[NUM_CHANNELS]; + + cs->fromTQColor(tqRgb(255, 255, 255), reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(0, 0, 0), reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], MIN_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_GREEN], MIN_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_BLUE], MIN_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(128, 64, 192), reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], (uint)UINT8_TO_UINT16(128)); + CHECK((uint)pixel[PIXEL_GREEN], (uint)UINT8_TO_UINT16(64)); + CHECK((uint)pixel[PIXEL_BLUE], (uint)UINT8_TO_UINT16(192)); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_ALPHA], MIN_CHANNEL_VALUE); + + cs->fromTQColor(tqRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast(pixel)); + + CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE); + CHECK((uint)pixel[PIXEL_ALPHA], UINT8_TO_UINT16(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + + TQColor c; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + + pixel[PIXEL_RED] = MIN_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4; + + cs->toTQColor(reinterpret_cast(pixel), &c); + + CHECK(c.red(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(c.green(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(c.blue(), (int)UINT16_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE; + pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + TQ_UINT8 opacity; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 255); + CHECK(c.green(), 255); + CHECK(c.blue(), 255); + CHECK(opacity, OPACITY_OPAQUE); + + pixel[PIXEL_RED] = MIN_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE; + pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE; + pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), 0); + CHECK(c.green(), 0); + CHECK(c.blue(), 0); + CHECK(opacity, OPACITY_TRANSPARENT); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4; + pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE / 2; + + cs->toTQColor(reinterpret_cast(pixel), &c, &opacity); + + CHECK(c.red(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + CHECK(c.green(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK(c.blue(), (int)UINT16_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4)); + CHECK((int)opacity, (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + #define NUM_PIXELS 4 + + KisRgbU16ColorSpace::Pixel pixels[NUM_PIXELS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + cs->setAlpha(reinterpret_cast(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS); + + CHECK((uint)pixels[0].red, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[0].green, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[0].blue, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[0].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2)); + + CHECK((uint)pixels[1].red, MAX_CHANNEL_VALUE / 3); + CHECK((uint)pixels[1].green, MAX_CHANNEL_VALUE / 2); + CHECK((uint)pixels[1].blue, MAX_CHANNEL_VALUE / 4); + CHECK((uint)pixels[1].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2)); + + CHECK((uint)pixels[2].red, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[2].green, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[2].blue, MAX_CHANNEL_VALUE); + CHECK((uint)pixels[2].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2)); + + CHECK((uint)pixels[3].red, MIN_CHANNEL_VALUE); + CHECK((uint)pixels[3].green, MIN_CHANNEL_VALUE); + CHECK((uint)pixels[3].blue, MIN_CHANNEL_VALUE); + CHECK((uint)pixels[3].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2)); + + pixel[PIXEL_RED] = MAX_CHANNEL_VALUE; + pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2; + pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE / 4; + pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE; + + TQString valueText = cs->channelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 2)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(MAX_CHANNEL_VALUE / 4)); + + valueText = cs->channelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(MIN_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), RED_CHANNEL); + CHECK(valueText, TQString().setNum(static_cast(MAX_CHANNEL_VALUE) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(static_cast(MAX_CHANNEL_VALUE / 2) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(static_cast(MAX_CHANNEL_VALUE / 4) / MAX_CHANNEL_VALUE)); + + valueText = cs->normalisedChannelValueText(reinterpret_cast(pixel), ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(static_cast(MIN_CHANNEL_VALUE) / MAX_CHANNEL_VALUE)); + + cs->setPixel(reinterpret_cast(pixel), 128, 192, 64, 99); + CHECK((uint)pixel[PIXEL_RED], 128u); + CHECK((uint)pixel[PIXEL_GREEN], 192u); + CHECK((uint)pixel[PIXEL_BLUE], 64u); + CHECK((uint)pixel[PIXEL_ALPHA], 99u); + + TQ_UINT16 red; + TQ_UINT16 green; + TQ_UINT16 blue; + TQ_UINT16 alpha; + + cs->getPixel(reinterpret_cast(pixel), &red, &green, &blue, &alpha); + CHECK((uint)red, 128u); + CHECK((uint)green, 192u); + CHECK((uint)blue, 64u); + CHECK((uint)alpha, 99u); +} + +void KisRgbU16ColorSpaceTester::testMixColors() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + + KisAbstractColorSpace * cs = new KisRgbU16ColorSpace(defProfile); + + // Test mixColors. + TQ_UINT16 pixel1[NUM_CHANNELS]; + TQ_UINT16 pixel2[NUM_CHANNELS]; + TQ_UINT16 outputPixel[NUM_CHANNELS]; + + outputPixel[PIXEL_RED] = 0; + outputPixel[PIXEL_GREEN] = 0; + outputPixel[PIXEL_BLUE] = 0; + outputPixel[PIXEL_ALPHA] = 0; + + pixel1[PIXEL_RED] = UINT16_MAX; + pixel1[PIXEL_GREEN] = UINT16_MAX; + pixel1[PIXEL_BLUE] = UINT16_MAX; + pixel1[PIXEL_ALPHA] = UINT16_MAX; + + pixel2[PIXEL_RED] = 0; + pixel2[PIXEL_GREEN] = 0; + pixel2[PIXEL_BLUE] = 0; + pixel2[PIXEL_ALPHA] = 0; + + const TQ_UINT8 *pixelPtrs[2]; + TQ_UINT8 weights[2]; + + pixelPtrs[0] = reinterpret_cast(pixel1); + pixelPtrs[1] = reinterpret_cast(pixel2); + + weights[0] = 255; + weights[1] = 0; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_ALPHA], UINT16_MAX); + + weights[0] = 0; + weights[1] = 255; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK((int)outputPixel[PIXEL_RED], 0); + CHECK((int)outputPixel[PIXEL_GREEN], 0); + CHECK((int)outputPixel[PIXEL_BLUE], 0); + CHECK((int)outputPixel[PIXEL_ALPHA], 0); + + weights[0] = 128; + weights[1] = 127; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_ALPHA], (128u * UINT16_MAX) / 255u); + + pixel1[PIXEL_RED] = 20000; + pixel1[PIXEL_GREEN] = 10000; + pixel1[PIXEL_BLUE] = 5000; + pixel1[PIXEL_ALPHA] = UINT16_MAX; + + pixel2[PIXEL_RED] = 10000; + pixel2[PIXEL_GREEN] = 20000; + pixel2[PIXEL_BLUE] = 2000; + pixel2[PIXEL_ALPHA] = UINT16_MAX; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK_TOLERANCE((uint)outputPixel[PIXEL_RED], (128u * 20000u + 127u * 10000u) / 255u, 5u); + CHECK_TOLERANCE((uint)outputPixel[PIXEL_GREEN], (128u * 10000u + 127u * 20000u) / 255u, 5u); + CHECK_TOLERANCE((uint)outputPixel[PIXEL_BLUE], (128u * 5000u + 127u * 2000u) / 255u, 5u); + CHECK((uint)outputPixel[PIXEL_ALPHA], UINT16_MAX); + + pixel1[PIXEL_RED] = 0; + pixel1[PIXEL_GREEN] = 0; + pixel1[PIXEL_BLUE] = 0; + pixel1[PIXEL_ALPHA] = 0; + + pixel2[PIXEL_RED] = UINT16_MAX; + pixel2[PIXEL_GREEN] = UINT16_MAX; + pixel2[PIXEL_BLUE] = UINT16_MAX; + pixel2[PIXEL_ALPHA] = UINT16_MAX; + + weights[0] = 89; + weights[1] = 166; + + cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast(outputPixel)); + + CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX); + CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX); + CHECK_TOLERANCE((uint)outputPixel[PIXEL_ALPHA], (89u * 0u + 166u * UINT16_MAX) / 255u, 5u); +} + +#define PIXELS_WIDTH 2 +#define PIXELS_HEIGHT 2 + +void KisRgbU16ColorSpaceTester::testToTQImage() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + + KisAbstractColorSpace * cs = new KisRgbU16ColorSpace(defProfile); + + KisRgbU16ColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + TQImage image = cs->convertToTQImage(reinterpret_cast(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0); + + TQRgb c = image.pixel(0, 0); + + CHECK(tqRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4)); + + c = image.pixel(1, 0); + + CHECK(tqRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 3)); + CHECK(tqGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + CHECK_TOLERANCE(tqBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4), 1u); + CHECK(tqAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2)); + + c = image.pixel(0, 1); + + CHECK(tqRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + + c = image.pixel(1, 1); + + CHECK(tqRed(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqGreen(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqBlue(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE)); + CHECK(tqAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE)); +} + +#define NUM_ROWS 2 +#define NUM_COLUMNS 2 +#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE) +#define MASK_ROW_STRIDE NUM_COLUMNS + +/* +1 alpha 1 0 alpha 1 +1 alpha 0.5 0 alpha 1 +1 alpha 0.5 0 alpha 0.5 +1 alpha 0 0 alpha 0.5 + +*/ + +void KisRgbU16ColorSpaceTester::testCompositeOps() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + + KisRgbU16ColorSpace *cs = new KisRgbU16ColorSpace(defProfile); + + KisRgbU16ColorSpace::Pixel srcPixel; + KisRgbU16ColorSpace::Pixel dstPixel; + + srcPixel.red = UINT8_TO_UINT16(102); + srcPixel.green = UINT8_TO_UINT16(170); + srcPixel.blue = UINT8_TO_UINT16(238); + srcPixel.alpha = KisRgbU16ColorSpace::U16_OPACITY_OPAQUE; + + dstPixel = srcPixel; + + cs->compositeDivide(reinterpret_cast(&dstPixel), 1, reinterpret_cast(&srcPixel), + 1, 0, 0, 1, 1, KisRgbU16ColorSpace::U16_OPACITY_OPAQUE); + /* + CHECK(dstPixel.red, (TQ_UINT16)UINT8_TO_UINT16(253)); + CHECK(dstPixel.green, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.blue, (TQ_UINT16)UINT8_TO_UINT16(254)); + CHECK(dstPixel.alpha, KisRgbU16ColorSpace::U16_OPACITY_OPAQUE); + + TQ_UINT16 srcColor = 43690; + TQ_UINT16 dstColor = 43690; + + srcColor = TQMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u); + + CHECK((int)srcColor, 65534); + + TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u); + + CHECK((int)newColor, 65534); + */ + + /* + KisRgbU16ColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + KisRgbU16ColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = { + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4}, + {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2}, + {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE}, + {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE} + }; + + cs->compositeOver(reinterpret_cast(dstPixels), DST_ROW_STRIDE, reinterpret_cast(srcPixels), + SRC_ROW_STRIDE, tqmask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity); + */ + + delete cs; +} + diff --git a/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h b/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h new file mode 100644 index 00000000..848cf1ac --- /dev/null +++ b/chalk/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_STRATEGY_COLORSPACE_RGB_U16_TESTER_H +#define KIS_STRATEGY_COLORSPACE_RGB_U16_TESTER_H + +#include + +#define CHECK_TOLERANCE( x, y, tolerance ) \ +if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \ +{ \ + success(TQString(__FILE__) + "[" + TQString::number(__LINE__) + "]: passed " + #x); \ +} \ +else \ +{ \ + failure(TQString(__FILE__) + "[" + TQString::number(__LINE__) + TQString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + TQString::number(x)); \ +} \ + +class KisRgbU16ColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); + void testToTQImage(); + void testCompositeOps(); +}; + +#endif + diff --git a/chalk/colorspaces/rgb_u8/Makefile.am b/chalk/colorspaces/rgb_u8/Makefile.am new file mode 100644 index 00000000..0b692fdf --- /dev/null +++ b/chalk/colorspaces/rgb_u8/Makefile.am @@ -0,0 +1,33 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = chalkrgbplugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalkrgb.la +libchalkrgb_la_SOURCES = kis_rgb_colorspace.cc +libchalkrgb_la_LDFLAGS = $(all_libraries) $(LIB_QT) +libchalkrgb_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalkrgbplugin.la + +# Srcs for the plugin +chalkrgbplugin_la_SOURCES = rgb_plugin.cc +noinst_HEADERS = rgb_plugin.h kis_rgb_colorspace.h + +chalkrgbplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalkrgbplugin_la_LIBADD = libchalkrgb.la ../../chalkcolor/libchalkcolor.la + +chalkrgbplugin_la_METASOURCES = AUTO +#METASOURCES = AUTO # XXX: which of the two? + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . templates $(TESTSDIR) + diff --git a/chalk/colorspaces/rgb_u8/chalkrgbplugin.desktop b/chalk/colorspaces/rgb_u8/chalkrgbplugin.desktop new file mode 100644 index 00000000..1a65c773 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/chalkrgbplugin.desktop @@ -0,0 +1,99 @@ +[Desktop Entry] +Name=RGB Color Model +Name[bg]=Цветови модел RGB +Name[br]=Gobari al livioù RGB +Name[ca]=Model de color RGB +Name[cy]=Model Lliw RGB +Name[da]=RGB-farvemodel +Name[de]=RGB-Farbmodell +Name[el]=Χρωματικό μοντέλο RGB +Name[en_GB]=RGB Colour Model +Name[eo]=RGB-kolormodelo +Name[es]=Modelo de color RGB +Name[et]=RGB värvimudel +Name[eu]=RGB kolore-eredua +Name[fa]=مدل رنگ RGB +Name[fi]=RGB-värimalli +Name[fr]=Modèle de couleurs RVB +Name[fy]=RGB-kleurmodel +Name[gl]=Modelo de Cores RGB +Name[he]=מודל צבעים RGB +Name[hi]=आरजीबी रंग नमूना +Name[hu]=RGB színmodell +Name[is]=RGB litategund +Name[it]=Modello di colore RGB +Name[ja]=RGB カラーモデル +Name[km]=គំរូ​ពណ៌ RGB +Name[lt]=RGB spalvų modelis +Name[lv]=RGB krāsu modelis +Name[ms]=Model Warna RGB +Name[nb]=RGB-fargemodell +Name[nds]=RGB-Klöörmodell +Name[ne]=RGB रङ मोडेल +Name[nl]=RGB-kleurmodel +Name[nn]=RGB-fargemodell +Name[pl]=Przestrzeń barw RGB +Name[pt]=Modelo de Cor RGB +Name[pt_BR]=Modelo de Cor RGB +Name[ru]=RGB +Name[se]=RGB-ivdnemálle +Name[sk]=Model farieb RGB +Name[sl]=Barvni model RGB +Name[sr]=RGB модел боја +Name[sr@Latn]=RGB model boja +Name[sv]=RGB-färgmodell +Name[ta]=RGB வண்ண மாதிரி +Name[tr]=RGB Renk Modeli +Name[uk]=Модель кольору RGB +Name[uz]=RGB rang usuli +Name[uz@cyrillic]=RGB ранг усули +Name[zh_CN]=RGB 色彩模型 +Name[zh_TW]=RGB 色彩模型 +Comment=Color model for 8-bit/channel RGB images +Comment[bg]=Цветови модел за 8 битови изображения RGB +Comment[ca]=Model de color per a 8 bits/canal d'imatges RGB +Comment[cy]=Model lliw ar gyfer delweddau RGB 8-did/sianel +Comment[da]=Farvemodel for 8-bit/kanal RGB-billeder +Comment[de]=Farbmodell für 8-bit pro Kanal RGB-Bilder +Comment[el]=Χρωματικό μοντέλο για 8-bit/κανάλι RGB εικόνες +Comment[en_GB]=Colour model for 8-bit/channel RGB images +Comment[es]=Modelo de color para imágenes de 8 bits/canal RGB +Comment[et]=8-bitiste kanalitega RGB-piltide värvimudel +Comment[eu]=8-bit/kanaleko RGB irudien kolore-eredua +Comment[fa]=مدل رنگ برای تصاویر ۸ بیتی/RGB مجرا +Comment[fi]=Värimalli 8-bittisille/kanavaisille RGB-kuville +Comment[fr]=Modèle de couleurs pour des images RVB en 8 bits/plage +Comment[fy]=Kleurmodel foar 8-bit/kanaal RGB-ôfbyldings +Comment[gl]=Modelo de Cores para imaxe RGB de 8-bit/canal +Comment[he]=מודל צבעים עבור תמונות RGB של 8 סיביות/ערוצים +Comment[hi]=8-बिट/चैनल आरजीबी छवियों के लिए रंग नमूना +Comment[hu]=Színmodell 8 bit/csatorna RGB képekhez +Comment[is]=Litategund fyrir 8-bita/rás RGB myndir +Comment[it]=Modello di colore per immagini RGB a canale di 8 bit +Comment[ja]=8 ビット/チャンネル RGB 画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព RGB ៨ ប៊ីត/មួយ​ឆានែល +Comment[ms]=Model warna imej RGB 8-bit/saluran +Comment[nb]=Fargemodell for RGB-bilde med 8 bit per kanal +Comment[nds]=Klöörmodell för RGB-Biller mit 8-Bit per Kanaal +Comment[ne]=८-बिट/च्यानल RGB छविहरूका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 8-bit/kanaal RGB-afbeeldingen +Comment[nn]=Fargemodell for RGB-bilete med 8 bit per kanal +Comment[pl]=Przestrzeń barw dla obrazków RGB 8-bitów/kanał +Comment[pt]=Modelo de cor para imagens RGB com 8 bits por canal +Comment[pt_BR]=Modelo de cor para imagens com 8-bits de canal RGB +Comment[ru]=Цветовое пространство RGB (8-бит/канал) +Comment[sk]=Model farieb pre RGB obrázky s 8-bitovými číslami na kanál +Comment[sl]=Barvni model za slike RGB z 8 biti/kanal +Comment[sr]=Модел боја за RGB слике са 8 битова/каналу +Comment[sr@Latn]=Model boja za RGB slike sa 8 bitova/kanalu +Comment[sv]=Färgmodell för 8-bitar/kanal RGB-bilder +Comment[ta]=8/பிட்/வழி RGB பிம்பங்களுக்கான வண்ண முறை +Comment[tg]=Mодели ранга барои 8-бит /канал тасвирҳои RGB +Comment[tr]=8-bit/kanal RGB görüntüler için renk modeli. +Comment[uk]=Модель кольорів для зображень RGB з 8-бітами/канал +Comment[zh_CN]=8 位/通道 RGB 图像的色彩模型 +Comment[zh_TW]=8-bit/色頻 RGB 圖片的色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkrgbplugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/composite.h b/chalk/colorspaces/rgb_u8/composite.h new file mode 100644 index 00000000..fbd02778 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/composite.h @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + + Some code is derived from GraphicsMagick/magick/composite.c and is + subject to the following license and copyright: + + Copyright (C) 2002 GraphicsMagick Group, an organization dedicated + to making software imaging solutions freely available. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + ("GraphicsMagick"), to deal in GraphicsMagick without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of GraphicsMagick, + and to permit persons to whom GraphicsMagick is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of GraphicsMagick. + + The software is provided "as is", without warranty of any kind, express + or implied, including but not limited to the warranties of + merchantability, fitness for a particular purpose and noninfringement. + In no event shall GraphicsMagick Group be liable for any claim, + damages or other liability, whether in an action of contract, tort or + otherwise, arising from, out of or in connection with GraphicsMagick + or the use or other dealings in GraphicsMagick. + + Except as contained in this notice, the name of the GraphicsMagick + Group shall not be used in advertising or otherwise to promote the + sale, use or other dealings in GraphicsMagick without prior written + authorization from the GraphicsMagick Group. + + Other code is derived from gwenview/src/qxcfi.* - this is released under + the terms of the LGPL + + */ + +#ifndef COMPOSITE_H_ +#define COMPOSITE_H_ + +#include + +#include + +/** + * Image composition functions that can be used by the colour strategies. + * + * XXX: perhaps each composition function ought to be a strategy of itself. + * Chalk is still missing something like a capabilities database that ties + * together image formats, colour systems, composition functions etc., that + * determines which goes with which and defines user visible text for all this. + * + * For now, this is a quick hack; once things are working again, I'll investigate + * doing this nicely (famous last words...) + * + * XXX: Except for Over, none of the operators uses the opacity parameter + */ + + +// Straight from image.h + +#define PixelIntensity(pixel) ((unsigned int) \ + (((double)306.0 * (pixel[PIXEL_RED]) + \ + (double)601.0 * (pixel[PIXEL_GREEN]) + \ + (double)117.0 * (pixel[PIXEL_BLUE)) \ + / 1024.0)) + +#define PixelIntensityToQuantum(pixel) ((TQ_UINT8)PixelIntensity(pixel)) + +#define PixelIntensityToDouble(pixel) ((double)PixelIntensity(pixel)) + +#define RoundSignedToQuantum(value) ((TQ_UINT8) (value < 0 ? 0 : \ + (value > TQ_UINT8_MAX) ? TQ_UINT8_MAX : value + 0.5)) + +#define RoundToQuantum(value) ((TQ_UINT8) (value > TQ_UINT8_MAX ? TQ_UINT8_MAX : \ + value + 0.5)) + +// And from studio.h +#define AbsoluteValue(x) ((x) < 0 ? -(x) : (x)) + +void compositeIn(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + + if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) + { + memcpy(d, s, pixelSize * sizeof(TQ_UINT8)); + continue; + } + if (d[PIXEL_ALPHA] == OPACITY_TRANSPARENT) + continue; + + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + alpha=(double) (((double) UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) / UINT8_MAX); + d[PIXEL_RED]=(TQ_UINT8) (((double) UINT8_MAX - sAlpha) * + (UINT8_MAX-dAlpha) * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5); + d[PIXEL_GREEN]=(TQ_UINT8) (((double) UINT8_MAX - sAlpha)* + (UINT8_MAX-dAlpha) * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5); + d[PIXEL_BLUE]=(TQ_UINT8) (((double) UINT8_MAX - sAlpha)* + (UINT8_MAX - dAlpha) * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5); + d[PIXEL_ALPHA]=(TQ_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5); + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeOut(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) + { + memcpy(d, s, pixelSize * sizeof(TQ_UINT8)); + break; + } + if (d[PIXEL_ALPHA] == OPACITY_OPAQUE) + { + d[PIXEL_ALPHA]=OPACITY_TRANSPARENT; + break; + } + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + alpha=(double) (UINT8_MAX - sAlpha) * d[PIXEL_ALPHA]/UINT8_MAX; + d[PIXEL_RED] = (TQ_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5); + d[PIXEL_GREEN] = (TQ_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5); + d[PIXEL_BLUE] = (TQ_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5); + d[PIXEL_ALPHA]=(TQ_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5); + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeAtop(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha, red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + alpha = ((double)(UINT8_MAX - sAlpha) * + (UINT8_MAX - dAlpha) + (double) sAlpha * + (UINT8_MAX - dAlpha)) / UINT8_MAX; + + red = ((double)(UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[PIXEL_RED] / UINT8_MAX + + (double) sAlpha * (UINT8_MAX-dAlpha) * d[PIXEL_RED]/UINT8_MAX) / alpha; + d[PIXEL_RED] = (TQ_UINT8) (red > UINT8_MAX ? UINT8_MAX : red + 0.5); + + green = ((double) (UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[PIXEL_GREEN] / UINT8_MAX + + (double) sAlpha * (UINT8_MAX-dAlpha) * d[PIXEL_GREEN]/UINT8_MAX)/alpha; + d[PIXEL_GREEN] = (TQ_UINT8) (green > UINT8_MAX ? UINT8_MAX : green + 0.5); + + blue = ((double) (UINT8_MAX - sAlpha) * (UINT8_MAX- dAlpha) * s[PIXEL_BLUE] / UINT8_MAX + + (double) sAlpha * (UINT8_MAX - dAlpha) * d[PIXEL_BLUE]/UINT8_MAX) / alpha; + d[PIXEL_BLUE] = (TQ_UINT8) (blue > UINT8_MAX ? UINT8_MAX : blue + 0.5); + d[PIXEL_ALPHA]=(TQ_UINT8) (UINT8_MAX - (alpha > UINT8_MAX ? UINT8_MAX : alpha) + 0.5); + } + dst += dstRowSize; + src += srcRowSize; + } +} + + +void compositeXor(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha, red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + alpha =((double) (UINT8_MAX -sAlpha)* + dAlpha+(double) (UINT8_MAX -dAlpha)* + sAlpha)/UINT8_MAX ; + red=((double) (UINT8_MAX -sAlpha)*dAlpha* + s[PIXEL_RED]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)* + sAlpha*d[PIXEL_RED]/UINT8_MAX )/alpha ; + d[PIXEL_RED]=RoundSignedToQuantum(red); + green=((double) (UINT8_MAX -sAlpha)*dAlpha* + s[PIXEL_GREEN]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)* + sAlpha*d[PIXEL_GREEN]/UINT8_MAX )/alpha ; + d[PIXEL_GREEN]=RoundSignedToQuantum(green); + blue=((double) (UINT8_MAX -sAlpha)*dAlpha* + s[PIXEL_BLUE]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)* + sAlpha*d[PIXEL_BLUE]/UINT8_MAX )/alpha ; + d[PIXEL_BLUE]=RoundSignedToQuantum(blue); + d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha ); + } + dst += dstRowSize; + src += srcRowSize; + } + +} + + +void compositePlus(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha, red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + red=((double) (UINT8_MAX -sAlpha)*s[PIXEL_RED]+(double) + (UINT8_MAX -dAlpha)*d[PIXEL_RED])/UINT8_MAX ; + d[PIXEL_RED]=RoundSignedToQuantum(red); + green=((double) (UINT8_MAX -sAlpha)*s[PIXEL_GREEN]+(double) + (UINT8_MAX -dAlpha)*d[PIXEL_GREEN])/UINT8_MAX ; + d[PIXEL_GREEN]=RoundSignedToQuantum(green); + blue=((double) (UINT8_MAX -sAlpha)*s[PIXEL_BLUE]+(double) + (UINT8_MAX -dAlpha)*d[PIXEL_BLUE])/UINT8_MAX ; + d[PIXEL_BLUE]=RoundSignedToQuantum(blue); + alpha =((double) (UINT8_MAX -sAlpha)+ + (double) (UINT8_MAX -dAlpha))/UINT8_MAX ; + d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha ); + } + dst += dstRowSize; + src += srcRowSize; + } +} + + + +void compositeMinus(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double alpha, red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + red=((double) (UINT8_MAX -dAlpha)*d[PIXEL_RED]- + (double) (UINT8_MAX -sAlpha)*s[PIXEL_RED])/UINT8_MAX ; + d[PIXEL_RED]=RoundSignedToQuantum(red); + green=((double) (UINT8_MAX -dAlpha)*d[PIXEL_GREEN]- + (double) (UINT8_MAX -sAlpha)*s[PIXEL_GREEN])/UINT8_MAX ; + d[PIXEL_GREEN]=RoundSignedToQuantum(green); + blue=((double) (UINT8_MAX -dAlpha)*d[PIXEL_BLUE]- + (double) (UINT8_MAX -sAlpha)*s[PIXEL_BLUE])/UINT8_MAX ; + d[PIXEL_BLUE]=RoundSignedToQuantum(blue); + alpha =((double) (UINT8_MAX -dAlpha)- + (double) (UINT8_MAX -sAlpha))/UINT8_MAX ; + d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha ); + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeAdd(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + double red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + red=(double) s[PIXEL_RED]+d[PIXEL_RED]; + d[PIXEL_RED]=(TQ_UINT8) + (red > UINT8_MAX ? red-=UINT8_MAX : red+0.5); + green=(double) s[PIXEL_GREEN]+d[PIXEL_GREEN]; + d[PIXEL_GREEN]=(TQ_UINT8) + (green > UINT8_MAX ? green-=UINT8_MAX : green+0.5); + blue=(double) s[PIXEL_BLUE]+d[PIXEL_BLUE]; + d[PIXEL_BLUE]=(TQ_UINT8) + (blue > UINT8_MAX ? blue-=UINT8_MAX : blue+0.5); + d[PIXEL_ALPHA]=OPACITY_OPAQUE; + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeSubtract(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double red, green, blue; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + + red=(double) s[PIXEL_RED]-d[PIXEL_RED]; + d[PIXEL_RED]=(TQ_UINT8) + (red < 0 ? red+=UINT8_MAX : red+0.5); + green=(double) s[PIXEL_GREEN]-d[PIXEL_GREEN]; + d[PIXEL_GREEN]=(TQ_UINT8) + (green < 0 ? green+=UINT8_MAX : green+0.5); + blue=(double) s[PIXEL_BLUE]-d[PIXEL_BLUE]; + d[PIXEL_BLUE]=(TQ_UINT8) + (blue < 0 ? blue+=UINT8_MAX : blue+0.5); + d[PIXEL_ALPHA]=OPACITY_OPAQUE; + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeDiff(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + d[PIXEL_RED]=(TQ_UINT8) + AbsoluteValue(s[PIXEL_RED]-(double) d[PIXEL_RED]); + d[PIXEL_GREEN]=(TQ_UINT8) + AbsoluteValue(s[PIXEL_GREEN]-(double) d[PIXEL_GREEN]); + d[PIXEL_BLUE]=(TQ_UINT8) + AbsoluteValue(s[PIXEL_BLUE]-(double) d[PIXEL_BLUE]); + d[PIXEL_ALPHA]=UINT8_MAX - (TQ_UINT8) + AbsoluteValue(sAlpha-(double) dAlpha); + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeBumpmap(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double intensity; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + // Is this correct? It's not this way in GM. + if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) + continue; + + // And I'm not sure whether this is correct, either. + intensity = ((double)306.0 * s[PIXEL_RED] + + (double)601.0 * s[PIXEL_GREEN] + + (double)117.0 * s[PIXEL_BLUE]) / 1024.0; + + d[PIXEL_RED]=(TQ_UINT8) (((double) + intensity * d[PIXEL_RED])/UINT8_MAX +0.5); + d[PIXEL_GREEN]=(TQ_UINT8) (((double) + intensity * d[PIXEL_GREEN])/UINT8_MAX +0.5); + d[PIXEL_BLUE]=(TQ_UINT8) (((double) + intensity * d[PIXEL_BLUE])/UINT8_MAX +0.5); + d[PIXEL_ALPHA]= (TQ_UINT8) (((double) + intensity * d[PIXEL_ALPHA])/UINT8_MAX +0.5); + + + } + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeCopy(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + TQ_UINT8 *d; + const TQ_UINT8 *s; + d = dst; + s = src; + TQ_UINT32 len = cols * pixelSize; + + while (rows-- > 0) { + memcpy(d, s, len); + d += dstRowSize; + s += srcRowSize; + } +} + +void compositeCopyChannel(TQ_UINT8 pixel, + TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + TQ_UINT8 *d; + const TQ_UINT8 *s; + TQ_INT32 i; + + while (rows-- > 0) { + d = dst; + s = src; + + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + d[pixel] = s[pixel]; + } + + dst += dstRowSize; + src += srcRowSize; + } + +} + +void compositeCopyRed(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_RED, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + +void compositeCopyGreen(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_GREEN, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + +void compositeCopyBlue(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + compositeCopyChannel(PIXEL_BLUE, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); +} + + +void compositeCopyOpacity(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + + // XXX: mess with intensity if there isn't an alpha channel, according to GM. + compositeCopyChannel(PIXEL_ALPHA, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity); + +} + + +void compositeClear(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 /*srcRowSize*/, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + + TQ_INT32 linesize = pixelSize * sizeof(TQ_UINT8) * cols; + TQ_UINT8 *d; + const TQ_UINT8 *s; + + d = dst; + s = src; + + while (rows-- > 0) { + memset(d, 0, linesize); + d += dstRowSize; + } + +} + + +void compositeDissolve(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + // XXX: correct? + if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) continue; + + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + d[PIXEL_RED]=(TQ_UINT8) (((double) sAlpha*s[PIXEL_RED]+ + (UINT8_MAX -sAlpha)*d[PIXEL_RED])/UINT8_MAX +0.5); + d[PIXEL_GREEN]= (TQ_UINT8) (((double) sAlpha*s[PIXEL_GREEN]+ + (UINT8_MAX -sAlpha)*d[PIXEL_GREEN])/UINT8_MAX +0.5); + d[PIXEL_BLUE] = (TQ_UINT8) (((double) sAlpha*s[PIXEL_BLUE]+ + (UINT8_MAX -sAlpha)*d[PIXEL_BLUE])/UINT8_MAX +0.5); + d[PIXEL_ALPHA] = OPACITY_OPAQUE; + } + dst += dstRowSize; + src += srcRowSize; + } + +} + + +void compositeDisplace(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/ = OPACITY_OPAQUE) +{ + TQ_INT32 linesize = pixelSize * sizeof(TQ_UINT8) * cols; + TQ_UINT8 *d; + const TQ_UINT8 *s; + d = dst; + s = src; + + while (rows-- > 0) { + memcpy(d, s, linesize); + d += dstRowSize; + s += srcRowSize; + } + +} + +#if 0 +void compositeModulate(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + if (opacity == OPACITY_TRANSPARENT) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 i; + + double sAlpha, dAlpha; + long offset; + + while (rows-- > 0) { + d = dst; + s = src; + for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) { + // XXX: correct? + if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) continue; + + sAlpha = UINT8_MAX - s[PIXEL_ALPHA]; + dAlpha = UINT8_MAX - d[PIXEL_ALPHA]; + + + offset=(long) (PixelIntensityToQuantum(&source)-midpoint); + if (offset == 0) + continue; + TransformHSL(d[PIXEL_RED],d[PIXEL_GREEN],d[PIXEL_BLUE], + &hue,&saturation,&brightness); + brightness+=(percent_brightness*offset)/midpoint; + if (brightness < 0.0) + brightness=0.0; + else + if (brightness > 1.0) + brightness=1.0; + HSLTransform(hue,saturation,brightness,&d[PIXEL_RED], + &d[PIXEL_GREEN],&d[PIXEL_BLUE]); + + + } + dst += dstRowSize; + src += srcRowSize; + } + + +} + + +void compositeThreshold(TQ_INT32 pixelSize, + TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 opacity = OPACITY_OPAQUE) +{ + TQ_INT32 linesize = pixelSize * sizeof(TQ_UINT8) * cols; + TQ_UINT8 *d; + const TQ_UINT8 *s; + TQ_UINT8 alpha; + TQ_UINT8 invAlpha; + TQ_INT32 i; + +} + +#endif + +void compositeColorize(TQ_INT32, + TQ_UINT8 *, + TQ_INT32 , + const TQ_UINT8 *, + TQ_INT32 , + TQ_INT32 , + TQ_INT32 , + TQ_UINT8 ) +{ +} + + +void compositeLuminize(TQ_INT32 , + TQ_UINT8 *, + TQ_INT32 , + const TQ_UINT8 *, + TQ_INT32 , + TQ_INT32 , + TQ_INT32 , + TQ_UINT8 ) +{ + +} + +#endif + diff --git a/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.cc b/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.cc new file mode 100644 index 00000000..34ab79fc --- /dev/null +++ b/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.cc @@ -0,0 +1,1501 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include LCMS_HEADER + +#include +#include + +#include +#include + +#include "kis_rgb_colorspace.h" +#include "kis_u8_base_colorspace.h" +#include "kis_color_conversions.h" +#include "kis_integer_maths.h" +#include "kis_colorspace_factory_registry.h" + +#include "composite.h" + +#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL)) +#define upscale(value) (value) // ((TQ_UINT8) (257UL*(value))) + +namespace { + const TQ_INT32 MAX_CHANNEL_RGB = 3; + const TQ_INT32 MAX_CHANNEL_RGBA = 4; +} + +KisRgbColorSpace::KisRgbColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisU8BaseColorSpace(KisID("RGBA", i18n("RGB (8-bit integer/channel)")), TYPE_BGRA_8, icSigRgbData, tqparent, p) +{ + m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(255,0,0))); + m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,255,0))); + m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,0,255))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 3, KisChannelInfo::ALPHA, KisChannelInfo::UINT8)); + + m_alphaPos = PIXEL_ALPHA; + init(); +} + +KisRgbColorSpace::~KisRgbColorSpace() +{ +} + +void KisRgbColorSpace::setPixel(TQ_UINT8 *pixel, TQ_UINT8 red, TQ_UINT8 green, TQ_UINT8 blue, TQ_UINT8 alpha) const +{ + pixel[PIXEL_RED] = red; + pixel[PIXEL_GREEN] = green; + pixel[PIXEL_BLUE] = blue; + pixel[PIXEL_ALPHA] = alpha; +} + +void KisRgbColorSpace::getPixel(const TQ_UINT8 *pixel, TQ_UINT8 *red, TQ_UINT8 *green, TQ_UINT8 *blue, TQ_UINT8 *alpha) const +{ + *red = pixel[PIXEL_RED]; + *green = pixel[PIXEL_GREEN]; + *blue = pixel[PIXEL_BLUE]; + *alpha = pixel[PIXEL_ALPHA]; +} + +void KisRgbColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + + while (nColors--) + { + TQ_UINT32 alpha = (*colors)[PIXEL_ALPHA]; + // although we only mult by weight and not by weight*256/255 + // we divide by the same amount later, so there is no need + TQ_UINT32 alphaTimesWeight = alpha * *weights; + + totalRed += (*colors)[PIXEL_RED] * alphaTimesWeight; + totalGreen += (*colors)[PIXEL_GREEN] * alphaTimesWeight; + totalBlue += (*colors)[PIXEL_BLUE] * alphaTimesWeight; + totalAlpha += alphaTimesWeight; + + weights++; + colors++; + } + + // note this is correct - if you look at the above calculation + if (totalAlpha > 255*255) totalAlpha = 255*255; + + // Divide by 255. + dst[PIXEL_ALPHA] =(((totalAlpha + 0x80)>>8)+totalAlpha + 0x80) >>8; + + if (totalAlpha > 0) { + totalRed = totalRed / totalAlpha; + totalGreen = totalGreen / totalAlpha; + totalBlue = totalBlue / totalAlpha; + } // else the values are already 0 too + + TQ_UINT32 dstRed = totalRed; + //Q_ASSERT(dstRed <= 255); + if (dstRed > 255) dstRed = 255; + dst[PIXEL_RED] = dstRed; + + TQ_UINT32 dstGreen = totalGreen; + //Q_ASSERT(dstGreen <= 255); + if (dstGreen > 255) dstGreen = 255; + dst[PIXEL_GREEN] = dstGreen; + + TQ_UINT32 dstBlue = totalBlue; + //Q_ASSERT(dstBlue <= 255); + if (dstBlue > 255) dstBlue = 255; + dst[PIXEL_BLUE] = dstBlue; +} + +void KisRgbColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const +{ + TQ_INT64 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0; + TQ_INT32 totalWeight = 0, totalWeightTransparent = 0; + while (nColors--) + { + TQ_INT32 weight = *kernelValues; + + if (weight != 0) { + if((*colors)[PIXEL_ALPHA] == 0) + { + totalWeightTransparent += weight; + } else { + totalRed += (*colors)[PIXEL_RED] * weight; + totalGreen += (*colors)[PIXEL_GREEN] * weight; + totalBlue += (*colors)[PIXEL_BLUE] * weight; + } + totalAlpha += (*colors)[PIXEL_ALPHA] * weight; + totalWeight += weight; + } + colors++; + kernelValues++; + } + if(totalWeightTransparent == 0) + { + if (channelFlags & KisChannelInfo::FLAG_COLOR) { + dst[PIXEL_RED] = CLAMP((totalRed / factor) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP((totalGreen / factor) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP((totalBlue / factor) + offset, 0, TQ_UINT8_MAX); + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } + } else if(totalWeightTransparent != totalWeight && (channelFlags & KisChannelInfo::FLAG_COLOR)) { + if(totalWeight == factor) + { + TQ_INT64 a = ( totalWeight - totalWeightTransparent ); + dst[PIXEL_RED] = CLAMP((totalRed / a) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP((totalGreen / a) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP((totalBlue / a) + offset, 0, TQ_UINT8_MAX); + } else { + double a = totalWeight / ( factor * ( totalWeight - totalWeightTransparent ) ); // use double as it can saturate + dst[PIXEL_RED] = CLAMP( (TQ_UINT8)(totalRed * a) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_GREEN] = CLAMP( (TQ_UINT8)(totalGreen * a) + offset, 0, TQ_UINT8_MAX); + dst[PIXEL_BLUE] = CLAMP( (TQ_UINT8)(totalBlue * a) + offset, 0, TQ_UINT8_MAX); + } + } + if (channelFlags & KisChannelInfo::FLAG_ALPHA) { + dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX); + } +} + + +void KisRgbColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) +{ + TQ_UINT32 psize = pixelSize(); + + while (nPixels--) + { + src[PIXEL_RED] = TQ_UINT8_MAX - src[PIXEL_RED]; + src[PIXEL_GREEN] = TQ_UINT8_MAX - src[PIXEL_GREEN]; + src[PIXEL_BLUE] = TQ_UINT8_MAX - src[PIXEL_BLUE]; + + src += psize; + } +} + + +void KisRgbColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const +{ + TQ_UINT32 pSize = pixelSize(); + + while (nPixels--) { + if (compensate) { + dst[PIXEL_RED] = (TQ_INT8) TQMIN(255,((src[PIXEL_RED] * shade) / (compensation * 255))); + dst[PIXEL_GREEN] = (TQ_INT8) TQMIN(255,((src[PIXEL_GREEN] * shade) / (compensation * 255))); + dst[PIXEL_BLUE] = (TQ_INT8) TQMIN(255,((src[PIXEL_BLUE] * shade) / (compensation * 255))); + } + else { + dst[PIXEL_RED] = (TQ_INT8) TQMIN(255, (src[PIXEL_RED] * shade / 255)); + dst[PIXEL_BLUE] = (TQ_INT8) TQMIN(255, (src[PIXEL_BLUE] * shade / 255)); + dst[PIXEL_GREEN] = (TQ_INT8) TQMIN(255, (src[PIXEL_GREEN] * shade / 255)); + } + dst += pSize; + src += pSize; + } +} + +TQ_UINT8 KisRgbColorSpace::intensity8(const TQ_UINT8 * src) const +{ + return (TQ_UINT8)((src[PIXEL_RED] * 0.30 + src[PIXEL_GREEN] * 0.59 + src[PIXEL_BLUE] * 0.11) + 0.5); +} + +TQValueVector KisRgbColorSpace::channels() const +{ + return m_channels; +} + +TQ_UINT32 KisRgbColorSpace::nChannels() const +{ + return MAX_CHANNEL_RGBA; +} + +TQ_UINT32 KisRgbColorSpace::nColorChannels() const +{ + return MAX_CHANNEL_RGB; +} + +TQ_UINT32 KisRgbColorSpace::pixelSize() const +{ + return MAX_CHANNEL_RGBA; +} + +TQImage KisRgbColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, float /*exposure*/) + +{ + Q_ASSERT(data); + TQImage img = TQImage(const_cast(data), width, height, 32, 0, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + // XXX: The previous version of this code used the quantum data directly + // as an optimisation. We're introducing a copy overhead here which could + // be factored out again if needed. + img = img.copy(); + + if (dstProfile != 0) { + KisColorSpace *dstCS = m_parent->getColorSpace(KisID("RGBA",""), dstProfile->productName()); + convertPixelsTo(img.bits(), + img.bits(), dstCS, + width * height, renderingIntent); + } + + return img; +} + + + + +void KisRgbColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, + const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(TQ_UINT8)); + } else { + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(TQ_UINT8)); + } else { + dst[PIXEL_RED] = UINT8_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend); + dst[PIXEL_GREEN] = UINT8_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend); + dst[PIXEL_BLUE] = UINT8_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + + +void KisRgbColorSpace::compositeAlphaDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, + const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcAlpha, opacity); + } + + if (srcAlpha != OPACITY_TRANSPARENT && srcAlpha >= dstAlpha) { + dst[PIXEL_ALPHA] = srcAlpha; + memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(TQ_UINT8)); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + + +void KisRgbColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + TQ_UINT8 srcColor = src[PIXEL_RED]; + TQ_UINT8 dstColor = dst[PIXEL_RED]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[PIXEL_RED] = UINT8_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_GREEN]; + dstColor = dst[PIXEL_GREEN]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[PIXEL_GREEN] = UINT8_BLEND(srcColor, dstColor, srcBlend); + + srcColor = src[PIXEL_BLUE]; + dstColor = dst[PIXEL_BLUE]; + + srcColor = UINT8_MULT(srcColor, dstColor); + + dst[PIXEL_BLUE] = UINT8_BLEND(srcColor, dstColor, srcBlend); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor)); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX); + if (UINT8_MAX - srcColor > UINT8_MAX) srcColor = UINT8_MAX; + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMIN(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) { + + TQ_UINT8 srcColor = src[channel]; + TQ_UINT8 dstColor = dst[channel]; + + srcColor = TQMAX(srcColor, dstColor); + + TQ_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend); + + dst[channel] = newColor; + } + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeHue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + int dstRed = dst[PIXEL_RED]; + int dstGreen = dst[PIXEL_GREEN]; + int dstBlue = dst[PIXEL_BLUE]; + + int srcHue; + int srcSaturation; + int srcValue; + int dstHue; + int dstSaturation; + int dstValue; + + rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue); + rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + int srcRed; + int srcGreen; + int srcBlue; + + hsv_to_rgb(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeSaturation(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + int dstRed = dst[PIXEL_RED]; + int dstGreen = dst[PIXEL_GREEN]; + int dstBlue = dst[PIXEL_BLUE]; + + int srcHue; + int srcSaturation; + int srcValue; + int dstHue; + int dstSaturation; + int dstValue; + + rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue); + rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + int srcRed; + int srcGreen; + int srcBlue; + + hsv_to_rgb(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeValue(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + int dstRed = dst[PIXEL_RED]; + int dstGreen = dst[PIXEL_GREEN]; + int dstBlue = dst[PIXEL_BLUE]; + + int srcHue; + int srcSaturation; + int srcValue; + int dstHue; + int dstSaturation; + int dstValue; + + rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue); + rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue); + + int srcRed; + int srcGreen; + int srcBlue; + + hsv_to_rgb(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeColor(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + TQ_INT32 columns = numColumns; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + srcAlpha = TQMIN(srcAlpha, dstAlpha); + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity); + } + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + int dstRed = dst[PIXEL_RED]; + int dstGreen = dst[PIXEL_GREEN]; + int dstBlue = dst[PIXEL_BLUE]; + + int srcHue; + int srcSaturation; + int srcLightness; + int dstHue; + int dstSaturation; + int dstLightness; + + rgb_to_hls(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcLightness, &srcSaturation); + rgb_to_hls(dstRed, dstGreen, dstBlue, &dstHue, &dstLightness, &dstSaturation); + + TQ_UINT8 srcRed; + TQ_UINT8 srcGreen; + TQ_UINT8 srcBlue; + + hls_to_rgb(srcHue, dstLightness, srcSaturation, &srcRed, &srcGreen, &srcBlue); + + dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend); + dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend); + dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend); + } + + columns--; + src += MAX_CHANNEL_RGBA; + dst += MAX_CHANNEL_RGBA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } +} + +void KisRgbColorSpace::compositeErase(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowSize, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_INT32 rows, + TQ_INT32 cols, + TQ_UINT8 /*opacity*/) +{ + TQ_INT32 i; + TQ_UINT8 srcAlpha; + + while (rows-- > 0) + { + const TQ_UINT8 *s = src; + TQ_UINT8 *d = dst; + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (i = cols; i > 0; i--, s+=MAX_CHANNEL_RGBA, d+=MAX_CHANNEL_RGBA) + { + srcAlpha = s[PIXEL_ALPHA]; + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *tqmask); + tqmask++; + } + d[PIXEL_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_ALPHA]); + } + + dst += dstRowSize; + if(srcAlphaMask) + srcAlphaMask += tqmaskRowStride; + src += srcRowSize; + } +} + +void KisRgbColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ALPHA_DARKEN: + compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_IN: + compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_OUT: + compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ATOP: + compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_XOR: + compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_PLUS: + compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MINUS: + compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_ADD: + compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SUBTRACT: + compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIFF: + compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_MULT: + compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DIVIDE: + compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BUMPMAP: + compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_RED: + compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_GREEN: + compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_BLUE: + compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY_OPACITY: + compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_CLEAR: + compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISSOLVE: + compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_DISPLACE: + compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#if 0 + case COMPOSITE_MODULATE: + compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_THRESHOLD: + compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; +#endif + case COMPOSITE_NO: + // No composition. + break; + case COMPOSITE_DARKEN: + compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_LIGHTEN: + compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_HUE: + compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_SATURATION: + compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_VALUE: + compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLOR: + compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COLORIZE: + compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_LUMINIZE: + compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity); + break; + case COMPOSITE_SCREEN: + compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_OVERLAY: + compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_DODGE: + compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_BURN: + compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +KisCompositeOpList KisRgbColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_MULT)); + list.append(KisCompositeOp(COMPOSITE_BURN)); + list.append(KisCompositeOp(COMPOSITE_DODGE)); + list.append(KisCompositeOp(COMPOSITE_DIVIDE)); + list.append(KisCompositeOp(COMPOSITE_SCREEN)); + list.append(KisCompositeOp(COMPOSITE_OVERLAY)); + list.append(KisCompositeOp(COMPOSITE_DARKEN)); + list.append(KisCompositeOp(COMPOSITE_LIGHTEN)); + list.append(KisCompositeOp(COMPOSITE_HUE)); + list.append(KisCompositeOp(COMPOSITE_SATURATION)); + list.append(KisCompositeOp(COMPOSITE_VALUE)); + list.append(KisCompositeOp(COMPOSITE_COLOR)); + list.append(KisCompositeOp(COMPOSITE_PLUS)); + list.append(KisCompositeOp(COMPOSITE_MINUS)); + list.append(KisCompositeOp(COMPOSITE_SUBTRACT)); + list.append(KisCompositeOp(COMPOSITE_ADD)); + + return list; +} diff --git a/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.h b/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.h new file mode 100644 index 00000000..53281faf --- /dev/null +++ b/chalk/colorspaces/rgb_u8/kis_rgb_colorspace.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_RGB_H_ +#define KIS_STRATEGY_COLORSPACE_RGB_H_ + +#include "klocale.h" + +#include "kis_global.h" +#include "kis_u8_base_colorspace.h" +#include "koffice_export.h" + +const TQ_UINT8 PIXEL_BLUE = 0; +const TQ_UINT8 PIXEL_GREEN = 1; +const TQ_UINT8 PIXEL_RED = 2; +const TQ_UINT8 PIXEL_ALPHA = 3; + +class KRITATOOL_EXPORT KisRgbColorSpace : public KisU8BaseColorSpace { +public: + KisRgbColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisRgbColorSpace(); + + virtual bool willDegrade(ColorSpaceIndependence) + { + return false; + }; + + +public: + void setPixel(TQ_UINT8 *pixel, TQ_UINT8 red, TQ_UINT8 green, TQ_UINT8 blue, TQ_UINT8 alpha) const; + void getPixel(const TQ_UINT8 *pixel, TQ_UINT8 *red, TQ_UINT8 *green, TQ_UINT8 *blue, TQ_UINT8 *alpha) const; + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile = 0, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeAlphaDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); +}; + +class KisRgbColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("RGBA", i18n("RGB (8-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_BGRA_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile * p) { return new KisRgbColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return "sRGB built-in - (lcms internal)"; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_RGB_H_ diff --git a/chalk/colorspaces/rgb_u8/rgb_plugin.cc b/chalk/colorspaces/rgb_u8/rgb_plugin.cc new file mode 100644 index 00000000..0794456e --- /dev/null +++ b/chalk/colorspaces/rgb_u8/rgb_plugin.cc @@ -0,0 +1,74 @@ +/* +* rgb_plugin.cc -- Part of Chalk +* +* Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "rgb_plugin.h" +#include "kis_rgb_colorspace.h" + +typedef KGenericFactory RGBPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkrgbplugin, RGBPluginFactory( "chalk" ) ) + + +RGBPlugin::RGBPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(RGBPluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast(tqparent); + + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + f->addProfile(defProfile); + + + KisColorSpaceFactory * csFactory = new KisRgbColorSpaceFactory(); + f->add(csFactory); + + KisColorSpace * colorSpaceRGBA = new KisRgbColorSpace(f, 0); + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("RGB8HISTO", i18n("RGB8")), colorSpaceRGBA) ); + } + +} + +RGBPlugin::~RGBPlugin() +{ +} + +#include "rgb_plugin.moc" diff --git a/chalk/colorspaces/rgb_u8/rgb_plugin.h b/chalk/colorspaces/rgb_u8/rgb_plugin.h new file mode 100644 index 00000000..08ccd890 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/rgb_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RGB_PLUGIN_H_ +#define RGB_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the RGB colour space strategy. + */ +class RGBPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + RGBPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~RGBPlugin(); + +}; + + +#endif // RGB_PLUGIN_H_ diff --git a/chalk/colorspaces/rgb_u8/rgbplugin.rc b/chalk/colorspaces/rgb_u8/rgbplugin.rc new file mode 100644 index 00000000..943f5e25 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/rgbplugin.rc @@ -0,0 +1,9 @@ + + +&Image + &Mode + + + + + diff --git a/chalk/colorspaces/rgb_u8/templates/.directory b/chalk/colorspaces/rgb_u8/templates/.directory new file mode 100644 index 00000000..4b475643 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/.directory @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=RGB +Name[cy]=CGwGl (RGB) +Name[fr]=RVB +Name[hi]=आरजीबी +X-KDE-DefaultTab=true diff --git a/chalk/colorspaces/rgb_u8/templates/Makefile.am b/chalk/colorspaces/rgb_u8/templates/Makefile.am new file mode 100644 index 00000000..216701e7 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/Makefile.am @@ -0,0 +1,8 @@ +templates_DATA = .directory transparent_1024x768.desktop transparent_1280x1024.desktop transparent_1600x1200.desktop transparent_640x480.desktop white_1024x768.desktop white_1280x1024.desktop white_1600x1200.desktop white_640x480.desktop +templatesdir = $(kde_datadir)/chalk/templates/rgb + +templatesrc_DATA = transparent_1024x768.kra transparent_1280x1024.kra transparent_1600x1200.kra transparent_640x480.kra white_1024x768.kra white_1280x1024.kra white_1600x1200.kra white_640x480.kra +templatesrcdir = $(kde_datadir)/chalk/templates/rgb/.source + +templatesicon_ICON = AUTO +templatesicondir = $(kde_datadir)/chalk/icons diff --git a/chalk/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png b/chalk/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png new file mode 100644 index 00000000..e3108556 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png differ diff --git a/chalk/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz b/chalk/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz new file mode 100644 index 00000000..3ea7b854 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz differ diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.desktop b/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.desktop new file mode 100644 index 00000000..02722c8a --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.desktop @@ -0,0 +1,91 @@ +[Desktop Entry] +Type=Link +URL=.source/transparent_1024x768.kra +Icon=template_rgb_empty +Name=Transparent 1024 x 768 +Name[bg]=Прозрачно 1024x768 +Name[br]=Treuzwelus 1024 x 768 +Name[cy]=Tryloyw 1024 x 768 +Name[da]=Gennemsigtig 1024 x 768 +Name[el]=Διαφανής 1024 x 768 +Name[es]=1024 x 768 transparente +Name[et]=Läbipaistev 1024 x 768 +Name[eu]=Gardena 1024 x 768 +Name[fa]=شفاف ۷۶۸ × ۱۰۲۴ +Name[fi]=Läpinäkyvä 1024x768 +Name[fr]=Image transparente 1024 x 768 +Name[fy]=Trochsichtich 1024 x 768 +Name[gl]=Transparente 1024 x 768 +Name[he]=‏1024‎ x 768 שקוף +Name[hu]=Áttetsző 1024 x 768 +Name[is]=Gegnsæ 1024 x 768 +Name[it]=Trasparente 1024 × 768 +Name[ja]=透明 1024 x 768 +Name[km]=ថ្លា 1024 x 768 +Name[lt]=Permatomas 1024 x 768 +Name[lv]=Caurspīdīgs 1024 x 768 +Name[ms]=Lutsinar 1024 x 768 +Name[nb]=Gjennomsiktig 1024 × 768 +Name[nds]=Dörsichtig 1024 x 768 +Name[ne]=पारदर्शी १०२४ x ७६८ +Name[nn]=Gjennomsiktig 1024 × 768 +Name[pl]=Przezroczysty 1024 x 768 +Name[pt]=Transparente 1024 x 768 +Name[pt_BR]=Transparente de 1024 x 768 +Name[ru]=Рисунок 1024x768, прозрачный фон +Name[se]=Čađačuovgi 1024 × 768 +Name[sk]=Priehľadný 1024 x 768 +Name[sl]=Prosojna 1024 x 768 +Name[sr]=Провидна 1024 x 768 +Name[sr@Latn]=Providna 1024 x 768 +Name[sv]=Genomskinlig 1024 x 768 +Name[uk]=Прозоре 1024 x 768 +Name[uz]=Shaffof 1024 x 768 +Name[uz@cyrillic]=Шаффоф 1024 x 768 +Name[zh_CN]=透明 1024 x 768 +Name[zh_TW]=透明 1024 x 768 +Comment=Creates a transparent image of 1024 x 768 pixels. +Comment[bg]=Създава прозрачно изображение с размери 1024x768 пиксела. +Comment[ca]=Crea una imatge transparent de 1024 x 768 píxels. +Comment[cy]=Creu delwedd dryloyw o 1024 x 768 picsel. +Comment[da]=Laver et gennemsigtigt billede på 1024 x 768 billedpunkter. +Comment[de]=Erstellt ein transparentes Bild mit 1024 x 768 Pixeln. +Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1024 x 768 εικονοστοιχείων. +Comment[eo]=Kreas travideblan bildon el 1024 x 768 rastrumeroj. +Comment[es]=Crea una imagen transparente de 1024 x 768 píxeles. +Comment[et]=Loob läbipaistva pildi mõõtmetega 1024 x 768 pikslit. +Comment[eu]=1024 x 768 pixeleko irudi garden bat sortzen du. +Comment[fa]=یک تصویر شفاف ۷۶۸ × ۱۰۲۴ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo läpinäkyvän 1024x768 pikselin kuvan. +Comment[fr]=Crée une image transparente de 1024 x 768 pixels. +Comment[fy]=Makket in trochsichtige ôfbylding oan fan 1024 x 768 byldpunten. +Comment[gl]=Cria unha imaxe transparente de 1024 x 768 pixels. +Comment[he]=יצירת תמונה שקופה בגודל ‎1024 x 768 פיקסלים +Comment[hu]=Létrehoz egy 1024 x 768 képpontos áttetsző képet. +Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1024 x 768 punktar. +Comment[it]=Crea un'immagine trasparente di 1024 × 768 pixel. +Comment[ja]=1024 x 768 ピクセルの透視画像を作成 +Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1024 x 768 ភីកសែល ។ +Comment[lt]=Sukuria permatomą 1024 x 768 pikselių paveiksliuką. +Comment[ms]=Cipta imej lutsinar 1024 x 768 piksel. +Comment[nb]=Lager et gjennomsiktig bilde på 1024 x 768 piksler. +Comment[nds]=Stellt en dörsichtig Bild mit 1024 x 768 Pixels op. +Comment[ne]=१०२४ x ७६८ पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een transparante afbeelding aan van 1024 x 768 pixels. +Comment[nn]=Lagar eit gjennomsiktig bilete på 1024 × 768 pikslar. +Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1024 x 768 pikseli. +Comment[pt]=Cria uma imagem transparente com 1024 x 768 pontos. +Comment[pt_BR]=Cria uma imagem transparente de 1024 x 768 pixels. +Comment[ru]=Рисунок 1024x768, прозрачный фон +Comment[se]=Ráhkada čađačuovgi gova mas t 1024 × 768 govvačuoggá +Comment[sk]=Vytvorí obrázok s rozmermi 1024 x 768 pixelov a priehľadným pozadím. +Comment[sl]=Ustvari prosojno sliko velikosti 1024 x 768 pik. +Comment[sr]=Прави провидну слику са 1024 x 768 пиксела. +Comment[sr@Latn]=Pravi providnu sliku sa 1024 x 768 piksela. +Comment[sv]=Skapar en genomskinlig bild med 1024 x 768 bildpunkter. +Comment[uk]=Створює прозоре зображення 1024 x 768 пікселів. +Comment[uz]=Oʻlchami 1024 x 768 nuqta boʻlgan shaffof rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1024 x 768 нуқта бўлган шаффоф расмни яратиш. +Comment[zh_CN]=创建 1024 x 768 像素的透明图像。 +Comment[zh_TW]=建立一個 1024 x 768 像素的透明圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.kra b/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.kra new file mode 100644 index 00000000..2eb55d6a Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/transparent_1024x768.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop b/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop new file mode 100644 index 00000000..4d99ddce --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Type=Link +URL=.source/transparent_1280x1024.kra +Icon=template_rgb_empty +Name=Transparent 1280 x 1024 +Name[bg]=Прозрачно 1280x1204 +Name[br]=Treuzwelus 1280 x 1024 +Name[cy]=Tryloyw 1280 x 1024 +Name[da]=Gennemsigtig 1280 x 1024 +Name[el]=Διαφανής 1280 x 1024 +Name[eo]=Travidebla 1280 x 1024 +Name[es]=1280 x 1024 transparente +Name[et]=Läbipaistev 1280 x 1024 +Name[eu]=Gardena 1280 x 1024 +Name[fa]=شفاف ۱۰۲۴ × ۱۲۸۰ +Name[fi]=Läpinäkyvä 1280x1024 +Name[fr]=Image transparente 1280 x 1024 +Name[fy]=Trochsichtich 1280 x 1024 +Name[gl]=Transparente 1280 x 1024 +Name[he]=‏1280‎ x 1024 שקוף +Name[hu]=Áttetsző 1280 x 1024 +Name[is]=Gegnsæ 1280 x 1024 +Name[it]=Trasparente 1280 × 1024 +Name[ja]=透明 1280 x 1024 +Name[km]=ថ្លា 1280 x 1024 +Name[lt]=Permatomas 1280 x 1024 +Name[lv]=Caurspīdīgs 1280 x 1024 +Name[ms]=Lutsinar 1280 x 1024 +Name[nb]=Gjennomsiktig 1280 x 1024 +Name[nds]=Dörsichtig 1280 x 1024 +Name[ne]=पारदर्शी १२८० x १०२४ +Name[nn]=Gjennomsiktig 1280 × 1024 +Name[pl]=Przezroczysty 1280 x 1024 +Name[pt]=Transparente 1280 x 1024 +Name[pt_BR]=Transparente de 1280 x 1024 +Name[ru]=Рисунок 1280x1024, прозрачный фон +Name[se]=Čađačuovgi 1280 × 1024 +Name[sk]=Priehľadný 1280 x 1024 +Name[sl]=Prosojna 1280 x 1024 +Name[sr]=Провидна 1280 x 1024 +Name[sr@Latn]=Providna 1280 x 1024 +Name[sv]=Genomskinlig 1280 x 1024 +Name[uk]=Прозоре 1280 x 1024 +Name[uz]=Shaffof 1280 x 1024 +Name[uz@cyrillic]=Шаффоф 1280 x 1024 +Name[zh_CN]=透明 1280 x 1024 +Name[zh_TW]=透明 1280 x 1024 +Comment=Creates a transparent image of 1280 x 1024 pixels. +Comment[bg]=Създава прозрачно изображение с размери 1280x1024 пиксела. +Comment[ca]=Crea una imatge transparent de 1280 x 1024 píxels. +Comment[cy]=Creu delwedd dryloyw o 1280 x 1024 picsel. +Comment[da]=Laver et gennemsigtigt billede på 1280 x 1024 billedpunkter. +Comment[de]=Erstellt ein transparentes Bild mit 1280 x 1024 Pixeln. +Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1280 x 1024 εικονοστοιχείων. +Comment[eo]=Kreas travideblan bildon el 1280 x 1024 rastrumeroj. +Comment[es]=Crea una imagen transparente de 1280 x 1024 píxeles. +Comment[et]=Loob läbipaistva pildi mõõtmetega 1280 x 1024 pikslit. +Comment[eu]=1280 x 1024 pixeleko irudi garden bat sortzen du. +Comment[fa]=یک تصویر شفاف ۱۰۲۴ × ۱۲۸۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo läpinäkyvän 1280x1024 pikselin kuvan. +Comment[fr]=Crée une image transparente de 1280 x 1024 pixels. +Comment[fy]=Makket in trochsichtige ôfbylding oan fan 1280 x 1024 byldpunten. +Comment[gl]=Cria unha imaxe transparente de 1280 x 1024 pixels. +Comment[he]=יצירת תמונה שקופה בגודל ‎1280 x 1024 פיקסלים +Comment[hu]=Létrehoz egy 1280 x 1024 képpontos áttetsző képet. +Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1280 x 1024 punktar. +Comment[it]=Crea un'immagine trasparente di 1280 × 1024 pixel. +Comment[ja]=1280 x 1024 ピクセルの透視画像を作成 +Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1280 x 1024 ភីកសែល ។ +Comment[lt]=Sukuria permatomą 1280 x 1024 pikselių paveiksliuką. +Comment[ms]=Cipta imej lutsinar 1280 x 1024 piksel. +Comment[nb]=Lager et gjennomsiktig bilde på 1280 x 1024 piksler. +Comment[nds]=Stellt en dörsichtig Bild mit 1280 x 1024 Pixels op. +Comment[ne]=१२८० x १०२४ पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een transparante afbeelding aan van 1280 x 1024 pixels. +Comment[nn]=Lagar eit gjennomsiktig bilete på 1280 × 1024 pikslar. +Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1280 x 1024 pikseli. +Comment[pt]=Cria uma imagem transparente com 1280 x 1024 pontos. +Comment[pt_BR]=Cria uma imagem transparente de 1280 x 1024 pixels. +Comment[ru]=Рисунок 1280x1024, прозрачный фон +Comment[se]=Ráhkada čađačuovgi gova mas lea 1280 × 1024 govvačuoggá +Comment[sk]=Vytvorí obrázok s rozmermi 1280 x 1024 pixelov a priehľadným pozadím. +Comment[sl]=Ustvari prosojno sliko velikosti 1280 x 1024 pik. +Comment[sr]=Прави провидну слику са 1280 x 1024 пиксела. +Comment[sr@Latn]=Pravi providnu sliku sa 1280 x 1024 piksela. +Comment[sv]=Skapar en genomskinlig bild med 1280 x 1024 bildpunkter. +Comment[uk]=Створює прозоре зображення 1280 x 1024 пікселів. +Comment[uz]=Oʻlchami 1280 x 1024 nuqta boʻlgan shaffof rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1280 x 1024 нуқта бўлган шаффоф расмни яратиш. +Comment[zh_CN]=创建 1280x 1024 像素的透明图像。 +Comment[zh_TW]=建立一個 1280 x 1024 像素的透明圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.kra b/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.kra new file mode 100644 index 00000000..09e23256 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/transparent_1280x1024.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop b/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop new file mode 100644 index 00000000..0699b4da --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop @@ -0,0 +1,97 @@ +[Desktop Entry] +Type=Link +URL=.source/transparent_1600x1200.kra +Icon=template_rgb_empty +Name=Transparent 1600 x 1200 +Name[bg]=Прозрачно 1600x1200 +Name[br]=Treuzwelus 1600 x 1200 +Name[cy]=Tryloyw 1600 x 1200 +Name[da]=Gennemsigtig 1600 x 1200 +Name[el]=Διαφανής 1600 x 1200 +Name[es]=1600 x 1200 transparente +Name[et]=Läbipaistev 1600 x 1200 +Name[eu]=Gardena 1600 x 1200 +Name[fa]=شفاف ۱۲۰۰ × ۱۶۰۰ +Name[fi]=Läpinäkyvä 1600x1200 +Name[fr]=Image transparente 1600 x 1200 +Name[fy]=Trochsichtich 1600 x 1200 +Name[gl]=Transparente 1600 x 1200 +Name[he]=‏1600‎ x 1200 שקוף +Name[hi]=पारदर्शी 1600 x 1200 +Name[hu]=Áttetsző 1600 x 1200 +Name[is]=Gegnsæ 1600 x 1200 +Name[it]=Trasparente 1600 × 1200 +Name[ja]=透明 1600 x 1200 +Name[km]=ថ្លា 1600 x 1200 +Name[lt]=Permatomas 1600 x 1200 +Name[lv]=Caurspīdīgs 1600 x 1200 +Name[ms]=Lutsinar 1600 x 1200 +Name[nb]=Gjennomsiktig 1600 × 1200 +Name[nds]=Dörsichtig 1600 x 1200 +Name[ne]=पारदर्शी १६०० x १२०० +Name[nl]=Transparant 1600 x 1200 +Name[nn]=Gjennomsiktig 1600 × 1200 +Name[pl]=Przezroczysty 1600 x 1200 +Name[pt]=Transparente 1600 x 1200 +Name[pt_BR]=Transparente de 1600 x 1200 +Name[ru]=Рисунок 1600x1200, прозрачный фон +Name[se]=Čađačuovgi 1600 × 1200 +Name[sk]=Priehľadný 1600 x 1200 +Name[sl]=Prosojna 1600 x 1200 +Name[sr]=Провидна 1600 x 1200 +Name[sr@Latn]=Providna 1600 x 1200 +Name[sv]=Genomskinlig 1600 x 1200 +Name[ta]=தெரியக்கூடிய 1600 x 1200 +Name[tr]=Saydam 1600 x 1200 +Name[uk]=Прозоре 1600 x 1200 +Name[uz]=Shaffof 1600 x 1200 +Name[uz@cyrillic]=Шаффоф 1600 x 1200 +Name[zh_CN]=透明 1600 x 1200 +Name[zh_TW]=透明 1600 x 1200 +Comment=Creates a transparent image of 1600 x 1200 pixels. +Comment[bg]=Създаване на прозрачно изображение с размери 1600x1200 пиксела. +Comment[ca]=Crea una imatge transparent de 1600 x 1200 píxels. +Comment[cy]=Creu delwedd dryloyw o 1600 x 1200 picsel. +Comment[da]=Laver et gennemsigtigt billede på 1600 x 1200 billedpunkter. +Comment[de]=Erstellt ein transparentes Bild mit 1600 x 1200 Pixeln. +Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1600 x 1200 εικονοστοιχείων. +Comment[es]=Crea una imagen transparente de 1600 x 1200 píxeles. +Comment[et]=Loob läbipaistva pildi mõõtmetega 1600 x 1200 pikslit. +Comment[eu]=1600 x 1200 pixeleko irudi garden bat sortzen du. +Comment[fa]=یک تصویر شفاف ۱۲۰۰ × ۱۶۰۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo läpinäkyvän 1600x1200 pikselin kuvan. +Comment[fr]=Crée une image transparente de 1600 x 1200 pixels. +Comment[fy]=Makket in trochsichtige ôfbylding oan fan 11600 x 1200 byldpunten. +Comment[gl]=Cria unha imaxe transparente de 1600 x 1200 pixels. +Comment[he]=יצירת תמונה שקופה בגודל ‎1600 x 1200 פיקסלים +Comment[hi]=1600 x 1200 पिक्सेल की पारदर्शी छवि बनाता है. +Comment[hu]=Létrehoz egy 1600 x 1200 képpontos áttetsző képet. +Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1600 x 1200 punktar. +Comment[it]=Crea un'immagine trasparente di 1600 × 1200 pixel. +Comment[ja]=1600 x 1200 ピクセルの透視画像を作成 +Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1600 x 1200 ភីកសែល ។ +Comment[lt]=Sukuria permatomą 1600 x 1200 pikselių paveiksliuką. +Comment[ms]=Cipta imej lutsinar 1600 x 1200 piksel. +Comment[nb]=Lager et gjennomsiktig bilde på 1600 x 1200 piksler. +Comment[nds]=Stellt en dörsichtig Bild mit 1600 x 1200 Pixels op. +Comment[ne]=१६०० x १२०० पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ। +Comment[nl]=Maakt een transparante afbeelding aan van 1600 x 1200 pixels. +Comment[nn]=Lagar eit gjennomsiktig bilete på 1600 × 1200 pikslar. +Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1600 x 1200 pikseli. +Comment[pt]=Cria uma imagem transparente com 1600 x 1200 pontos. +Comment[pt_BR]=Cria uma imagem transparente de 1600 x 1200 pixéis. +Comment[ru]=Рисунок 1600x1200, прозрачный фон +Comment[se]=Ráhkada čađačuovgi gova mas lea 1600 × 1200 govvačuoggá. +Comment[sk]=Vytvorí obrázok s rozmermi 1600 x 1200 pixelov a priehľadným pozadím. +Comment[sl]=Ustvari prosojno sliko velikosti 1600 x 1200 pik. +Comment[sr]=Прави провидну слику са 1600 x 1200 пиксела. +Comment[sr@Latn]=Pravi providnu sliku sa 1600 x 1200 piksela. +Comment[sv]=Skapar en genomskinlig bild med 1600 x 1200 bildpunkter. +Comment[ta]=1600 x 1200 படத்துணுக்குகளில் ஒரு தெரியக்கூடிய பிம்பத்தை உருவாக்குகிறது. +Comment[tr]=1600 x 1200 piksel ebadında transparan bir görüntü oluşturur. +Comment[uk]=Створює прозоре зображення 1600 x 1200 пікселів. +Comment[uz]=Oʻlchami 1600 x 1200 nuqta boʻlgan shaffof rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1600 x 1200 нуқта бўлган шаффоф расмни яратиш. +Comment[zh_CN]=创建 1600 x 1200 像素的透明图像。 +Comment[zh_TW]=建立一個 1600 x 1200 像素的透明圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.kra b/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.kra new file mode 100644 index 00000000..beb6dea3 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/transparent_1600x1200.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_640x480.desktop b/chalk/colorspaces/rgb_u8/templates/transparent_640x480.desktop new file mode 100644 index 00000000..afa115ef --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/transparent_640x480.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Type=Link +URL=.source/transparent_640x480.kra +Icon=template_rgb_empty +Name=Transparent 640 x 480 +Name[bg]=Прозрачно 640x480 +Name[br]=Treuzwelus 640 x 480 +Name[cy]=Tryloyw 640 x 480 +Name[da]=Gennemsigtig 640 x 480 +Name[el]=Διαφανής 640 x 480 +Name[eo]=Travidebla 640 x 480 +Name[es]=640 x 480 transparente +Name[et]=Läbipaistev 640 x 480 +Name[eu]=Gardena 640 x 480 +Name[fa]=شفاف ۴۸۰ × ۶۴۰ +Name[fi]=Läpinäkyvä 640x480 +Name[fr]=Image transparente 640 x 480 +Name[fy]=Trochsichtich 640 x 480 +Name[gl]=Transparente 640 x 480 +Name[he]=‏640 x 480 שקוף +Name[hu]=Áttetsző 640 x 480 +Name[is]=Gegnsæ 640 x 480 +Name[it]=Trasparente 640 × 480 +Name[ja]=透明 640 x 480 +Name[km]=ថ្លា 640 x 480 +Name[lt]=Permatomas 640 x 480 +Name[lv]=Caurspīdīgs 640 x 480 +Name[ms]=Lutsinar 640 x 480 +Name[nb]=Gjennomsiktig 640 x 480 +Name[nds]=Dörsichtig 640 x 480 +Name[ne]=पारदर्शी ६४० x ४८० +Name[nn]=Gjennomsiktig 640 × 480 +Name[pl]=Przezroczysty 640 x 480 +Name[pt]=Transparente 640 x 480 +Name[pt_BR]=Transparente de 640 x 480 +Name[ru]=Рисунок 640x480, прозрачный фон +Name[se]=Čađačuovgi 640 × 480 +Name[sk]=Priehľadný 640 x 480 +Name[sl]=Prosojna 640 x 480 +Name[sr]=Провидна 640 x 480 +Name[sr@Latn]=Providna 640 x 480 +Name[sv]=Genomskinlig 640 x 480 +Name[uk]=Прозоре 640 x 480 +Name[uz]=Shaffof 640 x 480 +Name[uz@cyrillic]=Шаффоф 640 x 480 +Name[zh_CN]=透明 640 x 480 +Name[zh_TW]=透明 640 x 480 +Comment=Creates a transparent image of 640 x 480 pixels. +Comment[bg]=Създаване на прозрачно изображение с размери 640x480 пиксела. +Comment[ca]=Crea una imatge transparent de 640 x 480 píxels. +Comment[cy]=Creu delwedd dryloyw o 640 x 480 picsel. +Comment[da]=Laver et gennemsigtigt billede på 640 x 480 billedpunkter. +Comment[de]=Erstellt ein transparentes Bild mit 640 x 480 Pixeln. +Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 640 x 480 εικονοστοιχείων. +Comment[eo]=Kreas travideblan bildon el 640 x 480 rastrumeroj. +Comment[es]=Crea una imagen transparente de 640 x 480 píxeles. +Comment[et]=Loob läbipaistva pildi mõõtmetega 640 x 480 pikslit. +Comment[eu]=640 x 480 pixeleko irudi garden bat sortzen du. +Comment[fa]=یک تصویر شفاف ۴۸۰ × ۶۴۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo läpinäkyvän 640x480 pikselin kuvan. +Comment[fr]=Crée une image transparente de 640 x 480 pixels. +Comment[fy]=Makket in trochsichtige ôfbylding oan fan 640 x 480 byldpunten. +Comment[gl]=Cria unha imaxe transparente de 640 x 480 pixels. +Comment[he]=יצירת תמונה שקופה בגודל ‎640 x 480 פיקסלים +Comment[hu]=Létrehoz egy 640 x 480 képpontos áttetsző képet. +Comment[is]=Býr til gegnsæja mynd í hlutföllunum 640 x 480 punktar. +Comment[it]=Crea un'immagine trasparente di 640 × 480 pixel. +Comment[ja]=640 x 480 ピクセルの透視画像を作成 +Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 640 x 480 ភីកសែល ។ +Comment[lt]=Sukuria permatomą 640 x 480 pikselių paveiksliuką. +Comment[ms]=Cipta imej lutsinar 640 x 480 piksel. +Comment[nb]=Lager et gjennomsiktig bilde på 640 x 480 piksler. +Comment[nds]=Stellt en dörsichtig Bild mit 640 x 480 Pixels op. +Comment[ne]=६४० x ४८० पिक्सेलको पारदर्शी सिर्जना गर्दछ । +Comment[nl]=Maakt een transparante afbeelding aan van 640 x 480 pixels. +Comment[nn]=Lagar eit gjennomsiktig bilete på 640 × 480 pikslar. +Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 640 x 480 pikseli. +Comment[pt]=Cria uma imagem transparente com 640 x 480 pontos. +Comment[pt_BR]=Cria uma imagem transparente de 640 x 480 pixels. +Comment[ru]=Рисунок 640x480, прозрачный фон +Comment[se]=Ráhkada čađačuovgi gova mas lea 640 × 480 govvačuoggá. +Comment[sk]=Vytvorí obrázok s rozmermi 640 x 480 pixelov a priehľadným pozadím. +Comment[sl]=Ustvari prosojno sliko velikosti 640 x 480 pik. +Comment[sr]=Прави провидну слику са 640 x 480 пиксела. +Comment[sr@Latn]=Pravi providnu sliku sa 640 x 480 piksela. +Comment[sv]=Skapar en genomskinlig bild med 640 x 480 bildpunkter. +Comment[uk]=Створює прозоре зображення 640 x 480 пікселів. +Comment[uz]=Oʻlchami 640 x 480 nuqta boʻlgan shaffof rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта бўлган шаффоф расмни яратиш. +Comment[zh_CN]=创建 640 x 480 像素的透明图像。 +Comment[zh_TW]=建立一個 640 x 480 像素的透明圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/transparent_640x480.kra b/chalk/colorspaces/rgb_u8/templates/transparent_640x480.kra new file mode 100644 index 00000000..064a77d3 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/transparent_640x480.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/white_1024x768.desktop b/chalk/colorspaces/rgb_u8/templates/white_1024x768.desktop new file mode 100644 index 00000000..65e41633 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/white_1024x768.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Type=Link +URL=.source/white_1024x768.kra +Icon=template_rgb_empty +Name=White 1024 x 768 +Name[bg]=Бяло 1024x768 +Name[br]=Gwenn 1024 x 768 +Name[ca]=Blanc 1024 x 768 +Name[cy]=Gwyn 1024 x 768 +Name[da]=Hvidt 1024 x 768 +Name[de]=Weiß 1024 x 768 +Name[el]=Λευκή 1024 x 768 +Name[eo]=Blanka 1024 x 768 +Name[es]=1024 x 768 blanco +Name[et]=Valge 1024 x 768 +Name[eu]=Zuria 1024 x 768 +Name[fa]=سفید ۷۶۸ × ۱۰۲۴ +Name[fi]=Valkoinen 1024x768 +Name[fr]=Image blanche 1024 x 768 +Name[fy]=Wyt 1024 x 768 +Name[ga]=Bán 1024×768 +Name[gl]=Branca 1024 x 768 +Name[he]=לבן ‎1024 x 768 +Name[hi]=सफेद 1024 x 768 +Name[hu]=Fehér 1024 x 768 +Name[is]=Hvít 1024 x 768 +Name[it]=Bianco 1024 × 768 +Name[ja]=白 1024 x 768 +Name[km]=ពណ៌ស 1024 x 768 +Name[lt]=Baltas 1024 x 768 +Name[lv]=Balts 1024 x 768 +Name[ms]=Putih 1024 x 768 +Name[nb]=Hvitt 1024 x 768 +Name[nds]=Witt 1024 x 768 +Name[ne]=सेतो १०२४ x ७६८ +Name[nl]=Wit 1024 x 768 +Name[nn]=Kvitt 1024 × 768 +Name[pl]=Biały 1024 x 768 +Name[pt]=Branca 1024 x 768 +Name[pt_BR]=1024 x 768 em Branco +Name[ru]=Рисунок 1024x768, белый фон +Name[se]=Vilges 1024 × 768 +Name[sk]=Biely 1024 x 768 +Name[sl]=Bela 1024 x 768 +Name[sr]=Бела 1024 x 768 +Name[sr@Latn]=Bela 1024 x 768 +Name[sv]=Vit 1024 x 768 +Name[ta]=வெள்ளை 1024 x 768 +Name[tr]=Beyaz 1024 x 768 +Name[uk]=Біле 1024 x 768 +Name[uz]=Oq 1024 x 768 +Name[uz@cyrillic]=Оқ 1024 x 768 +Name[zh_CN]=白色 1024 x 768 +Name[zh_TW]=白色 1024 x 768 +Comment=Creates a white RGB image of 1024 x 768 pixels. +Comment[bg]=Създаване на бяло изображение RGB с размери 1024x768 пиксела. +Comment[ca]=Crea una imatge blanca RGB de 1024 x 768 píxels. +Comment[cy]=Creu delwedd RGB wen o 1024 x 768 picsel. +Comment[da]=Laver et hvidt RGB-billede på 1024 x 768 billedpunkter. +Comment[de]=Erstellt ein weißes RGB-Bild mit 1024 x 768 Pixeln. +Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1024 x 768 εικονοστοιχείων. +Comment[eo]=Kreas blankan RGB-bildon el 1024 x 768 rastrumeroj. +Comment[es]=Crea una imagen RGB de 1024 x 768 píxeles. +Comment[et]=Loob valge RGB-pildi mõõtmetega 1024 x 768 pikslit. +Comment[eu]=1024 x 768 pixeleko RGB irudi zuri bat sortzen du. +Comment[fa]=یک تصویر RGB سفید ۷۶۸ × ۱۰۲۴ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo valkoisen 1024x768 pikselin RGB-kuvan. +Comment[fr]=Crée une image blanche RVB de 1024 x 768 pixels. +Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1024 x 768 byldpunten. +Comment[gl]=Cria unha imaxe RGB branca de 1024 x 768 pixels. +Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1024 x 768 פיקסלים +Comment[hi]=1024 x 768 पिक्सेल की सफेद आरजीबी छवि बनाता है. +Comment[hu]=Létrehoz egy 1024 x 768 képpontos fehér RGB képet. +Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1024 x 768 punktar. +Comment[it]=Crea un'immagine RGB bianca di 1024 × 768 pixel. +Comment[ja]=1024 x 768 ピクセルの RGB 画像を作成 +Comment[km]=បង្កើត​រូបភាព RGB ពណ៌​ស​ទំហំ 1024 x 768 ភីកសែល ។ +Comment[lt]=Sukuria baltą 1024 x 768 pikselių RGB paveiksliuką. +Comment[ms]=Cipta imej RGB putih 1024 x 768 piksel. +Comment[nb]=Lager et hvitt RGB-bilde på 1024 x 768 piksler. +Comment[nds]=Stellt en witt RGB-Bild mit 1024 x 768 Pixels op. +Comment[ne]=१०२४ x ७६८ पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een witte RGB-afbeelding aan van 1024 x 768 pixels. +Comment[nn]=Lagar eit kvitt RGB-bilete på 1024 × 768 pikslar. +Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1024 x 768 pikseli. +Comment[pt]=Cria uma imagem RGB branca com 1024 x 768 pontos. +Comment[pt_BR]=Cria uma imagem RGB em branco de 1024 x 768 pixéis. +Comment[ru]=Рисунок RGB 1024x768, белый фон +Comment[se]=Ráhkada vilges RGB-gova mas lea 1024 × 768 govvačuoggá. +Comment[sk]=Vytvorí RGB obrázok s rozmermi 1024 x 768 pixelov a bielym pozadím. +Comment[sl]=Ustvari belo sliko RGB velikosti 1024 x 768 pik. +Comment[sr]=Прави белу RGB слику са 1024 x 768 пиксела. +Comment[sr@Latn]=Pravi belu RGB sliku sa 1024 x 768 piksela. +Comment[sv]=Skapar en vit RGB-bild med 1024 x 768 bildpunkter. +Comment[ta]=1024 x 768 படத்துணுக்குகளில் ஒரு வெள்ளை RGB பிம்பத்தை உருவாக்குகிறது. +Comment[tr]=1024 x 768 piksel ebadında beyaz bir RGB görüntü oluşturur. +Comment[uk]=Створює біле зображення у форматі RGB, 640 x 480 пікселів. +Comment[uz]=Oʻlchami 1024 x 768 nuqta boʻlgan oq RGB rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1024 x 768 нуқта бўлган оқ RGB расмни яратиш. +Comment[zh_CN]=创建 1024 x 768 像素的 RGB 白色背景图像。 +Comment[zh_TW]=建立一個 1024 x 768 像素的白色 RGB 圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/white_1024x768.kra b/chalk/colorspaces/rgb_u8/templates/white_1024x768.kra new file mode 100644 index 00000000..65239226 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/white_1024x768.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/white_1280x1024.desktop b/chalk/colorspaces/rgb_u8/templates/white_1280x1024.desktop new file mode 100644 index 00000000..e2d4a1a6 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/white_1280x1024.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Type=Link +URL=.source/white_1280x1024.kra +Icon=template_rgb_empty +Name=White 1280 x 1024 +Name[bg]=Бяло 1280x1024 +Name[br]=Gwenn 1280 x 1024 +Name[ca]=Blanc 1280 x 1024 +Name[cy]=Gwyn 1280 x 1024 +Name[da]=Hvidt 1280 x 1024 +Name[de]=Weiß 1280 x 1024 +Name[el]=Λευκή 1280 x 1024 +Name[eo]=Blanka 1280 x 1024 +Name[es]=1280 x 1024 blanco +Name[et]=Valge 1280 x 1024 +Name[eu]=Zuria 1280 x 1024 +Name[fa]=سفید ۱۰۲۴ × ۱۲۸۰ +Name[fi]=Valkoinen 1280x1024 +Name[fr]=Image blanche 1280 x 1024 +Name[fy]=Wyt 1280 x 1024 +Name[ga]=Bán 1280×1024 +Name[gl]=Branca 1280 x 1024 +Name[he]=לבן ‎1280 x 1024 +Name[hu]=Fehér 1280 x 1024 +Name[is]=Hvít 1280 x 1024 +Name[it]=Bianco 1280 × 1024 +Name[ja]=白 1280 x 1024 +Name[km]=ពណ៌ស 1280 x 1024 +Name[lt]=Baltas 1280 x 1024 +Name[lv]=Balts 1280 x 1024 +Name[ms]=Putih 1280 x 1024 +Name[nb]=Hvit 1280 x 1024 +Name[nds]=Witt 1280 x 1024 +Name[ne]=सेतो १२८० x १०२४ +Name[nn]=Kvitt 1280 × 1024 +Name[pl]=Biały 1280 x 1024 +Name[pt]=Branca 1280 x 1024 +Name[pt_BR]=1280 x 1024 em Branco +Name[ru]=Рисунок 1280x1024, белый фон +Name[se]=Vilges 1280 × 1024 +Name[sk]=Biely 1280 x 1024 +Name[sl]=Bela 1280 x 1024 +Name[sr]=Бела 1280 x 1024 +Name[sr@Latn]=Bela 1280 x 1024 +Name[sv]=Vit 1280 x 1024 +Name[uk]=Біле 1280 x 1024 +Name[uz]=Oq 1280 x 1024 +Name[uz@cyrillic]=Оқ 1280 x 1024 +Name[zh_CN]=白色 1280 x 1024 +Name[zh_TW]=白色 1280 x 1024 +Comment=Creates a white RGB image of 1280 x 1024 pixels. +Comment[bg]=Създаване на бяло изображение RGB с размери 1280x1024 пиксела. +Comment[ca]=Crea una imatge blanca RGB de 1280 x 1024 píxels. +Comment[cy]=Creu delwedd RGB wen o 1280 x 1024 picsel. +Comment[da]=Laver et hvidt RGB-billede på 1280 x 1024 billedpunkter. +Comment[de]=Erstellt ein weißes RGB-Bild mit 1280 x 1024 Pixeln. +Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1280 x 1024 εικονοστοιχείων. +Comment[eo]=Kreas blankan RGB-bildon el 1280 x 1024 rastrumeroj. +Comment[es]=Crea una imagen RGB de 1280 x 1024 píxeles. +Comment[et]=Loob valge RGB-pildi mõõtmetega 61280 x 1024 pikslit. +Comment[eu]=1280 x 1024 pixeleko RGB irudi zuri bat sortzen du. +Comment[fa]=یک تصویر RGB سفید ۱۰۲۴ × ۱۲۸۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo valkoisen 1280x1024 pikselin RGB-kuvan. +Comment[fr]=Crée une image blanche RVB de 1280 x 1024 pixels. +Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1280 x 768 byldpunten. +Comment[gl]=Cria unha imaxe RGB branca de 1280 x 1024 pixels. +Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1280 x 1024 פיקסלים +Comment[hu]=Létrehoz egy 1280 x 1024 képpontos fehér RGB képet. +Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1280 x 1024 punktar. +Comment[it]=Crea un'immagine RGB bianca di 1280 × 1024 pixel. +Comment[ja]=1280 x 1024 ピクセルの RGB 画像を作成 +Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 1280 x 1024 ភីកសែល ។ +Comment[lt]=Sukuria baltą 1280 x 1024 pikselių RGB paveiksliuką. +Comment[ms]=Cipta imej RGB putih 1280 x 1024 piksel. +Comment[nb]=Lager et hvitt bilde på 1280 x 1024 piksler. +Comment[nds]=Stellt en witt RGB-Bild mit 1280 x 1024 Pixels op. +Comment[ne]=१२८० x १०२४ पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een witte RGB-afbeelding aan van 1280 x 1024 pixels. +Comment[nn]=Lagar eit kvitt RGB-bilete på 1280 × 1024 pikslar. +Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1280 x 1024 pikseli. +Comment[pt]=Cria uma imagem RGB branca com 1280 x 1024 pontos. +Comment[pt_BR]=Cria uma imagem RGB em branco de 1280 x 1024 pixels. +Comment[ru]=Рисунок RGB 1280x1024, белый фон +Comment[se]=Ráhkada vilges RGB-gova mas lea 1280 × 1024 govvačuoggá. +Comment[sk]=Vytvorí RGB obrázok s rozmermi 1280 x 1024 pixelov a bielym pozadím. +Comment[sl]=Ustvari belo sliko RGB velikosti 1280 x 1024 pik. +Comment[sr]=Прави белу RGB слику са 1280 x 1024 пиксела. +Comment[sr@Latn]=Pravi belu RGB sliku sa 1280 x 1024 piksela. +Comment[sv]=Skapar en vit RGB-bild med 1280 x 1024 bildpunkter. +Comment[uk]=Створює біле зображення у форматі RGB, 1280 x 1024 пікселів. +Comment[uz]=Oʻlchami 1280 x 1024 nuqta boʻlgan oq RGB rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1280 x 1024 нуқта бўлган оқ RGB расмни яратиш. +Comment[zh_CN]=创建 1080 x 1024 像素的 RGB 白色背景图像。 +Comment[zh_TW]=建立一個 1280 x 1024 像素的白色 RGB 圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/white_1280x1024.kra b/chalk/colorspaces/rgb_u8/templates/white_1280x1024.kra new file mode 100644 index 00000000..b9e2456a Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/white_1280x1024.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/white_1600x1200.desktop b/chalk/colorspaces/rgb_u8/templates/white_1600x1200.desktop new file mode 100644 index 00000000..9f27127a --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/white_1600x1200.desktop @@ -0,0 +1,95 @@ +[Desktop Entry] +Type=Link +URL=.source/white_1600x1200.kra +Icon=template_rgb_empty +Name=White 1600 x 1200 +Name[bg]=Бяло 1600x1200 +Name[br]=Gwenn 1600 x 1200 +Name[ca]=Blanc 1600 x 1200 +Name[cy]=Gwyn 1600 x 1200 +Name[da]=Hvidt 1600 x 1200 +Name[de]=Weiß 1600 x 1200 +Name[el]=Λευκή 1600 x 1200 +Name[eo]=Blanka 1600 x 1200 +Name[es]=1600 x 1200 blanco +Name[et]=Valge 1600 x 1200 +Name[eu]=Zuria 1600 x 1200 +Name[fa]=سفید ۱۲۰۰ × ۱۶۰۰ +Name[fi]=Valkoinen 1600x1200 +Name[fr]=Image blanche 1600 x 1200 +Name[fy]=Wyt 1600 x 1200 +Name[ga]=Bán 1600×1200 +Name[gl]=Branca 1600 x 1200 +Name[he]=לבן ‎1600 x 1200 +Name[hu]=Fehér 1600 x 1200 +Name[is]=Hvít 1600 x 1200 +Name[it]=Bianco 1600 × 1200 +Name[ja]=白 1600 x 1200 +Name[km]=ពណ៌ស 1600 x 1200 +Name[lt]=Baltas 1600 x 1200 +Name[lv]=Balts 1600 x 1200 +Name[ms]=Putih 1600 x 1200 +Name[nb]=Hvit 1600 x 1200 +Name[nds]=Witt 1600 x 1200 +Name[ne]=सेतो १६०० x १२०० +Name[nn]=Kvitt 1600 × 1200 +Name[pl]=Biały 1600 x 1200 +Name[pt]=Branca 1600 x 1200 +Name[pt_BR]=1600 x 1200 em Branco +Name[ru]=Рисунок 1600x1200, белый фон +Name[se]=Vilges 1600 × 1200 +Name[sk]=Biely 1600 x 1200 +Name[sl]=Bela 1600 x 1200 +Name[sr]=Бела 1600 x 1200 +Name[sr@Latn]=Bela 1600 x 1200 +Name[sv]=Vit 1600 x 1200 +Name[uk]=Біле 1600 x 1200 +Name[uz]=Oq 1600 x 1200 +Name[uz@cyrillic]=Оқ 1600 x 1200 +Name[zh_CN]=白色 1600 x 1200 +Name[zh_TW]=白色 1600 x 1200 +Comment=Creates a white RGB image of 1600 x 1200 pixels. +Comment[bg]=Създаване на бяло изображение RGB с размери 1600x1200 пиксела. +Comment[ca]=Crea una imatge blanca RGB de 1600 x 1200 píxels. +Comment[cy]=Creu delwedd RGB wen o 1600 x 1200 picsel. +Comment[da]=Laver et hvidt RGB-billede på 1600 x 1200 billedpunkter. +Comment[de]=Erstellt ein weißes RGB-Bild mit 1600 x 1200 Pixeln. +Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1600 x 1200 εικονοστοιχείων. +Comment[eo]=Kreas blankan RGB-bildon el 1600 x 1200 rastrumeroj. +Comment[es]=Crea una imagen RGB de 1600 x 1200 píxeles. +Comment[et]=Loob valge RGB-pildi mõõtmetega 1600 x 1200 pikslit. +Comment[eu]=1600 x 1200 pixeleko RGB irudi zuri bat sortzen du. +Comment[fa]=یک تصویر RGB سفید ۱۲۰۰ × ۱۶۰۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo valkoisen 1600x1200 pikselin RGB-kuvan. +Comment[fr]=Crée une image blanche RVB de 1600 x 1200 pixels. +Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1600 x 1200 byldpunten. +Comment[gl]=Cria unha imaxe RGB branca de 1600 x 1200 pixels. +Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1600 x 1200 פיקסלים +Comment[hu]=Létrehoz egy 1600 x 1200 képpontos fehér RGB képet. +Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1600 x 1200 punktar. +Comment[it]=Crea un'immagine RGB bianca di 1600 × 1200 pixel. +Comment[ja]=1600 x 1200 ピクセルの RGB 画像を作成 +Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 1600 x 1200 ភីកសែល ។ +Comment[lt]=Sukuria baltą 1600 x 1200 pikselių RGB paveiksliuką. +Comment[ms]=Cipta imej RGB putih 1600 x 1200 piksel. +Comment[nb]=Lager et hvitt bilde på 1600 x 1200 piksler. +Comment[nds]=Stellt en witt RGB-Bild mit 1600 x 1200 Pixels op +Comment[ne]=१६०० x १२०० पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een witte RGB-afbeelding aan van 1600 x 1200 pixels. +Comment[nn]=Lagar eit kvitt RGB-bilete på 1600 × 1200 pikslar. +Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1600 x1200 pikseli. +Comment[pt]=Cria uma imagem RGB branca com 1600 x 1200 pontos. +Comment[pt_BR]=Cria uma imagem RGB em branco de 1600 x 1200 pixels. +Comment[ru]=Рисунок RGB 1600x1200, белый фон +Comment[se]=Ráhkada vilges RGB-gova mas lea 1600 × 1200 govvačuoggá. +Comment[sk]=Vytvorí RGB obrázok s rozmermi 1600 x 1200 pixelov a bielym pozadím. +Comment[sl]=Ustvari belo sliko RGB velikosti 1600 x 1200 pik. +Comment[sr]=Прави белу RGB слику са 1600 x 1200 пиксела. +Comment[sr@Latn]=Pravi belu RGB sliku sa 1600 x 1200 piksela. +Comment[sv]=Skapar en vit RGB-bild med 1600 x 1200 bildpunkter. +Comment[uk]=Створює біле зображення у форматі RGB, 1600 x 1200 пікселів. +Comment[uz]=Oʻlchami 1600 x 1200 nuqta boʻlgan oq RGB rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 1600 x 1200 нуқта бўлган оқ RGB расмни яратиш. +Comment[zh_CN]=创建 1600 x 1200 像素的 RGB 白色背景图像。 +Comment[zh_TW]=建立一個 1600 x 1200 像素的白色 RGB 圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/white_1600x1200.kra b/chalk/colorspaces/rgb_u8/templates/white_1600x1200.kra new file mode 100644 index 00000000..2576f73e Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/white_1600x1200.kra differ diff --git a/chalk/colorspaces/rgb_u8/templates/white_640x480.desktop b/chalk/colorspaces/rgb_u8/templates/white_640x480.desktop new file mode 100644 index 00000000..7fe13f5a --- /dev/null +++ b/chalk/colorspaces/rgb_u8/templates/white_640x480.desktop @@ -0,0 +1,102 @@ +[Desktop Entry] +Type=Link +URL=.source/white_640x480.kra +Icon=template_rgb_empty +Name=White 640x480 +Name[bg]=Бяло 640x480 +Name[br]=Gwenn 640x480 +Name[ca]=Blanc 640x480 +Name[cy]=Gwyn 640 x 480 +Name[da]=Hvidt 640x480 +Name[de]=Weiß 640x480 +Name[el]=Λευκή 640x480 +Name[eo]=Blanka 640x480 +Name[es]=640x480 blanco +Name[et]=Valge 640x480 +Name[eu]=Zuria 640x480 +Name[fa]=سفید ۴۸۰ × ۶۴۰ +Name[fi]=Valkoinen 640x480 +Name[fr]=Image blanche 640 x 480 +Name[fy]=Wyt 640x480 +Name[ga]=Bán 640×480 +Name[gl]=Branca 640x480 +Name[he]=לבן 640x480 +Name[hi]=सफेद 640x480 +Name[hu]=Fehér 640 x 480 +Name[is]=Hvít 640x480 +Name[it]=Bianco 640×480 +Name[ja]=白 640 x 480 +Name[km]=ពណ៌​ស​640 x 480 +Name[lt]=Baltas 640x480 +Name[lv]=Balts 640x480 +Name[ms]=Putih 640x480 +Name[nb]=Hvitt 640 x 480 +Name[nds]=Witt 640x480 +Name[ne]=सेतो ६४०x४८० +Name[nl]=Wit 640 x 480 +Name[nn]=Kvitt 640 × 480 +Name[pl]=Biały 640x480 +Name[pt]=Branca 640x480 +Name[pt_BR]=640x480 em Branco +Name[ru]=Рисунок 640x480, белый фон +Name[se]=Vilges 640 × 480 +Name[sk]=Biely 640x480 +Name[sl]=Bela 640x480 +Name[sr]=Бела 640x480 +Name[sr@Latn]=Bela 640x480 +Name[sv]=Vit 640x480 +Name[ta]=வெள்ளை 640x480 +Name[tr]=Beyaz 640x480 +Name[uk]=Біле 640x480 +Name[uz]=Oq 640 x 480 +Name[uz@cyrillic]=Оқ 640 x 480 +Name[zh_CN]=白色 640 x 480 +Name[zh_TW]=白色 640x480 +Comment=Creates a white RGB image of 640 x 480 pixels. +Comment[bg]=Създаване на бяло изображение RGB с размери 640x480 пиксела. +Comment[ca]=Crea una imatge blanca RGB de 640 x 480 píxels. +Comment[cy]=Creu delwedd RGB wen o 640 x 480 picsel. +Comment[da]=Laver et hvidt RGB-billede på 640 x 480 billedpunkter. +Comment[de]=Erstellt ein weißes RGB-Bild mit 640 x 480 Pixeln. +Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 640 x 480 εικονοστοιχείων. +Comment[eo]=Kreas blankan RGB-bildon el 640 x 480 rastrumeroj. +Comment[es]=Crea una imagen RGB de 640 x 480 píxeles. +Comment[et]=Loob valge RGB pildi mõõtmetega 640 x 480 pikslit. +Comment[eu]=640 x 480 pixeleko RGB irudi zuri bat sortzen du. +Comment[fa]=یک تصویر RGB سفید ۴۸۰ × ۶۴۰ تصویردانه‌ای ایجاد می‌کند. +Comment[fi]=Luo valkoisen 640x480 pikselin RGB-kuvan. +Comment[fr]=Crée une image blanche RVB de 640 x 480 pixels. +Comment[fy]=Makket in wite RGB-ôfbylding oan fan 640 x 480 byldpunten. +Comment[gl]=Cria unha imaxe RGB branca de 640 x 480 pixels. +Comment[he]=יצירת תמונת RGB לבנה בגודל ‎640 x 480 פיקסלים +Comment[hi]=640 x 480 पिक्सेल का, सफेद आरजीबी छवि बनाता है +Comment[hu]=Létrehoz egy 640 x 480 képpontos fehér RGB képet. +Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 640 x 480 punktar. +Comment[it]=Crea un'immagine RGB bianca di 640 × 480 pixel. +Comment[ja]=640 x 480 ピクセルの RGB 画像を作成 +Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 640 x 480 ភីកសែល ។ +Comment[lt]=Sukuria baltą 640 x 480 pikselių RGB paveiksliuką. +Comment[ms]=Cipta imej RGB putih 640 x 480 piksel. +Comment[nb]=Lager et hvitt bilde på 640 x 480 piksler. +Comment[nds]=Stellt en witt RGB-Bild mit 640 x 480 Pixels op. +Comment[ne]=६४० x ४८० पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ । +Comment[nl]=Maakt een witte RGB-afbeelding aan van 640 x 480 pixels. +Comment[nn]=Lagar eit kvitt RGB-bilete på 640 × 480 pikslar. +Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 640 x 480 pikseli. +Comment[pt]=Cria uma imagem RGB branca com 640 x 480 pontos. +Comment[pt_BR]=Cria uma imagem RGB em branco de 640 x 480 pixéis. +Comment[ru]=Рисунок RGB 640x480, белый фон +Comment[se]=Ráhkada vilges RGB-gova mas lea 640 × 480 govvačuoggá. +Comment[sk]=Vytvorí RGB obrázok s rozmermi 640 x 480 pixelov a bielym pozadím. +Comment[sl]=Ustvari belo sliko RGB velikosti 640 x 480 pik. +Comment[sr]=Прави белу RGB слику са 640 x 480 пиксела. +Comment[sr@Latn]=Pravi belu RGB sliku sa 640 x 480 piksela. +Comment[sv]=Skapar en vit RGB-bild med 640 x 480 bildpunkter. +Comment[ta]=640 x 480 படத்துணுக்குகளில் ஒரு வெள்ளை RGB பிம்பத்தை உருவாக்குகிறது. +Comment[tr]=640 x 480 piksel ebadında beyaz bir RGB görüntü oluşturur. +Comment[uk]=Створює біле зображення у форматі RGB, 640 x 480 пікселів. +Comment[uz]=Oʻlchami 640 x 480 nuqta boʻlgan oq RGB rasmni yaratish. +Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта бўлган оқ RGB расмни яратиш. +Comment[zh_CN]=创建 640 x 480 像素的 RGB 白色背景图像。 +Comment[zh_TW]=建立一個 640 x 480 像素的白色 RGB 圖片。 +X-Chalk-Version=2 diff --git a/chalk/colorspaces/rgb_u8/templates/white_640x480.kra b/chalk/colorspaces/rgb_u8/templates/white_640x480.kra new file mode 100644 index 00000000..559af627 Binary files /dev/null and b/chalk/colorspaces/rgb_u8/templates/white_640x480.kra differ diff --git a/chalk/colorspaces/rgb_u8/tests/Makefile.am b/chalk/colorspaces/rgb_u8/tests/Makefile.am new file mode 100644 index 00000000..5e9497a5 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/tests/Makefile.am @@ -0,0 +1,17 @@ +AM_CPPFLAGS = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/.. \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_strategy_colorspace_rgb_tester.la + +kunittest_kis_strategy_colorspace_rgb_tester_la_SOURCES = kis_strategy_colorspace_rgb_tester.cpp +kunittest_kis_strategy_colorspace_rgb_tester_la_LIBADD = -lkunittest ../libchalkrgb.la +kunittest_kis_strategy_colorspace_rgb_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_strategy_colorspace_rgb_tester.la + kunittestmodrunner + diff --git a/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp b/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp new file mode 100644 index 00000000..1d3526f4 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_factory.h" +#include "kis_strategy_colorspace_rgb_tester.h" +#include "kis_rgb_colorspace.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_tester, "RGB ColorSpace Tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisRgbColorSpaceTester ); + +void KisRgbColorSpaceTester::allTests() +{ + // We need this so that the colour profile loading can operate without crashing. + KisFactory *factory = new KisFactory(); + + testBasics(); + testMixColors(); + + delete factory; +} + +#define NUM_CHANNELS 4 + +#define RED_CHANNEL 0 +#define GREEN_CHANNEL 1 +#define BLUE_CHANNEL 2 +#define ALPHA_CHANNEL 3 + +void KisRgbColorSpaceTester::testBasics() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + KisRgbColorSpace *cs = new KisRgbColorSpace(defProfile); + + TQ_UINT8 pixel[NUM_CHANNELS]; + + pixel[PIXEL_RED] = 255; + pixel[PIXEL_GREEN] = 128; + pixel[PIXEL_BLUE] = 64; + pixel[PIXEL_ALPHA] = 0; + + TQString valueText = cs->channelValueText(pixel, RED_CHANNEL); + CHECK(valueText, TQString("255")); + + valueText = cs->channelValueText(pixel, GREEN_CHANNEL); + CHECK(valueText, TQString("128")); + + valueText = cs->channelValueText(pixel, BLUE_CHANNEL); + CHECK(valueText, TQString("64")); + + valueText = cs->channelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, TQString("0")); + + valueText = cs->normalisedChannelValueText(pixel, RED_CHANNEL); + CHECK(valueText, TQString().setNum(1.0)); + + valueText = cs->normalisedChannelValueText(pixel, GREEN_CHANNEL); + CHECK(valueText, TQString().setNum(128.0 / 255.0)); + + valueText = cs->normalisedChannelValueText(pixel, BLUE_CHANNEL); + CHECK(valueText, TQString().setNum(64.0 / 255.0)); + + valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL); + CHECK(valueText, TQString().setNum(0.0)); + + cs->setPixel(pixel, 128, 192, 64, 99); + CHECK((uint)pixel[PIXEL_RED], 128u); + CHECK((uint)pixel[PIXEL_GREEN], 192u); + CHECK((uint)pixel[PIXEL_BLUE], 64u); + CHECK((uint)pixel[PIXEL_ALPHA], 99u); + + TQ_UINT8 red; + TQ_UINT8 green; + TQ_UINT8 blue; + TQ_UINT8 alpha; + + cs->getPixel(pixel, &red, &green, &blue, &alpha); + CHECK((uint)red, 128u); + CHECK((uint)green, 192u); + CHECK((uint)blue, 64u); + CHECK((uint)alpha, 99u); +} + +void KisRgbColorSpaceTester::testMixColors() +{ + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + KisRgbColorSpace *cs = new KisRgbColorSpace(defProfile); + + + // Test mixColors. + TQ_UINT8 pixel1[4]; + TQ_UINT8 pixel2[4]; + TQ_UINT8 outputPixel[4]; + + pixel1[PIXEL_RED] = 255; + pixel1[PIXEL_GREEN] = 255; + pixel1[PIXEL_BLUE] = 255; + pixel1[PIXEL_ALPHA] = 255; + + pixel2[PIXEL_RED] = 0; + pixel2[PIXEL_GREEN] = 0; + pixel2[PIXEL_BLUE] = 0; + pixel2[PIXEL_ALPHA] = 0; + + const TQ_UINT8 *pixelPtrs[2]; + TQ_UINT8 weights[2]; + + pixelPtrs[0] = pixel1; + pixelPtrs[1] = pixel2; + + weights[0] = 255; + weights[1] = 0; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[PIXEL_RED], 255); + CHECK((int)outputPixel[PIXEL_GREEN], 255); + CHECK((int)outputPixel[PIXEL_BLUE], 255); + CHECK((int)outputPixel[PIXEL_ALPHA], 255); + + weights[0] = 0; + weights[1] = 255; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[PIXEL_RED], 0); + CHECK((int)outputPixel[PIXEL_GREEN], 0); + CHECK((int)outputPixel[PIXEL_BLUE], 0); + CHECK((int)outputPixel[PIXEL_ALPHA], 0); + + weights[0] = 128; + weights[1] = 127; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[PIXEL_RED], 255); + CHECK((int)outputPixel[PIXEL_GREEN], 255); + CHECK((int)outputPixel[PIXEL_BLUE], 255); + CHECK((int)outputPixel[PIXEL_ALPHA], 128); + + pixel1[PIXEL_RED] = 200; + pixel1[PIXEL_GREEN] = 100; + pixel1[PIXEL_BLUE] = 50; + pixel1[PIXEL_ALPHA] = 255; + + pixel2[PIXEL_RED] = 100; + pixel2[PIXEL_GREEN] = 200; + pixel2[PIXEL_BLUE] = 20; + pixel2[PIXEL_ALPHA] = 255; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[PIXEL_RED], 150); + CHECK((int)outputPixel[PIXEL_GREEN], 150); + CHECK((int)outputPixel[PIXEL_BLUE], 35); + CHECK((int)outputPixel[PIXEL_ALPHA], 255); + + pixel1[PIXEL_RED] = 0; + pixel1[PIXEL_GREEN] = 0; + pixel1[PIXEL_BLUE] = 0; + pixel1[PIXEL_ALPHA] = 0; + + pixel2[PIXEL_RED] = 255; + pixel2[PIXEL_GREEN] = 255; + pixel2[PIXEL_BLUE] = 255; + pixel2[PIXEL_ALPHA] = 254; + + weights[0] = 89; + weights[1] = 166; + + cs->mixColors(pixelPtrs, weights, 2, outputPixel); + + CHECK((int)outputPixel[PIXEL_RED], 255); + CHECK((int)outputPixel[PIXEL_GREEN], 255); + CHECK((int)outputPixel[PIXEL_BLUE], 255); + CHECK((int)outputPixel[PIXEL_ALPHA], 165); +} + diff --git a/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h b/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h new file mode 100644 index 00000000..16fc4e83 --- /dev/null +++ b/chalk/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_STRATEGY_COLORSPACE_RGB_TESTER_H +#define KIS_STRATEGY_COLORSPACE_RGB_TESTER_H + +#include + +class KisRgbColorSpaceTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testBasics(); + void testMixColors(); +}; + +#endif + diff --git a/chalk/colorspaces/wet/Makefile.am b/chalk/colorspaces/wet/Makefile.am new file mode 100644 index 00000000..a5500db5 --- /dev/null +++ b/chalk/colorspaces/wet/Makefile.am @@ -0,0 +1,28 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = wetplugin.rc +kde_services_DATA = chalkwetplugin.desktop + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + -I$(srcdir)/../../ui \ + -I$(srcdir)/../../kopalette \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkwetplugin.la + +chalkwetplugin_la_SOURCES = kis_wet_colorspace.cc wet_plugin.cc kis_wetop.cc kis_wet_palette_widget.cc kis_wetness_visualisation_filter.cc kis_texture_painter.cc kis_texture_filter.cc wetphysicsfilter.cc wdgpressure.ui +noinst_HEADERS = kis_wet_colorspace.h wet_plugin.h wetphysicsfilter.h kis_wetop.cc kis_wet_palette_widget.h kis_texture_painter.h kis_wetness_visualisation_filter.h kis_texture_filter.h wetphysicsfilter.h + +chalkwetplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms -L../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../chalk/core/.libs -lchalkimage \ + -L../../../chalk/ui/.libs -lchalkui +chalkwetplugin_la_LIBADD = ../../libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +chalkwetplugin_la_METASOURCES = AUTO + diff --git a/chalk/colorspaces/wet/chalkwetplugin.desktop b/chalk/colorspaces/wet/chalkwetplugin.desktop new file mode 100644 index 00000000..28a33d9b --- /dev/null +++ b/chalk/colorspaces/wet/chalkwetplugin.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Name=Watercolor Paint Plugin +Name[bg]=Приставка акварелни бои +Name[ca]=Connector de pintura aquarel·la +Name[cy]=Ategyn Paent Dyfrlliw +Name[da]=Plugin for vandfarvemaling +Name[de]=Modul für Wasserfarben-Effekte +Name[el]=Πρόσθετο υδατογραφίας +Name[eo]=Akvokolorpentrada kromaĵo +Name[es]=Complemento de pintura de acuarela +Name[et]=Vesivärvijoonistuse plugin +Name[eu]=Akuarelazko margoen plugina +Name[fa]=وصلۀ رنگ‌آمیزی آبرنگ +Name[fi]=Vesivärikuvaliitännäinen +Name[fr]=Module de dessin à l'aquarelle +Name[fy]=Wetter skilderplugin +Name[gl]=Plugin de Pintura con Cores de Auga +Name[he]=תוסף צביעה בצבעי מים +Name[hu]=Vízfesték modul +Name[is]=Vatnslita íforrit +Name[it]=Plugin per la pittura ad acquerello +Name[ja]=水彩プラグイン +Name[km]=កម្មវិធី​ជំនួយ​សម្រាប់​គូរ​គំនូរ​ពណ៌​ទឹក +Name[lv]=Zīmēšanas ar ūdenskrāsām spraudnis +Name[ms]=Plugin Warna Cat Air +Name[nb]=Paint-programtillegg for vannfarger +Name[nds]=Waterklöör-Effektmoduul +Name[ne]=पानी रङ पेन्ट प्लगइन +Name[nl]=Waterkleur schilderplugin +Name[nn]=Programtillegg for vassfargar +Name[pl]=Wtyczka malowania akwarelami +Name[pt]='Plugin' de Pintura a Água +Name[pt_BR]=Plug-in de Marca D'água +Name[ru]=Акварель +Name[sk]=Modul pre vodové farby +Name[sl]=Vstavek za slikanje z vodnimi barvami +Name[sr]=Прикључак за сликање воденим бојама +Name[sr@Latn]=Priključak za slikanje vodenim bojama +Name[sv]=Insticksprogram för vattenfärgsmålning +Name[uk]=Втулок малювання акварельними фарбами +Name[zh_CN]=水彩绘画插件 +Name[zh_TW]=水色繪畫外掛程式 +Comment=Color model and tools for painting with simulated watercolors +Comment[bg]=Цветови модел и инструменти за рисуване със симулирани акварелни бои +Comment[ca]=Model de color i eines per a pintar amb aquarel·les simulades +Comment[cy]=Model lliw ac offer ar gyfer paentio efo dyfrliwiau wedi'u hefelychu +Comment[da]=Farvemodel og værktøjer til at male med simulerede vandfarver +Comment[de]=Farbmodell und Werkzeuge zum Malen mit simulierten Wasserfarben +Comment[el]=Χρωματικό μοντέλο και εργαλεία για τη ζωγραφική με εξομοίωση χρωμάτων υδατογραφίας +Comment[en_GB]=Colour model and tools for painting with simulated watercolours +Comment[es]=Modelo de color y herramientas para pintar con acuarelas simuladas +Comment[et]=Vesivärvijoonistuse simulatsiooni värvimudel ja tööriistad +Comment[eu]=Akuarelen itxuraz margotzeko tresnak eta kolore-eredua +Comment[fa]=مدل رنگ و ابزارها برای رنگ‌آمیزی با آبرنگهای شبیه‌سازی شده +Comment[fi]=Värimalli ja työkalut simuloiduille vesiväreille +Comment[fr]=Modèle de couleurs et outils pour dessiner avec des couleurs simulées d'aquarelle +Comment[fy]=Kleurmodel en -ark foar it skilderjen mei simulearre wetterkleuren +Comment[gl]=Modelo de cores e ferramentas para pintar con cores de auga simulados +Comment[he]=מודל צבעים וכלים לצביעה תוך הדמיה של צבעי מים +Comment[hu]=Színmodell és eszközök szimulált vízfestékes képekhez +Comment[is]=Litategundir og tól til að teikna með vatnslitum +Comment[it]=Modello di colore e strumenti per il disegno con acquerelli simulati +Comment[ja]=水彩画をシミュレートして描画するためのカラーモデルとツール +Comment[km]=គំរូពណ៌ និង​ឧបករណ៍​សម្រាប់​គូរ​គំនូរ​ដែល​មាន​ពណ៌​ស្រដៀង​ទឹក +Comment[ms]=Model warna dan alat lukisan dengan cat air tiruan +Comment[nb]=Fargemodell og verktøy for maling med simulerte vannfarger +Comment[nds]=Klöörmodell un Warktüüch för't Malen mit Waterklöreneffekten +Comment[ne]=बनावटी पानीरङहरू सँग पेन्टीङ्गका लागि रङ मोडेल +Comment[nl]=Kleurmodel en -gereedschappen voor het schilderen met gesimuleerde waterkleuren +Comment[nn]=Fargemodell og verktøy for måling med simulerte vassfargar +Comment[pl]=Przestrzeń barw oraz narzędzia do symulacji malowania farbami akwarelowymi +Comment[pt]=Modelo de cor e ferramentas para pintar com cores aquosas simuladas +Comment[pt_BR]=Modelo de cor e ferramentas para pintura de cores simuladas de água +Comment[ru]=Цветовое пространство и инструменты рисования акварелью +Comment[sk]=Model farieb a nástroje na kreslenie vodovými farbami +Comment[sl]=Barvni model in orodja za slikanje s similiranimi vodnimi barvami +Comment[sr]=Модел боја и алати за сликање симулираним воденим бојама +Comment[sr@Latn]=Model boja i alati za slikanje simuliranim vodenim bojama +Comment[sv]=Färgmodell och verktyg för att måla med simulerade vattenfärger +Comment[uk]=Модель кольорів та засобів для малювання з симулюванням акварелі +Comment[zh_CN]=模拟水彩绘画的色彩模型和工具 +Comment[zh_TW]=以模擬水色繪製的色彩模型與工具 +ServiceTypes=Chalk/ColorSpace,Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkwetplugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/wet/kis_texture_filter.cc b/chalk/colorspaces/wet/kis_texture_filter.cc new file mode 100644 index 00000000..6f58cd14 --- /dev/null +++ b/chalk/colorspaces/wet/kis_texture_filter.cc @@ -0,0 +1,43 @@ +/* + * kis_texture_filter.cc -- Part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include "kis_texture_painter.h" +#include "kis_texture_filter.h" + +void WetPaintDevAction::act(KisPaintDeviceSP device, TQ_INT32 w, TQ_INT32 h) const { + KisColorSpace * cs = device->colorSpace(); + + if (cs->id() != KisID("WET","")) { + kdDebug(DBG_AREA_CMS) << "You set this kind of texture on non-wet layers!.\n"; + return; + } else { + kdDebug(DBG_AREA_CMS) << "Wet Paint Action activated!\n"; + } + + // XXX if params of the painter get configurable, make them here configurable as well? + KisTexturePainter painter(device); + painter.createTexture(0, 0, w, h); + painter.end(); +} + diff --git a/chalk/colorspaces/wet/kis_texture_filter.h b/chalk/colorspaces/wet/kis_texture_filter.h new file mode 100644 index 00000000..75f12e88 --- /dev/null +++ b/chalk/colorspaces/wet/kis_texture_filter.h @@ -0,0 +1,38 @@ +/* + * kis_texture_filter.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _TEXTURE_FILTER_H +#define _TEXTURE_FILTER_H + +#include +#include +#include + +/// Initializes a wet paint device with a texture +class WetPaintDevAction : public KisPaintDeviceAction { +public: + virtual ~WetPaintDevAction() {} + + virtual void act(KisPaintDeviceSP device, TQ_INT32 w = 0, TQ_INT32 h = 0) const; + virtual TQString name() const { return i18n("Wet Texture"); } + virtual TQString description() const { return i18n("Add a texture to the wet canvas"); } +}; + +#endif // _TEXTURE_FILTER_H diff --git a/chalk/colorspaces/wet/kis_texture_painter.cc b/chalk/colorspaces/wet/kis_texture_painter.cc new file mode 100644 index 00000000..4b11b989 --- /dev/null +++ b/chalk/colorspaces/wet/kis_texture_painter.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_wet_colorspace.h" +#include "kis_texture_painter.h" + +KisTexturePainter::KisTexturePainter() + : super() +{ + // XXX make at least one of these configurable, probably blurh + m_height = 1; + m_blurh = 0.7; +} + +KisTexturePainter::KisTexturePainter(KisPaintDeviceSP device) : super(device) +{ + m_height = 1; + m_blurh = 0.7; +} + +void KisTexturePainter::createTexture( TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + double hscale = 128 * m_height / RAND_MAX; + + int ibh = (int) floor(256 * m_blurh + 0.5); + + // initialize with random data + for (int y2 = 0; y2 < h; y2++) { + KisHLineIterator i = m_device->createHLineIterator(x, y + y2, w, true); + while (!i.isDone()) { + WetPack* pack = reinterpret_cast(i.rawData()); + WetPix* w = &(pack->adsorb); + w->h = ( TQ_UINT16)floor(128 + hscale * rand()); + ++i; + } + } + + int lh; + + // Blur horizontally + for (int y2 = 0; y2 < h; y2++) { + KisHLineIterator i = m_device->createHLineIterator(x, y + y2, w, true); + + WetPack* pack = reinterpret_cast(i.rawData()); + WetPix* w = &(pack->adsorb); + lh = w->h; + ++i; + + while (!i.isDone()) { + pack = reinterpret_cast(i.rawData()); + w = &(pack->adsorb); + w->h += ((lh - w->h) * ibh + 128) >> 8; + lh = w->h; + // XXX to make it easier for us later on, we store the height data in paint + // as well! + w = &(pack->paint); + w->h = lh; + ++i; + } + } + + //Qt::Vertical blurring was commented out in wetdreams, the effect seems to be achievable + // without this. + // I think this is because with blur in one direction, you get more the effect of + // having 'fibers' in your paper +} diff --git a/chalk/colorspaces/wet/kis_texture_painter.h b/chalk/colorspaces/wet/kis_texture_painter.h new file mode 100644 index 00000000..00bcd135 --- /dev/null +++ b/chalk/colorspaces/wet/kis_texture_painter.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TEXTURE_PAINTER_H_ +#define KIS_TEXTURE_PAINTER_H_ + +#include "kis_types.h" +#include "kis_painter.h" + +class KisTexturePainter : public KisPainter +{ + + typedef KisPainter super; + +public: + + KisTexturePainter(); + KisTexturePainter(KisPaintDeviceSP device); + + void createTexture( TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + +private: + double m_blurh, m_height; + +}; +#endif //KIS_TEXTURE_PAINTER_H_ diff --git a/chalk/colorspaces/wet/kis_wet_colorspace.cc b/chalk/colorspaces/wet/kis_wet_colorspace.cc new file mode 100644 index 00000000..7d6f0d67 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wet_colorspace.cc @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include LCMS_HEADER + +#include + +#include +#include +#include +#include "kis_abstract_colorspace.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_image.h" +#include "kis_wet_colorspace.h" +#include "wetphysicsfilter.h" +#include "kis_integer_maths.h" + +namespace { + static const WetPix m_paint = { 707, 0, 707, 0, 707, 0, 240, 0 }; + + /* colors from Curtis et al, Siggraph 97 */ + + static const WetPix m_paintbox[] = { + {496, 0, 16992, 0, 3808, 0, 0, 0}, + {16992, 9744, 21712, 6400, 25024, 3296, 0, 0}, + {6512, 6512, 6512, 4880, 11312, 0, 0, 0}, + {16002, 0, 2848, 0, 16992, 0, 0, 0}, + {22672, 0, 5328, 2272, 4288, 2640, 0, 0}, + {8000, 0, 16992, 0, 28352, 0, 0, 0}, + {5696, 5696, 12416, 2496, 28352, 0, 0, 0}, + {0, 0, 5136, 0, 28352, 0, 0, 0}, + {2320, 1760, 7344, 4656, 28352, 0, 0, 0}, + {8000, 0, 3312, 0, 5504, 0, 0, 0}, + {13680, 0, 16992, 0, 3312, 0, 0, 0}, + {5264, 5136, 1056, 544, 6448, 6304, 0, 0}, + {11440, 11440, 11440, 11440, 11440, 11440, 0, 0}, + {11312, 0, 11312, 0, 11312, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} }; + + static const int m_nPaints = 15; +} + +void wetPixToDouble(WetPixDbl * dst, WetPix *src) +{ + dst->rd = (1.0 / 8192.0) * src->rd; + dst->rw = (1.0 / 8192.0) * src->rw; + dst->gd = (1.0 / 8192.0) * src->gd; + dst->gw = (1.0 / 8192.0) * src->gw; + dst->bd = (1.0 / 8192.0) * src->bd; + dst->bw = (1.0 / 8192.0) * src->bw; + dst->w = (1.0 / 8192.0) * src->w; + dst->h = (1.0 / 8192.0) * src->h; +} + +void wetPixFromDouble(WetPix * dst, WetPixDbl *src) +{ + int v; + + v = (int)floor (8192.0 * src->rd + 0.5); + dst->rd = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->rw + 0.5); + dst->rw = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->gd + 0.5); + dst->gd = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->gw + 0.5); + dst->gw = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->bd + 0.5); + dst->bd = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->bw + 0.5); + dst->bw = CLAMP(v, 0, 65535); + + v = (int)floor (8192.0 * src->w + 0.5); + dst->w = CLAMP(v, 0, 511); + + v = (int)floor (8192.0 * src->h + 0.5); + dst->h = CLAMP(v, 0, 511); + +} + +int getH(int r, int g, int b) +{ + int h, s, v; + TQColor c(r,g, b); + c.getHsv(&h, &s, &v); + return h; +} + +KisWetColorSpace::KisWetColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) : + KisAbstractColorSpace(KisID("WET", i18n("Watercolors")), 0, icMaxEnumData, tqparent, p) +{ + wet_init_render_tab(); + + m_paintNames << i18n("Quinacridone Rose") + << i18n("Indian Red") + << i18n("Cadmium Yellow") + << i18n("Hookers Green") + << i18n("Cerulean Blue") + << i18n("Burnt Umber") + << i18n("Cadmium Red") + << i18n("Brilliant Orange") + << i18n("Hansa Yellow") + << i18n("Phthalo Green") + << i18n("French Ultramarine") + << i18n("Interference Lilac") + << i18n("Titanium White") + << i18n("Ivory Black") + << i18n("Pure Water"); + + m_channels.push_back(new KisChannelInfo(i18n("Red Concentration"), "Rc", 0, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Myth Red"), "Rm", 1, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Green Concentration"), "Gc", 2, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Myth Green"), "Gm", 3, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Blue Concentration"), "Bc", 4, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Myth Blue"), "Bm", 5, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Water Volume"), "W", 6, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Paper Height"), "H", 7, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16)); + + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Red Concentration"), "Rc", 8, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Red"), "Rm", 9, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Green Concentration"), "Gc", 10, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Green"), "Gm", 11, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Blue Concentration"), "Bc", 12, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Blue"), "Bm", 13, KisChannelInfo::COLOR, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Water Volume"), "W", 14, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16)); + m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Paper Height"), "H", 15, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16)); + + // Store the hue; we'll pick the paintbox color that closest to the given TQColor's hue. + m_conversionMap[getH(240, 32, 160)] = m_paintbox[0]; // Quinacridone Rose + m_conversionMap[getH(159, 88, 43)] = m_paintbox[1]; // Indian Red + m_conversionMap[getH(254, 220, 64)] = m_paintbox[2]; // Cadmium Yellow + m_conversionMap[getH(36, 180, 32)] = m_paintbox[3]; // Hookers Green + m_conversionMap[getH(16, 185, 215)] = m_paintbox[4]; // Cerulean Blue + m_conversionMap[getH(96, 32, 8)] = m_paintbox[5]; // Burnt Umber + m_conversionMap[getH(254, 96, 8)] = m_paintbox[6]; // Cadmium Red + m_conversionMap[getH(255, 136, 8)] = m_paintbox[7]; // Brilliant Orange + m_conversionMap[getH(240, 199, 8)] = m_paintbox[8]; // Hansa Yellow + m_conversionMap[getH(96, 170, 130)] = m_paintbox[9]; // Phthalo Green + m_conversionMap[getH(48, 32, 170)] = m_paintbox[10]; // French Ultramarine + m_conversionMap[getH(118, 16, 135)] = m_paintbox[11]; // Interference Lilac + m_conversionMap[getH(254, 254, 254)] = m_paintbox[12]; // Titanium White + m_conversionMap[getH(64, 64, 74)] = m_paintbox[13]; // Ivory Black + + m_paintwetness = false; + phasebig = 0; +} + + +KisWetColorSpace::~KisWetColorSpace() +{ +} + +void KisWetColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + WetPack* p = reinterpret_cast(dst); + + int h = getH(c.red(), c.green(), c.blue()); + int delta = 256; + int key = 0; + TQMap::Iterator it; + TQMap::Iterator end = m_conversionMap.end(); + for (it = m_conversionMap.begin(); it != end; ++it) { + if (abs(it.key() - h) < delta) { + delta = abs(it.key() - h); + key = it.key(); + } + } + + // Translate the special TQCOlors from our paintbox to wetpaint paints. + if (m_conversionMap.tqcontains(key)) { + (*p).paint = m_conversionMap[key]; + (*p).adsorb = m_conversionMap[key]; // or maybe best add water here? + } else { + // water + (*p).paint = m_paintbox[14]; + (*p).adsorb = m_paintbox[14]; + } +} + +void KisWetColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 /*opacity*/, TQ_UINT8 *dst, KisProfile * /*profile*/) +{ + fromTQColor(c, dst); +} + + TQ_UINT8 KisWetColorSpace::getAlpha(const TQ_UINT8 */*pixel*/) const +{ + return OPACITY_OPAQUE; +} + +void KisWetColorSpace::setAlpha( TQ_UINT8 * /*pixels*/, TQ_UINT8 /*alpha*/, TQ_INT32 /*nPixels*/) const +{ +} + +void KisWetColorSpace::multiplyAlpha( TQ_UINT8 * /*pixels*/, TQ_UINT8 /*alpha*/, TQ_INT32 /*nPixels*/) +{ +} + +void KisWetColorSpace::applyAlphaU8Mask( TQ_UINT8 * /*pixels*/, TQ_UINT8 * /*alpha*/, TQ_INT32 /*nPixels*/) +{ +} + +void KisWetColorSpace::applyInverseAlphaU8Mask( TQ_UINT8 * /*pixels*/, TQ_UINT8 * /*alpha*/, TQ_INT32 /*nPixels*/) +{ +} + + TQ_UINT8 KisWetColorSpace::scaleToU8(const TQ_UINT8 * /*srcPixel*/, TQ_INT32 /*channelPos*/) +{ + return 0; +} + +TQ_UINT16 KisWetColorSpace::scaleToU16(const TQ_UINT8 * /*srcPixel*/, TQ_INT32 /*channelPos*/) +{ + return 0; +} + + +void KisWetColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * /*profile*/) +{ + TQ_UINT8 * rgb = new TQ_UINT8[3]; + Q_CHECK_PTR(rgb); + + memset(rgb, 255, 3); + + // Composite the two layers in each pixelSize + + WetPack * wp = (WetPack*)src; + + // First the adsorption layer + wet_composite(RGB, rgb, &wp->adsorb); + + // Then the paint layer (which comes first in our double-packed pixel) + wet_composite(RGB, rgb, &wp->paint); + + c->setRgb(rgb[0], rgb[1], rgb[2]); + + delete[]rgb; +} + +void KisWetColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 */*opacity*/, KisProfile * /*profile*/) +{ + toTQColor(src, c); +} + +void KisWetColorSpace::mixColors(const TQ_UINT8 **/*colors*/, const TQ_UINT8 */*weights*/, TQ_UINT32 /*nColors*/, TQ_UINT8 */*dst*/) const +{ +} + +TQValueVector KisWetColorSpace::channels() const +{ + return m_channels; +} + + TQ_UINT32 KisWetColorSpace::nChannels() const +{ + return 16; +} + + TQ_UINT32 KisWetColorSpace::nColorChannels() const +{ + return 12; +} + + TQ_UINT32 KisWetColorSpace::nSubstanceChannels() const +{ + return 4; +} + + + TQ_UINT32 KisWetColorSpace::pixelSize() const +{ + return 32; // This color strategy wants an unsigned short for each + // channel, and every pixel consists of two wetpix structs + // -- even though for many purposes we need only one wetpix + // struct. +} + + + +// XXX: use profiles to display correctly on calibrated displays. +TQImage KisWetColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float /*exposure*/) +{ + + TQImage img(width, height, 32); + + TQ_UINT8 *rgb = (TQ_UINT8*) img.bits(); + const WetPack* wetData = reinterpret_cast(data); + + // Clear to white -- the following code actually composits the contents of the + // wet pixels with the contents of the image buffer, so they need to be + // prepared + memset(rgb, 255, width * height * 4); + // Composite the two layers in each pixelSize + + TQ_INT32 i = 0; + while ( i < width * height) { + // First the adsorption layers + WetPack* wp = const_cast(&wetData[i]); // XXX don't do these things! + // XXX Probably won't work on MSB archs! + wet_composite(BGR, rgb, &(wp->adsorb)); + // Then the paint layer (which comes first in our double-packed pixel) + wet_composite(BGR, rgb, &(wp->paint)); + + // XXX pay attention to this comment!! + // Display the wet stripes -- this only works if we have at least three scanlines in height, + // because otherwise the phase trick won't work. + + // Because we work in a stateless thing, and we can't just draw this wetness + // indication AFTER this (e.g. like the selection), we have to do un nice things: + // Because we (hopefully atm!) don't use the height of the paint wetpix, we abuse + // that to store a state. It's not perfect, but it works for now... + if (m_paintwetness) { + wet_render_wetness(rgb, wp); + } + + i++; + rgb += sizeof( TQ_UINT32); // Because the TQImage is 4 bytes deep. + + } + + return img; +} + +void KisWetColorSpace::bitBlt( TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 */*srcAlphaMask*/, + TQ_INT32 /*tqmaskRowStride*/, + TQ_UINT8 /*opacity*/, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + if (rows <= 0 || cols <= 0) + return; + + TQ_UINT8 *d; + const TQ_UINT8 *s; + + TQ_INT32 linesize = pixelSize() * cols; + d = dst; + s = src; + + // Do as if we 'stack' them atop of each other + if (op == COMPOSITE_OVER) { + while (rows-- > 0) { + for (int i = 0; i < cols; i++) { + WetPack* dstPack = &(reinterpret_cast(d))[i]; + const WetPack* srcPack = &(reinterpret_cast(s))[i]; + combinePixels(&(dstPack->paint), &(dstPack->paint), &(srcPack->paint)); + combinePixels(&(dstPack->adsorb), &(dstPack->adsorb), &(srcPack->adsorb)); + } + d += dstRowSize; // size?? + s += srcRowStride; + } + + return; + } + + // Just copy the src onto the dst, we don't do fancy things here, + // we do those in the paint op, because we need pressure to determine + // paint deposition. + + while (rows-- > 0) { + memcpy(d, s, linesize); + d += dstRowSize; // size?? + s += srcRowStride; + } +} + +void KisWetColorSpace::wet_init_render_tab() +{ + int i; + + double d; + int a, b; + + wet_render_tab = new TQ_UINT32[4096]; + Q_CHECK_PTR(wet_render_tab); + + for (i = 0; i < 4096; i++) + { + d = i * (1.0 / 512.0); + + if (i == 0) + a = 0; + else + a = (int) floor (0xff00 / i + 0.5); + + b = (int) floor (0x8000 * exp (-d) + 0.5); + wet_render_tab[i] = (a << 16) | b; + } + +} + +void KisWetColorSpace::wet_composite(RGBMode m, TQ_UINT8 *rgb, WetPix * wet) +{ + int r, g, b; + int d, w; + int ab; + int wa; + + if (m == RGB) + r = rgb[0]; + else + r = rgb[2]; + w = wet[0].rw >> 4; + d = wet[0].rd >> 4; + + ab = wet_render_tab[d]; + + wa = (w * (ab >> 16) + 0x80) >> 8; + r = wa + (((r - wa) * (ab & 0xffff) + 0x4000) >> 15); + if (m == RGB) + rgb[0] = r; + else + rgb[2] = r; + + // Green is 1 both in RGB as BGR + g = rgb[1]; + w = wet[0].gw >> 4; + d = wet[0].gd >> 4; + d = d >= 4096 ? 4095 : d; + ab = wet_render_tab[d]; + wa = (w * (ab >> 16) + 0x80) >> 8; + g = wa + (((g - wa) * (ab & 0xffff) + 0x4000) >> 15); + rgb[1] = g; + + if (m == RGB) + b = rgb[2]; + else + b = rgb[0]; + w = wet[0].bw >> 4; + d = wet[0].bd >> 4; + d = d >= 4096 ? 4095 : d; + ab = wet_render_tab[d]; + wa = (w * (ab >> 16) + 0x80) >> 8; + b = wa + (((b - wa) * (ab & 0xffff) + 0x4000) >> 15); + if (m == RGB) + rgb[2] = b; + else + rgb[0] = b; +} + +void KisWetColorSpace::wet_render_wetness( TQ_UINT8 * rgb, WetPack * pack) +{ + int highlight = 255 - (pack->paint.w >> 1); + + if (highlight < 255 && ((phase++) % 3 == 0)) { + for (int i = 0; i < 3; i++) + rgb[i] = 255 - (((255 - rgb[i]) * highlight) >> 8); + } + phase &= 3; +} + +KisCompositeOpList KisWetColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + + return list; +} + +TQString KisWetColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(pixel[channelPosition]); +} + +TQString KisWetColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const TQ_UINT16 *pixel = reinterpret_cast(U8_pixel); + TQ_UINT32 channelPosition = m_channels[channelIndex]->pos(); + + return TQString().setNum(static_cast(pixel[channelPosition]) / UINT16_MAX); +} + +TQValueList KisWetColorSpace::createBackgroundFilters() +{ + TQValueList filterList; + KisFilter * f = new WetPhysicsFilter(); + filterList << f; + return filterList; +} diff --git a/chalk/colorspaces/wet/kis_wet_colorspace.h b/chalk/colorspaces/wet/kis_wet_colorspace.h new file mode 100644 index 00000000..0523bf97 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wet_colorspace.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_STRATEGY_COLORSPACE_WET_H_ +#define KIS_STRATEGY_COLORSPACE_WET_H_ + +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" + +class KisFilter; + +/** + * The wet colourspace is one of the more complicated colour spaces. Every + * pixel actually consists of two pixels: the paint pixel and the adsorbtion + * pixel. This corresponds to the two layers of the wetpack structure in the + * original wetdreams code by Raph Levien. + */ + +// XXX: This should really be in a namespace. + +typedef struct _WetPix WetPix; +typedef struct _WetPixDbl WetPixDbl; +typedef struct _WetPack WetPack; + +/* + * White is made up of myth-red, myth-green, and myth-blue. Myth-red + * looks red when viewed reflectively, but cyan when viewed + * transmissively (thus, it vaguely resembles a dichroic + * filter). Myth-red over black is red, and myth-red over white is + * white. + * + * Total red channel concentration is myth-red concentration plus + * cyan concentration. + */ + +struct _WetPix { + TQ_UINT16 rd; /* Total red channel concentration */ + TQ_UINT16 rw; /* Myth-red concentration */ + + TQ_UINT16 gd; /* Total green channel concentration */ + TQ_UINT16 gw; /* Myth-green concentration */ + + TQ_UINT16 bd; /* Total blue channel concentration */ + TQ_UINT16 bw; /* Myth-blue concentration */ + + TQ_UINT16 w; /* Water volume */ + TQ_UINT16 h; /* Height of paper surface XXX: This might just as well be a single + channel in our colour model that has two of + these wetpix structs for every paint device pixels*/ +}; + +struct _WetPack { + WetPix paint; /* Paint layer */ + WetPix adsorb; /* Adsorbtion layer */ +}; + +struct _WetPixDbl { + double rd; /* Total red channel concentration */ + double rw; /* Myth-red concentration */ + double gd; /* Total green channel concentration */ + double gw; /* Myth-green concentration */ + double bd; /* Total blue channel concentration */ + double bw; /* Myth-blue concentration */ + double w; /* Water volume */ + double h; /* Height of paper surface */ +}; + + + +void wetPixToDouble(WetPixDbl * dst, WetPix *src); +void wetPixFromDouble(WetPix * dst, WetPixDbl *src); + + +class KisWetColorSpace : public KisAbstractColorSpace { +public: + KisWetColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p); + virtual ~KisWetColorSpace(); + + + virtual bool willDegrade(ColorSpaceIndependence independence) + { + if (independence == TO_RGBA8 || independence == TO_LAB16) + return true; + else + return false; + }; + + + + +public: + + // Semi-clever: we have only fifteen wet paint colors that are mapped to the + // qcolors that are put in the painter by the special wet paint palette. Other + // TQColors are mapped to plain water... + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const; + virtual void setAlpha( TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + virtual void multiplyAlpha( TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels); + + virtual void applyAlphaU8Mask( TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask( TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 nSubstanceChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + virtual TQValueList createBackgroundFilters(); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + void setPaintWetness(bool b) { m_paintwetness = b; } // XXX this needs better design! + bool paintWetness() { return m_paintwetness; } + void resetPhase() { phase = phasebig++; phasebig &= 3; } + + void combinePixels(WetPix* dst, WetPix const* src1, WetPix const* src2) const { + dst->rd = src1->rd + src2->rd; + dst->rw = src1->rw + src2->rw; + dst->gd = src1->gd + src2->gd; + dst->gw = src1->gw + src2->gw; + dst->bd = src1->bd + src2->bd; + dst->bw = src1->bw + src2->bw; + dst->w = src1->w + src2->w; + } +protected: + virtual void bitBlt( TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); +private: + + // This was static, but since we have only one instance of the color strategy, + // it can be just as well a private member variable. + void wet_init_render_tab(); + + /// Convert a single pixel from its wet representation to rgb: internal rgb: rgb[0] = R, etc + typedef enum { RGB, BGR } RGBMode; + void wet_composite(RGBMode m, TQ_UINT8 *rgb, WetPix * wet); + + void wet_render_wetness( TQ_UINT8 * rgb, WetPack * pack); + +private: + TQ_UINT32 * wet_render_tab; + + TQStringList m_paintNames; + TQMap m_conversionMap; + + bool m_paintwetness; + int phase, phasebig; + +}; + +class KisWetColorSpaceFactory : public KisColorSpaceFactory +{ +public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("WET", i18n("Watercolors")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return 0; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisWetColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return ""; }; +}; + +#endif // KIS_STRATEGY_COLORSPACE_WET_H_ diff --git a/chalk/colorspaces/wet/kis_wet_palette_widget.cc b/chalk/colorspaces/wet/kis_wet_palette_widget.cc new file mode 100644 index 00000000..eb6556d2 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wet_palette_widget.cc @@ -0,0 +1,245 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 1999 Matthias Elter (me@kde.org) + * Copyright (c) 2001-2002 Igor Jansen (rm@kde.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_wet_colorspace.h" +#include "kis_wet_palette_widget.h" + +KisWetPaletteWidget::KisWetPaletteWidget(TQWidget *tqparent, const char *name) : super(tqparent, name) +{ + m_subject = 0; + + TQVBoxLayout * vl = new TQVBoxLayout(this, 0, -1, "main tqlayout"); + + TQGridLayout * l = new TQGridLayout(vl, 2, 8, 2, "color wells grid"); + + KisColorCup * b; + int WIDTH = 24; + int HEIGHT = 24; + + b = new KisColorCup(this); + b->setColor( TQColor(240, 32, 160) ); + l->addWidget(b, 0, 0); + TQToolTip::add(b, i18n("Quinacridone Rose")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(159, 88, 43)); + l->addWidget(b, 0, 1); + TQToolTip::add(b,i18n("Indian Red")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor( TQColor(254, 220, 64) ); + l->addWidget(b, 0, 2); + TQToolTip::add(b,i18n("Cadmium Yellow")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(36, 180, 32)); + l->addWidget(b, 0, 3); + TQToolTip::add(b,i18n("Hookers Green")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(16, 185, 215)); + l->addWidget(b, 0, 4); + TQToolTip::add(b,i18n("Cerulean Blue")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(96, 32, 8)); + l->addWidget(b, 0, 5); + TQToolTip::add(b,i18n("Burnt Umber")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(254, 96, 8)); + l->addWidget(b, 0, 6); + TQToolTip::add(b,i18n("Cadmium Red")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(255, 136, 8)); + l->addWidget(b, 0, 7); + TQToolTip::add(b,i18n("Brilliant Orange")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(240, 199, 8)); + l->addWidget(b, 1, 0); + TQToolTip::add(b,i18n("Hansa Yellow")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(96, 170, 130)); + l->addWidget(b, 1, 1); + TQToolTip::add(b,i18n("Phthalo Green")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(48, 32, 170)); + l->addWidget(b, 1, 2); + TQToolTip::add(b,i18n("French Ultramarine")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(118, 16, 135)); + l->addWidget(b, 1, 3); + TQToolTip::add(b,i18n("Interference Lilac")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(254, 254, 254)); + l->addWidget(b, 1, 4); + TQToolTip::add(b,i18n("Titanium White")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(64, 64, 74)); + l->addWidget(b, 1, 5); + TQToolTip::add(b,i18n("Ivory Black")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + b = new KisColorCup(this); + b->setColor(TQColor(255, 255, 255)); + l->addWidget(b, 1, 6); + TQToolTip::add(b,i18n("Pure Water")); + b->setFixedSize(WIDTH, HEIGHT); + connect(b, TQT_SIGNAL(changed(const TQColor &)), TQT_SLOT(slotFGColorSelected(const TQColor &))); + + TQGridLayout * g2 = new TQGridLayout(vl, 2, 2); + + TQLabel * label = new TQLabel(i18n("Paint strength:"), this); + g2->addWidget(label, 0, 0); + m_strength = new KDoubleNumInput(0.0, 2.0, 1.0, 0.1, 1, this); + m_strength->setRange(0.0, 2.0, 0.1, true); + connect(m_strength, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotStrengthChanged(double))); + g2->addWidget(m_strength, 0, 1); + + label = new TQLabel(i18n("Wetness:"), this); + g2->addWidget(label, 1, 0); + m_wetness = new KIntNumInput(16, this); + connect(m_wetness, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotWetnessChanged(int))); + m_wetness->setRange(0, 16, true); + g2->addWidget(m_wetness, 1, 1); + + g2->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Expanding, TQSizePolicy::Minimum)); + +} + +void KisWetPaletteWidget::update(KisCanvasSubject *subject) +{ + m_subject = subject; + +} + +void KisWetPaletteWidget::slotFGColorSelected(const TQColor& c) +{ + KisWetColorSpace* cs = dynamic_cast(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), "")); + Q_ASSERT(cs); + + WetPack pack; + TQ_UINT8* data = reinterpret_cast< TQ_UINT8*>(&pack); + cs->fromTQColor(c, data); + pack.paint.w = 15 * m_wetness->value(); + // upscale from double to uint16: + pack.paint.h = static_cast< TQ_UINT16>(m_strength->value() * (double)(0xffff/2)); + KisColor color(data, cs); + + if(m_subject) + m_subject->setFGColor(color); +} + +void KisWetPaletteWidget::slotWetnessChanged(int n) +{ + if (!m_subject) + return; + + KisWetColorSpace* cs = dynamic_cast(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), "")); + Q_ASSERT(cs); + + KisColor color = m_subject->fgColor(); + color.convertTo(cs); + WetPack pack = *(reinterpret_cast(color.data())); + pack.paint.w = 15 * n; + + color.setColor(reinterpret_cast< TQ_UINT8*>(&pack), cs); + m_subject->setFGColor(color); +} + +void KisWetPaletteWidget::slotStrengthChanged(double n) +{ + if (!m_subject) + return; + + KisWetColorSpace* cs = dynamic_cast( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), "")); + Q_ASSERT(cs); + + KisColor color = m_subject->fgColor(); + color.convertTo(cs); + WetPack pack = *(reinterpret_cast(color.data())); + pack.paint.h = static_cast< TQ_UINT16>(n * (double)(0xffff/2)); // upscale from double to uint16 + + color.setColor(reinterpret_cast< TQ_UINT8*>(&pack), cs); + m_subject->setFGColor(color); +} + + +#include "kis_wet_palette_widget.moc" diff --git a/chalk/colorspaces/wet/kis_wet_palette_widget.h b/chalk/colorspaces/wet/kis_wet_palette_widget.h new file mode 100644 index 00000000..10c177e6 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wet_palette_widget.h @@ -0,0 +1,68 @@ +/* This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_WET_PALETTE_WIDGET_H +#define KIS_WET_PALETTE_WIDGET_H + +#include "tqwidget.h" +#include "tqpushbutton.h" + +#include "kis_canvas_subject.h" +#include "kis_canvas_observer.h" + +#include + +class KoFrameButton; +class TQGridLayout; +class TQColor; +class TQLabel; +class TQSpinBox; +class TQColor; +class KIntNumInput; +class KDoubleNumInput; + +class KRITAUI_EXPORT KisWetPaletteWidget + : public TQWidget, + public KisCanvasObserver +{ + Q_OBJECT + TQ_OBJECT + typedef TQWidget super; + +public: + KisWetPaletteWidget(TQWidget *tqparent = 0L, const char *name = 0); + virtual ~KisWetPaletteWidget() {} + +protected slots: + + void slotFGColorSelected(const TQColor& c); + void slotWetnessChanged(int); + void slotStrengthChanged(double); + +private: + void update(KisCanvasSubject*); + +private: + KisCanvasSubject *m_subject; + KDoubleNumInput* m_strength; + KIntNumInput* m_wetness; + + +}; + +#endif diff --git a/chalk/colorspaces/wet/kis_wetness_visualisation_filter.cc b/chalk/colorspaces/wet/kis_wetness_visualisation_filter.cc new file mode 100644 index 00000000..853b11a2 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wetness_visualisation_filter.cc @@ -0,0 +1,77 @@ +/* + * kis_wetness_visualisation_filter.cc -- Part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include "kis_meta_registry.h" +#include +#include +#include +#include +#include "kis_wet_colorspace.h" +#include +#include "kis_wetness_visualisation_filter.h" + +WetnessVisualisationFilter::WetnessVisualisationFilter(KisView* view) + : m_view(view), m_action(0) { + connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTimeout())); +} + +// XXX this needs to work on a per-layer basis! + +void WetnessVisualisationFilter::setAction(KToggleAction* action) { + m_action = action; + if (!m_action) + return; + KisWetColorSpace* cs = dynamic_cast( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") ); + Q_ASSERT(cs); + m_action->setChecked(cs->paintWetness()); +} + +void WetnessVisualisationFilter::slotActivated() { + kdDebug(DBG_AREA_CMS) << "activated" << endl; + if (!m_action) { + kdDebug(DBG_AREA_CMS) << "no action" << endl; + return; + } + KisWetColorSpace* cs = dynamic_cast( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") ); + Q_ASSERT(cs); + if (!m_action->isChecked()) { + m_timer.stop(); + cs->setPaintWetness(false); + } else { + m_timer.start(500); + cs->setPaintWetness(true); + } +} + +void WetnessVisualisationFilter::slotTimeout() { + KisWetColorSpace* cs = dynamic_cast( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") ); + Q_ASSERT(cs); + if (!cs) return; + cs->resetPhase(); + +} + +#include "kis_wetness_visualisation_filter.moc" diff --git a/chalk/colorspaces/wet/kis_wetness_visualisation_filter.h b/chalk/colorspaces/wet/kis_wetness_visualisation_filter.h new file mode 100644 index 00000000..979d580c --- /dev/null +++ b/chalk/colorspaces/wet/kis_wetness_visualisation_filter.h @@ -0,0 +1,51 @@ +/* + * kis_wetness_visualisation_filter.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _WETNESS_VISUALISATION_FILTER_H +#define _WETNESS_VISUALISATION_FILTER_H + +#include +#include +#include + +class KisView; + +class WetnessVisualisationFilter : public TQObject +{ + Q_OBJECT + TQ_OBJECT +public: + WetnessVisualisationFilter(KisView* view); + virtual ~WetnessVisualisationFilter() {} + void setAction(KToggleAction* action); + // XXX: Figure out a way to match a filter exactly to a colorspace + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + virtual bool workWith(KisColorSpace* cs) { return (cs->id() == KisID("WET")); }; +private slots: + void slotActivated(); + void slotTimeout(); + +private: + KisView * m_view; + KToggleAction * m_action; + TQTimer m_timer; +}; + +#endif // _WETNESS_VISUALISATION_FILTER_H diff --git a/chalk/colorspaces/wet/kis_wetop.cc b/chalk/colorspaces/wet/kis_wetop.cc new file mode 100644 index 00000000..70e07280 --- /dev/null +++ b/chalk/colorspaces/wet/kis_wetop.cc @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_input_device.h" + +#include "kis_wetop.h" +#include "kis_wet_colorspace.h" + +KisWetOpSettings::KisWetOpSettings(TQWidget *tqparent) + : super(tqparent) +{ + m_options = new WetPaintOptions(tqparent, "wet option widget"); +} + +bool KisWetOpSettings::varySize() const +{ + return m_options->checkSize->isChecked(); +} + +bool KisWetOpSettings::varyWetness() const +{ + return m_options->checkWetness->isChecked(); +} + +bool KisWetOpSettings::varyStrength() const +{ + return m_options->checkStrength->isChecked(); +} + +KisPaintOp * KisWetOpFactory::createOp(const KisPaintOpSettings *settings, KisPainter * painter) +{ + const KisWetOpSettings *wetopSettings = dynamic_cast(settings); + Q_ASSERT(settings == 0 || wetopSettings != 0); + + KisPaintOp * op = new KisWetOp(wetopSettings, painter); + Q_CHECK_PTR(op); + return op; +} + +KisPaintOpSettings* KisWetOpFactory::settings(TQWidget * tqparent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return 0; + } else { + return new KisWetOpSettings(tqparent); + } +} + +KisWetOp::KisWetOp(const KisWetOpSettings * settings, KisPainter * painter) + : super(painter) +{ + if (settings) { + m_size = settings->varySize(); + m_wetness = settings->varyWetness(); + m_strength = settings->varyStrength(); + } else { + m_size = false; + m_wetness = false; + m_strength = false; + } +} + +KisWetOp::~KisWetOp() +{ +} + +void KisWetOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + if (!m_painter) return; + + if (!m_painter->device()) return; + KisPaintDeviceSP device = m_painter->device(); + if (!m_painter->device()) return; + + KisBrush *brush = m_painter->brush(); + Q_ASSERT(brush); + + if (! brush->canPaintFor(info) ) + return; + + KisPaintInformation inf(info); + + if (!m_size) + inf.pressure = PRESSURE_DEFAULT; + + KisPaintDeviceSP dab = 0; + + if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { + dab = brush->image(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), inf); + } + else { + KisAlphaMaskSP tqmask = brush->tqmask(inf); + dab = computeDab(tqmask, KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + + KisColorSpace * cs = device->colorSpace(); + + if (cs->id() != KisID("WET","")) { + kdDebug(DBG_AREA_CMS) << "You cannot paint wet paint on dry pixels.\n"; + return; + } + + KisColor paintColor = m_painter->paintColor(); + paintColor.convertTo(cs); + // hopefully this does + // nothing, conversions are bad ( wet->rgb->wet gives horrible mismatches, due to + // the conversion to rgb actually rendering the paint above white + + WetPack* paintPack = reinterpret_cast(paintColor.data()); + WetPix paint = paintPack->paint; + + // Get the paint info (we store the strength in the otherwise unused (?) height field of + // the paint + // double wetness = paint.w; // XXX: Was unused + // strength is a double in the 0 - 2 range, but upscaled to TQ_UINT16: + //kdDebug() << "Original strength as in paint.h: " << paint.h << endl; + + double strength = 2.0 * static_cast(paint.h) / (double)(0xffff); + + //kdDebug() << "Before strength: " << strength << endl; + + if (m_strength) + strength = strength * (strength + info.pressure) * 0.5; + else + strength = strength * (strength + PRESSURE_DEFAULT) * 0.5; + + double pressure = 0.75 + 0.25 * info.pressure; + + //kdDebug() << "info.pressure " << info.pressure << ", local pressure: " << pressure << ", strength: " << strength << endl; + + WetPack currentPack; + WetPix currentPix; + double eff_height; + double press, contact; + + int tqmaskW = brush->tqmaskWidth(inf); + int tqmaskH = brush->tqmaskHeight(inf); + KoPoint dest = (pos - (brush->hotSpot(inf))); + int xStart = (int)dest.x(); + int yStart = (int)dest.y(); + + for (int y = 0; y < tqmaskH; y++) { + KisHLineIteratorPixel dabIt = dab->createHLineIterator(0, y, tqmaskW, false); + KisHLineIteratorPixel it = device->createHLineIterator(xStart, yStart+y, tqmaskW, true); + + while (!dabIt.isDone()) { + // This only does something with .paint, and not with adsorb. + currentPack = *(reinterpret_cast(it.rawData())); + WetPix currentData = currentPack.adsorb; + currentPix = currentPack.paint; + + // Hardcoded threshold for the dab 'strength': above it, it will get painted + if (*dabIt.rawData() > 125) + press = pressure * 0.25; + else + press = -1; + //kdDebug() << "After mysterious line, press becomes: " << press << ", this is the same as in the orignal. Good" << endl; + // XXX - 192 is probably only useful for paper with a texture... + eff_height = (currentData.h + currentData.w - 192.0) * (1.0 / 255.0); + contact = (press + eff_height) * 0.2; + double old_contact = contact; + if (contact > 0.5) + contact = 1.0 - 0.5 * exp(-2.0 * contact - 1.0); + + //kdDebug() << "Contact was " << old_contact << " and has become: " << contact << endl; + if (contact > 0.0001) { + int v; + double rnd = rand() * (1.0 / RAND_MAX); + + v = currentPix.rd; + currentPix.rd = floor(v + (paint.rd * strength - v) * contact + rnd); + //kdDebug() << "Rd was " << v << " and has become " << currentPix.rd << endl; + v = currentPix.rw; + currentPix.rw = floor(v + (paint.rw * strength - v) * contact + rnd); + v = currentPix.gd; + currentPix.gd = floor(v + (paint.gd * strength - v) * contact + rnd); + v = currentPix.gw; + currentPix.gw = floor(v + (paint.gw * strength - v) * contact + rnd); + v = currentPix.bd; + currentPix.bd = floor(v + (paint.bd * strength - v) * contact + rnd); + v = currentPix.bw; + currentPix.bw = floor(v + (paint.bw * strength - v) * contact + rnd); + v = currentPix.w; + if (m_wetness) + currentPix.w = (CLAMP(floor( + v + (paint.w * (0.5 + pressure) - v) * contact + rnd), 0, 512)); + else + currentPix.w = floor(v + (paint.w - v) * contact + rnd); + + currentPack.paint = currentPix; + *(reinterpret_cast(it.rawData())) = currentPack; + } + ++dabIt; + ++it; + } + } + + m_painter->addDirtyRect(TQRect(xStart, yStart, tqmaskW, tqmaskH)); +} diff --git a/chalk/colorspaces/wet/kis_wetop.h b/chalk/colorspaces/wet/kis_wetop.h new file mode 100644 index 00000000..37cd594a --- /dev/null +++ b/chalk/colorspaces/wet/kis_wetop.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WETOP_H_ +#define KIS_WETOP_H_ + +#include "kis_paintop.h" +#include "kis_types.h" +#include "kis_colorspace.h" +#include "wdgpressure.h" + +class KisPoint; +class KisPainter; +class KisInputDevice; + +class KisWetOpFactory : public KisPaintOpFactory { +public: + KisWetOpFactory() {} + virtual ~KisWetOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("wetbrush", i18n("Watercolor Brush")); } + virtual bool userVisible(KisColorSpace* cs) { return cs->id() == KisID("WET", ""); } + virtual KisPaintOpSettings *settings(TQWidget * tqparent, const KisInputDevice& inputDevice); +}; + +class KisWetOpSettings : public KisPaintOpSettings { + typedef KisPaintOpSettings super; +public: + KisWetOpSettings(TQWidget *tqparent); + + bool varySize() const; + bool varyWetness() const; + bool varyStrength() const; + + virtual TQWidget *widget() const { return m_options; } + +private: + WetPaintOptions *m_options; +}; + +class KisWetOp : public KisPaintOp { + + typedef KisPaintOp super; + bool m_size; + bool m_wetness; + bool m_strength; + +public: + + KisWetOp(const KisWetOpSettings *settings, KisPainter * painter); + virtual ~KisWetOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +}; + +#endif // KIS_WETOP_H_ diff --git a/chalk/colorspaces/wet/todo b/chalk/colorspaces/wet/todo new file mode 100644 index 00000000..2f6d358b --- /dev/null +++ b/chalk/colorspaces/wet/todo @@ -0,0 +1,24 @@ +* Implement wet model +* Implement wet paintop +* Implement dry filter +* Enable/disable all relevant gui bits on switching to/from a wet layer +* Create something that can periodically call the dry filter +* A palette with the special colour for wet painting: a docker tab for the colour docker. + +Perhaps: a special layer type or paint device, with an extensible option widget. + +When to create the height field? Ideally, the height field should be visualized in subtle shades +of grey before painting. + +How to hack into the creation of paint devices? We need initializers, extra options, status +widgets and thread or timer based continuous running filters. + +-> Maybe add an initializePaintDevice(rect) method to the color strategy that is called with the image +rect on creation. Then, for uninitialized rects (because of autolayers extension) call the method again. + +A wet layer is equivalent to the wetpack; two layers, i.e., stacked pixels, per pixel. + +The filter will contain the physics model: paint flow, drying and adsorbing onto the lower "layer" + + + diff --git a/chalk/colorspaces/wet/wdgpressure.ui b/chalk/colorspaces/wet/wdgpressure.ui new file mode 100644 index 00000000..96727ff1 --- /dev/null +++ b/chalk/colorspaces/wet/wdgpressure.ui @@ -0,0 +1,60 @@ + +WetPaintOptions + + + WetPaintOptions + + + + 0 + 0 + 382 + 31 + + + + + unnamed + + + 0 + + + + textLabel1 + + + Pressure effects: + + + + + checkSize + + + Size + + + true + + + + + checkWetness + + + Wetness + + + + + checkStrength + + + Strength + + + + + + diff --git a/chalk/colorspaces/wet/wet_plugin.cc b/chalk/colorspaces/wet/wet_plugin.cc new file mode 100644 index 00000000..1f65b83c --- /dev/null +++ b/chalk/colorspaces/wet/wet_plugin.cc @@ -0,0 +1,128 @@ +/* + * wet_plugin.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "kis_meta_registry.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wet_plugin.h" +#include "kis_wet_palette_widget.h" +#include "kis_wet_colorspace.h" +#include "kis_wetop.h" +#include "kis_wetness_visualisation_filter.h" +#include "kis_texture_filter.h" +#include "wetphysicsfilter.h" + +typedef KGenericFactory WetPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwetplugin, WetPluginFactory( "chalkcore" ) ) + + +WetPlugin::WetPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(WetPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) { + KisColorSpaceFactoryRegistry * f = dynamic_cast(tqparent); + + KisColorSpace* colorSpaceWet = new KisWetColorSpace(f, 0); + + KisColorSpaceFactory * csf = new KisWetColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceWet); + + // colorspace + f->add(csf); + + // histogram producer + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("WETHISTO", i18n("Wet")), colorSpaceWet) ); + + // wet brush op + KisPaintOpRegistry::instance()->add(new KisWetOpFactory); + + // Dry filter + KisFilterRegistry::instance()->add( new WetPhysicsFilter() ); + + // Texture Action: + f->addPaintDeviceAction(colorSpaceWet, new WetPaintDevAction); + } + else if (tqparent->inherits("KisView")) + { + setInstance(WetPluginFactory::instance()); + setXMLFile(locate("data","chalkplugins/wetplugin.rc"), true); + + m_view = dynamic_cast(tqparent); + // Wetness visualisation + WetnessVisualisationFilter * wf = new WetnessVisualisationFilter(m_view); + wf->setAction(new KToggleAction(i18n("Wetness Visualisation"), 0, 0, wf, + TQT_SLOT(slotActivated()), actionCollection(), "wetnessvisualisation")); + + // Create the wet palette + KisWetPaletteWidget * w = new KisWetPaletteWidget(m_view); + Q_CHECK_PTR(w); + + w->setCaption(i18n("Watercolors")); + + m_view->canvasSubject()->paletteManager()->addWidget(w, "watercolor docker", chalk::COLORBOX, INT_MAX, PALETTE_DOCKER, false); + m_view->canvasSubject()->attach(w); + } + + +} + +WetPlugin::~WetPlugin() +{ +} + +#include "wet_plugin.moc" diff --git a/chalk/colorspaces/wet/wet_plugin.h b/chalk/colorspaces/wet/wet_plugin.h new file mode 100644 index 00000000..d2fdc083 --- /dev/null +++ b/chalk/colorspaces/wet/wet_plugin.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WET_PLUGIN_H_ +#define WET_PLUGIN_H_ + +#include + +#include "kis_types.h" + +class KisView; +class KisWetColorSpace; + +/** + * A plugin wrapper around the WET colour space strategy. + */ +class WetPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + WetPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~WetPlugin(); + +private: + + KisView* m_view; + +}; + +#endif // WET_PLUGIN_H_ diff --git a/chalk/colorspaces/wet/wetdreams/Makefile b/chalk/colorspaces/wet/wetdreams/Makefile new file mode 100644 index 00000000..3daf4d76 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/Makefile @@ -0,0 +1,6 @@ +CFLAGS = -O3 `gtk-config --cflags` -Wall -ansi -pedantic +LDFLAGS = -O3 `gtk-config --libs` -Wall -ansi -pedantic + +all: wetmain + +wetmain: wetmain.o wetpix.o wetpaint.o wettexture.o wetphysics.o diff --git a/chalk/colorspaces/wet/wetdreams/wetmain.c b/chalk/colorspaces/wet/wetdreams/wetmain.c new file mode 100644 index 00000000..151385f5 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetmain.c @@ -0,0 +1,517 @@ +#include +#include +#include +#include "wetpix.h" +#include "wetpaint.h" +#include "wettexture.h" +#include "wetphysics.h" +WetPack *pack; /* The global wet pack */ + +double lastx, lasty; +double dist; +double spacing = 2; + +WetPix paint = { 707, 0, 707, 0, 707, 0, 240, 0 }; + +/* colors from Curtis et al, Siggraph 97 */ + +WetPix paintbox[] = { + {496, 0, 16992, 0, 3808, 0, 0, 0}, + {16992, 9744, 21712, 6400, 25024, 3296, 0, 0}, + {6512, 6512, 6512, 4880, 11312, 0, 0, 0}, + {16002, 0, 2848, 0, 16992, 0, 0, 0}, + {22672, 0, 5328, 2272, 4288, 2640, 0, 0}, + {8000, 0, 16992, 0, 28352, 0, 0, 0}, + {5696, 5696, 12416, 2496, 28352, 0, 0, 0}, + {0, 0, 5136, 0, 28352, 0, 0, 0}, + {2320, 1760, 7344, 4656, 28352, 0, 0, 0}, + {8000, 0, 3312, 0, 5504, 0, 0, 0}, + {13680, 0, 16992, 0, 3312, 0, 0, 0}, + {5264, 5136, 1056, 544, 6448, 6304, 0, 0}, + {11440, 11440, 11440, 11440, 11440, 11440, 0, 0}, + {11312, 0, 11312, 0, 11312, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +int n_paints = 15; + +char *paintstr = "select paint"; + +GtkWidget *paintname; + +char *paintnames[] = { + "Quinacridone Rose", + "Indian Red", + "Cadmium Yellow", + "Hookers Green", + "Cerulean Blue", + "Burnt Umber", + "Cadmium Red", + "Brilliant Orange", + "Hansa Yellow", + "Phthalo Green", + "French Ultramarine", + "Interference Lilac", + "Titanium White", + "Ivory Black", + "Pure Water" +}; + +GtkWidget *autodryb; +int timo = 0; +int adsorb_cnt; + +GtkObject *brushsize_adjust; + +GtkObject *wetness_adjust; + +GtkObject *strength_adjust; + +static void stop_drying(void) +{ + timo = 0; + gtk_label_set_text(GTK_LABEL(paintname), paintstr); +} + +static double strength_func(double strength, double pressure) +{ + return strength * (strength + pressure) * 0.5; +} + +static gint wet_button_press(GtkWidget * widget, GdkEventButton * event) +{ +#define noVERBOSE +#ifdef VERBOSE + g_print("button press %f %f %f\n", event->x, event->y, + event->pressure); + +#endif + wet_dab(pack->layers[1], + &paint, + event->x, + event->y, + ((GtkAdjustment *) brushsize_adjust)->value * + event->pressure, 0.75 + 0.25 * event->pressure, + strength_func(((GtkAdjustment *) strength_adjust)->value, + event->pressure)); + + lastx = event->x; + lasty = event->y; + dist = 0; + + stop_drying(); + + gtk_widget_queue_draw(widget); + return TRUE; +} + +static gint wet_motion(GtkWidget * widget, GdkEventMotion * event) +{ + double delta; +#ifdef VERBOSE + g_print("motion %f %f %f %d\n", event->x, event->y, + event->pressure, event->state); + +#endif + stop_drying(); + + if (!(event->state & 256)) + return TRUE; + + delta = sqrt((event->x - lastx) * (event->x - lastx) + + (event->y - lasty) * (event->y - lasty)); + + dist += delta; + + if (dist >= spacing) { + /* todo: interpolate position and pressure of the dab */ + wet_dab(pack->layers[1], + &paint, + event->x, + event->y, + ((GtkAdjustment *) brushsize_adjust)->value * + event->pressure, 0.75 + 0.25 * event->pressure, + strength_func(((GtkAdjustment *) strength_adjust)-> + value, event->pressure)); + gtk_widget_queue_draw(widget); + dist -= spacing; + } + + lastx = event->x; + lasty = event->y; + + return TRUE; +} + +static void dry(GtkWidget * da) +{ + g_print("drying..."); + gtk_label_set_text(GTK_LABEL(paintname), "drying..."); + gtk_widget_draw(paintname, NULL); + gdk_flush(); + wet_flow(pack->layers[1]); + adsorb_cnt++; + if (adsorb_cnt == 2) { + wet_adsorb(pack->layers[1], pack->layers[0]); + wet_dry(pack->layers[1]); + adsorb_cnt = 0; + } + + gtk_widget_draw(da, NULL); +#if 0 + gtk_label_set_text(GTK_LABEL(paintname), paintstr); +#endif + g_print("done\n"); +} + +static gint wet_dry_button_press(GtkWidget * widget, GtkWidget * da) +{ + dry(da); + + timo = 0; + + return TRUE; +} + +static gint clear_button_press(GtkWidget * widget, GtkWidget * da) +{ + wet_layer_clear(pack->layers[0]); + wet_layer_clone_texture(pack->layers[0], pack->layers[1]); + wet_layer_clear(pack->layers[1]); + wet_layer_clone_texture(pack->layers[1], pack->layers[0]); + + gtk_widget_draw(da, NULL); + + stop_drying(); + + return TRUE; +} + +static gint dry_timer(gpointer * dummy) +{ + GtkWidget *da = (GtkWidget *) dummy; + + timo++; + if (timo >= 10) { + if (gtk_toggle_button_get_active + (GTK_TOGGLE_BUTTON(autodryb))) { + dry(da); + } + + timo -= 2; + } + return TRUE; +} + +static gint +wet_expose(GtkWidget * widget, GdkEventExpose * event, WetPack * pack) +{ + byte *rgb; + int rowstride; + +#ifdef VERBOSE + g_print("expose: %d layers\n", pack->n_layers); +#endif + + rowstride = event->area.width * 3; + rowstride = (rowstride + 3) & -4; /* align to 4-byte boundary */ + rgb = g_new(byte, event->area.height * rowstride); + + wet_pack_render(rgb, rowstride, + pack, + event->area.x, event->area.y, + event->area.width, event->area.height); + + gdk_draw_rgb_image(widget->window, + widget->style->black_gc, + event->area.x, event->area.y, + event->area.width, event->area.height, + GDK_RGB_DITHER_MAX, rgb, rowstride); + + g_free(rgb); + return FALSE; +} + + +static void init_input(void) +{ + GList *tmp_list; + GdkDeviceInfo *info; + + tmp_list = gdk_input_list_devices(); + + info = NULL; + while (tmp_list) { + info = (GdkDeviceInfo *) tmp_list->data; +#ifdef VERBOSE + g_print("device: %s\n", info->name); +#endif + if (!g_strcasecmp(info->name, "wacom") || + !g_strcasecmp(info->name, "stylus") || + !g_strcasecmp(info->name, "eraser")) { + gdk_input_set_mode(info->deviceid, + GDK_MODE_SCREEN); + } + tmp_list = tmp_list->next; + } + if (!info) + return; +} + +static gint +pselect_expose(GtkWidget * widget, GdkEventExpose * event, WetPack * pack) +{ + byte *rgb; + int x; + int paint_quad, paint_num; + int last_pn; + int bg; + +#ifdef VERBOSE + g_print("expose: %d layers\n", pack->n_layers); +#endif + + rgb = g_new(byte, pack->layers[0]->width * 3); + + last_pn = 0; + for (x = 0; x < pack->layers[0]->width; x++) { + paint_quad = + floor(4 * x * n_paints / pack->layers[0]->width + 0.5); + paint_num = paint_quad >> 2; + if (last_pn != paint_num) { + rgb[x * 3] = 255; + rgb[x * 3 + 1] = 255; + rgb[x * 3 + 2] = 255; + last_pn = paint_num; + } else { + if ((paint_quad & 3) > 0 && (paint_quad & 3) < 3) + bg = 0; + else + bg = 255; + rgb[x * 3] = bg; + rgb[x * 3 + 1] = bg; + rgb[x * 3 + 2] = bg; + wet_composite(&rgb[x * 3], 0, &paintbox[paint_num], + 0, 1, 1); + } + } + + gdk_draw_rgb_image(widget->window, + widget->style->black_gc, + event->area.x, event->area.y, + event->area.width, event->area.height, + GDK_RGB_DITHER_MAX, + rgb + (event->area.x) * 3, 0); + + g_free(rgb); + return FALSE; +} + +static gint +pselect_button_press(GtkWidget * widget, GdkEventButton * event) +{ + int paint_num; + int wet; + +#ifdef VERBOSE + g_print("pselect button press %f %f %f\n", event->x, event->y, + event->pressure); + +#endif + paint_num = floor((event->x * n_paints) / pack->layers[0]->width); + + /* preserve wetness */ + wet = paint.w; + paint = paintbox[paint_num]; + paint.w = wet; + paintstr = paintnames[paint_num]; + /* + gtk_adjustment_set_value (GTK_ADJUSTMENT (wetness_adjust), paint.w); + */ + gtk_label_set_text(GTK_LABEL(paintname), paintstr); + + stop_drying(); + + return TRUE; +} + +static void wetness_update(GtkAdjustment * adj, gpointer data) +{ + paint.w = floor(15 * adj->value + 0.5); +} + +int main(int argc, char **argv) +{ + GtkWidget *w; + GtkWidget *v; + GtkWidget *eb; + GtkWidget *da; + GtkWidget *peb; + GtkWidget *pda; + GtkWidget *h; + GtkWidget *b; + GtkWidget *db; + GtkWidget *h2; + GtkWidget *l; + GtkWidget *brushsize; + GtkWidget *wetness; + GtkWidget *strength; + int xs = 512; + int ys = 512; + + gtk_init(&argc, &argv); + + if (argc >= 3) { + xs = atoi(argv[1]); + ys = atoi(argv[2]); + if (xs == 0) + xs = 512; + if (ys == 0) + ys = 512; + } + + + init_input(); + + gdk_rgb_init(); + + gtk_widget_set_default_colormap(gdk_rgb_get_cmap()); + gtk_widget_set_default_visual(gdk_rgb_get_visual()); + + pack = wet_pack_new(xs, ys); + + wet_pack_maketexture(pack, 1, 0.7, 0.5); + + w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_signal_connect(GTK_OBJECT(w), "destroy", + (GtkSignalFunc) gtk_main_quit, NULL); + + v = gtk_vbox_new(FALSE, 2); + gtk_container_add(GTK_CONTAINER(w), v); + gtk_widget_show(v); + + eb = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(v), eb); + gtk_widget_show(eb); + + gtk_widget_set_extension_events(eb, GDK_EXTENSION_EVENTS_ALL); + + gtk_widget_set_events(eb, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_KEY_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_PROXIMITY_OUT_MASK); + + gtk_signal_connect(GTK_OBJECT(eb), "button_press_event", + (GtkSignalFunc) wet_button_press, NULL); + gtk_signal_connect(GTK_OBJECT(eb), "motion_notify_event", + (GtkSignalFunc) wet_motion, NULL); + + da = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(da), xs, ys); + gtk_container_add(GTK_CONTAINER(eb), da); + gtk_widget_show(da); + + gtk_signal_connect(GTK_OBJECT(da), "expose_event", + (GtkSignalFunc) wet_expose, pack); + + peb = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(v), peb); + gtk_widget_show(peb); + + gtk_widget_set_extension_events(peb, GDK_EXTENSION_EVENTS_ALL); + + gtk_widget_set_events(peb, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_KEY_PRESS_MASK + | GDK_PROXIMITY_OUT_MASK); + + gtk_signal_connect(GTK_OBJECT(peb), "button_press_event", + (GtkSignalFunc) pselect_button_press, NULL); + + pda = gtk_drawing_area_new(); + gtk_drawing_area_size(GTK_DRAWING_AREA(pda), xs, 16); + gtk_container_add(GTK_CONTAINER(peb), pda); + gtk_widget_show(pda); + + gtk_signal_connect(GTK_OBJECT(pda), "expose_event", + (GtkSignalFunc) pselect_expose, pack); + + paintname = gtk_label_new(paintstr); + gtk_container_add(GTK_CONTAINER(v), paintname); + gtk_widget_show(paintname); + + h = gtk_hbox_new(TRUE, 5); + gtk_container_add(GTK_CONTAINER(v), h); + gtk_widget_show(h); + + b = gtk_button_new_with_label("Dry"); + gtk_container_add(GTK_CONTAINER(h), b); + gtk_widget_show(b); + + gtk_signal_connect(GTK_OBJECT(b), "clicked", + (GtkSignalFunc) wet_dry_button_press, da); + + autodryb = gtk_toggle_button_new_with_label("Auto Dry"); + gtk_container_add(GTK_CONTAINER(h), autodryb); + gtk_widget_show(autodryb); + + db = gtk_button_new_with_label("Clear"); + gtk_container_add(GTK_CONTAINER(h), db); + gtk_widget_show(db); + + gtk_signal_connect(GTK_OBJECT(db), "clicked", + (GtkSignalFunc) clear_button_press, da); + + h2 = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(v), h2); + gtk_widget_show(h2); + + l = gtk_label_new("Brush size: "); + gtk_container_add(GTK_CONTAINER(h2), l); + gtk_widget_show(l); + + brushsize_adjust = gtk_adjustment_new(10, 0, 32, 0.1, 0.1, 0); + brushsize = gtk_hscale_new(GTK_ADJUSTMENT(brushsize_adjust)); + gtk_container_add(GTK_CONTAINER(h2), brushsize); + gtk_widget_show(brushsize); + + h2 = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(v), h2); + gtk_widget_show(h2); + + l = gtk_label_new("Wetness: "); + gtk_container_add(GTK_CONTAINER(h2), l); + gtk_widget_show(l); + + wetness_adjust = gtk_adjustment_new(16, 0, 16, 1.0, 1.0, 0); + wetness = gtk_hscale_new(GTK_ADJUSTMENT(wetness_adjust)); + gtk_container_add(GTK_CONTAINER(h2), wetness); + gtk_widget_show(wetness); + gtk_signal_connect(GTK_OBJECT(wetness_adjust), "value_changed", + (GtkSignalFunc) wetness_update, NULL); + + h2 = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(v), h2); + gtk_widget_show(h2); + + l = gtk_label_new("Strength: "); + gtk_container_add(GTK_CONTAINER(h2), l); + gtk_widget_show(l); + + strength_adjust = gtk_adjustment_new(1, 0, 2, 0.1, 0.1, 0); + strength = gtk_hscale_new(GTK_ADJUSTMENT(strength_adjust)); + gtk_scale_set_digits(GTK_SCALE(strength), 2); + gtk_container_add(GTK_CONTAINER(h2), strength); + gtk_widget_show(strength); + + gtk_widget_show(w); + + gtk_timeout_add(50, (GtkFunction) dry_timer, da); + + gtk_main(); + + return 0; +} diff --git a/chalk/colorspaces/wet/wetdreams/wetpaint.c b/chalk/colorspaces/wet/wetdreams/wetpaint.c new file mode 100644 index 00000000..c1ac0d0c --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetpaint.c @@ -0,0 +1,101 @@ + +#include +#include +#include "wetpix.h" +#include "wetphysics.h" +#include "wetpaint.h" + +/* This function is not entirely satisfactory - the compositing is basically + opaque, and it really should do wet compositing. */ +void +wet_dab(WetLayer * layer, + WetPix * paint, + double x, double y, double r, double pressure, double strength) +{ + double r_fringe; + int x0, y0; + int x1, y1; + WetPix *wet_line; + int xp, yp; + double xx, yy, rr; + double eff_height; + double press, contact; + WetPixDbl wet_tmp, wet_tmp2; + + r_fringe = r + 1; + x0 = floor(x - r_fringe); + y0 = floor(y - r_fringe); + x1 = ceil(x + r_fringe); + y1 = ceil(y + r_fringe); + if (x0 < 0) + x0 = 0; + if (y0 < 0) + y0 = 0; + if (x1 >= layer->width) + x1 = layer->width; + if (y1 >= layer->height) + y1 = layer->height; + + wet_line = layer->buf + y0 * layer->rowstride; + for (yp = y0; yp < y1; yp++) { + yy = (yp + 0.5 - y); + yy *= yy; + for (xp = x0; xp < x1; xp++) { + xx = (xp + 0.5 - x); + xx *= xx; + rr = yy + xx; + if (rr < r * r) + press = pressure * 0.25; + else + press = -1; + eff_height = + (wet_line[xp].h + wet_line[xp].w - + 192) * (1.0 / 255); + contact = (press + eff_height) * 0.2; + if (contact > 0.5) + contact = + 1 - 0.5 * exp(-2.0 * contact - 1); + if (contact > 0.0001) { + int v; + double rnd = rand() * (1.0 / RAND_MAX); + + v = wet_line[xp].rd; + wet_line[xp].rd = + floor(v + + (paint->rd * strength - + v) * contact + rnd); + v = wet_line[xp].rw; + wet_line[xp].rw = + floor(v + + (paint->rw * strength - + v) * contact + rnd); + v = wet_line[xp].gd; + wet_line[xp].gd = + floor(v + + (paint->gd * strength - + v) * contact + rnd); + v = wet_line[xp].gw; + wet_line[xp].gw = + floor(v + + (paint->gw * strength - + v) * contact + rnd); + v = wet_line[xp].bd; + wet_line[xp].bd = + floor(v + + (paint->bd * strength - + v) * contact + rnd); + v = wet_line[xp].bw; + wet_line[xp].bw = + floor(v + + (paint->bw * strength - + v) * contact + rnd); + v = wet_line[xp].w; + wet_line[xp].w = + floor(v + (paint->w - v) * contact + + rnd); + + } + } + wet_line += layer->rowstride; + } +} diff --git a/chalk/colorspaces/wet/wetdreams/wetpaint.h b/chalk/colorspaces/wet/wetdreams/wetpaint.h new file mode 100644 index 00000000..5cec2659 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetpaint.h @@ -0,0 +1,4 @@ +void wet_dab(WetLayer * layer, + WetPix * paint, + double x, double y, + double r, double pressure, double strength); diff --git a/chalk/colorspaces/wet/wetdreams/wetphysics.c b/chalk/colorspaces/wet/wetdreams/wetphysics.c new file mode 100644 index 00000000..d8b321a8 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetphysics.c @@ -0,0 +1,334 @@ +/* Cool physics functions for wet paint */ + +#include +#include +#include "wetpix.h" +#include "wetphysics.h" + +/* symmetric combine, i.e. wet mixing. + + This does not set the dst h field. +*/ +void wet_pix_combine(WetPixDbl * dst, WetPixDbl * src1, WetPixDbl * src2) +{ + dst->rd = src1->rd + src2->rd; + dst->rw = src1->rw + src2->rw; +#if 0 + g_print("rd %f rw %f\n", dst->rd, dst->rw); +#endif + dst->gd = src1->gd + src2->gd; + dst->gw = src1->gw + src2->gw; + dst->bd = src1->bd + src2->bd; + dst->bw = src1->bw + src2->bw; + dst->w = src1->w + src2->w; +#if 0 + g_print("%f + %f -> %f\n", src1->w, src2->w, dst->w); +#endif +} + +void wet_pix_dilute(WetPixDbl * dst, WetPix * src, double dilution) +{ + double scale = dilution * (1.0 / 8192.0); + + + dst->rd = src->rd * scale; +#if 0 + g_print("dilution %f scale %f rd %f\n", dilution, scale, dst->rd); +#endif + dst->rw = src->rw * scale; + dst->gd = src->gd * scale; + dst->gw = src->gw * scale; + dst->bd = src->bd * scale; + dst->bw = src->bw * scale; + dst->w = src->w * (1.0 / 8192.0); + dst->h = src->h * (1.0 / 8192.0); +} + +void wet_pix_reduce(WetPixDbl * dst, WetPix * src, double dilution) +{ + wet_pix_dilute(dst, src, dilution); + dst->w *= dilution; +} + +/* allows visualization of adsorption by rotating the hue 120 degrees */ +/* layer-merge combining. src1 is the top layer + + This does not set the dst h or w fields. +*/ +void +wet_pix_merge(WetPixDbl * dst, WetPixDbl * src1, double dilution1, + WetPixDbl * src2) +{ + double d1, w1, d2, w2; + double ed1, ed2; + + if (src1->rd < 1e-4) { + dst->rd = src2->rd; + dst->rw = src2->rw; + } else if (src2->rd < 1e-4) { + dst->rd = src1->rd * dilution1; + dst->rw = src1->rw * dilution1; + } else { + d1 = src1->rd; + w1 = src1->rw; + d2 = src2->rd; + w2 = src2->rw; + dst->rd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->rw = dst->rd * ((1 - ed1) * w1 / d1 + + ed1 * (1 - ed2) * w2 / d2) / + (1 - ed1 * ed2); + } + + if (src1->gd < 1e-4) { + dst->gd = src2->gd; + dst->gw = src2->gw; + } else if (src2->gd < 1e-4) { + dst->gd = src1->gd * dilution1; + dst->gw = src1->gw * dilution1; + } else { + d1 = src1->gd; + w1 = src1->gw; + d2 = src2->gd; + w2 = src2->gw; + dst->gd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->gw = dst->gd * ((1 - ed1) * w1 / d1 + + ed1 * (1 - ed2) * w2 / d2) / + (1 - ed1 * ed2); + } + + if (src1->bd < 1e-4) { + dst->bd = src2->bd; + dst->bw = src2->bw; + } else if (src2->bd < 1e-4) { + dst->bd = src1->bd * dilution1; + dst->bw = src1->bw * dilution1; + } else { + d1 = src1->bd; + w1 = src1->bw; + d2 = src2->bd; + w2 = src2->bw; + dst->bd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->bw = dst->bd * ((1 - ed1) * w1 / d1 + + ed1 * (1 - ed2) * w2 / d2) / + (1 - ed1 * ed2); + } + +} + +void wet_flow(WetLayer * layer) +{ + /* XXX: Is this like a convolution operation? BSAR */ + int x, y; + int width = layer->width; + int height = layer->height; + int rs = layer->rowstride; + double *flow_t, *flow_b, *flow_l, *flow_r; + double *fluid, *outflow; + WetPix *wet_line = layer->buf; + WetPix *wet_old; + int my_height; + int ix; + double ft, fb, fl, fr; /* top, bottom, left, right */ + WetPixDbl wet_mix, wet_tmp; + + flow_t = g_new(double, width * height); + flow_b = g_new(double, width * height); + flow_l = g_new(double, width * height); + flow_r = g_new(double, width * height); + fluid = g_new(double, width * height); + outflow = g_new(double, width * height); + wet_old = g_new(WetPix, width * height); + + /* assumes rowstride == width */ + memcpy(wet_old, layer->buf, sizeof(WetPix) * width * height); + + ix = width + 1; + for (y = 1; y < height - 1; y++) { + wet_line += rs; + for (x = 1; x < width - 1; x++) { + if (wet_line[x].w > 0) { + my_height = wet_line[x].h + wet_line[x].w; + ft = (wet_line[x - rs].h + + wet_line[x - rs].w) - my_height; + fb = (wet_line[x + rs].h + + wet_line[x + rs].w) - my_height; + fl = (wet_line[x - 1].h + + wet_line[x - 1].w) - my_height; + fr = (wet_line[x + 1].h + + wet_line[x + 1].w) - my_height; + + fluid[ix] = + 0.4 * sqrt(wet_line[x].w * 1.0 / + 255.0); + + /* smooth out the flow a bit */ + flow_t[ix] = + 0.1 * (10 + ft * 0.75 - fb * 0.25); + if (flow_t[ix] > 1) + flow_t[ix] = 1; + if (flow_t[ix] < 0) + flow_t[ix] = 0; + flow_b[ix] = + 0.1 * (10 + fb * 0.75 - ft * 0.25); + if (flow_b[ix] > 1) + flow_b[ix] = 1; + if (flow_b[ix] < 0) + flow_b[ix] = 0; + flow_l[ix] = + 0.1 * (10 + fl * 0.75 - fr * 0.25); + if (flow_l[ix] > 1) + flow_l[ix] = 1; + if (flow_l[ix] < 0) + flow_l[ix] = 0; + flow_r[ix] = + 0.1 * (10 + fr * 0.75 - fl * 0.25); + if (flow_r[ix] > 1) + flow_r[ix] = 1; + if (flow_r[ix] < 0) + flow_r[ix] = 0; + + outflow[ix] = 0; + } + ix++; + } + ix += 2; + } + + ix = width + 1; + wet_line = layer->buf; + for (y = 1; y < height - 1; y++) { + wet_line += rs; + for (x = 1; x < width - 1; x++) { + if (wet_line[x].w > 0) { + /* reduce flow in dry areas */ + flow_t[ix] *= fluid[ix] * fluid[ix - rs]; + outflow[ix - rs] += flow_t[ix]; + flow_b[ix] *= fluid[ix] * fluid[ix + rs]; + outflow[ix + rs] += flow_b[ix]; + flow_l[ix] *= fluid[ix] * fluid[ix - 1]; + outflow[ix - 1] += flow_l[ix]; + flow_r[ix] *= fluid[ix] * fluid[ix + 1]; + outflow[ix + 1] += flow_r[ix]; + } + ix++; + } + ix += 2; + } + + wet_line = layer->buf; + ix = width + 1; + for (y = 1; y < height - 1; y++) { + wet_line += rs; + for (x = 1; x < width - 1; x++) { + if (wet_line[x].w > 0) { + wet_pix_reduce(&wet_mix, &wet_old[ix], + 1 - outflow[ix]); + + wet_pix_reduce(&wet_tmp, &wet_old[ix - rs], + flow_t[ix]); + wet_pix_combine(&wet_mix, &wet_mix, + &wet_tmp); + wet_pix_reduce(&wet_tmp, &wet_old[ix + rs], + flow_b[ix]); + wet_pix_combine(&wet_mix, &wet_mix, + &wet_tmp); + wet_pix_reduce(&wet_tmp, &wet_old[ix - 1], + flow_l[ix]); + wet_pix_combine(&wet_mix, &wet_mix, + &wet_tmp); + wet_pix_reduce(&wet_tmp, &wet_old[ix + 1], + flow_r[ix]); + wet_pix_combine(&wet_mix, &wet_mix, + &wet_tmp); + + wet_pix_from_double(&wet_line[x], + &wet_mix); + +#if 0 + if (ix % 3201 == 0) + g_print("%f %f %f %f %f %f\n", + outflow[ix], + flow_t[ix], + flow_b[ix], + flow_l[ix], + flow_r[ix], fluid[ix]); +#endif + } + ix++; + } + ix += 2; + } + + g_free(flow_t); + g_free(flow_b); + g_free(flow_l); + g_free(flow_r); + g_free(fluid); + g_free(outflow); + g_free(wet_old); +} + +void wet_dry(WetLayer * layer) +{ + int x, y; + WetPix *wet_line = layer->buf; + int width = layer->width; + int height = layer->height; + int rs = layer->rowstride; + int w; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + w = wet_line[x].w; + w -= 1; + if (w > 0) + wet_line[x].w = w; + else + wet_line[x].w = 0; + + } + wet_line += rs; + } +} + +/* Move stuff from the upperlayer to the lower layer. This is filter-level stuff*/ +void wet_adsorb(WetLayer * layer, WetLayer * adsorb) +{ + int x, y; + WetPix *wet_line = layer->buf; + WetPix *ads_line = adsorb->buf; + int width = layer->width; + int height = layer->height; + int rs = layer->rowstride; + double ads; + WetPixDbl wet_top; + WetPixDbl wet_bot; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + /* do adsorption */ + if (wet_line[x].w == 0) + continue; + ads = 0.5 / MAX(wet_line[x].w, 1); + + wet_pix_to_double(&wet_top, &wet_line[x]); + wet_pix_to_double(&wet_bot, &ads_line[x]); + wet_pix_merge(&wet_bot, &wet_top, ads, &wet_bot); + wet_pix_from_double(&ads_line[x], &wet_bot); + wet_line[x].rd = wet_line[x].rd * (1 - ads); + wet_line[x].rw = wet_line[x].rw * (1 - ads); + wet_line[x].gd = wet_line[x].gd * (1 - ads); + wet_line[x].gw = wet_line[x].gw * (1 - ads); + wet_line[x].bd = wet_line[x].bd * (1 - ads); + wet_line[x].bw = wet_line[x].bw * (1 - ads); + } + wet_line += rs; + ads_line += rs; + } +} diff --git a/chalk/colorspaces/wet/wetdreams/wetphysics.h b/chalk/colorspaces/wet/wetdreams/wetphysics.h new file mode 100644 index 00000000..25140956 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetphysics.h @@ -0,0 +1,9 @@ +void wet_pix_combine(WetPixDbl * dst, WetPixDbl * src1, WetPixDbl * src2); + +void wet_pix_dilute(WetPixDbl * dst, WetPix * src, double dilution); + +void wet_flow(WetLayer * layer); + +void wet_dry(WetLayer * layer); + +void wet_adsorb(WetLayer * layer, WetLayer * adsorb); diff --git a/chalk/colorspaces/wet/wetdreams/wetpix.c b/chalk/colorspaces/wet/wetdreams/wetpix.c new file mode 100644 index 00000000..812a038d --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetpix.c @@ -0,0 +1,332 @@ +/* Routines for manipulating wet pixels. + + Copyright 1999 Raph Levien + + Released under GPL. + + A wet pixel is a sequence of eight bytes, arranged as follows: + + Red value when composited over black + Green value when composited over black + Blue value when composited over black + Volume of water + Red value when composited over white + Green value when composited over white + Blue value when composited over white + Height of paper surface + +*/ + +#include +#include +#include +#include "wetpix.h" + +u32 *wet_render_tab = NULL; + +static void wet_init_render_tab(void) +{ + int i; + double d; + int a, b; + + wet_render_tab = g_new(u32, 4096); + for (i = 0; i < 4096; i++) { + d = i * (1.0 / 512.0); + if (i == 0) + a = 0; + else + a = floor(0xff00 / i + 0.5); + b = floor(0x8000 * exp(-d) + 0.5); +#if 0 + g_print("%d: %x %x\n", i, a, b); +#endif + wet_render_tab[i] = (a << 16) | b; + } +} + +void +wet_composite(byte * rgb, int rgb_rowstride, + WetPix * wet, int wet_rowstride, + int width, int height) +{ + int x, y; + byte *rgb_line = rgb; + WetPix *wet_line = wet; + + if (wet_render_tab == NULL) + wet_init_render_tab(); + + for (y = 0; y < height; y++) { + byte *rgb_ptr = rgb_line; + WetPix *wet_ptr = wet_line; + for (x = 0; x < width; x++) { + int r, g, b; + int d, w; + int ab; + int wa; + + r = rgb_ptr[0]; + w = wet_ptr[0].rw >> 4; + d = wet_ptr[0].rd >> 4; + /* + d = d >= 4096 ? 4095 : d; + */ + ab = wet_render_tab[d]; + wa = (w * (ab >> 16) + 0x80) >> 8; + r = wa + + (((r - wa) * (ab & 0xffff) + 0x4000) >> 15); + rgb_ptr[0] = r; + +#if 0 + if (x == 128 && y == 128) { + g_print("w %d d %d r %d\n", w, d, r); + } +#endif + + g = rgb_ptr[1]; + w = wet_ptr[0].gw >> 4; + d = wet_ptr[0].gd >> 4; + d = d >= 4096 ? 4095 : d; + ab = wet_render_tab[d]; + wa = (w * (ab >> 16) + 0x80) >> 8; + g = wa + + (((g - wa) * (ab & 0xffff) + 0x4000) >> 15); + rgb_ptr[1] = g; + + b = rgb_ptr[2]; + w = wet_ptr[0].bw >> 4; + d = wet_ptr[0].bd >> 4; + d = d >= 4096 ? 4095 : d; + ab = wet_render_tab[d]; + wa = (w * (ab >> 16) + 0x80) >> 8; + b = wa + + (((b - wa) * (ab & 0xffff) + 0x4000) >> 15); + rgb_ptr[2] = b; + + rgb_ptr += 3; + wet_ptr++; + } + rgb_line += rgb_rowstride; + wet_line += wet_rowstride; + } +} + +void +wet_render_wetness(byte * rgb, int rgb_rowstride, + WetLayer * layer, int x0, int y0, int width, int height) +{ + static int wet_phase = 0; + int x, y; + byte *rgb_line = rgb; + WetPix *wet_line = layer->buf + (y0 * layer->rowstride) + x0; + int highlight; + + for (y = 0; y < height; y++) { + byte *rgb_ptr = rgb_line; + WetPix *wet_ptr = wet_line; + for (x = 0; x < width; x++) { + if (((x + y) & 3) == wet_phase) { + highlight = 255 - (wet_ptr[0].w >> 1); + if (highlight < 255) { + rgb_ptr[0] = + 255 - + (((255 - + rgb_ptr[0]) * + highlight) >> 8); + rgb_ptr[1] = + 255 - + (((255 - + rgb_ptr[1]) * + highlight) >> 8); + rgb_ptr[2] = + 255 - + (((255 - + rgb_ptr[2]) * + highlight) >> 8); + } + } + rgb_ptr += 3; + wet_ptr++; + } + rgb_line += rgb_rowstride; + wet_line += layer->rowstride; + } + wet_phase += 1; + wet_phase &= 3; +} + +void +wet_composite_layer(byte * rgb, int rgb_rowstride, + WetLayer * layer, + int x0, int y0, int width, int height) +{ + /* todo: sanitycheck bounds */ + wet_composite(rgb, rgb_rowstride, + layer->buf + (y0 * layer->rowstride) + x0, + layer->rowstride, width, height); +} + +void +wet_pack_render(byte * rgb, int rgb_rowstride, + WetPack * pack, int x0, int y0, int width, int height) +{ + int y; + byte *rgb_line = rgb; + int i; + + /* clear rgb buffer to white */ + for (y = 0; y < height; y++) { + memset(rgb_line, 255, width * 3); + rgb_line += rgb_rowstride; + } + + /* black stripe */ +/* rgb_line = rgb; + for (y = y0; y < 8 && y < y0 + height; y++) + { + memset (rgb_line, 0, width * 3); + rgb_line += rgb_rowstride; + } +*/ + + for (i = 0; i < pack->n_layers; i++) + wet_composite_layer(rgb, rgb_rowstride, + pack->layers[i], + x0, y0, width, height); + + wet_render_wetness(rgb, rgb_rowstride, + pack->layers[pack->n_layers - 1], + x0, y0, width, height); +} + +WetLayer *wet_layer_new(int width, int height) +{ + WetLayer *layer; + + layer = g_new(WetLayer, 1); + + layer->buf = g_new(WetPix, width * height); + layer->width = width; + layer->height = height; + layer->rowstride = width; + + return layer; +} + +void wet_layer_clear(WetLayer * layer) +{ + int x, y; + WetPix *wet_line = layer->buf; + int width = layer->width; + + for (y = 0; y < layer->height; y++) { + for (x = 0; x < width; x++) { + /* transparent, dry, smooth */ + wet_line[x].rd = 0; + wet_line[x].rw = 0; + wet_line[x].gd = 0; + wet_line[x].gw = 0; + wet_line[x].bd = 0; + wet_line[x].bw = 0; + wet_line[x].w = 0; + wet_line[x].h = 128; + } + wet_line += layer->rowstride; + } +} + +WetPack *wet_pack_new(int width, int height) +{ + WetPack *pack; + + pack = g_new(WetPack, 1); + + pack->n_layers = 2; + pack->layers = g_new(WetLayer *, pack->n_layers); + pack->layers[0] = wet_layer_new(width, height); + wet_layer_clear(pack->layers[0]); + pack->layers[1] = wet_layer_new(width, height); + wet_layer_clear(pack->layers[1]); + + return pack; +} + +void wet_pix_to_double(WetPixDbl * dst, WetPix * src) +{ + dst->rd = (1.0 / 8192.0) * src->rd; + dst->rw = (1.0 / 8192.0) * src->rw; + dst->gd = (1.0 / 8192.0) * src->gd; + dst->gw = (1.0 / 8192.0) * src->gw; + dst->bd = (1.0 / 8192.0) * src->bd; + dst->bw = (1.0 / 8192.0) * src->bw; + dst->w = (1.0 / 8192.0) * src->w; + dst->h = (1.0 / 8192.0) * src->h; +} + +void wet_pix_from_double(WetPix * dst, WetPixDbl * src) +{ + int v; + + v = floor(8192.0 * src->rd + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->rd = v; + + g_print("src->rd = %f, dst->rd = %d\n", src->rd, dst->rd); + + v = floor(8192.0 * src->rw + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->rw = v; + + v = floor(8192.0 * src->gd + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->gd = v; + + v = floor(8192.0 * src->gw + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->gw = v; + + v = floor(8192.0 * src->bd + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->bd = v; + + v = floor(8192.0 * src->bw + 0.5); + if (v < 0) + v = 0; + if (v > 65535) + v = 65535; + dst->bw = v; + + v = floor(8192.0 * src->w + 0.5); + if (v < 0) + v = 0; + if (v > 511) + v = 511; + dst->w = v; +#if 0 + g_print("src->w = %f, dst->w = %d\n", src->w, dst->w); +#endif + + v = floor(8192.0 * src->h + 0.5); + if (v < 0) + v = 0; + if (v > 511) + v = 511; + dst->h = v; + +} diff --git a/chalk/colorspaces/wet/wetdreams/wetpix.h b/chalk/colorspaces/wet/wetdreams/wetpix.h new file mode 100644 index 00000000..3dc7913f --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wetpix.h @@ -0,0 +1,87 @@ +/* Routines for manipulating wet pixels. + + Copyright 1999 Raph Levien + + Released under GPL. + + A wet pixel is an eight word sequence, representing partially + transparent wet paint on a paper surface. + +*/ + +typedef unsigned char byte; +typedef unsigned short u16; +typedef unsigned int u32; + +typedef struct _WetPix WetPix; +typedef struct _WetLayer WetLayer; +typedef struct _WetPack WetPack; + +typedef struct _WetPixDbl WetPixDbl; + +/* White is made up of myth-red, myth-green, and myth-blue. Myth-red + looks red when viewed reflectively, but cyan when viewed + transmissively (thus, it vaguely resembles a dichroic + filter). Myth-red over black is red, and myth-red over white is + white. + + Total red channel concentration is myth-red concentration plus + cyan concentration. + +*/ + +struct _WetPix { + u16 rd; /* Total red channel concentration */ + u16 rw; /* Myth-red concentration */ + u16 gd; /* Total green channel concentration */ + u16 gw; /* Myth-green concentration */ + u16 bd; /* Total blue channel concentration */ + u16 bw; /* Myth-blue concentration */ + u16 w; /* Water volume */ + u16 h; /* Height of paper surface */ +}; + +struct _WetLayer { + WetPix *buf; + int width; + int height; + int rowstride; +}; + +struct _WetPack { + int n_layers; + WetLayer **layers; +}; + +struct _WetPixDbl { + double rd; /* Total red channel concentration */ + double rw; /* Myth-red concentration */ + double gd; /* Total green channel concentration */ + double gw; /* Myth-green concentration */ + double bd; /* Total blue channel concentration */ + double bw; /* Myth-blue concentration */ + double w; /* Water volume */ + double h; /* Height of paper surface */ +}; + +void wet_composite(byte * rgb, int rgb_rowstride, + WetPix * wet, int wet_rowstride, + int width, int height); + +void wet_composite_layer(byte * rgb, int rgb_rowstride, + WetLayer * layer, + int x0, int y0, int width, int height); + +void wet_pack_render(byte * rgb, int rgb_rowstride, + WetPack * pack, + int x0, int y0, int width, int height); + +WetLayer *wet_layer_new(int width, int height); + +void wet_layer_clear(WetLayer * layer); + +WetPack *wet_pack_new(int width, int height); + +void wet_pix_to_double(WetPixDbl * dst, WetPix * src); + +void wet_pix_from_double(WetPix * dst, WetPixDbl * src); diff --git a/chalk/colorspaces/wet/wetdreams/wettexture.c b/chalk/colorspaces/wet/wetdreams/wettexture.c new file mode 100644 index 00000000..620ad8b5 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wettexture.c @@ -0,0 +1,84 @@ +/* synthesize a surface texture */ + +#include +#include +#include "wetpix.h" + +void +wet_layer_maketexture(WetLayer * layer, + double height, double blurh, double blurv) +{ + int x, y; + int width = layer->width; + int lheight = layer->height; + int rowstride = layer->rowstride; + WetPix *wet_line = layer->buf; + double hscale = 128 * height / RAND_MAX; + int lh; + int ibh, ibv; + + ibh = floor(256 * blurh + 0.5); +#ifdef VERBOSE + g_print("ibh = %d\n", ibh); +#endif + ibv = floor(256 * blurv + 0.5); + + for (y = 0; y < lheight; y++) { + for (x = 0; x < width; x++) { + wet_line[x].h = floor(128 + hscale * rand()); + } + /* g_print ("%d\n", wet_line[0].h); */ + wet_line += rowstride; + } + + wet_line = layer->buf; + for (y = 0; y < lheight; y++) { + lh = wet_line[0].h; + for (x = 1; x < width; x++) { + wet_line[x].h += + ((lh - wet_line[x].h) * ibh + 128) >> 8; + lh = wet_line[x].h; + } + wet_line += rowstride; + } + +#if 0 + for (x = 0; x < width; x++) { + wet_line = layer->buf + x; + lh = wet_line[0].h; + for (y = 1; y < lheight; y++) { + wet_line += rowstride; + wet_line[0].h += + ((lh - wet_line[0].h) * ibv + 128) >> 8; + lh = wet_line[0].h; + } + } +#endif +} + +void wet_layer_clone_texture(WetLayer * dst, WetLayer * src) +{ + int x, y; + int width = src->width; + WetPix *dst_line = dst->buf; + WetPix *src_line = src->buf; + + for (y = 0; y < src->height; y++) { + for (x = 0; x < width; x++) { + dst_line[x].h = src_line[x].h; + } + dst_line += dst->rowstride; + src_line += src->rowstride; + } +} + +void +wet_pack_maketexture(WetPack * pack, + double height, double blurh, double blurv) +{ + int i; + + wet_layer_maketexture(pack->layers[0], height, blurh, blurv); + for (i = 1; i < pack->n_layers; i++) + wet_layer_clone_texture(pack->layers[i], pack->layers[0]); +} diff --git a/chalk/colorspaces/wet/wetdreams/wettexture.h b/chalk/colorspaces/wet/wetdreams/wettexture.h new file mode 100644 index 00000000..c3cbc0d2 --- /dev/null +++ b/chalk/colorspaces/wet/wetdreams/wettexture.h @@ -0,0 +1,9 @@ +/* synthesize a surface texture */ + +void wet_layer_maketexture(WetLayer * layer, + double height, double blurh, double blurv); + +void wet_layer_clone_texture(WetLayer * dst, WetLayer * src); + +void wet_pack_maketexture(WetPack * pack, + double height, double blurh, double blurv); diff --git a/chalk/colorspaces/wet/wetphysicsfilter.cc b/chalk/colorspaces/wet/wetphysicsfilter.cc new file mode 100644 index 00000000..d63574fd --- /dev/null +++ b/chalk/colorspaces/wet/wetphysicsfilter.cc @@ -0,0 +1,424 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "wetphysicsfilter.h" + +/* + * [11:14] CyrilleB: I think I know why watercolor drying creates that funny pattern (you can see it if you have a very wet canvas with lots of paint and leave it drying for a while): our dry filter must have an off-by-one error to the right and bottom, which is also why the buggy drying didn't remove all of previously applied paint but left a fringe. + * [11:14] does the drying behave kind of like an error diffusion? + * [11:14] (it sounds like error diffusion artifacts,.) + * [11:15] pippin: not sure what error diffusion is... + * [11:15] used for digital halftoning + * [11:15] take a greyscale image,.. you want to end up with binary (could be less, but let's use 1bit result) + * [11:15] boud: the funny pattern is also in wetdreams when you disable wetness visualisation + * [11:15] CyrilleB: I don't mean the checkerboard pattern + * [11:16] then for each pixel you calculate the difference between the current value and the desired value (0 or 255) + * [11:16] boud: which one then ? + * [11:16] the error is distributed to the neighbour pixels (to the right, down and down to the left in pixels which have not yet been processed + * [11:16] ) + * [11:16] CyrilleB: it's only aptqparent when you let something dry for some time, it looks like meandering snakes (like the old game "snake") + * [11:16] pippin: somehow yes + * [11:16] pippin: that is possible + * [11:17] boud: this leads to "bleeding" of data to the right and down,.. + * [11:17] pippin: but on the other hand, when the filter worked on the old tiles (empty ones) it also left a fringe of color. + * [11:17] having the "error" spread in different directions on each iteration might fix something like this,. + * [11:18] Which leads me to think it's an off-by one. + * [11:25] No, it isn't off by one. Then pippin must be right. + * [11:26] if I am, this is a fun debug session, not even having the code or the visual results available,. just hanging around on irc :) + * [11:27] Well, I don't have time to investigate right now, but it sounds very plausible. + * [11:27] pippin: :) + * [11:28] of course, the code _is_ available :-) + * [11:28] if there is some form of diffusion matrix that is directional around the current pixel,. having that tqmask rotate depending on the modulus of the current iteration # should cancel such an effect out + */ +WetPhysicsFilter::WetPhysicsFilter() + : KisFilter(id(), "artistic", i18n("Dry the Paint")) +{ + m_adsorbCount = 0; +} + +void WetPhysicsFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + kdDebug() << "Physics processing " << src->name() << m_adsorbCount << endl; + // XXX: It would be nice be able to interleave this, instead of + // having the same loop over our pixels three times. + flow(src, dst, rect); + if (m_adsorbCount++ == 2) { +// XXX I think we could combine dry and adsorb, yes + adsorb(src, dst, rect); + dry(src, dst, rect); + m_adsorbCount = 0; + } + setProgressDone(); // Must be called even if you don't really support progression +} + + +void WetPhysicsFilter::flow(KisPaintDeviceSP src, KisPaintDeviceSP /*dst*/, const TQRect & r) +{ + /* XXX: Is this like a convolution operation? BSAR */ + int width = r.width(); + int height = r.height(); + + kdDebug() << "Flowing: " << r << endl; + + /* width of a line in a layer in pixel units, not in bytes -- used to move to the next + line in the fluid tqmasks below */ + int rs = width; // rowstride + + double * flow_t = new double[width * height]; + Q_CHECK_PTR(flow_t); + + double * flow_b = new double[width * height]; + Q_CHECK_PTR(flow_b); + + double * flow_l = new double[width * height]; + Q_CHECK_PTR(flow_l); + + double * flow_r = new double[width * height]; + Q_CHECK_PTR(flow_r); + + double * fluid = new double[width * height]; + Q_CHECK_PTR(fluid); + + double * outflow = new double[width * height]; + Q_CHECK_PTR(outflow); + + // Height of the paper surface. Do we also increase height because of paint deposits? + int my_height; + + // Flow to the top, bottom, left, right of the currentpixel + double ft, fb, fl, fr; + + // Temporary pixel constructs + WetPixDbl wet_mix, wet_tmp; + + // XXX If the flow touches areas that have not been initialized with a height field yet, + // create a heigth field. + + // We need three iterators, because we're working on a five-point convolution kernel (no corner pixels are being used) + + // First iteration: compute fluid deposits around the paper. + TQ_INT32 dx, dy; + dx = r.x(); + dy = r.y(); + + int ix = width + 1; // keeps track where we are in the one-dimensional arrays + + for (TQ_INT32 y2 = 1; y2 < height - 1; ++y2) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(dx, dy + y2, width, false); + KisHLineIteratorPixel upIt = src->createHLineIterator(dx + 1, dy + y2 - 1, width - 2, false); + KisHLineIteratorPixel downIt = src->createHLineIterator(dx + 1, dy + y2 + 1, width - 2, false); + + // .paint is the first field in our wetpack, so this is ok (even though not nice) + WetPix left = *(reinterpret_cast(srcIt.rawData())); + ++srcIt; + WetPix current = *(reinterpret_cast(srcIt.rawData())); + ++srcIt; + WetPix right = *(reinterpret_cast(srcIt.rawData())); + WetPix up, down; + + while (!srcIt.isDone()) { + up = *(reinterpret_cast(upIt.rawData())); + down = *(reinterpret_cast(downIt.rawData())); + + if (current.w > 0) { + my_height = current.h + current.w; + ft = (up.h + up.w) - my_height; + fb = (down.h + down.w) - my_height; + fl = (left.h + left.w) - my_height; + fr = (right.h + right.w) - my_height; + + fluid[ix] = 0.4 * sqrt(current.w * 1.0 / 255.0); + + /* smooth out the flow a bit */ + flow_t[ix] = CLAMP(0.1 * (10 + ft * 0.75 - fb * 0.25), 0, 1); + + flow_b[ix] = CLAMP(0.1 * (10 + fb * 0.75 - ft * 0.25), 0, 1); + + flow_l[ix] = CLAMP(0.1 * (10 + fl * 0.75 - fr * 0.25), 0, 1); + + flow_r[ix] = CLAMP(0.1 * (10 + fr * 0.75 - fl * 0.25), 0, 1); + + outflow[ix] = 0; + } + + ++srcIt; + ++upIt; + ++downIt; + ix++; + left = current; + current = right; + right = *(reinterpret_cast(srcIt.rawData())); + } + ix+=2; // one for the last pixel on the line, and one for the first of the next line + } + // Second iteration: Reduce flow in dry areas + ix = width + 1; + + for (TQ_INT32 y2 = 1; y2 < height - 1; ++y2) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(dx + 1, dy + y2, width - 2, false); + while (!srcIt.isDone()) { + if ((reinterpret_cast(srcIt.rawData()))->w > 0) { + /* reduce flow in dry areas */ + flow_t[ix] *= fluid[ix] * fluid[ix - rs]; + outflow[ix - rs] += flow_t[ix]; + flow_b[ix] *= fluid[ix] * fluid[ix + rs]; + outflow[ix + rs] += flow_b[ix]; + flow_l[ix] *= fluid[ix] * fluid[ix - 1]; + outflow[ix - 1] += flow_l[ix]; + flow_r[ix] *= fluid[ix] * fluid[ix + 1]; + outflow[ix + 1] += flow_r[ix]; + } + ++srcIt; + ix++; + } + ix += 2; + } + + // Third iteration: Combine the paint from the flow areas. + ix = width + 1; + for (TQ_INT32 y2 = 1; y2 < height - 1; ++y2) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(dx, dy + y2, width, false); + KisHLineIteratorPixel upIt = src->createHLineIterator(dx + 1, dy + y2 - 1, width - 2, false); + KisHLineIteratorPixel downIt = src->createHLineIterator(dx + 1, dy + y2 + 1, width - 2, false); + + KisHLineIteratorPixel dstIt = src->createHLineIterator(dx + 1, dy + y2, width - 2, true); + + WetPix left = *(reinterpret_cast(srcIt.oldRawData())); + ++srcIt; + WetPix current = *(reinterpret_cast(srcIt.oldRawData())); + ++srcIt; + WetPix right = *(reinterpret_cast(srcIt.oldRawData())); + WetPix up, down; + + while (!srcIt.isDone()) { + up = *(reinterpret_cast(upIt.oldRawData())); + down = *(reinterpret_cast(downIt.oldRawData())); + + if ((reinterpret_cast(srcIt.rawData()))->w > 0) { + reducePixel(&wet_mix, ¤t, 1 - outflow[ix]); + reducePixel(&wet_tmp, &up, flow_t[ix]); + combinePixels(&wet_mix, &wet_mix, &wet_tmp); + reducePixel(&wet_tmp, &down, flow_b[ix]); + combinePixels(&wet_mix, &wet_mix, &wet_tmp); + reducePixel(&wet_tmp, &left, flow_l[ix]); + combinePixels(&wet_mix, &wet_mix, &wet_tmp); + reducePixel(&wet_tmp, &right, flow_r[ix]); + combinePixels(&wet_mix, &wet_mix, &wet_tmp); + WetPix* target = reinterpret_cast(dstIt.rawData()); + wetPixFromDouble(target, &wet_mix); + } + ++srcIt; + ++dstIt; + ++upIt; + ++downIt; + ix++; + + left = current; + current = right; + right = *(reinterpret_cast(srcIt.oldRawData())); + } + ix += 2; + } + + delete[] flow_t; + delete[] flow_b; + delete[] flow_l; + delete[] flow_r; + delete[] fluid; + delete[] outflow; +} + +void WetPhysicsFilter::dry(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & r) +{ + kdDebug () << "Drying " << r << endl; + for (TQ_INT32 y = 0; y < r.height(); y++) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), r.y() + y, r.width(), false); + KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x(), r.y() + y, r.width(), true); + + TQ_UINT16 w; + while (!srcIt.isDone()) { + // Two wet pixels in one KisWetColorSpace pixels. + + WetPack pack = *(reinterpret_cast(srcIt.rawData())); + WetPix* p = &(pack.paint); + + w = p->w; // no -1 here because we work on unsigned ints! + + if (w > 0) + p->w = w - 1; + else + p->w = 0; + + *(reinterpret_cast(dstIt.rawData())) = pack; + + ++dstIt; + ++srcIt; + } + } +} + +void WetPhysicsFilter::adsorb(KisPaintDeviceSP src, KisPaintDeviceSP /*dst*/, const TQRect & r) +{ + kdDebug() << "Adsorbing " << r << endl; + for (TQ_INT32 y = 0; y < r.height(); y++) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), r.y() + y, r.width(), true); + + double ads; + + WetPixDbl wet_top; + WetPixDbl wet_bot; + + WetPack * pack; + TQ_UINT16 w; + + while (!srcIt.isDone()) { + // Two wet pixels in one KisWetColorSpace pixels. + pack = reinterpret_cast(srcIt.rawData()); + WetPix* paint = &pack->paint; + WetPix* adsorb = &pack->adsorb; + + /* do adsorption */ + w = paint->w; + + if (w == 0) { + ++srcIt; + } + else { + + ads = 0.5 / TQMAX(w, 1); + + wetPixToDouble(&wet_top, paint); + wetPixToDouble(&wet_bot, adsorb); + + mergePixel(&wet_bot, &wet_top, ads, &wet_bot); + wetPixFromDouble(adsorb, &wet_bot); + + paint->rd = (TQ_UINT16) (paint->rd*(1 - ads)); + paint->rw = (TQ_UINT16) (paint->rw*(1 - ads)); + paint->gd = (TQ_UINT16) (paint->gd*(1 - ads)); + paint->gw = (TQ_UINT16) (paint->gw*(1 - ads)); + paint->bd = (TQ_UINT16) (paint->bd*(1 - ads)); + paint->bw = (TQ_UINT16) (paint->bw*(1 - ads)); + + ++srcIt; + } + } + } +} + +void WetPhysicsFilter::combinePixels (WetPixDbl *dst, WetPixDbl *src1, WetPixDbl *src2) +{ + dst->rd = src1->rd + src2->rd; + dst->rw = src1->rw + src2->rw; + dst->gd = src1->gd + src2->gd; + dst->gw = src1->gw + src2->gw; + dst->bd = src1->bd + src2->bd; + dst->bw = src1->bw + src2->bw; + dst->w = src1->w + src2->w; +} + +void WetPhysicsFilter::dilutePixel (WetPixDbl *dst, WetPix *src, double dilution) +{ + double scale = dilution * (1.0 / 8192.0); + + dst->rd = src->rd * scale; + dst->rw = src->rw * scale; + dst->gd = src->gd * scale; + dst->gw = src->gw * scale; + dst->bd = src->bd * scale; + dst->bw = src->bw * scale; + dst->w = src->w * (1.0 / 8192.0); + dst->h = src->h * (1.0 / 8192.0); +} + + +void WetPhysicsFilter::reducePixel (WetPixDbl *dst, WetPix *src, double dilution) +{ + dilutePixel(dst, src, dilution); + dst->w *= dilution; +} + +void WetPhysicsFilter::mergePixel (WetPixDbl *dst, WetPixDbl *src1, double dilution1, + WetPixDbl *src2) +{ + double d1, w1, d2, w2; + double ed1, ed2; + + if (src1->rd < 1e-4) { + dst->rd = src2->rd; + dst->rw = src2->rw; + } else if (src2->rd < 1e-4) { + dst->rd = src1->rd * dilution1; + dst->rw = src1->rw * dilution1; + } else { + d1 = src1->rd; + w1 = src1->rw; + d2 = src2->rd; + w2 = src2->rw; + dst->rd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->rw = dst->rd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2); + } + + if (src1->gd < 1e-4) { + dst->gd = src2->gd; + dst->gw = src2->gw; + } else if (src2->gd < 1e-4) { + dst->gd = src1->gd * dilution1; + dst->gw = src1->gw * dilution1; + } else { + d1 = src1->gd; + w1 = src1->gw; + d2 = src2->gd; + w2 = src2->gw; + dst->gd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->gw = dst->gd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2); + } + + if (src1->bd < 1e-4) { + dst->bd = src2->bd; + dst->bw = src2->bw; + } else if (src2->bd < 1e-4) { + dst->bd = src1->bd * dilution1; + dst->bw = src1->bw * dilution1; + } else { + d1 = src1->bd; + w1 = src1->bw; + d2 = src2->bd; + w2 = src2->bw; + dst->bd = d1 * dilution1 + d2; + ed1 = exp(-d1 * dilution1); + ed2 = exp(-d2); + dst->bw = dst->bd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2); + } +} diff --git a/chalk/colorspaces/wet/wetphysicsfilter.h b/chalk/colorspaces/wet/wetphysicsfilter.h new file mode 100644 index 00000000..eaae1a77 --- /dev/null +++ b/chalk/colorspaces/wet/wetphysicsfilter.h @@ -0,0 +1,87 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WET_PHYSICS_FILTER_H +#define WET_PHYSICS_FILTER_H + +#include + +#include +#include + +#include "kis_wet_colorspace.h" + +class KisID; +class TQRect; + + +/** + * The wet physics filter must be run regularly from a timer + * or preferably from a thread. Every time the filter is processed + * the paint flows; every third time, the paint is adsorbed unto the + * lower pixel and dried. + * + * Note: this might also be implemented as three separate filters. + * That might even be better. + */ +class WetPhysicsFilter: public KisFilter +{ +public: + WetPhysicsFilter(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect& r); + + static inline KisID id() { return KisID("wetphysics", i18n("Watercolor Physics Simulation Filter")); }; + + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + virtual bool workWith(KisColorSpace* cs) { return (cs->id() == KisID("WET")); }; + +private: + + void flow(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & r); + void dry(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & r); + + // Move stuff from the upperlayer to the lower layer. This is filter-level stuff. + void adsorb(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & r); + + // NOTE: this does not set the height fields + void combinePixels (WetPixDbl *dst, WetPixDbl *src1, WetPixDbl *src2); + void dilutePixel (WetPixDbl *dst, WetPix *src, double dilution); + void reducePixel (WetPixDbl *dst, WetPix *src, double dilution); + + /* + * Allows visualization of adsorption by rotating the hue 120 degrees + * layer-merge combining. src1 is the top layer + * + * This does not set the dst h or w fields. + */ + void mergePixel (WetPixDbl *dst, WetPixDbl *src1, double dilution1, WetPixDbl *src2); + + +private: + + TQ_INT32 m_adsorbCount; + + +}; + +#endif diff --git a/chalk/colorspaces/wet/wetplugin.rc b/chalk/colorspaces/wet/wetplugin.rc new file mode 100644 index 00000000..6e933472 --- /dev/null +++ b/chalk/colorspaces/wet/wetplugin.rc @@ -0,0 +1,8 @@ + + + +&View + + + + diff --git a/chalk/colorspaces/wetsticky/Makefile.am b/chalk/colorspaces/wetsticky/Makefile.am new file mode 100644 index 00000000..4ade368a --- /dev/null +++ b/chalk/colorspaces/wetsticky/Makefile.am @@ -0,0 +1,25 @@ +kde_services_DATA = chalkwsplugin.desktop +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../core/color_strategy \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../ui \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkwsplugin.la + +chalkwsplugin_la_SOURCES = wet_sticky_plugin.cc kis_wet_sticky_colorspace.cc kis_ws_engine_filter.cc +noinst_HEADERS = wet_sticky_plugin.h kis_wet_sticky_colorspace.h kis_ws_engine_filter.h + +chalkwsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkwsplugin_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +chalkwsplugin_la_METASOURCES = AUTO + +SUBDIRS=brushop + + diff --git a/chalk/colorspaces/wetsticky/README b/chalk/colorspaces/wetsticky/README new file mode 100644 index 00000000..b1844466 --- /dev/null +++ b/chalk/colorspaces/wetsticky/README @@ -0,0 +1,42 @@ +Wet & Sticky + +The Chalk Wet & Sticky module is derived from the seminal dissertation +"Wet & Stick: A Novel Model for Computer-Based Painting" by Malcom Tunde +Cockshott, and the implementation of that model by Tunde Cockshott, +David England and Kevin Waite. The complete source code to the first +implementation is included in the module_ws/ws and is released under +the terms of the GPL. + +The W&S model is implemented in the following components: + +* A color strategy +* A paint op +* A filter + +The color strategy implements the canvas; the paint op implements the +application of paint and the filter implements the paint simulation +engine. + +This system adds the following interesting capabilities to Chalk: + +* Extending the tool options dialog with a widget describing the + paint op. + +* Extending the paint op class with properties beyond opacity and + color to a more generic structure with can contain the many different + properties needed by more complex color models to calculate bitBlt's. + + All the ordinary paint ops still work, but they act as if they are + applying dry, thin paint, conforming to Cockshott's analysis of the + Shoup model (which Chalk implemented in the first instance) as a subset + of the W&S model. + +* Adding continuously running filters (either in separate threads or + called by a timer) to a particular paint device. + +* Adding a new way to mix colour; the older colour selection widgets + still work, but only give completely dry, infinitely thin paint. + +* Creating a layer with a fill of 'substrate' cells -- i.e, filling not just + with colour, but also with certain calculated amounts of height, + gravity and absorbency. diff --git a/chalk/colorspaces/wetsticky/TODO b/chalk/colorspaces/wetsticky/TODO new file mode 100644 index 00000000..513df2ff --- /dev/null +++ b/chalk/colorspaces/wetsticky/TODO @@ -0,0 +1,7 @@ +* Add paintopbox to toolbox +* Make all paint tools use the paintop from the paintop box +* Add paintop properties palette +* Add continuously running filters +* Add filler objects that can fill a given area computationally +* Add extensible properties for paint devices (to control things like drying) +* Add default fill hook dependent on colorspace diff --git a/chalk/colorspaces/wetsticky/brushop/Makefile.am b/chalk/colorspaces/wetsticky/brushop/Makefile.am new file mode 100644 index 00000000..8df4d61e --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/Makefile.am @@ -0,0 +1,28 @@ +kde_services_DATA = chalkwsbrushpaintop.desktop + +chalkimagesdir = $(prefix)/share/apps/chalk/images +chalkimages_DATA = wetpaintbrush.png + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../../core/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + + +chalkwsbrushpaintop_la_SOURCES = \ + wsbrushpaintop_plugin.cc \ + kis_wsbrushop.cc + +noinst_HEADERS= \ + wsbrushpaintop_plugin.h \ + kis_wsbrushop.h + +kde_module_LTLIBRARIES = chalkwsbrushpaintop.la + +chalkwsbrushpaintop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkwsbrushpaintop_la_LIBADD = ../../..//libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +chalkwsbrushpaintop_la_METASOURCES = AUTO diff --git a/chalk/colorspaces/wetsticky/brushop/README b/chalk/colorspaces/wetsticky/brushop/README new file mode 100644 index 00000000..81156a89 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/README @@ -0,0 +1,2 @@ +Template for plugin paintops. Paint tools use the paintop to determine how +to deposit their paint on the canvas, exactly. diff --git a/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop new file mode 100644 index 00000000..aa087bb9 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Name=Wet & Sticky Paintbrush Paintop +Name[bg]=Мокра и лепкава четка +Name[ca]=Pinzell humit i viscós de Paintop +Name[cy]=Brws paent gwlyb gludiog +Name[da]=Maleoperation med våd og klæbrig malerpensel +Name[de]=Maloperation mit feuchtem & klebrigem Farbpinsel +Name[el]=Βούρτσα υγρής και κολλώδους μπογιάς +Name[eo]=KDED-testmodulo +Name[es]=Pincel mojado y pegajoso para pintar +Name[et]=Märja lõuendi joonistamistoiming +Name[fa]=Paintop قلم‌موی چسبناک و مرطوب +Name[fr]=Pinceau paintop mouillé et gluant +Name[fy]=Kwasten foar wiete en kliemske ferfhannelings +Name[gl]=Pintado Mollado e Pegoñento +Name[hu]=Nedves és ragadós ecset +Name[is]=Blautur & klístraður pensill +Name[it]=Operazione con pennello bagnato e appiccicoso +Name[km]=ជក់​ទឹក & ស្អិត Paintop +Name[nb]=Fargemodell for våt og klissete pensel +Name[nds]=Malen mit en natten backigen Pinsel +Name[ne]=ओसिलो र टाँसिने पेन्टब्रस पेन्टप +Name[nl]=Kwasten voor natte en kleverige verfverrichtingen +Name[pl]=Mokre i lepkie włosie pędzla +Name[pt]=Modelo de Cores Molhado e Pegajoso +Name[pt_BR]=Modelo de Cores Molhado e Pegajoso +Name[ru]=Кисть с параметрами влажности и прилипания +Name[sk]=Mokrý a lepkavý štetec Paintop +Name[sl]=Slikanje z mokrim in lepljivim čopičem +Name[sr]=Модел боја мокре и лепљиве четкице +Name[sr@Latn]=Model boja mokre i lepljive četkice +Name[sv]=Målningsoperation med våt och klibbig målarpensel +Name[uk]=Пензель з параметрами вогкості і клейкості +Name[zh_CN]=湿性和粘性画布 +Name[zh_TW]=濕 & 黏的筆刷頭 +Comment=Wet & Sticky paintbrush +Comment[bg]=Мокра и лепкава четка +Comment[ca]=Pinzell humit i viscós +Comment[cy]=Brws paent gwlyb gludiog +Comment[da]=Våd og klæbrig malerpensel +Comment[de]=Feuchter & klebriger Farbpinsel +Comment[el]=Βούρτσα υγρής και κολλώδους μπογιάς +Comment[eo]=Malseka & Glueca peniko +Comment[es]=Pincel mojado y pegajoso +Comment[et]=Märja lõuendi pintsel +Comment[fa]=قلم‌موی چسبناک و مرطوب +Comment[fr]=Pinceau mouillé et gluant +Comment[fy]=Kwast foar wiete en kliemske ferfhannelings +Comment[gl]=Un pincel mollado e pegaxoso +Comment[hu]=Nedves és ragadós ecset +Comment[is]=Blautur og klístraður pensill +Comment[it]=Pennello bagnato e appiccicoso +Comment[ja]=Wet & Sticky ペイントブラシ +Comment[km]=ជក់​ទឹក & ស្អិត +Comment[nb]=Våt og klissete pensel +Comment[nds]=Natt un backig Pinsel +Comment[ne]=ओसिलो र टाँसिने पेन्टब्रस +Comment[nl]=Kwast voor nat en kleverige verfverichtingen +Comment[pl]=Mokry i lepki pędzel +Comment[pt]=Um pincel molhado e pegajoso +Comment[pt_BR]=Modelo de cores de tela Molhada & Pegajosa +Comment[ru]=Кисть с параметрами влажности и прилипания +Comment[sk]=Mokrý a lepkavý štetec +Comment[sl]=Moker in lepljiv čopič +Comment[sr]=Мокра и лепљива четкица +Comment[sr@Latn]=Mokra i lepljiva četkica +Comment[sv]=Våt och klibbig målarpensel +Comment[uk]=Пензель з параметрами вогкості і клейкості +Comment[zh_TW]=濕 & 黏的筆刷 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkwsbrushpaintop +X-Chalk-Version=2 diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc new file mode 100644 index 00000000..8b182e08 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" + +#include "kis_wsbrushop.h" + +KisPaintOp * KisWSBrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisWSBrushOp(painter); + Q_CHECK_PTR(op); + return op; +} + +KisWSBrushOp::KisWSBrushOp(KisPainter * painter) + : super(painter) +{ +} + +KisWSBrushOp::~KisWSBrushOp() +{ +} + +void KisWSBrushOp::paintAt(const KisPoint &pos, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/) +{ + // Painting should be implemented according to the following algorithm: + // retrieve brush + // if brush == tqmask + // retrieve tqmask + // else if brush == image + // retrieve image + // subsample (tqmask | image) for position -- pos should be double! + // apply filters to tqmask (colour | gradient | pattern | etc. + // composite filtered tqmask into temporary layer + // composite temporary layer into target layer + // @see: doc/brush.txt + + if (!m_painter -> device()) return; + + KisBrush *brush = m_painter -> brush(); + + Q_ASSERT(brush); + if (!brush) return; + + KisPaintDeviceSP device = m_painter -> device(); + + KisPoint hotSpot = brush -> hotSpot(pressure); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisLayerSP dab = 0; + + if (brush -> brushType() == IMAGE || brush -> brushType() == PIPE_IMAGE) { + dab = brush -> image(device -> colorSpace(), pressure, xFraction, yFraction); + } + else { + KisAlphaMaskSP tqmask = brush -> tqmask(pressure, xFraction, yFraction); + dab = computeDab(tqmask); + } + m_painter -> setPressure(pressure); + + TQRect dabRect = TQRect(0, 0, brush -> tqmaskWidth(pressure), brush -> tqmaskHeight(pressure)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device -> image(); + + if (image != 0) { + dstRect &= image -> bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + m_painter -> bltSelection(dstRect.x(), dstRect.y(), m_painter -> compositeOp(), dab.data(), m_painter -> opacity(), sx, sy, sw, sh); + m_painter -> addDirtyRect(dstRect); +} diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h new file mode 100644 index 00000000..65f5fb6c --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WSBRUSHOP_H_ +#define KIS_WSBRUSHOP_H_ + +#include "kis_paintop.h" +#include "kis_types.h" + +class KisPoint; +class KisPainter; + + +class KisWSBrushOpFactory : public KisPaintOpFactory { + +public: + KisWSBrushOpFactory() {} + virtual ~KisWSBrushOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("wsbrush", i18n("Wet & Sticky Paintbrush")); } + virtual TQString pixmap() { return "wetpaintbrush.png"; } +}; + +class KisWSBrushOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisWSBrushOp(KisPainter * painter); + virtual ~KisWSBrushOp(); + + void paintAt(const KisPoint &pos, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/); + +}; + +#endif // KIS_WSBRUSHOP_H_ diff --git a/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png new file mode 100644 index 00000000..8b681ec1 Binary files /dev/null and b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png differ diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc new file mode 100644 index 00000000..383bd9c5 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc @@ -0,0 +1,56 @@ +/* + * wsbrushpaintop_plugin.cc -- Part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "kis_wsbrushop.h" + +#include "wsbrushpaintop_plugin.h" + +typedef KGenericFactory WSBrushPaintOpPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwsbrushpaintop, WSBrushPaintOpPluginFactory( "chalkcore" ) ) + + +WSBrushPaintOpPlugin::WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(WSBrushPaintOpPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisFactory") ) + { + KisPaintOpRegistry::instance() -> add ( new KisWSBrushOpFactory ); + } + +} + +WSBrushPaintOpPlugin::~WSBrushPaintOpPlugin() +{ +} + +#include "wsbrushpaintop_plugin.moc" diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h new file mode 100644 index 00000000..7e77afec --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WSBRUSH_PAINTOP_PLUGIN_H_ +#define WSBRUSH_PAINTOP_PLUGIN_H_ + +#include + +#include "kis_types.h" + +class KisView; + +/** + * A plugin wrapper that adds the paintop factories to the paintop registry. + */ +class WSBrushPaintOpPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~WSBrushPaintOpPlugin(); + +private: + + KisView* m_view; +}; + +#endif // WSBRUSH_PAINTOP_PLUGIN_H_ diff --git a/chalk/colorspaces/wetsticky/chalkwsplugin.desktop b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop new file mode 100644 index 00000000..12fdc286 --- /dev/null +++ b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop @@ -0,0 +1,46 @@ +[Desktop Entry] +Name=Wet & Sticky Canvas Color Model +Name[bg]=Цветови модел за мокро и лепкаво платно +Name[ca]=Model de color de llenç humit i viscós +Name[cy]=Model Lliw Cynfas Gwlyb a Gludiog +Name[da]=Våd & klæbrig kanvasfarve-model +Name[de]=Farbmodell feuchte & klebrige Leinwand +Name[el]=Μοντέλο καμβά υγρής και κολλώδους μπογιάς +Name[en_GB]=Wet & Sticky Canvas Colour Model +Name[eo]=Kolormodelo por Malseka & Glueca Kanvaso +Name[es]=Modelo de color de lienzo mojado y pegajoso +Name[et]=Märja lõuendi värvimudel +Name[eu]=Oihal heze eta itsaskorraren kolore-eredua +Name[fa]=مدل رنگ صفحه مجازی چسبناک و مرطوب +Name[fi]=Märkä ja tahmea kangasvärimalli +Name[fr]=Modèle de couleurs gluantes et mouillées +Name[fy]=wiete en kliemske canvasmodel +Name[gl]=Modelo de Cores de Tea Mollado e Pegoñento +Name[hu]=Nedves és ragadós vászon színmodell +Name[is]=Blaut & klístruð litategund +Name[it]=Modello di colore per tela bagnata +Name[ja]=Wet & Sticky キャンバスカラーモデル +Name[km]=ម៉ូដែល​ពណ៌​ទឹក & ស្អិត +Name[ms]=Model Warna Kanvas Basah & Lekit +Name[nb]=Fargemodell for vått og klissete lerret +Name[nds]=Klöörmodell natt un backig Lienwand +Name[ne]=ओसिलो र टाँसिने चित्रपट रङ मोडेल +Name[nl]=Nat en kleverig canvasmodel +Name[nn]=Fargemodell for vått lerret +Name[pl]=Przestrzeń barw mokrego i lepkiego płótna +Name[pt]=Modelo de Cores de Tela Molhado e Pegajoso +Name[pt_BR]=Modelo de cores de tela Molhada & Pegajosa +Name[ru]=Цветовое пространство с параметрами влажности и прилипания +Name[sk]=Model farieb pre mokré a lepkavé plátno +Name[sl]=Barvni model z mokrim in lepljivim platnom +Name[sr]=Модел боја мокрог и лепљивог платна +Name[sr@Latn]=Model boja mokrog i lepljivog platna +Name[sv]=Våt och klibbig dukfärgmodell +Name[uk]=Канва моделі кольорів з параметрами вогкості і клейкості +Name[zh_CN]=湿性/粘性画布色彩模型 +Name[zh_TW]=濕 & 黏的畫布色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkwsplugin +X-Chalk-Version=2 + diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc new file mode 100644 index 00000000..44426382 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include "kis_color_conversions.h" +#include "kis_abstract_colorspace.h" +#include "kis_colorspace_registry.h" +#include "kis_image.h" +#include "kis_wet_sticky_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_types.h" +#include "kis_channelinfo.h" + +#define NOWSDEBUG + +using namespace WetAndSticky; + +enum WetStickyChannelIndex { + BLUE_CHANNEL_INDEX, + GREEN_CHANNEL_INDEX, + RED_CHANNEL_INDEX, + ALPHA_CHANNEL_INDEX, + HUE_CHANNEL_INDEX, + SATURATION_CHANNEL_INDEX, + LIGHTNESS_CHANNEL_INDEX, + LITQUID_CONTENT_CHANNEL_INDEX, + DRYING_RATE_CHANNEL_INDEX, + MISCIBILITY_CHANNEL_INDEX, + GRAVITATIONAL_DIRECTION_INDEX, + GRAVITATIONAL_STRENGTH_CHANNEL_INDEX, + ABSORBANCY_CHANNEL_INDEX, + PAINT_VOLUME_CHANNEL_INDEX +}; + +KisWetStickyColorSpace::KisWetStickyColorSpace() : + KisAbstractColorSpace(KisID("W&S", i18n("Wet & Sticky")), 0, icMaxEnumData) +{ + TQ_INT32 pos = 0; + + // Basic representational definition + m_channels.push_back(new KisChannelInfo(i18n("Blue"), "B", pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Green"), "G", ++pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Red"), "R", ++pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", ++pos, ALPHA, 1)); + + // Paint definition + m_channels.push_back(new KisChannelInfo(i18n("Hue"), "H", ++pos, COLOR, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Saturation"), "S", pos+=sizeof(float) , COLOR, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Lightness"), "L", pos+=sizeof(float), COLOR, sizeof(float))); + + m_channels.push_back(new KisChannelInfo(i18n("Liquid Content"), "Q", pos+=sizeof(float), SUBSTANCE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Drying Rate"), "D", ++pos, SUBSTANCE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Miscibility"), "M", ++pos, SUBSTANCE, 1)); + + // Substrate definition + m_channels.push_back(new KisChannelInfo(i18n("Gravitational Direction"), "Gd", ++pos, SUBSTRATE, sizeof(enumDirection))); + m_channels.push_back(new KisChannelInfo(i18n("Gravitational Strength"), "Gs", pos+=sizeof(enumDirection), SUBSTRATE, 1)); + + m_channels.push_back(new KisChannelInfo(i18n("Absorbency"), "Ad", ++pos, SUBSTRATE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Paint Volume"), "V", ++pos, SUBSTANCE, 1)); + + m_alphaPos = 3; + m_alphaSize = 1; + setDefaultProfile( 0 ); + +#ifdef WSDEBUG + TQValueVector_it it; + int i = 0; + for (it = m_channels.begin(); it != m_channels.end(); ++it) + { + KisChannelInfo * ch = (*it); + kdDebug(DBG_AREA_CMS) << "Channel: " << ch->name() << ", " << ch->pos() << ", " << i << "\n"; + ++i; + } + + kdDebug(DBG_AREA_CMS) << "Size of cell: " << sizeof(CELL) << "\n"; +#endif +} + + +KisWetStickyColorSpace::~KisWetStickyColorSpace() +{ +} + +void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + TQ_UINT8 r, g, b; + + r = c.red(); + g = c.green(); + b = c.blue(); + + p -> red = r; + p -> green = g; + p -> blue = b; + p -> alpha = OPACITY_OPAQUE; + + rgb_to_hls(r, g, b, &p->hue, &p->lightness, &p->saturation); + + p -> liquid_content = 0; + p -> drying_rate = 0; + p -> miscibility = 0; + + p -> direction = DOWN; + p -> strength = 10; + + p -> absorbancy = 10; + p -> volume = 0; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "qcolor: " + << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() + << " native color: (" << TQString().setNum(p->red) << ", " + << TQString().setNum(p->green) << ", " + << TQString().setNum(p->blue) << ", " + << TQString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + TQ_UINT8 r, g, b; + + r = c.red(); + g = c.green(); + b = c.blue(); + + p -> red = r; + p -> green = g; + p -> blue = b; + p -> alpha = opacity; + rgb_to_hls(r, g, b, &p -> hue, &p -> lightness, &p -> saturation); + + p ->liquid_content = 0; + p ->drying_rate = 0; + p ->miscibility = 0; + + p -> direction = DOWN; + p -> strength = 10; + + p -> absorbancy = 10; + p -> volume = 0; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "qcolor: " + << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() << " opacity: " << opacity + << " native color: (" << TQString().setNum(p->red) << ", " + << TQString().setNum(p->green) << ", " + << TQString().setNum(p->blue) << ", " + << TQString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) src; + + c -> setRgb(p -> red, + p -> green, + p -> blue); +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n"; +#endif +} + +void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile) +{ + + CELL_PTR p = (CELL_PTR) src; + + c -> setRgb(p -> red, + p -> green, + p -> blue); + + *opacity = p -> alpha; +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n"; +#endif +} + + + +KisPixelRO KisWetStickyColorSpace::toKisPixelRO(const TQ_UINT8 *src, KisProfile * profile) +{ + return KisPixelRO (src, src, this, profile); +} + +KisPixel KisWetStickyColorSpace::toKisPixel(TQ_UINT8 *src, KisProfile * profile) +{ + return KisPixel (src, src, this, profile); +} + +void KisWetStickyColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ +} + +TQ_UINT8 KisWetStickyColorSpace::getAlpha(const TQ_UINT8 *pixel) const +{ + return ((CELL_PTR)pixel)->alpha; +} + +void KisWetStickyColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + while (nPixels > 0) { + ((CELL_PTR)pixels)->alpha = alpha; + --nPixels; + pixels+=pixelSize(); + } +} + +void KisWetStickyColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ +} + +void KisWetStickyColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ +} + +TQ_UINT8 KisWetStickyColorSpace::scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) +{ + return 0; +} + +TQ_UINT16 KisWetStickyColorSpace::scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) +{ + return 0; +} + + +TQValueVector KisWetStickyColorSpace::channels() const +{ + return m_channels; +} + +bool KisWetStickyColorSpace::hasAlpha() const +{ + return true; +} + +TQ_INT32 KisWetStickyColorSpace::nChannels() const +{ + return 14; +} + +TQ_INT32 KisWetStickyColorSpace::nColorChannels() const +{ + return 3; +} + +TQ_INT32 KisWetStickyColorSpace::nSubstanceChannels() const +{ + return 4; + +} + +TQ_INT32 KisWetStickyColorSpace::pixelSize() const +{ + return sizeof(CELL); +} + + +TQImage KisWetStickyColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float /*exposure*/) +{ + + TQImage img(width, height, 32, 0, TQImage::LittleEndian); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + CELL_PTR p = (CELL_PTR) data; + + while ( i < width * height) { + + const TQ_UINT8 PIXEL_BLUE = 0; + const TQ_UINT8 PIXEL_GREEN = 1; + const TQ_UINT8 PIXEL_RED = 2; + const TQ_UINT8 PIXEL_ALPHA = 3; + + *( j + PIXEL_ALPHA ) = p -> alpha; + *( j + PIXEL_RED ) = p -> red; + *( j + PIXEL_GREEN ) = p -> green; + *( j + PIXEL_BLUE ) = p -> blue; + + p++; + i++; + j += 4; // Because we're hard-coded 32 bits deep, 4 bytes + } + return img; +} + +bool KisWetStickyColorSpace::convertPixelsTo(const TQ_UINT8 * src, KisProfile * /*srcProfile*/, + TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + TQ_UINT32 numPixels, + TQ_INT32 /*renderingIntent*/) +{ + TQ_INT32 dSize = dstColorSpace -> pixelSize(); + TQ_INT32 sSize = pixelSize(); + + TQ_UINT32 j = 0; + TQ_UINT32 i = 0; + TQColor c; + CELL_PTR cp; + while ( i < numPixels ) { + cp = (CELL_PTR) (src + i); + + c.setRgb(cp -> red, + cp -> green, + cp -> blue); + + dstColorSpace -> fromTQColor(c, cp -> alpha, (dst + j), dstProfile); + + i += sSize; + j += dSize; + + } + return true; + +} + +void KisWetStickyColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + default: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + } + +} + + +void KisWetStickyColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + // XXX: This is basically the same as with rgb and used to composite layers for Composition for + // painting works differently + + + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + CELL_PTR dstCell = (CELL_PTR) dst; + CELL_PTR srcCell = (CELL_PTR) src; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Source: " << rows << ", " << columns << " color: " << + srcCell->red << ", " << srcCell->blue << ", " << srcCell->green << ", " << srcCell->alpha << ", " << srcCell->volume << "\n"; + + + kdDebug(DBG_AREA_CMS) << "Destination: " << rows << ", " << columns << " color: " << + dstCell->red << ", " << dstCell->blue << ", " << dstCell->green << ", " << dstCell->alpha << ", " << dstCell->volume << "\n"; + +#endif + + TQ_UINT8 srcAlpha = srcCell->alpha; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcCell->alpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, 3); // XXX: First three bytes for rgb? + } else { + TQ_UINT8 dstAlpha = dstCell->alpha; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dstCell->alpha = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, 3); //XXX: First three bytes for rgb? + } else { + dstCell->red = UINT8_BLEND(srcCell->red, dstCell->red, srcBlend); + dstCell->green = UINT8_BLEND(srcCell->green, dstCell->green, srcBlend); + dstCell->blue = UINT8_BLEND(srcCell->blue, dstCell->blue, srcBlend); + } + } + } + columns--; + src += sizeof(CELL); + dst += sizeof(CELL); + } + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } + +} + +void KisWetStickyColorSpace::compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity) +{ + TQ_INT32 linesize = sizeof(CELL) * columns; + TQ_UINT8 *d; + const TQ_UINT8 *s; + d = dst; + s = src; + + while (rows-- > 0) { + memcpy(d, s, linesize); + d += dstRowStride; + s += srcRowStride; + } + +} + + +KisCompositeOpList KisWetStickyColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + + return list; +} + +TQString KisWetStickyColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const CELL *pixel = reinterpret_cast(U8_pixel); + + switch (channelIndex) { + case BLUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> blue); + case GREEN_CHANNEL_INDEX: + return TQString().setNum(pixel -> green); + case RED_CHANNEL_INDEX: + return TQString().setNum(pixel -> red); + case ALPHA_CHANNEL_INDEX: + return TQString().setNum(pixel -> alpha); + case HUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return TQString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return TQString().setNum(pixel -> lightness); + case LITQUID_CONTENT_CHANNEL_INDEX: + return TQString().setNum(pixel -> liquid_content); + case DRYING_RATE_CHANNEL_INDEX: + return TQString().setNum(pixel -> drying_rate); + case MISCIBILITY_CHANNEL_INDEX: + return TQString().setNum(pixel -> miscibility); + case GRAVITATIONAL_DIRECTION_INDEX: + { + switch (pixel -> direction) { + case UP: + return i18n("Up"); + case DOWN: + return i18n("Down"); + case LEFT: + return i18n("Left"); + case RIGHT: + return i18n("Right"); + default: + Q_ASSERT(false); + return TQString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return TQString().setNum(pixel -> strength); + case ABSORBANCY_CHANNEL_INDEX: + return TQString().setNum(pixel -> absorbancy); + case PAINT_VOLUME_CHANNEL_INDEX: + return TQString().setNum(pixel -> volume); + default: + Q_ASSERT(false); + return TQString(); + } +} + +TQString KisWetStickyColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const CELL *pixel = reinterpret_cast(U8_pixel); + + //XXX: Are these right? + + switch (channelIndex) { + case BLUE_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> blue) / UINT8_MAX); + case GREEN_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> green) / UINT8_MAX); + case RED_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> red) / UINT8_MAX); + case ALPHA_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> alpha) / UINT8_MAX); + case HUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return TQString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return TQString().setNum(pixel -> lightness); + case LITQUID_CONTENT_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> liquid_content) / UINT8_MAX); + case DRYING_RATE_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> drying_rate) / UINT8_MAX); + case MISCIBILITY_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> miscibility) / UINT8_MAX); + case GRAVITATIONAL_DIRECTION_INDEX: + { + switch (pixel -> direction) { + case UP: + return i18n("Up"); + case DOWN: + return i18n("Down"); + case LEFT: + return i18n("Left"); + case RIGHT: + return i18n("Right"); + default: + Q_ASSERT(false); + return TQString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> strength) / UINT8_MAX); + case ABSORBANCY_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> absorbancy) / UINT8_MAX); + case PAINT_VOLUME_CHANNEL_INDEX: + return TQString().setNum(static_cast(pixel -> volume) / UINT8_MAX); + default: + Q_ASSERT(false); + return TQString(); + } +} + diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h new file mode 100644 index 00000000..57f3ac70 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLORSPACE_WET_STICKY_H_ +#define KIS_COLORSPACE_WET_STICKY_H_ + +#include + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" + +namespace WetAndSticky { + + /** + * A color is specified as a vector in HLS space. Hue is a value + * in the range 0..360 degrees with 0 degrees being red. Saturation + * and Lightness are both in the range [0,1]. A lightness of 0 means + * black, with 1 being white. A totally saturated color has saturation + * of 1. + */ + + enum enumDirection { + UP, + DOWN, + LEFT, + RIGHT + }; + + /** + * Defines the contents and attributes of a cell on the canvas. + */ + typedef struct cell { + TQ_UINT8 blue; + TQ_UINT8 green; + TQ_UINT8 red; + TQ_UINT8 alpha; + + float hue; + float saturation; + float lightness; + + TQ_UINT8 liquid_content; + TQ_UINT8 drying_rate; + TQ_UINT8 miscibility; + + enumDirection direction; + TQ_UINT8 strength; + + TQ_UINT8 absorbancy; /* How much paint can this cell hold? */ + TQ_UINT8 volume; /* The volume of paint. */ + + } CELL, *CELL_PTR; + + +} + + + +class KisWetStickyColorSpace : public KisAbstractColorSpace { +public: + KisWetStickyColorSpace(); + virtual ~KisWetStickyColorSpace(); + +public: + + + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 *pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + + virtual TQValueVector channels() const; + virtual bool hasAlpha() const; + virtual TQ_INT32 nChannels() const; + virtual TQ_INT32 nColorChannels() const; + virtual TQ_INT32 nSubstanceChannels() const; + virtual TQ_INT32 pixelSize() const; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * srcProfile, KisProfile * dstProfile, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + + virtual bool convertPixelsTo(const TQ_UINT8 * src, KisProfile * srcProfile, + TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + +private: + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeClear(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + +}; + +#endif // KIS_COLORSPACE_WET_STICKY_H_ diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc new file mode 100644 index 00000000..040d3002 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_ws_engine_filter.h" +#include "kis_wet_sticky_colorspace.h" + +/** + * The Wet & Sticky Engine filter is based on the wet & sticky model + * for computer painting designed by Tunde Cockshott and implemented + * by David England and Kevin Waite. + * + * The filter implements the engine that moves the paint according to + * gravity, viscosity and absorbency. + * + */ +KisWSEngineFilter::KisWSEngineFilter() : KisFilter(id(), "", i18n("&Wet & Sticky paint engine...")) +{ +} + + +/** + * Sets the POINT giving the coordinate location of the next + * cell on the canvas to be visited. There is an even probability + * of each cell being visited. + */ +TQPoint next_cell(TQ_UINT32 width, TQ_UINT32 height) +{ + return TQPoint(random() * width, random() * height); +} + +void single_step(KisColorSpace * cs, KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & rect, bool native) +{ + using namespace WetAndSticky; + + + TQPoint p = next_cell( rect.width(), rect.height() ); + + // XXX: We could optimize by randomly doing lines of 64 pixels + // -- maybe that would be enough to avoid the windscreen wiper + // effect. + KisHLineIterator iter = src -> createHLineIterator(p.x(), p.y(), 1, false); + + TQ_UINT8 *orig = iter.rawData(); + TQ_UINT8 *pix = orig; + + if (!orig) return; + + if (!native ) { + TQColor c; + TQ_UINT8 opacity; + + src -> colorSpace() -> toTQColor(pix, &c, &opacity); + TQ_UINT8 *pix = new TQ_UINT8[sizeof( cell )]; + Q_CHECK_PTR(pix); + + cs -> fromTQColor(c, opacity, pix); + } + + // Process + + CELL_PTR c = ( CELL_PTR )pix; + + + if ( !native ) { + // Set RGBA back + } + +} + +void KisWSEngineFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + + m_src = src; + m_dst = dst; + m_cfg = ( KisWSEngineFilterConfiguration * )configuration; + m_rect = rect; + + + kdDebug(DBG_AREA_FILTERS) << "WSEnginefilter called!\n"; + TQTime t; + t.restart(); + + // Two possibilities: we have our own, cool w&s pixel, and + // then we have real data to mess with, or we're filtering a + // boring shoup-model paint device and we can only work by + // synthesizing w&s pixels. + bool native = false; + // XXX: We need a better way to ID color strategies + if ( src -> colorSpace() -> id() == KisID("W&S","") ) native = true; + + // XXX: We need a better way to ID color strategies + KisColorSpace * cs = KisColorSpaceRegistry::instance()->get("W&S"); + + TQ_UINT32 pixels = 400; //m_cfg -> pixels(); + + kdDebug(DBG_AREA_FILTERS) << "Going to singlestep " << pixels << " pixels.\n"; + + // Determine whether we want an infinite loop + if ( pixels == 0 ) { + while ( true ) + single_step (cs, src, dst, rect, native); + } + // Or not. + else { + for ( TQ_UINT32 i = 0; i < pixels; ++i ) { + single_step (cs, src, dst, rect, native); + } + } + kdDebug(DBG_AREA_FILTERS) << "Done in " << t.elapsed() << " ms\n"; + +} + +KisFilterConfigWidget * KisWSEngineFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* kefcw = new KisWSEngineFilterConfigurationWidget(this,tqparent, ""); +// kdDebug(DBG_AREA_FILTERS) << kefcw << endl; +// return kefcw ; + return 0; +} + +KisFilterConfiguration* KisWSEngineFilter::configuration(TQWidget* nwidget, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* widget = (KisWSEngineFilterConfigurationWidget*) nwidget; + +// if( widget == 0 ) +// { +// return new KisWSEngineFilterConfiguration(30); +// } else { +// TQ_UINT32 depth = widget -> baseWidget() -> depthSpinBox -> value(); + +// return new KisWSEngineFilterConfiguration(depth); +// } + + + return new KisWSEngineFilterConfiguration( m_rect.height() * m_rect.width() ); +} + diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h new file mode 100644 index 00000000..d1c23810 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_WS_ENGINE_FILTER_H_ +#define _KIS_WS_ENGINE_FILTER_H_ + +#include + +#include +#include +#include + +class KisWSEngineFilterConfiguration : public KisFilterConfiguration +{ + +public: + + KisWSEngineFilterConfiguration() { m_pixels = 10000; } + + KisWSEngineFilterConfiguration(TQ_UINT32 pixels = 0) { m_pixels = pixels; } + + TQ_UINT32 pixels() { return m_pixels; } + +private: + + TQ_UINT32 m_pixels; // The number of pixels the filter should + // move. 0 means keep running indefinitely + + + +}; + +class KisWSEngineFilter : public KisFilter +{ + +public: + + KisWSEngineFilter(); + + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* cfg, const TQRect& rc); + + static inline KisID id() { return KisID("Wet & Sticky Engine", i18n("Wet & Sticky")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return false; } + virtual bool supportsIncrementalPainting() { return false; } + +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*, KisPaintDeviceSP dev); + + +private: + +private: + + KisWSEngineFilterConfiguration * m_cfg; + KisPaintDeviceSP m_src; + KisPaintDeviceSP m_dst; + TQRect m_rect; + +}; + +#endif // _KIS_WS_ENGINE_FILTER_H_ diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc new file mode 100644 index 00000000..525b18bb --- /dev/null +++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc @@ -0,0 +1,60 @@ +/* + * wet_sticky_plugin.cc -- Part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "wet_sticky_plugin.h" + +#include "kis_wet_sticky_colorspace.h" +#include "kis_ws_engine_filter.h" + +typedef KGenericFactory WetStickyPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwsplugin, WetStickyPluginFactory( "chalkcore" ) ) + + +WetStickyPlugin::WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(WetStickyPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisFactory") ) + { + KisColorSpace * colorSpaceWS = new KisWetStickyColorSpace(); + Q_CHECK_PTR(colorSpaceWS); + KisColorSpaceRegistry::instance() -> add(colorSpaceWS); + KisFilterRegistry::instance()->add(new KisWSEngineFilter()); + } + +} + +WetStickyPlugin::~WetStickyPlugin() +{ +} + +#include "wet_sticky_plugin.moc" diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.h b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h new file mode 100644 index 00000000..fe981a59 --- /dev/null +++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WET_STICKY_PLUGIN_H_ +#define WET_STICKY_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the Wet & Sticky colour space strategy. + * + * The Wet & Sticky paint system was first designed in 1991 by Tunde Cockshott + * and was further developed by David England and Kevin Waite. It was released + * under the GPL in 2005. + * + */ +class WetStickyPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~WetStickyPlugin(); + +}; + +#endif // WET_STICKY_PLUGIN_H_ diff --git a/chalk/colorspaces/wetsticky/ws/GNU b/chalk/colorspaces/wetsticky/ws/GNU new file mode 100644 index 00000000..e69de29b diff --git a/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt new file mode 100644 index 00000000..5e79907b --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which tqcontains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it tqcontains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/chalk/colorspaces/wetsticky/ws/README b/chalk/colorspaces/wetsticky/ws/README new file mode 100644 index 00000000..15f55e77 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/README @@ -0,0 +1,4 @@ + +The gear example + +This example program demonstrates how to use OpenGL display lists. diff --git a/chalk/colorspaces/wetsticky/ws/TODO b/chalk/colorspaces/wetsticky/ws/TODO new file mode 100644 index 00000000..91c48a03 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/TODO @@ -0,0 +1,24 @@ +1/ Load in portable pixmaps (PPM). Set an arbitrary paint attribute +map for each different colour. Otherwise load in a paint attribute +map definition file. +2/ Input from "brush". Incremental development of brush input. +First simple mixing then +empty brush moving paint +paint on top of paint +attribute application. +3/ Animation +1000000 = 1 fps +500000 = 2 fps +250000 = 4 fps +125000 = 8 fps +62500 = 16 fps +41660 = 24 fps + +4/ NK times 178.9 real 49.4 user 13.3 sys + Orig times 636.6 real 111.1 user 43.6 sys + +5/ Cross section through volume + +6/ Separate Colour scale window + +7/ Transparency diff --git a/chalk/colorspaces/wetsticky/ws/after.jpg b/chalk/colorspaces/wetsticky/ws/after.jpg new file mode 100644 index 00000000..5116efdb Binary files /dev/null and b/chalk/colorspaces/wetsticky/ws/after.jpg differ diff --git a/chalk/colorspaces/wetsticky/ws/anim.c b/chalk/colorspaces/wetsticky/ws/anim.c new file mode 100644 index 00000000..995a3dff --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/anim.c @@ -0,0 +1,154 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#define FRAME_LIMIT 36 + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "constants.h" +#include "types.h" + +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes +output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm[FRAME_LIMIT]; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +Display *display; +char pix_file[32]; +unsigned int delay; + +main(argc, argv) +int argc; +char *argv[]; +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + XEvent event; + int i, width, height; + int ret; + int c; + + extern char *optarg; + extern int optind; + + width = 300; + height = 300; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, &argc, argv); + + delay = 100000; /*default delay in microseconds between frames */ + + while ((c = getopt(argc, argv, "D:")) != -1) + switch (c) { + case 'D': + delay = atoi(optarg); + delay = delay * 1000000; + break; + } + + + display = XtDisplay(top_level); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + /*XtAddEventHandler(colour_canvas, ExposureMask, False, + expose_event, 0);*/ + + XtRealizeWidget(colour_shell); + + XSynchronize(display, True); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = 0; + values.foreground = 1; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + + + fprintf(stderr,"Read files ..."); + for (i=0; i < FRAME_LIMIT; i++) { + sprintf(pix_file,"pixmap.%d",i); + if ((XReadBitmapFile(display, XtWindow(colour_shell), pix_file, + &width, &height, &colour_pm[i], &ret, &ret)) != + BitmapSuccess) + perror("bad bitmap"); + } + fprintf(stderr,"done.\nBegin Animation\n"); + + + for (;;) { + for (i=0; i < FRAME_LIMIT; i++) { + XCopyPlane(display, colour_pm[i], + XtWindow(colour_canvas),gc, + 0, 0, 300, 300, 0, 0, 1); + fprintf(stderr,"pre sleep\n"); + usleep(delay); + } + + + } /* End for loop */ +}xk + diff --git a/chalk/colorspaces/wetsticky/ws/before.jpg b/chalk/colorspaces/wetsticky/ws/before.jpg new file mode 100644 index 00000000..fc26b989 Binary files /dev/null and b/chalk/colorspaces/wetsticky/ws/before.jpg differ diff --git a/chalk/colorspaces/wetsticky/ws/canvas.c b/chalk/colorspaces/wetsticky/ws/canvas.c new file mode 100644 index 00000000..77cfa17d --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/canvas.c @@ -0,0 +1,514 @@ +/* + FILE: canvas.c + PURPOSE: Hides the canvas and provides its access and + manipuation routines. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include + +/* Declare the canvas data structure local to this module. It can + only be accessed via routines given in the header file for this module. + The (0,0) location for the canvas is at the top-left. */ + +CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT]; + +/* This module maintains a list of the addresses of cells that have + been modified since the last redraw and therefore need updating. + Points are added to this list by the need_to_tqrepaint() routine + and are removed by the next_cell_for_tqrepaint() function. The + pointer to the current tail of the list is updated by side-effect. */ + +static POINT need_tqrepainting[REDRAW_LIMIT]; +static int next_free = 0; +static int next_to_tqrepaint = 0; + +/* *********************************************************************** */ + +int number_of_tqrepaints_needed() +/* Returns the number of cells that need to be tqrepainted. */ + +{ + return (next_free); +} + +/* *********************************************************************** */ + +void need_to_tqrepaint(point) +/* The cell at this location needs to be redrawn since it has + been altered. Scan the list to see if it is already + scheduled for a tqrepainting operation and only add it if + it is not there. */ + +POINT point; + +{ + int k; + + + /* If the list is already full then simply ignore the tqrepaint + request - it will get done eventually anyway. */ + + if (next_free == REDRAW_LIMIT) return; + + /* Check whether this point is already on the list. */ + + for (k=0; k < next_free; k++) { + if ((need_tqrepainting[k].x == point.x) && + (need_tqrepainting[k].y == point.y)) break; + } + + if (k < next_free) return; /* Already in the list. */ + + /* Add this new cell address to the end of the list. */ + + need_tqrepainting[next_free].x = point.x; + need_tqrepainting[next_free].y = point.y; + next_free++; +} + +/* *********************************************************************** */ + +void next_cell_for_tqrepaint(cell, locus) +/* This routine returns the next cell to be tqrepainted, together with its + location on the canvas. This is determined by taking the next point + from the need_tqrepainting list and accessing its cell. If the list is + empty then return NIL. + Note that the tqrepainting operation will clear out the list before + any other new positions are added. */ + + CELL_PTR *cell; + POINT_PTR locus; + +{ + if (next_to_tqrepaint >= next_free) { + next_to_tqrepaint = next_free = 0; + *(cell) = NIL; + return; + } + + *(cell) = get_cell(need_tqrepainting[next_to_tqrepaint]); + locus->x = need_tqrepainting[next_to_tqrepaint].x; + locus->y = need_tqrepainting[next_to_tqrepaint].y; + next_to_tqrepaint++; +} + +/* *********************************************************************** */ + +void next_cell_point (address) +/* Sets the POINT giving the coordinate location of the next + cell on the canvas to be visited. There is an even probability + of each cell being visited. */ + +POINT_PTR address; +{ + extern long random(); + + address->x = random() % CANVAS_WIDTH; + address->y = random() % CANVAS_HEIGHT; +} + + +/* *********************************************************************** */ + +CELL_PTR get_cell (point) +/* This function returns a pointer to the cell at the + given address on the canvas. */ + +POINT point; + +{ + return (&canvas[point.x][point.y]); +} + +/* *********************************************************************** */ + +DIRECTION anti_clockwise_from (arrow) +/* Returns the direction found going anti-clockwise from the + given direction. */ + +DIRECTION arrow; + +{ + switch (arrow) { + + case NORTH: return(WEST); + case EAST: return(NORTH); + case SOUTH: return(EAST); + case WEST: ; + + } + return(SOUTH); +} + +/* *********************************************************************** */ + +DIRECTION clockwise_from (arrow) +/* Returns the direction found going clockwise from the + given direction. */ + +DIRECTION arrow; + +{ + switch (arrow) { + + case NORTH: return(EAST); + case EAST: return(SOUTH); + case SOUTH: return(WEST); + case WEST: ; + + } + return(NORTH); +} + +/* *********************************************************************** */ + +BOOLEAN neighbour (aPoint, direction, bPoint) +/* Set bPoint to the coordinate of the point that can + be found by going one place in the given direction + from aPoint. The direction can be NORTH, EAST, WEST + or SOUTH. If bPoint will be off the canvas then the + function returns FALSE otherwise TRUE. */ + +POINT aPoint; +POINT_PTR bPoint; +DIRECTION direction; + +{ + int x, y; + + switch (direction) { + + case NORTH: x = 0; y = -1; break; + case EAST: x = 1; y = 0; break; + case SOUTH: x = 0; y = 1; break; + case WEST: x = -1; y = 0; break; + } + + bPoint->x = aPoint.x + x; + bPoint->y = aPoint.y + y; + + if ((bPoint->x >= CANVAS_WIDTH) || (bPoint->x < 0) || + (bPoint->y >= CANVAS_HEIGHT) || (bPoint->y < 0)) return(FALSE); + + return(TRUE); +} + +/* *********************************************************************** */ + +void initialise_paint (paint) +/* Set this paint to be a dry, unmixing white. */ + +PAINT_PTR paint; + +{ + paint->colour.hue = 255; + paint->colour.saturation = 0.0; + paint->colour.lightness = 1.0; + paint->liquid_content = 0; + paint->drying_rate = 0; + paint->miscibility = 0; +} + +/* *********************************************************************** */ + +void initialise_cell(cell) +/* Reset the given cell to a default value. */ + +CELL_PTR cell; + +{ + initialise_paint (&cell->contents); + + cell->volume = UNFILLED; /* Indicates that no paint has yet been applied. +*/ + cell->absorbancy = 10; + cell->gravity.direction = SOUTH; + cell->gravity.strength = DEFAULT_GRAVITY_STRENGTH; +} + + +/* *********************************************************************** */ + +void split_gravity() +/* This routine is for test purposes only. It causes the right + half of the canvas to have gravity going NORTH with the left + half having gravity going SOUTH. */ + +{ + POINT p; + CELL_PTR cell; + + /*for (p.x=CANVAS_WIDTH/2; p.x < CANVAS_WIDTH; p.x++) {*/ + for (p.x=165; p.x < CANVAS_WIDTH; p.x++) { + for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) { + cell = get_cell (p); + cell->gravity.direction = NORTH; + } + } +} + +/* *********************************************************************** */ + +void initialise_canvas() +/* Before it can be used the canvas needs to be initialised to + a default state. This involves setting each of the cells to + have no paint and for gravity to be uniformly down. Each cell + has the default absorbancy value. */ + +{ + POINT p; + CELL_PTR cell; + + for (p.x=0; p.x < CANVAS_WIDTH; p.x++) { + for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) { + cell = get_cell (p); + initialise_cell (cell); + } + } +} + +/* *********************************************************************** */ + +void print_cell_attributes(cell) +CELL_PTR cell; +{ + printf("Volume = %d\n", cell->volume); + + printf("Liquid content = %d%%\n", cell->contents.liquid_content); + printf("Drying rate = %d%%\n", cell->contents.drying_rate); + printf("Miscibility = %d%%\n\n", cell->contents.miscibility); + + printf("Saturation = %2f\n", cell->contents.colour.saturation); + printf("Lightness = %2f\n", cell->contents.colour.lightness); + printf("Hue = %d\n", cell->contents.colour.hue); + printf ("------------------------------\n\n"); +} + +/* *********************************************************************** */ + +void blob_cell_alpha (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 20; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + +/* *********************************************************************** */ + +void blob_cell_beta (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 80; + cell->contents.drying_rate = 20; + cell->contents.miscibility = 90; + + cell->contents.colour.hue = 70; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.7; + + cell->volume = 30; + +} +/* *********************************************************************** */ + +void blob_cell_gamma (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 80; + cell->contents.drying_rate = 40; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 100; + cell->contents.colour.saturation = 0.5; + cell->contents.colour.lightness = 0.4; + + cell->volume = 50; + +} + +/* *********************************************************************** */ + +void old_blob(width) +/* This routine puts a square blob of various paints + of the given side length centred on the canvas. + This is used for test purposes. */ + +int width; + +{ + int count, lump, startx, starty, x, y; + + width = (width > CANVAS_WIDTH) ? CANVAS_WIDTH : width; + width = (width > CANVAS_HEIGHT) ? CANVAS_HEIGHT : width; + + printf("This run used a square blob of side %d pixels\n", width); + printf ("centred on the canvas. The blob was split into three equal\n"); + printf ("vertical strips with the following paint attributes:\n\n"); + + startx = (CANVAS_WIDTH - width) / 2; + starty = (CANVAS_HEIGHT - width) / 2; + lump = width / 3; + + count=0; + for (x = startx; x < startx + width; x++) { + for (y = starty; y < starty + width; y++) { + switch (count / lump) { + + case 0: blob_cell_alpha (&canvas[x][y]); break; + case 1: blob_cell_beta (&canvas[x][y]); break; + default: blob_cell_gamma (&canvas[x][y]); break; + + } + } + count++; + } + split_gravity(); + + print_cell_attributes (&canvas[startx][starty]); + print_cell_attributes (&canvas[startx + lump][starty]); + print_cell_attributes (&canvas[startx + (2*lump)][starty]); +} + +gravity_set(x,y,x1,y1,attr) +int x; +int y; +int x1; +int y1; +int attr; +{ + /* set the canavs absorbancy and gravity to various test values + in the region (x,y),(x1,y1) + */ + + int i,j; + + for (i=x; i < x1; i++ ) + for (j=y; j < y1; j++) { + canvas[i][j].absorbancy = 10; /* default 10 */ + canvas[i][j].gravity.direction = SOUTH; + canvas[i][j].gravity.strength = DEFAULT_GRAVITY_STRENGTH; + /*DEFAULT_GRAVITY_STRENGTH*/ + } +} + +blob_set(x, y, x1, y1, attr) +int x; +int y; +int x1; +int y1; +int attr; +{ + /* Set a blob of paint in the rectangle (x,y),(x1,y1) with + the attribute, attr (can be volume, liquidity or dryness*/ + int i,j; + float colour; + + colour = (3.6 * 122); + colour = 64; + fprintf(stderr, "attribute value %d %d\n", attr, (int)colour); + + + for (i=x; i < x1; i++ ) + for (j=y; j < y1; j++) { + canvas[i][j].contents.liquid_content = 80; + canvas[i][j].contents.drying_rate = 50; + canvas[i][j].contents.miscibility = 80; + + canvas[i][j].contents.colour.hue = (int)colour; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.7; + + canvas[i][j].volume = attr; + } + + +} + +void blob(type) +int type; +{ + + /* paint nine test blobs on the canvas */ + + /* X Example 1 All attributes at 80% except vol 0 - 100%*/ + + /* X Example 2 All attributes at 80% except liq 0 - 100% */ + + /* X Example 3 All attributes at 80% except dry 0 - 100% */ + + /* X Example 4 All attributes at 80% except absorp 100 - 0% */ + + /* X Example 5 All attributes at 80% except gravity 0 - 100% */ + + /* X Example 6 All attributes at 80% except direction N,S,E & W */ + + blob_set(20, 20, 80, 80, 0); + gravity_set(0, 0, 100, 100, SOUTH); + + blob_set(120,20, 180, 80, 22); + gravity_set(150, 0, 300, 150, EAST); + + blob_set(220,20,280,80,33); + gravity_set(0, 150, 150, 300, NORTH); + + blob_set(20,120,80,180,44); + gravity_set(150, 150, 300, 300, WEST); + + blob_set(120,120,180,180,55); + gravity_set(100, 100, 200, 200, 55); + + blob_set(220,120, 280,180, 66); + gravity_set(200, 100, 300, 200, 66); + + blob_set(20,220,80,280,77); + gravity_set(0, 200, 100, 300, 77); + + blob_set(120,220,180,280,88); + gravity_set(100, 200, 200, 300, 88); + + blob_set(220,220,280,280, 100); + gravity_set(200, 200, 300, 300, 100); + +} + +void +load_file(filename, width, height) +char *filename; +int *width; +int *height; +{ + + /* Load in a file using the load_ppm_format() function + This loads in a file in Portable Pixmap format + */ + + load_ppm_format(filename, canvas, width, height); +} diff --git a/chalk/colorspaces/wetsticky/ws/canvas.h b/chalk/colorspaces/wetsticky/ws/canvas.h new file mode 100644 index 00000000..c2f2bcbf --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/canvas.h @@ -0,0 +1,70 @@ +/* + FILE: canvas.h + PURPOSE: Defines the public routines for manipulating the canvas. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + + +extern int number_of_tqrepaints_needed(); +/* Returns the number of cells needing to tqrepainted. */ + +extern void need_to_tqrepaint (/* POINT */); +/* Requests that the cell at the given point be tqrepainted + at the next update as it has been modified. */ + +extern void next_cell_for_tqrepaint (/* *CELL_PTR, POINT_PTR */); +/* Returns a pointer to a cell that needs to be updated as well + as the location of that cell on the canvas. If there are + no more cells to be redrawn then the pointer will be NIL. */ + +extern void next_cell_point (/* POINT_PTR */); +/* Sets the POINT giving the coordinate location of the next + cell on the canvas to be visited. There is an even probability + of each cell being visited. */ + +extern CELL_PTR get_cell (/* POINT */); +/* This function returns a pointer to the cell at the + given address on the canvas. */ + +extern DIRECTION anti_clockwise_from (/* DIRECTION */); +/* Returns the direction found going clockwise from the + given direction. */ + +extern DIRECTION clockwise_from (/* DIRECTION */); +/* Returns the direction found going clockwise from the + given direction. */ + +extern BOOLEAN neighbour (/* POINT, DIRECTION, POINT_PTR */); +/* Set bPoint to the coordinate of the point that can + be found by going one place in the given direction + from aPoint. The direction can be NORTH, EAST, WEST + or SOUTH. If bPoint will be off the canvas then the + function returns FALSE otherwise TRUE. */ + +extern void initialise_canvas(); +/* Before it can be used the canvas needs to be initialised to + a default state. This involves setting each of the cells to + have no paint and for gravity to be uniformly down. Each cell + has the default absorbancy value. */ + +extern void blob( /* int */); +/* This routine puts a square blob of black paint + of the given side length centred on the canvas. + This is used for test purposes. */ + +extern void load_file(/*char *, int *, int * */); +/* Load a file from a portable pixmap into the canvas */ diff --git a/chalk/colorspaces/wetsticky/ws/cmap.c b/chalk/colorspaces/wetsticky/ws/cmap.c new file mode 100644 index 00000000..0f11eaf7 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/cmap.c @@ -0,0 +1,681 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm; + +static Widget volume_shell; +static Widget volume_box; +static Widget volume_canvas; +static Pixmap volume_pm; + +static Widget dryness_shell; +static Widget dryness_box; +static Widget dryness_canvas; +static Pixmap dryness_pm; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +static Colormap cmap; +static XColor colours[256]; +void stroke(); +void stroke_motion(); + +Display *display; +int screen; +Screen *screen_ptr; +Window root; + +static int count=0; +static int frame_count=0; +char pix_file[64]; + +void StartWindow(); +void StartUpWindows(); + +static XtEventHandler +expose_event(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the colour window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + +} + + +static void +expose_volume(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the volume window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(volume_canvas), volume_pm, + XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0); + + +} + +static void +expose_dryness(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the dryness window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + +} + +int +GetHueValue(red, green, blue) +int red; +int green; +int blue; +{ + XColor colour; + + colour.red = red * 257; + colour.green = green * 257; + colour.blue = blue * 257; + colour.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(display, cmap, &colour) == 0) + fprintf(stderr,"colour allocation failed\n"); + + return (colour.pixel); +} + + +void +DrawPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + +int +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the volume to affect the colour + value + */ + + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + +int +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the dryness to affect the colour + value + */ + + if (XtWindow(dryness_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y); + + return(0); +} + +void +ClearWindow() +{ + XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas)); +} + +static void +CleanWindow(win) +Drawable win; +/* Fill a window with a solid, white rectangle */ +{ +XGCValues values; +long tqmask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, tqmask, &values); + + XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300); + +} + +void SetupCmap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[i].flags = DoRed | DoBlue | DoGreen; + } + + /* for (i=0;i<=127;i++) + colours[i].green = i*2*257; + + for (i=128;i>0;i--) + colours[255-i].green = (i-1)*2*257;*/ + + for (i=0;i<64;i++) + colours[i].green = i*4*257; + + for (i=64;i<128;i++) + colours[i].green = 65536-i*4*257; + + for (i=128;i<192;i++) + colours[i].green = (i-128)*2*257; + + for (i=192;i<255;i++) + colours[i].green = 65536-(i-128)*2*257; + + + for (i=0;i<256;i++) + colours[i].blue = 65536 - i*257; + + colours[0].red = 65535; + colours[0].green = 65535; + colours[0].blue = 65535; +} + +void +SetupGreyMap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[255 - i].flags = DoRed | DoBlue | DoGreen; + } + + + for (i=0;i<256;i++) + colours[i].green = i*257; + + for (i=0;i<256;i++) + colours[i].blue = i*257; + + colours[255].red = 255*257; + colours[255].green = 255*257; + colours[255].blue = 255*257; + +} + + +main(argc, argv) +int argc; +char **argv; +/* Create colour window heirarchy and add event handlers */ +{ + + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + +int width; +int height; + int i; + + + width = 300; + height = 300; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, &argc, argv); + + + display = XtDisplay(top_level); + screen = DefaultScreen(display); + screen_ptr = ScreenOfDisplay(display, DefaultScreen(display)); + + root = RootWindow(display, screen); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0); + + XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0); + + XtAddEventHandler(colour_canvas, Button1MotionMask, + False, stroke_motion, 0); + + XtRealizeWidget(colour_shell); + + cmap = XCreateColormap( display, XtWindow(colour_shell), + XDefaultVisualOfScreen(screen_ptr), AllocAll); + + for (i=0; i <= 255; i++) + colours[i].pixel = i; + + XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256); + + /*SetupCmap();*/ + + SetupGreyMap(); + + XStoreColors(display, cmap, colours, 256); + + i=0; + while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr), + True, NULL, 0, &colours[i].pixel, 1 ) ) { + colours[i].pixel = i; + i++; + } + + XSetWindowColormap(display, XtWindow(colour_shell), cmap); + + XInstallColormap(display, cmap); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + colour_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(colour_pm); + + StartWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + + StartUpWindows(); +} + + +void StartWindow(width, height) +int width; +int height; +/* Create Volume heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + volume_shell = XtCreateApplicationShell("volume_frame", + topLevelShellWidgetClass, NULL, 0); + + volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass, + volume_shell, NULL, 0); + + volume_canvas = XtCreateManagedWidget("", labelWidgetClass, + volume_box, args, XtNumber(args)); + + XtAddEventHandler(volume_canvas, ExposureMask, False, + expose_volume, 0); + + XtRealizeWidget(volume_shell); + + XSetWindowColormap(display, XtWindow(volume_shell), cmap); + + volume_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(volume_pm); + + +} + +void StartDrynessWindow(width, height) +int width; +int height; +/* Create dryness heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + dryness_shell = XtCreateApplicationShell("dryness_frame", + topLevelShellWidgetClass, NULL, 0); + + dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass, + dryness_shell, NULL, 0); + dryness_canvas += XtCreateManagedWidget("", labelWidgetClass, + dryness_box, args, XtNumber(args)); + + XtAddEventHandler(dryness_canvas, ExposureMask, False, + expose_dryness, 0); + + XtRealizeWidget(dryness_shell); + + XSetWindowColormap(display, XtWindow(dryness_shell), cmap); + + dryness_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(dryness_pm); + +} + +static void +draw_labels() +{ + XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10, + "Colour", strlen("Colour")); + XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10, + "Colour", strlen("Colour")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10, + "Volume", strlen("Volume")); + XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10, + "Volume", strlen("Volume")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10, + "Bump Map", strlen("Bump Map")); + XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10, + "Bump Map", strlen("Bump Map")); +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + int colour, volColour, dryness; + POINT p; + + p.x = x; + p.y = y; + + /* The current display simply maps hue onto the indices of the colour + table. This involves some scaling since hues are in the range [0,360) + with the colour table being [0,256). */ + + colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0)); + + /*DrawPoint(x,y,colour); */ + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */ + + volColour = MIN(cell->volume * 2, 255); + volColour = MAX(volColour, 0); + /* Make unfilled cells have a zero vol. */ + + /*DrawVolumePoint(x,y,volColour);*/ + + /* Dryness will be in the range [0,255]. */ + dryness = (cell->contents.liquid_content * 255) / 100; + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + +void draw_false_colour_scale() +/* This routine places a scale along the top of the volume window + showing the colours being used. Low is at the left edge. + The colour palette has indices 0..255. */ +{ + int x, y; + + /*for (x=0; x < 255; x++) + for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/ +} + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (x=0; x < CANVAS_WIDTH; x++) { + for (y=0; y < CANVAS_HEIGHT; y++) { + p.x = x; + p.y = y; + /*cell = get_cell(p);*/ + paint_cell(cell, x, y); + } + } + draw_false_colour_scale(); + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (x=0; x < CANVAS_WIDTH; x++) { + for (y=0; y < CANVAS_HEIGHT; y++) { + p.x = x; + p.y = y; + /*cell = get_cell(p);*/ + /*colour = (int) new_intensity_value(p);*/ + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + + +void evolve_paint() +{ + +} + + + +void StartUpWindows() +{ +/* Start the X windows event loop and paint processing */ +XEvent event; + + + + for (;;) { + if (XtPending()) { + XtNextEvent(&event); + XtDispatchEvent(&event); + } + else { + /* Evolve paint and re-display*/ + evolve_paint(); + } + + } /* End for loop */ + + +} + +void +stroke(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ +/* brush_stroke(event->xbutton.x, event->xbutton.y);*/ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + +/* DrawPoint(event->xbutton.x, event->xbutton.y, 128); + DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128); + DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + /*XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1);*/ + + /*brush_stroke(event->xbutton.x, event->xbutton.y);*/ +} + + +void +stroke_motion(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + /*brush_stroke(event->xbutton.x, event->xbutton.y);*/ +} + diff --git a/chalk/colorspaces/wetsticky/ws/constants.h b/chalk/colorspaces/wetsticky/ws/constants.h new file mode 100644 index 00000000..fa72bc92 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/constants.h @@ -0,0 +1,69 @@ +/* + FILE: constants.h + PURPOSE: Constains all the #DEFINES for Wet&Sticky. + AUTHORS: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + +/* Some utility constants. */ + +#define TRUE 1 +#define FALSE 0 +#define YES 1 +#define NO 0 +#define NIL 0 +#define DEBUG 1 +#define VERSION "1.0" + +/* Define the constants for colours in the HLS space. */ + +#define UNFILLED -1 +#define MAX_COLOUR_INDEX 255 + + +/* Define the dimensions of the intelligent canvas. */ + +#define CANVAS_WIDTH 300 +#define CANVAS_HEIGHT 300 +#define SCALE_WIDTH 30 + + +/* Define constants that control the evolution of the paint. */ + +#define STEP_LIMIT 200 +#define REDRAW_LIMIT 500 + + +/* Define some constants used in testing the system. */ + +#define DEFAULT_BLOB_SIZE (CANVAS_WIDTH / 3) +#define BLOB_NAME "-blob" + + +/* Constants used in modelling gravity. */ + +#define NORTH 0 +#define EAST 1 +#define SOUTH 2 +#define WEST 3 + +#define DEFAULT_GRAVITY_STRENGTH 10 + + +/* Define some macros. */ + +#define MAX(A,B) ((A) > (B) ? (A) : (B)) +#define MIN(A,B) ((A) < (B) ? (A) : (B)) diff --git a/chalk/colorspaces/wetsticky/ws/engine.c b/chalk/colorspaces/wetsticky/ws/engine.c new file mode 100644 index 00000000..2fb4917e --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine.c @@ -0,0 +1,802 @@ +/* + FILE: engine.c + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include + +extern double HEIGHT_SCALE; + +/* *********************************************************************** */ + +int random_percent() +/* This function returns a random number in the range [0,100]. */ +{ + extern long random(); + + return (random() % 101); +} + +/* *********************************************************************** */ + +BOOLEAN allow_event_based_on(value) +/* The given value is a percentage. Compare this value + with a randomly generated percentage and if it is larger + then allow the event to happen (i.e. return TRUE) other- + wise return FALSE. */ + +int value; + +{ + if (value > random_percent()) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN age_paint(cell) +/* Make the paint in the given cell older, i.e. let + if dry out a bit if it isn't already dry. This + function returns TRUE if the paint was already + dry or becomes so, and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (cell->volume == 0) return(TRUE); + if (cell->contents.liquid_content == 0) return(TRUE); + if (allow_event_based_on(cell->contents.drying_rate) == TRUE) + cell->contents.liquid_content--; + + if (cell->contents.liquid_content == 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN similar_paint(aPaint, bPaint) +/* Determine whether the two paints are similar. It is + assumed that aPaint has come from the host cell (and + so it is its miscibility value that is used). The + function returns TRUE if the paints are similar and + FALSE otherwise. */ + +PAINT aPaint, bPaint; + +{ + int delta; + + delta = abs(aPaint.liquid_content - bPaint.liquid_content); + if (delta <= aPaint.miscibility) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +int surplus_paint(cell) +/* Returns the amount of paint held by this cell greater than its + absorbancy value. This is the amount of paint that can flow. */ + +CELL_PTR cell; + +{ + return (MAX(cell->volume - cell->absorbancy, 0)); +} + +/* *********************************************************************** */ + +BOOLEAN has_surplus_paint(cell) +/* Does the given cell have excess paint, i.e. can paint flow out + of this cell. Return TRUE if it can and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (surplus_paint(cell) > 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +void stop() { /* Used for breakpointing. */ } + +void donate_paint(source, srcLocus, amount, dest, destLocus) +/* The source cell is donating the specified volume of its paint + to the destination cell. The destination cell must mix this + new paint with its existing paint to yield a new paint. + This routine is also responsible for recording which cells + have been updated and so need tqrepainting. + + A special case is recognised where the destination has not yet + had any paint applied. This causes the donated paint to become + to new contents of this cell. + +*/ + +CELL_PTR source, dest; +POINT srcLocus, destLocus; +int amount; + +{ + float delta, ratio; + int iDelta; + + source->volume -= amount; + + if (dest->volume == UNFILLED) { + + /* The donated paint is going into an unfilled cell. + Copy the source's attributes into the destination. */ + + dest->volume = amount; + dest->contents.colour.hue = source->contents.colour.hue; + dest->contents.colour.lightness = source->contents.colour.lightness; + dest->contents.colour.saturation = source->contents.colour.saturation; + dest->contents.liquid_content = source->contents.liquid_content; + dest->contents.miscibility = source->contents.miscibility; + dest->contents.drying_rate = source->contents.drying_rate; + + } else { + + /* Need to mix the existing paint in the dest with this amount + of new paint from the source. This is done using a linear + interpolation mechanism using the relative amounts of the + paint as the control. */ + + if (dest->volume != 0) + ratio = amount / (float)(dest->volume); + + iDelta = source->contents.colour.hue - dest->contents.colour.hue; + if (iDelta != 0) { + dest->contents.colour.hue += (int)(ratio * iDelta); + if (dest->contents.colour.hue >= 360) + dest->contents.colour.hue -= 360; + } + + iDelta = source->contents.drying_rate - dest->contents.drying_rate; + dest->contents.drying_rate += (int)((int)ratio * iDelta); + dest->contents.drying_rate %= 101; + + iDelta = source->contents.liquid_content - dest->contents.liquid_content; + dest->contents.liquid_content += (int)(ratio * iDelta); + dest->contents.liquid_content %= 101; + + iDelta = source->contents.miscibility - dest -> contents.miscibility; + dest->contents.miscibility += (int)(ratio * iDelta); + dest->contents.miscibility %= 101; + + delta = source -> contents.colour.saturation - dest -> contents.colour.saturation; + dest -> contents.colour.saturation += ratio * delta; + + delta = source->contents.colour.lightness - dest->contents.colour.lightness; + dest->contents.colour.lightness += ratio * delta; + + dest->volume += amount; /* The new volume of paint in dest. */ + + } + + need_to_tqrepaint(destLocus); +} + +/* *********************************************************************** */ + +void handle_surface_tension(cell, locus) +/* This routine handles the surface tension around the given cell. +*/ + +CELL_PTR cell; +POINT locus; + +{ + DIRECTION direction[3]; + POINT loci[3]; + CELL_PTR buddy[3]; + BOOLEAN ok, similar[3]; + int weakCount, weak[3], count[3], excess, chosen, side, start, finish, +k, lowest; + + if (has_surplus_paint(cell) == FALSE) return; + + direction[0] = cell->gravity.direction; + direction[1] = clockwise_from(direction[0]); + direction[2] = anti_clockwise_from(direction[0]); + + for (k=0; k < 3; k++) { + ok = neighbour(locus, direction[k], &loci[k]); + if (ok == TRUE) { + buddy[k] = get_cell(loci[k]); + count[k] = 0; + } else count[k] = -1; + } + + for (k=0; k < 3; k++) + similar[k] = (count[k] == -1) + ? FALSE + : similar_paint(cell->contents, buddy[k]->contents); + + for (k=0; k < 3; k++) { + if ((count[k] != -1) && (similar[k] == FALSE)) { + count[k] = 0; + start = MAX(k-1, 0); + finish = MIN(k+1, 2); + for (side=start; side <= finish; side++) + if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++; + + } + } + + lowest = 4; + for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest); + + weakCount = 0; + for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k; + + /* The weak array now holds weakCount indices of those sides that have + the lowest surface tension and therefore where any paint would flow over. + Now it is necessary to see whether paint will actually flow based on + a probability level using the liquidity and volume of the paint in the + cell as parameters. Paint will flow over only one of the weakest sides + with the side chosen at random. */ + + if (random_percent() > cell->contents.liquid_content) return; /* Too +viscous. */ + + excess = surplus_paint(cell); + if (random_percent() > excess * 3) return; + /* The '3' in the previous statement is an empirically-derived multiplier. +*/ + + /* The paint will flow. Pick one of the weakest sides at random. */ + + chosen = weak[random_percent() % weakCount]; + donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]); +} + +/* *********************************************************************** */ + +BOOLEAN diffuse_paint(cell, locus) +/* Diffuse paint among the neighbours of the given cell. + If this cell does not have surplus paint then return + TRUE otherwise return FALSE. */ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + DIRECTION down, direction; + CELL_PTR buddy; + POINT nlocus; + BOOLEAN ok; + int excess; + + if (has_surplus_paint(cell) == FALSE) return(TRUE); + + down = cell->gravity.direction; + direction = ((random() & 01) == 0) + ? clockwise_from(down) + : anti_clockwise_from(down); + + ok = neighbour(locus, direction, &nlocus); + if (ok == FALSE) return(TRUE); + + buddy = get_cell(nlocus); + + if (similar_paint(cell->contents, buddy->contents) == FALSE) { + handle_surface_tension(cell, locus); + return(FALSE); + } + + if (buddy->volume >= cell->volume) return(FALSE); + + if (allow_event_based_on(cell->contents.liquid_content) == FALSE) + return(FALSE); + + /* Transfer one particle of paint from cell to its buddy. */ + + excess = (cell->volume - buddy->volume) / 2; + donate_paint(cell, locus, excess, buddy, nlocus); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN apply_gravity(cell, locus) +/* Subject the contents of the given cell to the effects + of gravity. Note that the direction of gravity is local + to the given cell. Locus is the address of this cell. + This function returns TRUE if the paint in this cell + cannot flow and FALSE otherwise. +*/ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + POINT downhill; + CELL_PTR down; + BOOLEAN ok, can_flow; + int barrier, excess; + + ok = neighbour(locus, cell->gravity.direction, &downhill); + if (ok == FALSE) return(TRUE); /* At bottom of canvas. */ + + down = get_cell(downhill); + + can_flow = down->volume < (cell->volume + cell->gravity.strength) + ? TRUE : FALSE; + + if (can_flow == FALSE) return(TRUE); + + /* Although this paint can flow introduce a random value that + uses the viscosity of the paint to determine whether it does + actually flow. */ + + barrier = random() % 10; + if (cell->contents.liquid_content > barrier) { + /* Paint is actually moving. Move half of the excess downward. */ + + excess = (cell->volume - cell->absorbancy) / 2; + donate_paint(cell, locus, excess, down, downhill); + } + + return(FALSE); +} + + +float lx, ly, lz; + +void +compute_shade_vectors() +{ + extern float lx, ly, lz; + float D; + + lx = 1.0; ly = -1.0; lz = 3.0; + + D = sqrt ( lx * lx + ly * ly + lz * lz ); + + lx = lx/D; ly = ly/D; lz = lz/D; + +} + +/* *********************************************************************** ** + ** +** new_intensity_value ** +** ** +** calculates shade value for a pixel from surface characteristics ** ** + ** +** Revision History ** +** ** +** Rev Date By Description ** +** 1.0 1/12/91 DE Original ** +** 1.1 1/04/92 DE Include Phong Shading ** +** 1.2 11/08/92 JWP Parameterized Specular Component ** ** + ** +*********************************************************************** */ + +float calc_d(); +float calc_g(); +float calc_f(); +float sqr(); +void printvector(); +void vectscale(); +void vectadd(); +float magnitude(); + +float +normalize (x, y, z) + float x, y, z; /*vector x, y, z components*/ +{ + float result; + + /* function calculates the amount to divide each vector component + to normalize it to a unit vector. The parameters are the x,y,z + components and the result is the amount to divide by */ + + result = sqrt (x*x + y*y + z*z); + return (result); + + } + + + +float Newnormalize(V, W) +float *V; +float *W; +{ + float temp; + + temp = normalize(V[0], V[1], V[2]); + + W[0] = V[0]/temp; + W[1] = V[1]/temp; + W[2] = V[2]/temp; + + return temp; +} + +float dot(V, W) + float V[3]; + float W[3]; +{ + + return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) ); + +} + +float Phong (Nv, Lv, Ev, shine) +float Nv[3]; +float Lv[3]; +float Ev[3]; +float shine; +{ + float Hv[3]; + + Newnormalize(Ev, Ev); + + Hv[0] = Ev[0] + Lv[0]; + Hv[1] = Ev[1] + Lv[1]; + Hv[2] = Ev[2] + Lv[2]; + + Newnormalize (Hv, Hv); + + shine = abs(shine); + return( pow(dot(Nv, Hv), shine) ); +} + + +/******************* Auxillary functions *****************************/ + +/* Function : calc_c +* Returns : the microfacet distribution function */ + +float calc_d(cos_alpha,c3) +float cos_alpha; +float c3; +{ +float d; +d=sqr( sqr(c3) / ( sqr(cos_alpha)*(sqr(c3) -1) +1)); return d; +} + +/* +* Function : calc_g +* Returns : the geometrical attenuation factor. * +* This function should return values between 0.0 and 1.0, so if it's * negative I will return 0.0 Anyway it does not seem to make any difference * at all whether I return 0.0, the negative value or the minimum of the * absolute values of (temp1,temp2,temp3) */ + +float calc_g(N,H,L,V) +float N[3]; /* Normal vector */ +float H[3]; /* Half-way vector */ +float L[3]; /* Light vector */ +float V[3]; /* View vector */ +{ + float temp1,temp2,temp3,ret; + float NdotH,NdotV,NdotL,VdotH; + NdotH=dot(N,H); + NdotV=dot(N,V); + NdotL=dot(N,L); + VdotH=dot(V,H); + temp1=1.0; + temp2=(2*NdotH*NdotV)/VdotH; + temp3=(2*NdotH*NdotL)/VdotH; + /* Find minimum value */ + if (temp1 < temp2) + if (temp1 < temp3) + ret=temp1; + else + ret=temp3; + else + if (temp2 < temp3) + ret=temp2; + else + ret=temp3; + if (ret < 0.0) + ret=0.0; + return ret; +} + +/* Function : calc_f +* Returns : the Fresnel term +*/ + +float calc_f(L,H,mu) +float L[3]; +float H[3]; +float mu; +{ + float temp1,temp2; + float c,g; + c=dot(L,H); + g=sqrt(sqr(mu)+sqr(c) -1); + temp1 = (sqr(g-c)/sqr(g+c))*0.5; + temp2 = 1+(sqr( c*(g+c)-1 ) / sqr( c*(g-c)+1)); return (temp1*temp2); +} + +/* Function : sqr +* Returns : the square of its argument +*/ + +float sqr(x) +float x; +{ + return (x*x); +} + +/* Function : printvector +* prints the contents of a vector with 3 elements */ + +void printvector(v) +float v[3]; +{ + printf("[%f,%f,%f] ",v[0],v[1],v[2]); +} + +void vectscale(v1, k, vout, n) +float *v1; +float k; +float *vout; +int n; +{ vout[0] = v1[0]*k; + vout[1] = v1[1]*k; + vout[2] = v1[2]*k; +} + +void vectadd(v1, v2, vout, n) +float *v1, *v2, *vout; +int n; +{ vout[0] = v1[0] + v2[0]; + vout[1] = v1[1] + v2[1]; + vout[2] = v1[2] + v2[2]; +} + +float magnitude(v) +float *v; +{ return( normalize(v[0], v[1], v[2]) ); +} + +float T_S(Nv, Lv, Ev, shine) +float Nv[3]; /* Normalized Normal vector */ +float Lv[3]; /* Normalized Light-source vector */ +float Ev[3]; /* Un-normalized Eye vector */ +float shine; /* parameter to absorb Phong coeff */ +{ + float Hv[3]; /* Half-way vector H */ + float cos_alpha; + float t; + float mdf; /* Micro facet distribtuion function */ + float gaf; /* Geometrical attenuation factor*/ float ft; /* The Fresnel term */ + float c3; + float mu; /* Refractive index */ + + /*initialize appearance constants*/ + c3 = shine; + mu = 200.0; + + /*normalize eye vector*/ + + Newnormalize(Ev, Ev); + +/* Calculate the half-way vector H, between the light vector and the +view vector */ + + vectadd(Ev,Lv,Hv,3); + t = magnitude(Hv,3); + + vectscale(Hv,(1/t),Hv,3); + + /* Calculate the micro-facet distribution function D */ + + cos_alpha=dot(Nv,Hv); + mdf=calc_d(cos_alpha,c3); + + + /* Calculate the geometrical attenuation factor */ + + gaf=calc_g(Nv,Hv,Lv,Ev); + + /* Calculate the Fresnel Term */ + + ft=calc_f(Lv,Hv,mu); + + /* Calculate specular component */ + + return( (mdf*gaf*ft) / dot(Nv,Lv) ); +} + + + + +float +new_intensity_value(a_pnt) +POINT a_pnt; +/* Calculate the new intensity value of a pixel +in order to construct a bump map of the paint surface +*/ +{ +float h, h1, h2, h3, h4; + float shininess; +float Ka, Kd, Ks; + float wetmax, degree, norm, distance; + float g; +float Nv[3]; + float Ev[3]; + float Hv[3]; + float Lv[3]; + extern float lx, ly, lz; +float intensity, light_intensity; +int liquid; +POINT b_pnt; +CELL_PTR cell; +CELL_PTR next_cell; + int x_cntr, y_cntr; + + Ka = 0.0; + Kd = 0.5; + Ks = 0.5; + + wetmax = 100.0; + distance = 2500.0; + light_intensity = 2.0; + shininess = 0.3; + + cell = get_cell(a_pnt); + + h = (float)cell->volume; + + if (neighbour(a_pnt, NORTH, &b_pnt)) { + next_cell = get_cell(b_pnt); + h1 = (float)next_cell->volume; + } else + h1 = h; + + if (neighbour(a_pnt, EAST, &b_pnt)) { + next_cell = get_cell(b_pnt); + h2 = (float)next_cell->volume; + } else + h2 = h; + + if (neighbour(a_pnt, SOUTH, &b_pnt)) { + next_cell = get_cell(b_pnt); + h3 = (float)next_cell->volume; + } else + h3 = h; + + if (neighbour(a_pnt, WEST, &b_pnt)) { + next_cell = get_cell(b_pnt); + h4 = (float)next_cell->volume; + } else + h4 = h; + + h1 = h1/HEIGHT_SCALE; + h2 = h2/HEIGHT_SCALE; + h3 = h3/HEIGHT_SCALE; + h4 = h4/HEIGHT_SCALE; + + /* test fix for "disappearing" paint */ + + if (cell->contents.liquid_content == 0) + liquid = 1; + else + liquid = cell->contents.liquid_content; + + degree = (float)abs(liquid)/wetmax; + + x_cntr= 150 - a_pnt.x; + y_cntr= 150 - a_pnt.y; + + Ks = light_intensity * Ks /* * degree*/ ; + + Kd = light_intensity * Kd; + +/* shininess = shininess/degree; */ + + + Nv[1] = h3 - h1; + Nv[0] = h4 - h2; + Nv[2] = 4.0; + + Newnormalize (Nv, Nv); + + Lv[0] = lx; + Lv[1] = ly; + Lv[2] = lz; + + g = dot(Lv, Nv)*Kd + Ka; + + g = g * (float)cell->contents.colour.hue; + + Ev[0] = (float)x_cntr; + Ev[1] = (float)y_cntr; + Ev[2] = distance; + + intensity = g + Ks*T_S(Nv, Lv, Ev, shininess); + + if ( intensity > 255.0 ) { + intensity = 0.0; + } else { + if (intensity < 0.0) + intensity = 255.0; + else + intensity = 255.0 - intensity; + } + + + /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n", + cell->contents.liquid_content, + cell->contents.colour.hue, + intensity, + g, + intensity - g);*/ + + +return (intensity); +} + + +/* *********************************************************************** */ + +void single_step() +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +{ + POINT locus; + CELL_PTR cell; + BOOLEAN done; + + next_cell_point(&locus); + cell = get_cell(locus); + + done = age_paint(cell); + if (done == TRUE) return; + + done = diffuse_paint(cell, locus); + if (done == TRUE) return; + + done = apply_gravity(cell, locus); +} + +brush_stroke(x,y) +int x; +int y; +{ + POINT pnt; + CELL_PTR cell; + + + pnt.x = x; + pnt.y = y; + + cell = get_cell(pnt); + + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 128; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + + diff --git a/chalk/colorspaces/wetsticky/ws/engine.h b/chalk/colorspaces/wetsticky/ws/engine.h new file mode 100644 index 00000000..b6072b0a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine.h @@ -0,0 +1,33 @@ +/* + FILE: engine.h + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + +extern void single_step(); +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +extern brush_stroke(); + +extern float intensity_value( /* POINT */); + +extern float new_intensity_value( /* POINT */); + +extern void compute_shade_vectors(); + + diff --git a/chalk/colorspaces/wetsticky/ws/engine3.c b/chalk/colorspaces/wetsticky/ws/engine3.c new file mode 100644 index 00000000..9fd274cd --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine3.c @@ -0,0 +1,617 @@ +/* + FILE: engine.c + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include + +#define HEIGHT_SCALE 1.0 + +/* *********************************************************************** */ + +int random_percent() +/* This function returns a random number in the range [0,100]. */ +{ + extern long random(); + + return (random() % 101); +} + +/* *********************************************************************** */ + +BOOLEAN allow_event_based_on(value) +/* The given value is a percentage. Compare this value + with a randomly generated percentage and if it is larger + then allow the event to happen (i.e. return TRUE) other- + wise return FALSE. */ + +int value; + +{ + if (value > random_percent()) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN age_paint(cell) +/* Make the paint in the given cell older, i.e. let + if dry out a bit if it isn't already dry. This + function returns TRUE if the paint was already + dry or becomes so, and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (cell->volume == 0) return(TRUE); + if (cell->contents.liquid_content == 0) return(TRUE); + if (allow_event_based_on(cell->contents.drying_rate) == TRUE) + cell->contents.liquid_content--; + + if (cell->contents.liquid_content == 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN similar_paint(aPaint, bPaint) +/* Determine whether the two paints are similar. It is + assumed that aPaint has come from the host cell (and + so it is its miscibility value that is used). The + function returns TRUE if the paints are similar and + FALSE otherwise. */ + +PAINT aPaint, bPaint; + +{ + int delta; + + delta = abs(aPaint.liquid_content - bPaint.liquid_content); + if (delta <= aPaint.miscibility) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +int surplus_paint(cell) +/* Returns the amount of paint held by this cell greater than its + absorbancy value. This is the amount of paint that can flow. */ + +CELL_PTR cell; + +{ + return (MAX(cell->volume - cell->absorbancy, 0)); +} + +/* *********************************************************************** */ + +BOOLEAN has_surplus_paint(cell) +/* Does the given cell have excess paint, i.e. can paint flow out + of this cell. Return TRUE if it can and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (surplus_paint(cell) > 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +void stop() { /* Used for breakpointing. */ } + +void donate_paint(source, srcLocus, amount, dest, destLocus) +/* The source cell is donating the specified volume of its paint + to the destination cell. The destination cell must mix this + new paint with its existing paint to yield a new paint. + This routine is also responsible for recording which cells + have been updated and so need tqrepainting. + + A special case is recognised where the destination has not yet + had any paint applied. This causes the donated paint to become + to new contents of this cell. + +*/ + +CELL_PTR source, dest; +POINT srcLocus, destLocus; +int amount; + +{ + float delta, ratio; + int iDelta; + + source->volume -= amount; + + if (dest->volume == UNFILLED) { + + /* The donated paint is going into an unfilled cell. + Copy the source's attributes into the destination. */ + + dest->volume = amount; + dest->contents.colour.hue = source->contents.colour.hue; + dest->contents.colour.lightness = source->contents.colour.lightness; + dest->contents.colour.saturation = source->contents.colour.saturation; + dest->contents.liquid_content = source->contents.liquid_content; + dest->contents.miscibility = source->contents.miscibility; + dest->contents.drying_rate = source->contents.drying_rate; + + } else { + + /* Need to mix the existing paint in the dest with this amount + of new paint from the source. This is done using a linear + interpolation mechanism using the relative amounts of the + paint as the control. */ + + ratio = amount / (float)(dest->volume); + + iDelta = source->contents.colour.hue - dest->contents.colour.hue; + if (iDelta != 0) { + dest->contents.colour.hue += (int)(ratio * iDelta); + if (dest->contents.colour.hue >= 360) + dest->contents.colour.hue -= 360; + } + + iDelta = source->contents.drying_rate - dest->contents.drying_rate; + dest->contents.drying_rate += (int)(ratio * iDelta); + dest->contents.drying_rate %= 101; + + iDelta = source->contents.liquid_content - dest->contents.liquid_content; + dest->contents.liquid_content += (int)(ratio * iDelta); + dest->contents.liquid_content %= 101; + + iDelta = source->contents.miscibility - dest->contents.miscibility; + dest->contents.miscibility += (int)(ratio * iDelta); + dest->contents.miscibility %= 101; + + delta = source->contents.colour.saturation - dest->contents.colour.saturation; + dest->contents.colour.saturation += ratio * delta; + + delta = source->contents.colour.lightness - dest->contents.colour.lightness; + dest->contents.colour.lightness += ratio * delta; + + dest->volume += amount; /* The new volume of paint in dest. */ + + } + + need_to_tqrepaint(destLocus); +} + +/* *********************************************************************** */ + +void handle_surface_tension(cell, locus) +/* This routine handles the surface tension around the given cell. +*/ + +CELL_PTR cell; +POINT locus; + +{ + DIRECTION direction[3]; + POINT loci[3]; + CELL_PTR buddy[3]; + BOOLEAN ok, similar[3]; + int weakCount, weak[3], count[3], excess, chosen, side, start, finish, k, lowest; + + if (has_surplus_paint(cell) == FALSE) return; + + direction[0] = cell->gravity.direction; + direction[1] = clockwise_from(direction[0]); + direction[2] = anti_clockwise_from(direction[0]); + + for (k=0; k < 3; k++) { + ok = neighbour(locus, direction[k], &loci[k]); + if (ok == TRUE) { + buddy[k] = get_cell(loci[k]); + count[k] = 0; + } else count[k] = -1; + } + + for (k=0; k < 3; k++) + similar[k] = (count[k] == -1) + ? FALSE + : similar_paint(cell->contents, buddy[k]->contents); + + for (k=0; k < 3; k++) { + if ((count[k] != -1) && (similar[k] == FALSE)) { + count[k] = 0; + start = MAX(k-1, 0); + finish = MIN(k+1, 2); + for (side=start; side <= finish; side++) + if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++; + + } + } + + lowest = 4; + for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest); + + weakCount = 0; + for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k; + + /* The weak array now holds weakCount indices of those sides that have + the lowest surface tension and therefore where any paint would flow over. + Now it is necessary to see whether paint will actually flow based on + a probability level using the liquidity and volume of the paint in the + cell as parameters. Paint will flow over only one of the weakest sides + with the side chosen at random. */ + + if (random_percent() > cell->contents.liquid_content) return; /* Too viscous. */ + + excess = surplus_paint(cell); + if (random_percent() > excess * 3) return; + /* The '3' in the previous statement is an empirically-derived multiplier. */ + + /* The paint will flow. Pick one of the weakest sides at random. */ + + chosen = weak[random_percent() % weakCount]; + donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]); +} + +/* *********************************************************************** */ + +BOOLEAN diffuse_paint(cell, locus) +/* Diffuse paint among the neighbours of the given cell. + If this cell does not have surplus paint then return + TRUE otherwise return FALSE. */ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + DIRECTION down, direction; + CELL_PTR buddy; + POINT nlocus; + BOOLEAN ok; + int excess; + + if (has_surplus_paint(cell) == FALSE) return(TRUE); + + down = cell->gravity.direction; + direction = ((random() & 01) == 0) + ? clockwise_from(down) + : anti_clockwise_from(down); + + ok = neighbour(locus, direction, &nlocus); + if (ok == FALSE) return(TRUE); + + buddy = get_cell(nlocus); + + if (similar_paint(cell->contents, buddy->contents) == FALSE) { + handle_surface_tension(cell, locus); + return(FALSE); + } + + if (buddy->volume >= cell->volume) return(FALSE); + + if (allow_event_based_on(cell->contents.liquid_content) == FALSE) + return(FALSE); + + /* Transfer one particle of paint from cell to its buddy. */ + + excess = (cell->volume - buddy->volume) / 2; + donate_paint(cell, locus, excess, buddy, nlocus); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN apply_gravity(cell, locus) +/* Subject the contents of the given cell to the effects + of gravity. Note that the direction of gravity is local + to the given cell. Locus is the address of this cell. + This function returns TRUE if the paint in this cell + cannot flow and FALSE otherwise. +*/ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + POINT downhill; + CELL_PTR down; + BOOLEAN ok, can_flow; + int barrier, excess; + + ok = neighbour(locus, cell->gravity.direction, &downhill); + if (ok == FALSE) return(TRUE); /* At bottom of canvas. */ + + down = get_cell(downhill); + + can_flow = down->volume < (cell->volume + cell->gravity.strength) + ? TRUE : FALSE; + + if (can_flow == FALSE) return(TRUE); + + /* Although this paint can flow introduce a random value that + uses the viscosity of the paint to determine whether it does + actually flow. */ + + barrier = random() % 10; + if (cell->contents.liquid_content > barrier) { + /* Paint is actually moving. Move half of the excess downward. */ + + excess = (cell->volume - cell->absorbancy) / 2; + donate_paint(cell, locus, excess, down, downhill); + } + + return(FALSE); +} + + +float lx, ly, lz; + +void +compute_shade_vectors() +{ + extern float lx, ly, lz; + float D; + + lx = -1.0; ly = 1.0; lz = 2.0; + + D = sqrt ( lx * lx + ly * ly + lz * lz ); + + lx = lx/D; ly = ly/D; lz = lz/D; + +} + +/* *********************************************************************** ** ** +** new_intensity_value ** +** ** +** calculates shade value for a pixel from surface characteristics ** ** ** +** Revision History ** +** ** +** Rev Date By Description ** +** 1.0 1/12/91 DE Original ** +** 1.1 1/04/92 DE Include Phong Shading ** +** 1.2 11/08/92 JWP Parameterized Specular Component ** ** ** +*********************************************************************** */ +float +normalize (x, y, z) + float x, y, z; /*vector x, y, z components*/ +{ + float result; + + /* function calculates the amount to divide each vector component + to normalize it to a unit vector. The parameters are the x, y, +z + components and the result is the amount to divide by */ + + result = sqrt (x*x + y*y + z*z); + return (result); + + } + + + +float Newnormalize(V, W) +float *V; +float *W; +{ +float temp; + +temp = normalize(V[0], V[1], V[2]); + +W[0] = V[0]/temp; +W[1] = V[1]/temp; +W[2] = V[2]/temp; + +return temp; +} + +float dot(V, W) +float V[3]; +float W[3]; +{ + +return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) ); + +} + +float Phong (Nv, Lv, Ev, shine) +float Nv[3]; +float Lv[3]; +float Ev[3]; +float shine; +{ +float Hv[3]; + +Newnormalize(Ev, Ev); + +Hv[0] = Ev[0] + Lv[0]; +Hv[1] = Ev[1] + Lv[1]; +Hv[2] = Ev[2] + Lv[2]; + +Newnormalize (Hv, Hv); + +shine = abs(shine); +return( pow(dot(Nv, Hv), shine) ); +} + + +float +new_intensity_value(a_pnt) +POINT a_pnt; +/* Calculate the new intensity value of a pixel +in order to construct a bump map of the paint surface +*/ +{ +float h, h1, h2, h3, h4; + int shininess; +float Ka, Kd, Ks; + float wetmax, degree, norm, distance; + float g; +float Nv[3]; + float Ev[3]; + float Hv[3]; + float Lv[3]; + extern float lx, ly, lz; +float intensity, light_intensity; +POINT b_pnt; +CELL_PTR cell; +CELL_PTR next_cell; + int x_cntr, y_cntr; + +Ka = 0.1; +Kd = 0.6; + Ks = 0.4; + + wetmax = 100.0; + distance = 2500.0; + light_intensity = 2.0; + shininess = 200; + +cell = get_cell(a_pnt); + +h = (float)cell->volume; + +if (neighbour(a_pnt, NORTH, &b_pnt)) { +next_cell = get_cell(b_pnt); +h1 = (float)next_cell->volume; +} else +h1 = h; + +if (neighbour(a_pnt, EAST, &b_pnt)) { +next_cell = get_cell(b_pnt); +h2 = (float)next_cell->volume; +} else +h2 = h; + +if (neighbour(a_pnt, SOUTH, &b_pnt)) { +next_cell = get_cell(b_pnt); +h3 = (float)next_cell->volume; +} else +h3 = h; + +if (neighbour(a_pnt, WEST, &b_pnt)) { +next_cell = get_cell(b_pnt); +h4 = (float)next_cell->volume; +} else +h4 = h; + +h1 = h1/HEIGHT_SCALE; +h2 = h2/HEIGHT_SCALE; +h3 = h3/HEIGHT_SCALE; +h4 = h4/HEIGHT_SCALE; + + degree = (float)abs(cell->contents.liquid_content)/wetmax; + + x_cntr= 150 - a_pnt.x; + y_cntr= 150 - a_pnt.y; + + Ks = light_intensity * Ks * degree; + + Kd = light_intensity * Kd; + + shininess = (int)degree * shininess + 1; + + + Nv[1] = h3 - h1; + Nv[0] = h4 - h2; +Nv[2] = 4.0; + + Newnormalize (Nv, Nv); + + Lv[0] = lx; +Lv[1] = ly; + Lv[2] = lz; + + g = dot(Lv, Nv)*Kd + Ka; + + g = g * (float)cell->contents.colour.hue; + +Ev[0] = (float)x_cntr; +Ev[1] = (float)y_cntr; +Ev[2] = distance; + + intensity = g + Ks*Phong(Nv, Lv, Ev, (float)shininess); + + if ( intensity > 255.0 ) { + intensity = 0.0; + } else { + if (intensity < 0.0) + intensity = 255.0; + else + intensity = 255.0 - intensity; + } + + + /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n", + cell->contents.liquid_content, + cell->contents.colour.hue, + intensity, + g, + intensity - g);*/ + + +return (intensity); +} + + +/* *********************************************************************** */ + +void single_step() +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +{ + POINT locus; + CELL_PTR cell; + BOOLEAN done; + + next_cell_point(&locus); + cell = get_cell(locus); + + done = age_paint(cell); + if (done == TRUE) return; + + done = diffuse_paint(cell, locus); + if (done == TRUE) return; + + done = apply_gravity(cell, locus); +} + +brush_stroke(x,y) +int x; +int y; +{ + POINT pnt; + CELL_PTR cell; + + + pnt.x = x; + pnt.y = y; + + cell = get_cell(pnt); + + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 128; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + diff --git a/chalk/colorspaces/wetsticky/ws/load_ppm.c b/chalk/colorspaces/wetsticky/ws/load_ppm.c new file mode 100644 index 00000000..6368ee08 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/load_ppm.c @@ -0,0 +1,244 @@ +/* + FILE: load_ppm.c + PURPOSE: Defines the routines to load a PPM portable pixmap image file. + AUTHOR: David England + VERSION: 1.00 (10-May-91) + + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" + +#include +#include +#include + +/* Max number of colors allowed in ppm input. */ +#define MAXCOLORS 256 + +extern CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT]; + +float +max_rgb(r,g,b) +float r; +float g; +float b; +{ + if ((r > g) && (r > b)) + return (r); + + if ((b > g) && (b > r)) + return (b); + + if ((g > b) && (g > r)) + return (g); + + return(0); +} + +float +min_rgb(r,g,b) +float r; +float g; +float b; +{ + if ((r < g) && (b < g)) + return (r); + + if ((b < g) && (b < r)) + return (b); + + if ((g < b) && (g < r)) + return (g); + + return(0); +} + + +int +GetHue(red, green, blue) /* rgb to hls */ +int red; +int green; +int blue; +{ + float min_col, max_col; + float h,s,l; + float rc, gc, bc; + float r, g, b; + + r = (float)red/255.0; + b = (float)green/255.0; + g = (float)blue/255.0; + + max_col = (float)max_rgb(r, g, b); + min_col = (float)min_rgb(r, g, b); + + l = (max_col + min_col)/2.0 ; + + if ( max_col == min_col) { + s = 0.0; + h = 0.0; + } else { + if ( l < 0.5) { + s = (max_col - min_col)/(max_col + min_col); + } else s = (max_col - min_col)/(2 - max_col - min_col); + + rc = (max_col -r)/( max_col - min_col); + gc = (max_col -g)/(max_col - min_col); + bc = (max_col -b)/(max_col - min_col); + + if (r == max_col) + h = bc - gc; + else if (g == max_col ) + h = 2 + rc - bc; + else if (b == max_col) + h = 4 + gc -rc; + + h = h * 60; + + if ( h < 0.0) + h = h + 360; + } + + return ((int)h); + + +} + +GetHuePaint(r,g,b) +int r; +int g; +int b; +{ + + /*if ((r == 0) && (g == 0) && (b ==0)) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + + canvas[i][j].contents.colour.hue = 0; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = 80; + return (0); + } + + if ((r == 255) && (g == 255) && ( b == 255)) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + + canvas[i][j].contents.colour.hue = 128; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = 80; + return (128); + }*/ +} + +load_ppm_format(filename, width, height) +char *filename; +int *width; +int *height; +{ + + FILE* ifp; + pixel **pixels; + int rows, cols, i, j; + pixval maxval; + int red, green, blue; + int hue; + + /*ppm_init( &argc, argv );*/ + + + + ifp = pm_openr( filename); + + pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); + + *(width) = cols; + *(height) = rows; + + fprintf(stderr,"Loading file %s, %dx%d. Please wait ", filename, rows, +cols); + + if (rows > CANVAS_HEIGHT) + rows = CANVAS_HEIGHT; + + if (cols > CANVAS_WIDTH) + cols = CANVAS_WIDTH; + + for (i=0; i< rows; i++) { + for (j=0; j< cols; j++) { + red = PPM_GETR(pixels[i][j]); + green = PPM_GETG(pixels[i][j]); + blue = PPM_GETB(pixels[i][j]); + + /*hue = GetHue(red, green, blue);*/ + + /* For gray scale only */ + + hue = 255 - red; + + + /*fprintf(stderr,"hue %d ", hue);*/ + /*GetHuePaint(red, green, blue, i, j);*/ + + canvas[i][j].contents.liquid_content = 80; + canvas[i][j].contents.drying_rate = 80; + canvas[i][j].contents.miscibility = 80; + + canvas[i][j].contents.colour.hue = hue; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = (float)hue/2.5; + + if (red == 0) + if (green == 0) + if ( blue == 0) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + canvas[i][j].contents.colour.hue = 0; + canvas[i][j].volume = 0; + } + + if (red == 255) + if (green == 255) + if ( blue == 255) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + canvas[i][j].contents.colour.hue = 360; + canvas[i][j].volume = 0; + } + + + } + if (( i %10) == 0){ + fprintf(stderr,"."); + fflush(stderr); + } + } + + printf(" done\n"); + + pm_close( ifp ); + + /*exit(0);*/ + +} diff --git a/chalk/colorspaces/wetsticky/ws/main.c b/chalk/colorspaces/wetsticky/ws/main.c new file mode 100644 index 00000000..8185557a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/main.c @@ -0,0 +1,105 @@ +/* + FILE: main.c + PURPOSE: The top-level program for Wet&Sticky + AUTHOR: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include "win_interface.h" +#include +#include +#include + +double HEIGHT_SCALE; + +void main(argc, argv) +int argc; +char *argv[]; + +/* + The Wet&Sticky program can be executed with optional parameters. + Those parameters used by the X graphics system are stripped out. + If no parameters are given then the program runs as a purely + interactive system. This requires input handling which is not + yet implemented. If the argument is the string '-blob' then the + program uses a square blob as the starting image. Otherwise the + program assumes the argument is a filename containing a previously + stored canvas. This is then loaded into the canvas as a starting + point. +*/ + +{ + char *filename; + extern void exit(); + int width; + int height; + extern int optind, opterr; + extern char *optarg; + int c,i; + int blob_flag; + + + fprintf(stdout, "Wet&Sticky Version %s\n", VERSION); + fprintf(stdout, "Implemented by K.Waite and D.England, 1991\n"); + fprintf(stdout, "Based on ideas by Tunde Cockshott\n\n"); + + + initialise_canvas(); + if (DEBUG) fprintf (stdout, "Finished initialising the canvas\n"); + + CreateWindows (&argc, argv, CANVAS_WIDTH , CANVAS_HEIGHT); + + filename = argv[1]; + + blob_flag = 1; + HEIGHT_SCALE = 20.0; + + opterr = 0; + fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE); + + while ((c = getopt(argc, argv, "f:s:")) != EOF) + switch (c) { + case 'f': + filename = optarg; + load_file(filename, &width, &height); + blob_flag = 0; + break; + case 's': + fprintf(stderr, "HEIGHT string %s \n",optarg); + HEIGHT_SCALE = atof(optarg); + break; + case '?': + break; + } + + if (blob_flag) + blob (DEFAULT_BLOB_SIZE); + + fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE); + + StartVolumeWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + StartDrynessWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + + if (DEBUG) fprintf (stdout, "Finished preparing X\n"); + + if (DEBUG) fprintf (stdout, "Passing control to window manager\n"); + StartWindows(); + exit(0); + +} diff --git a/chalk/colorspaces/wetsticky/ws/makefile b/chalk/colorspaces/wetsticky/ws/makefile new file mode 100644 index 00000000..a14beb9a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/makefile @@ -0,0 +1,55 @@ +CFLAGS = -O3 +#CFLAGS = -g #-std +LINT_FLAGS = -bchxu + +SOURCES = load_ppm.c canvas.c engine.c x_interface.c main.c +OBJECTS = x_interface.o load_ppm.o engine.o canvas.o +OBJECTS2= ogl_interface.o load_ppm.o engine.o canvas.o + +GFX_LIB=-L/usr/X11R6/lib \ + -lXaw -lXmu -lXt -lX11 -lm -lppm -lpgm -lpbm + +#PPM_LIBS = ppm/libppm.a ppm/libpgm.a ppm/libpbm.a + +OGL_LIBS=-L/usr/X11R6/lib \ + -laux -lGLU -lGL -lXext -lX11 -limp -lm -lppm -lpgm -lpbm + +OGL_INCS=-I/usr2/share/src/OpenGL/libaux + +CC=cc + +wet+sticky: constants.h canvas.h engine.h $(OBJECTS) main.c + ${CC} -o wet+sticky $(CFLAGS) main.c $(OBJECTS) $(GFX_LIB) + +wet+sticky2: constants.h canvas.h engine.h $(OBJECTS2) main.c + ${CC} -o wet+sticky2 $(CFLAGS) main.c $(OBJECTS2) $(OGL_LIBS) + +cmap: cmap.o + ${CC} -g -o cmap cmap.o $(GFX_LIB) + +anim: constants.h canvas.h engine.h anim.c + ${CC} -o anim $(CFLAGS) anim.c $(GFX_LIB) + +engine.o: types.h constants.h canvas.h engine.h + ${CC} -c $(CFLAGS) engine3.c + +canvas.o: types.h constants.h canvas.h + ${CC} -c $(CFLAGS) canvas.c + +x_interface.o: constants.h types.h canvas.h engine.h x_interface.c + ${CC} -c $(CFLAGS) x_interface.c + +ogl_interface.o: constants.h types.h canvas.h engine.h ogl_interface.c + ${CC} -c $(CFLAGS) ${OGL_INCS} ogl_interface.c + +load_ppm.o: constants.h types.h canvas.h engine.h load_ppm.c + ${CC} -c $(CFLAGS) load_ppm.c + +cmap.o: cmap.c + ${CC} -c -g cmap.c + +clean: + /bin/rm -f core + /bin/rm -f *.o + +lint: alint $(LINT_FLAGS) $(SOURCES) diff --git a/chalk/colorspaces/wetsticky/ws/mona.pgm b/chalk/colorspaces/wetsticky/ws/mona.pgm new file mode 100644 index 00000000..2060ee90 Binary files /dev/null and b/chalk/colorspaces/wetsticky/ws/mona.pgm differ diff --git a/chalk/colorspaces/wetsticky/ws/ogl_interface.c b/chalk/colorspaces/wetsticky/ws/ogl_interface.c new file mode 100644 index 00000000..953b10c8 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/ogl_interface.c @@ -0,0 +1,302 @@ +/* + FILE: xgl_interface.c + PURPOSE: Creation and access to a OpenGL window + to wet+sticky using OpenGL + AUTHOR: David England + VERSION: 1.00 (21-June-96) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include +#include +/*#include */ +/*#include "aux.h"*/ + +#include + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +static int count=0; + + +void nullProc() +{ +} + +void SetupCmap() +{ +} + +float Value(n1, n2, hue) +float n1, n2, hue; +{ + if (hue > 360 ) + hue = hue -360; + else if (hue < 0 ) + hue = hue +360; + if (hue < 60 ) + return n1+(n2-n1)*hue/60; + else if (hue < 180 ) + return n2; + else if (hue < 240 ) + return n1+(n2-n1)*(240-hue)/60; + else return n1; +} + + +RGB_COLOUR hls_to_rgb(h, l, s) +int h; +float l; +float s; +{ +RGB_COLOUR rgb_colour; +float m1, m2; + +if (l <= 0.5 ) + m2 = l*(1+s); +else + m2 = l+s - l*s; +m1 = 2*l-m2; + +rgb_colour.r = Value(m1, m2, h+120); +rgb_colour.g = Value(m1,m2, h); +rgb_colour.b = Value(m1,m2, h-120); + +return (rgb_colour); +} + +void +DrawPoint(x,y,hls_col) +int x; +int y; +HLS_COLOUR hls_col; +/* Draw a point on the window and the back-up Pixmap */ +{ +RGB_COLOUR rgb_colour; + + rgb_colour = hls_to_rgb(hls_col.hue, + hls_col.lightness, + hls_col.saturation); + + + printf("h %.2f l %.2f s %.2f\n", hls_col.hue, hls_col.lightness, + hls_col.saturation); + + printf( "r %.2f g %.2f b %.2f\n", rgb_colour.r, rgb_colour.g, + rgb_colour.b); + + glColor3f(rgb_colour.r, rgb_colour.g, rgb_colour.b); + + glBegin(GL_POINTS); + glVertex2s(x,y); + glVertex2s(x+1,y+1); + glEnd(); + +} + +void +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +{ +/*set colour, draw point at offset */ +} + +void +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + +} + +void +ClearWindow() +{ + +} + +static void +CleanWindow() +/* Fill a window with a solid, white rectangle */ +{ +} + + +void CreateWindows(argc, argv, width, height) +int *argc; +char **argv; +int width; +int height; + +{ + + auxInitDisplayMode( AUX_RGBA); + + auxInitPosition(50,50, width*3, height); + + auxInitWindow(argv[0]); + + glClearColor(1.0, 1.0, 1.0, 0.0); + + glClear(GL_COLOR_BUFFER_BIT); + +} + + +static void +draw_labels() +{ +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + DrawPoint(x,y, cell->contents.colour); + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*DrawVolumePoint(x,y,volColour);*/ + + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + glClear(GL_COLOR_BUFFER_BIT); + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (y=0; y < CANVAS_HEIGHT; y++) + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + paint_cell(cell, x, y); + } + + glFlush(); + sleep(10); + + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (y=0; y < CANVAS_HEIGHT; y++) { + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + colour = (int) new_intensity_value(p); + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + + +void evolve_paint() +{ + int k; + POINT p; + CELL_PTR cell; + int new_x, new_y; + extern int count; + + /*count++; + if (count > 500) { + fprintf(stderr,"."); + fflush(stderr); + bump_map(); + }*/ + + for (k=0; k < STEP_LIMIT; k++) single_step(); + while (TRUE) { + next_cell_for_tqrepaint(&cell, &p); + if (cell == NIL) return; + paint_cell(cell, p.x, p.y); + glFlush(); + } + + +} + +void StartVolumeWindow() +{ +} + +void StartDrynessWindow() +{ +} + +void StartWindows() +{ + + + draw_full_canvas(); + compute_shade_vectors(); /* Set vectors for shading */ + draw_labels(); + + /*auxIdleFunc(evolve_paint); + + auxMainLoop(draw_full_canvas);*/ + + +} + +void +stroke() +{ + +} + + +void +stroke_motion() +{ + +} + diff --git a/chalk/colorspaces/wetsticky/ws/test2.jpg b/chalk/colorspaces/wetsticky/ws/test2.jpg new file mode 100644 index 00000000..4254264f Binary files /dev/null and b/chalk/colorspaces/wetsticky/ws/test2.jpg differ diff --git a/chalk/colorspaces/wetsticky/ws/test3.jpg b/chalk/colorspaces/wetsticky/ws/test3.jpg new file mode 100644 index 00000000..2b25a0d5 Binary files /dev/null and b/chalk/colorspaces/wetsticky/ws/test3.jpg differ diff --git a/chalk/colorspaces/wetsticky/ws/types.h b/chalk/colorspaces/wetsticky/ws/types.h new file mode 100644 index 00000000..af671f53 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/types.h @@ -0,0 +1,72 @@ +/* + FILE: types.h + PURPOSE: Defines all the main types used in Wet&Sticky. + AUTHORS: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + + +*/ + + +/* A colour is specified as a vector in HLS space. Hue is a value + in the range 0..360 degrees with 0 degrees being red. Saturation + and Lightness are both in the range [0,1]. A lightness of 0 means + black, with 1 being white. A totally saturated colour has saturation + of 1. +*/ + +typedef struct hls_colour { short int hue; float saturation, lightness; } +HLS_COLOUR; + +typedef struct rgb_colour {float r; float g; float b;} +RGB_COLOUR; + + +/* The address of a cell on the canvas. */ + +typedef struct point { int x, y; } POINT, *POINT_PTR; + + +/* A direction can be NORTH, EAST, SOUTH or WEST. */ + +typedef short int DIRECTION; + +typedef short int BOOLEAN; /* FALSE or TRUE */ + + +typedef struct paint { + HLS_COLOUR colour; + int liquid_content; /* [0,100]. */ + int drying_rate; /* [0,100]. */ + int miscibility; /* [0,inf]. */ +} PAINT, *PAINT_PTR; + + +/* Defines the strength and direction of gravity for a cell. */ + +typedef struct gravity { + DIRECTION direction; + int strength; /* [0,Infinity). */ +} GRAVITY, *GRAVITY_PTR; + + +/* Defines the contents and attributes of a cell on the canvas. */ + +typedef struct cell { + PAINT contents; /* The paint in this cell. */ + GRAVITY gravity; /* This cell's gravity. */ + short int absorbancy; /* How much paint can this cell hold? */ + short int volume; /* The volume of paint. */ +} CELL, *CELL_PTR; diff --git a/chalk/colorspaces/wetsticky/ws/win_interface.h b/chalk/colorspaces/wetsticky/ws/win_interface.h new file mode 100644 index 00000000..ee7a064b --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/win_interface.h @@ -0,0 +1,28 @@ +/* +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + + +*/ + +extern void DrawPoint(/* int x, int y; int colour*/); +extern int DrawVolumePoint(/* int x, int y; int attr*/); +extern int DrawDrynessPoint(/* int x, int y; int attr*/); +extern void ClearWindow(); +extern void CreateWindows(/* int *argc, char *argv[], int width, int height*/); +extern void StartWindows(); /* enter infinite loop */ +extern void StartVolumeWindow(/*int width, int height*/); + /* display attribute window */ +extern void StartDrynessWindow(/*int width, int height*/); + /* display attribute window */ + + diff --git a/chalk/colorspaces/wetsticky/ws/x_interface.c b/chalk/colorspaces/wetsticky/ws/x_interface.c new file mode 100644 index 00000000..a8b54b3e --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/x_interface.c @@ -0,0 +1,795 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. +Contact David England d.england@livjm.ac.uk +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. Wet and Sticky is distributed in the +hope that it will be useful, but WITHOUT ANY WARRANTY; without even +the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. You +should have received a copy of the GNU General Public License along +with Wet and Sticky; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm; + +static Widget volume_shell; +static Widget volume_box; +static Widget volume_canvas; +static Pixmap volume_pm; + +static Widget dryness_shell; +static Widget dryness_box; +static Widget dryness_canvas; +static Pixmap dryness_pm; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +static Colormap cmap; +static XColor colours[256]; +void stroke(); +void stroke_motion(); + +Display *display; +int screen; +Screen *screen_ptr; +Window root; + +static int count=0; +static int frame_count=0; +char pix_file[64]; + +static void +expose_event(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the colour window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + +} + + +static void +expose_volume(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the volume window if an exposure event is received */ +int width, height; + + width = 300; + height = 300; + + XCopyArea(XtDisplay(volume_canvas), volume_pm, + XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0); + + +} + +static void +expose_dryness(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the dryness window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + +} + +void expose_canvases() +{ +int width, height; + +width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, 300, 300, 0,0); + +} + +int +GetHueValue(red, green, blue) +int red; +int green; +int blue; +{ + XColor colour; + + colour.red = red * 257; + colour.green = green * 257; + colour.blue = blue * 257; + colour.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(display, cmap, &colour) == 0) + fprintf(stderr,"colour allocation failed\n"); + + return (colour.pixel); +} + + +void +DrawPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* PROBS ? */ + + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + +void +DrawBackgroundPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* PROBS ? */ + + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + + +int +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + +int +DrawBackgroundVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + + +int +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the dryness to affect the colour + value + */ + + if (XtWindow(dryness_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + +/* XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y); +*/ + XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y); + + return(0); +} + +void +ClearWindow() +{ + XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas)); +} + +static void +CleanWindow(win) +Drawable win; +/* Fill a window with a solid, white rectangle */ +{ +XGCValues values; +long tqmask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, tqmask, &values); + + XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300); + +} + +void SetupCmap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[i].flags = DoRed | DoBlue | DoGreen; + } + + /* for (i=0;i<=127;i++) + colours[i].green = i*2*257; + + for (i=128;i>0;i--) + colours[255-i].green = (i-1)*2*257;*/ + + for (i=0;i<64;i++) + colours[i].green = i*4*257; + + for (i=64;i<128;i++) + colours[i].green = 65536-i*4*257; + + for (i=128;i<192;i++) + colours[i].green = (i-128)*2*257; + + for (i=192;i<255;i++) + colours[i].green = 65536-(i-128)*2*257; + + + for (i=0;i<256;i++) + colours[i].blue = 65536 - i*257; + + colours[0].red = 65535; + colours[0].green = 65535; + colours[0].blue = 65535; +} + +void +SetupGreyMap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[255 - i].flags = DoRed | DoBlue | DoGreen; + } + + + for (i=0;i<256;i++) + colours[i].green = i*257; + + for (i=0;i<256;i++) + colours[i].blue = i*257; + + colours[255].red = 255*257; + colours[255].green = 255*257; + colours[255].blue = 255*257; + +} + + +void CreateWindows(argc, argv, width, height) +int *argc; +char **argv; +int width; +int height; +/* Create colour window heirarchy and add event handlers */ +{ + + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + int i; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, argc, argv); + + + display = XtDisplay(top_level); + screen = DefaultScreen(display); + screen_ptr = ScreenOfDisplay(display, DefaultScreen(display)); + + root = RootWindow(display, screen); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0); + + XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0); + + XtAddEventHandler(colour_canvas, Button1MotionMask, + False, stroke_motion, 0); + + XtRealizeWidget(colour_shell); + + cmap = XCreateColormap( display, XtWindow(colour_shell), + XDefaultVisualOfScreen(screen_ptr), AllocAll); + + for (i=0; i <= 255; i++) + colours[i].pixel = i; + + XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256); + + SetupCmap(); + + /*SetupGreyMap();*/ + + XStoreColors(display, cmap, colours, 256); + + i=0; + while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr), + True, NULL, 0, &colours[i].pixel, 1 ) ) { + colours[i].pixel = i; + i++; + } + + XSetWindowColormap(display, XtWindow(colour_shell), cmap); + + XInstallColormap(display, cmap); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + colour_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(colour_pm); + +} + + +void StartVolumeWindow(width, height) +int width; +int height; +/* Create Volume heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + volume_shell = XtCreateApplicationShell("volume_frame", + topLevelShellWidgetClass, NULL, 0); + + volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass, + volume_shell, NULL, 0); + + volume_canvas = XtCreateManagedWidget("", labelWidgetClass, + volume_box, args, XtNumber(args)); + + XtAddEventHandler(volume_canvas, ExposureMask, False, + expose_volume, 0); + + XtRealizeWidget(volume_shell); + + XSetWindowColormap(display, XtWindow(volume_shell), cmap); + + volume_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(volume_pm); + + +} + +void StartDrynessWindow(width, height) +int width; +int height; +/* Create dryness heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + char name[32]; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + dryness_shell = XtCreateApplicationShell("dryness_frame", + topLevelShellWidgetClass, NULL, 0); + + dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass, + dryness_shell, NULL, 0); + dryness_canvas = XtCreateManagedWidget("Name", labelWidgetClass, + dryness_box, args, XtNumber(args)); + + fprintf(stderr,"Bumps %d\n",(int)dryness_canvas); + + XtAddEventHandler(dryness_canvas, ExposureMask, False, + expose_dryness, 0); + + XtRealizeWidget(dryness_shell); + + XSetWindowColormap(display, XtWindow(dryness_shell), cmap); + + dryness_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + XStoreName(display, XtWindow(dryness_shell), "bumps"); + + CleanWindow(dryness_pm); + +} + +static void +draw_labels() +{ + XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10, + "Colour", strlen("Colour")); + XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10, + "Colour", strlen("Colour")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10, + "Volume", strlen("Volume")); + XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10, + "Volume", strlen("Volume")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10, + "Bump Map", strlen("Bump Map")); + XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10, + "Bump Map", strlen("Bump Map")); +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + int colour, volColour, dryness; + POINT p; + + p.x = x; + p.y = y; + + /* The current display simply maps hue onto the indices of the colour + table. This involves some scaling since hues are in the range [0,360) + with the colour table being [0,256). */ + + colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0)); + + DrawBackgroundPoint(x,y,colour); + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */ + + volColour = MIN(cell->volume * 2, 255); + volColour = MAX(volColour, 0); + /* Make unfilled cells have a zero vol. */ + + DrawBackgroundVolumePoint(x,y,volColour); + + /* Dryness will be in the range [0,255]. */ + dryness = (cell->contents.liquid_content * 255) / 100; + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + +void draw_false_colour_scale() +/* This routine places a scale along the top of the volume window + showing the colours being used. Low is at the left edge. + The colour palette has indices 0..255. */ +{ + int x, y; + + /*for (x=0; x < 255; x++) + for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/ +} + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (y=0; y < CANVAS_HEIGHT; y++) + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + paint_cell(cell, x, y); + } + + expose_canvases(); + + draw_false_colour_scale(); + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (y=0; y < CANVAS_HEIGHT; y++) { + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + colour = (int) new_intensity_value(p); + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + +draw_cmap_line() + +{ + +int i; + + for (i=0; i< 255; i++) { + DrawDrynessPoint(0,i,i); + } +} + +void evolve_paint() +{ + int k; + POINT p; + CELL_PTR cell; + int new_x, new_y; + Window tempChild; + extern Window root; + extern int count; + extern int frame_count; + + count++; + if (count > 5000) { + fprintf(stderr,"."); + fflush(stderr); + bump_map(); + expose_canvases(); + + /*XTranslateCoordinates(display,XtWindow(dryness_canvas), root, + 0,0, &new_x, &new_y, &tempChild);*/ + /*if (frame_count < 10) + sprintf(pix_file,"xwd -name bumps -out pixmap0%d.xwd &" ,frame_count); + else + sprintf(pix_file,"xwd -name bumps -out pixmap%d.xwd &" ,frame_count); + */ + + + /*system(pix_file);*/ + /*XWriteBitmapFile(display, pix_file,dryness_pm, 300, 300,-1,-1 );*/ + count = 0; + frame_count++; + /*if (frame_count > 250) { + fprintf(stderr,"Done\n"); + sleep(2); + exit(0); + } */ + /*exit(0)*/; + } + + + + for (k=0; k < STEP_LIMIT; k++) single_step(); + while (TRUE) { + next_cell_for_tqrepaint(&cell, &p); + if (cell == NIL) return; + paint_cell(cell, p.x, p.y); + } + +} + + + +void StartWindows() +{ +/* Start the X windows event loop and paint processing */ +XEvent event; + + + draw_full_canvas(); + compute_shade_vectors(); /* Set vectors for shading */ + draw_labels(); + + for (;;) { + if (XtPending()) { + XtNextEvent(&event); + XtDispatchEvent(&event); + } + else { + /* Evolve paint and re-display*/ + evolve_paint(); + } + + } /* End for loop */ + + +} + +void +stroke(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ +/* brush_stroke(event->xbutton.x, event->xbutton.y);*/ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + +/* DrawPoint(event->xbutton.x, event->xbutton.y, 128); + DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128); + DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + brush_stroke(event->xbutton.x, event->xbutton.y); +} + + +void +stroke_motion(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + brush_stroke(event->xbutton.x, event->xbutton.y); +} + diff --git a/chalk/colorspaces/wetsticky/wstool.ui b/chalk/colorspaces/wetsticky/wstool.ui new file mode 100644 index 00000000..2f95d18b --- /dev/null +++ b/chalk/colorspaces/wetsticky/wstool.ui @@ -0,0 +1,262 @@ + +WdgWSPaintOp + + + WdgWSPaintOp + + + + 0 + 0 + 582 + 359 + + + + + unnamed + + + + grpGravity + + + &Gravity + + + + unnamed + + + + chkGravity + + + Paint &gravity + + + + + lblDirection + + + Direction: + + + intDryingRate + + + + + + Up + + + + + Right + + + + + Down + + + + + Left + + + + cmbGravitationalDirection + + + + + lblStrength + + + &Strength: + + + intGravitationalStrength + + + + + intGravitationalStrength + + + 0 + + + + + + + grpPaint + + + &Paint + + + + unnamed + + + + lblDryingRate + + + &Drying rate: + + + intDryingRate + + + + + chkLiquid + + + &Liquid content: + + + true + + + + + intDryingRate + + + 0 + + + 100 + + + + + intMiscibility + + + + + intLiquidContent + + + 0 + + + 100 + + + + + lblMiscibility + + + &Miscibility: + + + intMiscibility + + + + + + + grpSubstrate + + + &Canvas + + + + unnamed + + + + intHeight + + + + + lblHeight + + + &Height: + + + intHeight + + + + + intAbsorbency + + + 0 + + + 100 + + + + + lblAbsorbency + + + &Absorbency: + + + intAbsorbency + + + + + lblColor + + + &Color: + + + bnCanvasColor + + + + + chkCanvas + + + Paint canvas attributes + + + + + + + + bnCanvasColor + + + + + + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/colorspaces/ycbcr_u16/Makefile.am b/chalk/colorspaces/ycbcr_u16/Makefile.am new file mode 100644 index 00000000..d2e0aca3 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/Makefile.am @@ -0,0 +1,27 @@ +# Install the desktop file needed to detect the plugin +kde_services_DATA = chalk_ycbcr_u16_plugin.desktop + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalk_ycbcr_u16.la + +libchalk_ycbcr_u16_la_LDFLAGS = $(all_libraries) +libchalk_ycbcr_u16_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_ycbcr_u16_plugin.la + +# Srcs for the plugin +chalk_ycbcr_u16_plugin_la_SOURCES = ycbcr_u16_plugin.cc +noinst_HEADERS = ycbcr_u16_plugin.h kis_ycbcr_u16_colorspace.h + +chalk_ycbcr_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_ycbcr_u16_plugin_la_LIBADD = libchalk_ycbcr_u16.la ../../chalkcolor/libchalkcolor.la + +METASOURCES = AUTO + +libchalk_ycbcr_u16_la_SOURCES = kis_ycbcr_u16_colorspace.cc diff --git a/chalk/colorspaces/ycbcr_u16/chalk_ycbcr_u16_plugin.desktop b/chalk/colorspaces/ycbcr_u16/chalk_ycbcr_u16_plugin.desktop new file mode 100644 index 00000000..eaa0c2a1 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/chalk_ycbcr_u16_plugin.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Name=YCbCr Color Model (16-bit integer) +Name[bg]=Цветови модел YCbCr (16 бита) +Name[ca]=Model de color YCbCr (enters de 16 bits) +Name[da]=YCbCr-farvemodel (16-bit heltal) +Name[de]=YCbCr-Farbmodell (16-bit Ganzzahl) +Name[el]=Χρωματικό μοντέλο YCbCr (16-bit ακέραιοι) +Name[eo]=YCbCr-Kolormodelo (16-bita entjero) +Name[es]=Modelo de color YCbCr (entero de 16 bits) +Name[et]=YCbCr värvimudel (16-bitine täisarv) +Name[fa]=مدل رنگ YCbCr )عدد صحیح ۱۶ بیتی( +Name[fr]=Modèle de couleurs YCbCr (entiers 16 bits) +Name[fy]=YCbCr-kleurmodel (16-bit integer) +Name[gl]=Modelo de Cores YCbCr (inteiro de 16-bit) +Name[hu]=YCbCr színmodell (16 bites egész) +Name[it]=Modello di colore YCbCr (intero a 16 bit) +Name[ja]=YCbCr カラーモデル (16 ビット整数) +Name[km]=គំរូ​ពណ៌ CMYK (ចំនួន​គត់ ១៦ ប៊ីត) +Name[lt]=YCbCr spalvų modelis (16-bitų sveikasis) +Name[nb]=YCbCr-fargemodell (16-bit heltall) +Name[nds]=YCbCr-Klöörmodell (16-Bit Heeltall) +Name[ne]=वाईसी ी ी आर रङ मोडेल (१६-बिट इन्टिजर) +Name[nl]=YCbCr-kleurmodel (16-bit integer) +Name[pl]=Przestrzeń barw YCbCr (16-bitowa liczbowa całkowita) +Name[pt]=Modelo de Cor YCbCr (inteiros de 16 bits) +Name[pt_BR]=Modelo de Cor YCbCr (inteiros de 16 bits) +Name[ru]=YCbCr (целое 16-бит) +Name[sk]=Model farieb YCbCr (16-biové čísla) +Name[sl]=Barvni model YCbCr (16-bitno celo število) +Name[sr]=YCbCr модел боја (16-битно целобројно) +Name[sr@Latn]=YCbCr model boja (16-bitno celobrojno) +Name[sv]=YCbCr-färgmodell (16-bitars heltal) +Name[uk]=Модель кольорів YCbCr (16-бітне ціле) +Name[uz]=YCbCr rang usuli (16-bit butun) +Name[uz@cyrillic]=YCbCr ранг усули (16-бит бутун) +Name[zh_TW]=YCbCr 色彩模型 (16-bit 整數) +Comment=Color model for 16-bit integer per channel YCbCr images +Comment[bg]=Цветови модел за 16 битови YCbCr изображения +Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges YCbCr +Comment[da]=Farvemodel for 16-bit heltal pr kanal YCbCr-billeder +Comment[de]=Farbmodell für 16-bit pro Kanal YCbCr-Bilder +Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι YCbCr εικόνες +Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes YCbCr +Comment[et]=16-bitiste täisarvuliste kanalitega YCbCr-piltide värvimudel +Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی برای هر تصویر YCbCr مجرا +Comment[fr]=Modèle de couleurs pour des images YCbCr à 16 bits par canal +Comment[fy]=Kleurmodel foar16-bit/kanaal fan YCbCr-ôfbyldings +Comment[gl]=Modelo de Cores para imaxes YCbCr de inteiro de 16-bit por canal +Comment[hu]=Színmodell 16 bit/csatorna YCbCr képekhez +Comment[it]=Modello di colore per immagini YCbCr a canale di 16 bit interi +Comment[ja]=16 ビット整数/チャンネル YCbCr 画像のためのカラーモデル +Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព CMYK ចំនួនគត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល +Comment[nb]=Fargemodell for YCbCr-bilder med 16-bit heltall per kanal +Comment[nds]=Klöörmodell för YCbCr-Biller mit 16-Bit Heeltall pro Kanaal +Comment[ne]=प्रति च्यानल वाईसीबीसीआर छविहरूको १६-बिट इन्टिजरका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 16-bit/kanaal van YCbCr-afbeeldingen +Comment[pl]=Przestrzeń barw dla obrazków YCbCr z 16-bitowymi liczbami całkowitymi na kanał +Comment[pt]=Modelo de cor para imagens YCbCr com 16 bits por canal +Comment[pt_BR]=Modelo de cor para imagens YCbCr com 16 bits por canal +Comment[ru]=Цветовое пространство YCbCr (целое 16-бит/канал) +Comment[sk]=Model farieb pre YCbCr obrázky so 16 bitmi na kanál +Comment[sl]=Barvni model za slike YCbCr s 16 biti/kanal +Comment[sr]=Модел боја за YCbCr слике, 16-битно целобројно по каналу +Comment[sr@Latn]=Model boja za YCbCr slike, 16-bitno celobrojno po kanalu +Comment[sv]=Färgmodell för YCbCr-bilder med 16-bitars heltal per kanal +Comment[uk]=Модель кольорів для зображень YCbCr з цілим 16-біт/канал +Comment[zh_TW]=每色頻為 16-bit 的 YCbCr 圖片色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_ycbcr_u16_plugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc b/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc new file mode 100644 index 00000000..d8ea896b --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_ycbcr_u16_colorspace.h" + +#include + +#include + +const TQ_INT32 MAX_CHANNEL_YCbCr = 3; +const TQ_INT32 MAX_CHANNEL_YCbCrA = 4; + +KisYCbCrU16ColorSpace::KisYCbCrU16ColorSpace(KisColorSpaceFactoryRegistry* tqparent, KisProfile* /*p*/) + : KisU16BaseColorSpace(KisID("YCbCrAU16", i18n("YCbCr (16-bit integer/channel)")), TYPE_YCbCr_16, icSigYCbCrData, tqparent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16))); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16); + KisAbstractColorSpace::init(); +} + + +KisYCbCrU16ColorSpace::~KisYCbCrU16ColorSpace() +{ +} + +void KisYCbCrU16ColorSpace::setPixel(TQ_UINT8 *dst, TQ_UINT16 Y, TQ_UINT16 Cb, TQ_UINT16 Cr, TQ_UINT16 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->Y = Y; + dstPixel->Cb = Cb; + dstPixel->Cr = Cr; + dstPixel->alpha = alpha; +} + +void KisYCbCrU16ColorSpace::getPixel(const TQ_UINT8 *src, TQ_UINT16 *Y, TQ_UINT16 *Cb, TQ_UINT16 *Cr, TQ_UINT16 *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *Y = srcPixel->Y; + *Cb = srcPixel->Cb; + *Cr = srcPixel->Cr; + *alpha = srcPixel->alpha; + +} + +void KisYCbCrU16ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU16BaseColorSpace::fromTQColor(c, dstU8, profile); + } else { + Pixel *dst = reinterpret_cast(dstU8); + dst->Y = computeY( c.red(), c.green(), c.blue()); + dst->Cb = computeCb( c.red(), c.green(), c.blue()); + dst->Cr = computeCr( c.red(), c.green(), c.blue()); + } +} + +void KisYCbCrU16ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU16BaseColorSpace::fromTQColor(c, opacity, dstU8, profile); + } else { + Pixel *dst = reinterpret_cast(dstU8); + dst->Y = computeY( c.red(), c.green(), c.blue()); + dst->Cb = computeCb( c.red(), c.green(), c.blue()); + dst->Cr = computeCr( c.red(), c.green(), c.blue()); + dst->alpha = opacity; + } +} + +void KisYCbCrU16ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile * profile) +{ + if(getProfile()) + { + KisU16BaseColorSpace::toTQColor(srcU8, c, profile); + + } else { + const Pixel *src = reinterpret_cast(srcU8); + c->setRgb(computeRed(src->Y,src->Cb,src->Cr) >> 8, computeGreen(src->Y,src->Cb,src->Cr) >> 8, computeBlue(src->Y,src->Cb,src->Cr) >> 8); + } +} + +void KisYCbCrU16ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile) +{ + if(getProfile()) + { + KisU16BaseColorSpace::toTQColor(srcU8, c, opacity, profile); + } else { + const Pixel *src = reinterpret_cast(srcU8); + c->setRgb(computeRed(src->Y,src->Cb,src->Cr) >> 8, computeGreen(src->Y,src->Cb,src->Cr) >> 8, computeBlue(src->Y,src->Cb,src->Cr) >> 8); + *opacity = src->alpha; + } +} + +TQ_UINT8 KisYCbCrU16ColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8) +{ + if(getProfile()) + return KisU16BaseColorSpace::difference(src1U8, src2U8); + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return TQMAX(TQABS(src2->Y - src1->Y), TQMAX(TQABS(src2->Cb - src1->Cb), TQABS(src2->Cr - src1->Cr))) >> 8; + +} + +void KisYCbCrU16ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT16 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + TQ_UINT16 alpha = pixel->alpha; + float alphaTimesWeight = alpha * *weights; + + totalY += (TQ_UINT16)(pixel->Y * alphaTimesWeight); + totalCb += (TQ_UINT16)(pixel->Cb * alphaTimesWeight); + totalCr += (TQ_UINT16)(pixel->Cr * alphaTimesWeight); + newAlpha += (TQ_UINT16)(alphaTimesWeight); + + weights++; + colors++; + } + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > 0) { + totalY = totalY / newAlpha; + totalCb = totalCb / newAlpha; + totalCr = totalCr / newAlpha; + } + + dstPixel->Y = totalY; + dstPixel->Cb = totalCb; + dstPixel->Cr = totalCr; +} + +TQValueVector KisYCbCrU16ColorSpace::channels() const { + return m_channels; +} + +TQ_UINT32 KisYCbCrU16ColorSpace::nChannels() const { + return MAX_CHANNEL_YCbCrA; +} + +TQ_UINT32 KisYCbCrU16ColorSpace::nColorChannels() const { + return MAX_CHANNEL_YCbCr; +} + +TQ_UINT32 KisYCbCrU16ColorSpace::pixelSize() const { + return MAX_CHANNEL_YCbCrA * sizeof(TQ_UINT16); +} + + +TQImage KisYCbCrU16ColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, KisProfile * dstProfile, TQ_INT32 renderingIntent, float exposure ) +{ + if(getProfile()) + return KisU16BaseColorSpace::convertToTQImage( data, width, height, dstProfile, renderingIntent, exposure); + + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + while ( i < width * height * MAX_CHANNEL_YCbCrA) { + TQ_UINT16 Y = *( data + i + PIXEL_Y ); + TQ_UINT16 Cb = *( data + i + PIXEL_Cb ); + TQ_UINT16 Cr = *( data + i + PIXEL_Cr ); + *( j + 3) = *( data + i + PIXEL_ALPHA ) >> 8; + *( j + 2 ) = computeRed(Y,Cb,Cr) >> 8; + *( j + 1 ) = computeGreen(Y,Cb,Cr) >> 8; + *( j + 0 ) = computeBlue(Y,Cb,Cr) >> 8; + i += MAX_CHANNEL_YCbCrA; + j += 4; + } + return img; +} + + +void KisYCbCrU16ColorSpace::bitBlt(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *srcAlphaMask, TQ_INT32 tqmaskRowStride, TQ_UINT8 opacity, TQ_INT32 rows, TQ_INT32 cols, const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +void KisYCbCrU16ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT16 *src = reinterpret_cast(srcRowStart); + TQ_UINT16 *dst = reinterpret_cast(dstRowStart); + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + + if (srcAlpha != U16_OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT16_MULT(srcAlpha, opacity); + } + + if (srcAlpha == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(TQ_UINT16)); + } else { + TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT16 srcBlend; + + if (dstAlpha == U16_OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == U16_OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_YCbCr * sizeof(TQ_UINT16)); + } else { + dst[PIXEL_Y] = UINT16_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend); + dst[PIXEL_Cb] = UINT16_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend); + dst[PIXEL_Cr] = UINT16_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_YCbCrA; + dst += MAX_CHANNEL_YCbCrA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +void KisYCbCrU16ColorSpace::compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowSize, const TQ_UINT8 *src, TQ_INT32 srcRowSize, const TQ_UINT8 *srcAlphaMask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 cols, TQ_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT16 srcAlpha = s->alpha; + + // apply the alphatqmask + if (tqmask != 0) { + TQ_UINT8 U8_tqmask = *tqmask; + + if (U8_tqmask != OPACITY_OPAQUE) { + srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask)); + } + tqmask++; + } + d->alpha = UINT16_MULT(srcAlpha, d->alpha); + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +KisCompositeOpList KisYCbCrU16ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + return list; +} diff --git a/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h b/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h new file mode 100644 index 00000000..69c499f2 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_YCBCR_U16_COLORSPACE_H +#define KIS_YCBCR_U16_COLORSPACE_H + +#include + +#include + +#define LUMA_RED 0.2989 +#define LUMA_GREEN 0.587 +#define LUMA_BLUE 0.114 + +class KisYCbCrU16ColorSpace : public KisU16BaseColorSpace +{ + public: + KisYCbCrU16ColorSpace(KisColorSpaceFactoryRegistry* tqparent, KisProfile* p); + ~KisYCbCrU16ColorSpace(); + virtual bool willDegrade(ColorSpaceIndependence ) + { + return false; + }; + public: + void setPixel(TQ_UINT8 *pixel, TQ_UINT16 Y, TQ_UINT16 Cb, TQ_UINT16 Cr, TQ_UINT16 alpha) const; + void getPixel(const TQ_UINT8 *pixel, TQ_UINT16 *Y, TQ_UINT16 *Cb, TQ_UINT16 *Cr, TQ_UINT16 *alpha) const; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + + private: +#define CLAMP_TO_16BITCHANNEL(a) CLAMP(a, 0, TQ_UINT16_MAX) + inline TQ_UINT16 computeRed(TQ_UINT16 Y, TQ_UINT16 /*Cb*/, TQ_UINT16 Cr) + { + return (TQ_UINT16)( CLAMP_TO_16BITCHANNEL( (Cr - 32768)* (2-2*LUMA_RED) + Y ) ); + } + inline TQ_UINT16 computeGreen(TQ_UINT16 Y, TQ_UINT16 Cb, TQ_UINT16 Cr) + { + return (TQ_UINT16)( CLAMP_TO_16BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) ); + } + inline TQ_UINT16 computeBlue(TQ_UINT16 Y, TQ_UINT16 Cb, TQ_UINT16 /*Cr*/) + { + return (TQ_UINT16)( CLAMP_TO_16BITCHANNEL( (Cb - 32768)*(2 - 2 * LUMA_BLUE) + Y) ); + } + inline TQ_UINT16 computeY( TQ_UINT16 r, TQ_UINT16 b, TQ_UINT16 g) + { + return (TQ_UINT16)( CLAMP_TO_16BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) ); + } + inline TQ_UINT16 computeCb( TQ_UINT16 r, TQ_UINT16 b, TQ_UINT16 g) + { + return (TQ_UINT16)( CLAMP_TO_16BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 32768) ); + } + inline TQ_UINT16 computeCr( TQ_UINT16 r, TQ_UINT16 b, TQ_UINT16 g) + { + return (TQ_UINT8)( CLAMP_TO_16BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 32768) ); + } +#undef CLAMP_TO_16BITCHANNEL + + static const TQ_UINT8 PIXEL_Y = 0; + static const TQ_UINT8 PIXEL_Cb = 1; + static const TQ_UINT8 PIXEL_Cr = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + TQ_UINT16 Y; + TQ_UINT16 Cb; + TQ_UINT16 Cr; + TQ_UINT16 alpha; + }; +}; + +class KisYCbCrU16ColorSpaceFactory : public KisColorSpaceFactory +{ + public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("YCbCrAU16", i18n("YCbCr (16-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_YCbCr_16; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisYCbCrU16ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return ""; }; +}; + + +#endif diff --git a/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc b/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc new file mode 100644 index 00000000..d948097b --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc @@ -0,0 +1,60 @@ +/* + * ycbcr_u16_plugin.cc -- Part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include "ycbcr_u16_plugin.h" +#include "kis_ycbcr_u16_colorspace.h" + +typedef KGenericFactory YCbCrU16PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_ycbcr_u16_plugin, YCbCrU16PluginFactory( "chalk" ) ) + + +YCbCrU16Plugin::YCbCrU16Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(YCbCrU16PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceYCbCrU16 = new KisYCbCrU16ColorSpace(f, 0); + KisColorSpaceFactory * csf = new KisYCbCrU16ColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceYCbCrU16); + f->add(csf); + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("YCbCr16HISTO", i18n("YCbCr16")), colorSpaceYCbCrU16) ); + } + +} + +YCbCrU16Plugin::~YCbCrU16Plugin() +{ +} + +#include "ycbcr_u16_plugin.moc" diff --git a/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h b/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h new file mode 100644 index 00000000..ceb8ec6f --- /dev/null +++ b/chalk/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef YCBCR_U16_PLUGIN_H_ +#define YCBCR_U16_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the YCbCr U16 colour space strategy. + */ +class YCbCrU16Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + YCbCrU16Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~YCbCrU16Plugin(); + +}; + + +#endif // YCBCR_U16_PLUGIN_H_ diff --git a/chalk/colorspaces/ycbcr_u8/Makefile.am b/chalk/colorspaces/ycbcr_u8/Makefile.am new file mode 100644 index 00000000..67f7933a --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/Makefile.am @@ -0,0 +1,29 @@ +# Install the desktop file needed to detect the plugin + + +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../chalkcolor/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalk_ycbcr_u8.la + +libchalk_ycbcr_u8_la_LDFLAGS = $(all_libraries) +libchalk_ycbcr_u8_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalk_ycbcr_u8_plugin.la + +# Srcs for the plugin +chalk_ycbcr_u8_plugin_la_SOURCES = ycbcr_u8_plugin.cc +noinst_HEADERS = ycbcr_u8_plugin.h kis_ycbcr_u8_colorspace.h + +chalk_ycbcr_u8_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -llcms +chalk_ycbcr_u8_plugin_la_LIBADD = libchalk_ycbcr_u8.la ../../chalkcolor/libchalkcolor.la + +METASOURCES = AUTO + + +libchalk_ycbcr_u8_la_SOURCES = kis_ycbcr_u8_colorspace.cc +kde_services_DATA = chalk_ycbcr_u8_plugin.desktop diff --git a/chalk/colorspaces/ycbcr_u8/chalk_ycbcr_u8_plugin.desktop b/chalk/colorspaces/ycbcr_u8/chalk_ycbcr_u8_plugin.desktop new file mode 100644 index 00000000..6eafad7b --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/chalk_ycbcr_u8_plugin.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Name=YCbCr Color Model (8-bit integer) +Name[bg]=Цветови модел YCbCr (16 бита) +Name[ca]=Model de color YCbCr (enters de 16 bits) +Name[da]=YCbCr-farvemodel (8-bit heltal) +Name[de]=YCbCr-Farbmodell (8-bit Ganzzahl) +Name[el]=Χρωματικό μοντέλο YCbCr (16-bit ακέραιοι) +Name[eo]=YCbCr-Kolormodelo (8-bita entjero) +Name[es]=Modelo de color YCbCr (entero de 8 bits) +Name[et]=YCbCr värvimudel (8-bitine täisarv) +Name[fa]=مدل رنگ YCbCr )عدد صحیح ۸ بیتی( +Name[fr]=Modèle de couleurs YCbCr (entiers 8 bits) +Name[fy]=YCbCr-kleurmodel (8-bit integer) +Name[gl]=Modelo de Cores YCbCr (inteiro de 8-bit) +Name[hu]=YCbCr színmodell (8 bites egész) +Name[it]=Modello di colore YCbCr (intero a 8 bit) +Name[ja]=YCbCr カラーモデル (8 ビット整数) +Name[km]=គំរូ​ពណ៌ CMYK (ចំនួនគត់ ១៦ ប៊ីត) +Name[lt]=YCbCr spalvų modelis (8-bitų sveikasis) +Name[nb]=YCbCr fargemodell (8-bit heltall) +Name[nds]=YCbCr-Klöörmodell (8-Bit Heeltall) +Name[ne]=वाईसीबीसीआर रङ मोडेल (८-बिट इन्टिजर) +Name[nl]=YCbCr-kleurmodel (8-bit integer) +Name[pl]=Przestrzeń barw YCbCr (8-bitowa liczbowa całkowita) +Name[pt]=Modelo de Cor YCbCr (inteiros de 8 bits) +Name[pt_BR]=Modelo de Cor YCbCr (inteiros de 8 bits) +Name[ru]=YCbCr (целое 8-бит) +Name[sk]=Model farieb YCbCr (8-biové čísla) +Name[sl]=Barvni model YCbCr (8-bitno celo število) +Name[sr]=YCbCr модел боја (8-битно целобројно) +Name[sr@Latn]=YCbCr model boja (8-bitno celobrojno) +Name[sv]=YCbCr-färgmodell (8-bitars heltal) +Name[uk]=Модель кольорів YCbCr (ціле 8-біт) +Name[uz]=YCbCr rang usuli (8-bit butun) +Name[uz@cyrillic]=YCbCr ранг усули (8-бит бутун) +Name[zh_TW]=YCbCr 色彩模型 (16-bit 整數) +Comment=Color model for 8-bit integer per channel YCbCr images +Comment[bg]=Цветови модел за 16 битови YCbCr изображения +Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges YCbCr +Comment[da]=Farvemodel for 8-bit heltal pr kanal YCbCr-billeder +Comment[de]=Farbmodell für 8-bit pro Kanal YCbCr-Bilder +Comment[el]=Χρωματικό μοντέλο για 8-bit ακεραίους ανά κανάλι YCbCr εικόνες +Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes YCbCr +Comment[et]=8-bitiste täisarvuliste kanalitega YCbCr-piltide värvimudel +Comment[fa]=مدل رنگ برای عدد صحیح ۸ بیتی برای هر تصویر YCbCr مجرا +Comment[fr]=Modèle de couleurs pour des images YCbCr à 8 bits par canal +Comment[fy]=Kleurmodel foar 8-bit/kanaal fan YCbCr-ôfbyldings +Comment[gl]=Modelo de Cores para imaxes YCbCr de inteiro de 8-bit por canal +Comment[hu]=Színmodell 8 bit/csatorna YCbCr képekhez +Comment[it]=Modello di colore per immagini YCbCr a canale di 8 bit interi +Comment[ja]=8 ビット整数/チャンネル YCbCr 画像のためのカラーモデル +Comment[km]=ម៉ូដែល​ពណ៌​សម្រាប់​ចំនួន​គត់ 8-bit ក្នុង​ឆានែល​រូបភាព YCbCr +Comment[nb]=Fargemodell for YCbCr-bilder med 8 bit heltall per kanal +Comment[nds]=Klöörmodell för YCbCr-Biller mit 8-Bit Heeltall pro Kanaal +Comment[ne]=प्रति वाईसीबीसीआर छविहरूको ८-बिट इन्टिजरका लागि रङ मोडेल +Comment[nl]=Kleurmodel voor 8-bit/kanaal van YCbCr-afbeeldingen +Comment[pl]=Przestrzeń barw dla obrazków YCbCr z 8-bitowymi liczbami całkowitymi na kanał +Comment[pt]=Modelo de cor para imagens YCbCr com 8 bits por canal +Comment[pt_BR]=Modelo de cor para imagens YCbCr com 8 bits por canal +Comment[ru]=Цветовое пространство YCbCr (целое 8-бит/канал) +Comment[sk]=Model farieb pre YCbCr obrázky s 8 bitmi na kanál +Comment[sl]=Barvni model za slike YCbCr z 8 biti/kanal +Comment[sr]=Модел боја за YCbCr слике, 8-битно целобројно по каналу +Comment[sr@Latn]=Model boja za YCbCr slike, 8-bitno celobrojno po kanalu +Comment[sv]=Färgmodell för YCbCr-bilder med 8-bitars heltal per kanal +Comment[uk]=Модель кольорів для зображень YCbCr з цілим 8-біт/канал +Comment[zh_TW]=每色頻為 16-bit 的 YCbCr 圖片色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalk_ycbcr_u8_plugin +X-Chalk-Version=2 diff --git a/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc b/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc new file mode 100644 index 00000000..9c7548bf --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_ycbcr_u8_colorspace.h" + +#include + +#include + +const TQ_INT32 MAX_CHANNEL_YCbCr = 3; +const TQ_INT32 MAX_CHANNEL_YCbCrA = 4; + +KisYCbCrU8ColorSpace::KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* tqparent, KisProfile* /*p*/) + : KisU8BaseColorSpace(KisID("YCbCrAU8", i18n("YCbCr (8-bit integer/channel)")), TYPE_YCbCr_8, icSigYCbCrData, tqparent, 0) +{ + m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(TQ_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(TQ_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(TQ_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(TQ_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(TQ_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(TQ_UINT8))); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(TQ_UINT8), KisChannelInfo::ALPHA, KisChannelInfo::UINT8, sizeof(TQ_UINT8))); + + m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT8); + KisAbstractColorSpace::init(); +} + + +KisYCbCrU8ColorSpace::~KisYCbCrU8ColorSpace() +{ +} + +void KisYCbCrU8ColorSpace::setPixel(TQ_UINT8 *dst, TQ_UINT8 Y, TQ_UINT8 Cb, TQ_UINT8 Cr, TQ_UINT8 alpha) const +{ + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->Y = Y; + dstPixel->Cb = Cb; + dstPixel->Cr = Cr; + dstPixel->alpha = alpha; +} + +void KisYCbCrU8ColorSpace::getPixel(const TQ_UINT8 *src, TQ_UINT8 *Y, TQ_UINT8 *Cb, TQ_UINT8 *Cr, TQ_UINT8 *alpha) const +{ + const Pixel *srcPixel = reinterpret_cast(src); + + *Y = srcPixel->Y; + *Cb = srcPixel->Cb; + *Cr = srcPixel->Cr; + *alpha = srcPixel->alpha; + +} + +void KisYCbCrU8ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU8BaseColorSpace::fromTQColor(c, dstU8, profile); + } else { + Pixel *dst = reinterpret_cast(dstU8); + dst->Y = computeY( c.red(), c.green(), c.blue()); + dst->Cb = computeCb( c.red(), c.green(), c.blue()); + dst->Cr = computeCr( c.red(), c.green(), c.blue()); + } +} + +void KisYCbCrU8ColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dstU8, KisProfile * profile ) +{ + if(getProfile()) + { + KisU8BaseColorSpace::fromTQColor(c, opacity, dstU8, profile); + } else { + Pixel *dst = reinterpret_cast(dstU8); + dst->Y = computeY( c.red(), c.green(), c.blue()); + dst->Cb = computeCb( c.red(), c.green(), c.blue()); + dst->Cr = computeCr( c.red(), c.green(), c.blue()); + dst->alpha = opacity; + } +} + +void KisYCbCrU8ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, KisProfile * profile) +{ + if(getProfile()) + { + KisU8BaseColorSpace::toTQColor(srcU8, c, profile); + + } else { + const Pixel *src = reinterpret_cast(srcU8); + c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr)); + } +} + +void KisYCbCrU8ColorSpace::toTQColor(const TQ_UINT8 *srcU8, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile) +{ + if(getProfile()) + { + KisU8BaseColorSpace::toTQColor(srcU8, c, opacity, profile); + } else { + const Pixel *src = reinterpret_cast(srcU8); + c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr)); + *opacity = src->alpha; + } +} + +TQ_UINT8 KisYCbCrU8ColorSpace::difference(const TQ_UINT8 *src1U8, const TQ_UINT8 *src2U8) +{ + if(getProfile()) + return KisU8BaseColorSpace::difference(src1U8, src2U8); + const Pixel *src1 = reinterpret_cast(src1U8); + const Pixel *src2 = reinterpret_cast(src2U8); + + return TQMAX(TQABS(src2->Y - src1->Y), TQMAX(TQABS(src2->Cb - src1->Cb), TQABS(src2->Cr - src1->Cr))); + +} + +void KisYCbCrU8ColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ + TQ_UINT8 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0; + + while (nColors--) + { + const Pixel *pixel = reinterpret_cast(*colors); + + TQ_UINT8 alpha = pixel->alpha; + float alphaTimesWeight = alpha * *weights; + + totalY += (TQ_UINT8)(pixel->Y * alphaTimesWeight); + totalCb += (TQ_UINT8)(pixel->Cb * alphaTimesWeight); + totalCr += (TQ_UINT8)(pixel->Cr * alphaTimesWeight); + newAlpha += (TQ_UINT8)(alphaTimesWeight); + + weights++; + colors++; + } + + Pixel *dstPixel = reinterpret_cast(dst); + + dstPixel->alpha = newAlpha; + + if (newAlpha > 0) { + totalY = totalY / newAlpha; + totalCb = totalCb / newAlpha; + totalCr = totalCr / newAlpha; + } + + dstPixel->Y = totalY; + dstPixel->Cb = totalCb; + dstPixel->Cr = totalCr; +} + +TQValueVector KisYCbCrU8ColorSpace::channels() const { + return m_channels; +} + +TQ_UINT32 KisYCbCrU8ColorSpace::nChannels() const { + return MAX_CHANNEL_YCbCrA; +} + +TQ_UINT32 KisYCbCrU8ColorSpace::nColorChannels() const { + return MAX_CHANNEL_YCbCr; +} + +TQ_UINT32 KisYCbCrU8ColorSpace::pixelSize() const { + return MAX_CHANNEL_YCbCrA*sizeof(TQ_UINT8); +} + + +TQImage KisYCbCrU8ColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, KisProfile * dstProfile, TQ_INT32 renderingIntent, float exposure ) +{ + if(getProfile()) + return KisU8BaseColorSpace::convertToTQImage( data, width, height, dstProfile, renderingIntent, exposure); + + TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian); + img.setAlphaBuffer(true); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + while ( i < width * height * MAX_CHANNEL_YCbCrA) { + TQ_UINT8 Y = *( data + i + PIXEL_Y ); + TQ_UINT8 Cb = *( data + i + PIXEL_Cb ); + TQ_UINT8 Cr = *( data + i + PIXEL_Cr ); + *( j + 3) = *( data + i + PIXEL_ALPHA ); + *( j + 2 ) = computeRed(Y,Cb,Cr); + *( j + 1 ) = computeGreen(Y,Cb,Cr); + *( j + 0 ) = computeBlue(Y,Cb,Cr); + i += MAX_CHANNEL_YCbCrA; + j += 4; + } + return img; +} + + +void KisYCbCrU8ColorSpace::bitBlt(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *srcAlphaMask, TQ_INT32 tqmaskRowStride, TQ_UINT8 opacity, TQ_INT32 rows, TQ_INT32 cols, const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_ERASE: + compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity); + break; + default: + break; + } +} + +void KisYCbCrU8ColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + TQ_UINT8 srcAlpha = src[PIXEL_ALPHA]; + + // apply the alphatqmask + if (tqmask != 0) { + if (*tqmask != OPACITY_OPAQUE) { + srcAlpha *= *tqmask; + } + tqmask++; + } + + if (srcAlpha > OPACITY_TRANSPARENT) { + + if (opacity < OPACITY_OPAQUE) { + srcAlpha *= opacity; + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(TQ_UINT8)); + } else { + TQ_UINT8 dstAlpha = dst[PIXEL_ALPHA]; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE ) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + (OPACITY_OPAQUE - dstAlpha) * srcAlpha; + dst[PIXEL_ALPHA] = newAlpha; + + if (newAlpha > 0) { + srcBlend = srcAlpha / newAlpha; + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, MAX_CHANNEL_YCbCr * sizeof(TQ_UINT8)); + } else { + dst[PIXEL_Y] = UINT8_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend); + dst[PIXEL_Cb] = UINT8_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend); + dst[PIXEL_Cr] = UINT8_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend); + } + } + } + + columns--; + src += MAX_CHANNEL_YCbCrA; + dst += MAX_CHANNEL_YCbCrA; + } + + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + if(tqmaskRowStart) { + tqmaskRowStart += tqmaskRowStride; + } + } +} + +void KisYCbCrU8ColorSpace::compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowSize, const TQ_UINT8 *src, TQ_INT32 srcRowSize, const TQ_UINT8 *srcAlphaMask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 cols, TQ_UINT8 /*opacity*/) +{ + while (rows-- > 0) + { + const Pixel *s = reinterpret_cast(src); + Pixel *d = reinterpret_cast(dst); + const TQ_UINT8 *tqmask = srcAlphaMask; + + for (TQ_INT32 i = cols; i > 0; i--, s++, d++) + { + TQ_UINT8 srcAlpha = s -> alpha; + + // apply the alphatqmask + if (tqmask != 0) { + if (*tqmask != OPACITY_OPAQUE) { + srcAlpha = *tqmask; + } + tqmask++; + } + d -> alpha = srcAlpha * d -> alpha; + } + + dst += dstRowSize; + src += srcRowSize; + if(srcAlphaMask) { + srcAlphaMask += tqmaskRowStride; + } + } +} + +void KisYCbCrU8ColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 */*tqmask*/, TQ_INT32 /*tqmaskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 /*opacity*/) +{ + while (rows > 0) { + memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel)); + --rows; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + } +} + +KisCompositeOpList KisYCbCrU8ColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + return list; +} diff --git a/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h b/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h new file mode 100644 index 00000000..a0308881 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_YCBCR_U8_COLORSPACE_H +#define KIS_YCBCR_U8_COLORSPACE_H + +#include + +#include + +#define LUMA_RED 0.2989 +#define LUMA_GREEN 0.587 +#define LUMA_BLUE 0.114 + +class KisYCbCrU8ColorSpace : public KisU8BaseColorSpace +{ + public: + KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* tqparent, KisProfile* p); + ~KisYCbCrU8ColorSpace(); + virtual bool willDegrade(ColorSpaceIndependence ) + { + return false; + }; + public: + void setPixel(TQ_UINT8 *pixel, TQ_UINT8 Y, TQ_UINT8 Cb, TQ_UINT8 Cr, TQ_UINT8 alpha) const; + void getPixel(const TQ_UINT8 *pixel, TQ_UINT8 *Y, TQ_UINT8 *Cb, TQ_UINT8 *Cr, TQ_UINT8 *alpha) const; + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2); + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + + virtual TQValueVector channels() const; + virtual TQ_UINT32 nChannels() const; + virtual TQ_UINT32 nColorChannels() const; + virtual TQ_UINT32 pixelSize() const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * dstProfile, + TQ_INT32 renderingIntent, + float exposure = 0.0f); + + virtual KisCompositeOpList userVisiblecompositeOps() const; + + protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + + private: +#define CLAMP_TO_8BITCHANNEL(a) CLAMP(a, 0, TQ_UINT8_MAX) + inline TQ_UINT8 computeRed(TQ_UINT8 Y, TQ_UINT8 /*Cb*/, TQ_UINT8 Cr) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( (Cr - 128)* (2-2*LUMA_RED) + Y ) ); + } + inline TQ_UINT8 computeGreen(TQ_UINT8 Y, TQ_UINT8 Cb, TQ_UINT8 Cr) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) ); + } + inline TQ_UINT8 computeBlue(TQ_UINT8 Y, TQ_UINT8 Cb, TQ_UINT8 /*Cr*/) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( (Cb - 128)*(2 - 2 * LUMA_BLUE) + Y) ); + } + inline TQ_UINT8 computeY( TQ_UINT8 r, TQ_UINT8 b, TQ_UINT8 g) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) ); + } + inline TQ_UINT8 computeCb( TQ_UINT8 r, TQ_UINT8 b, TQ_UINT8 g) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 128) ); + } + inline TQ_UINT8 computeCr( TQ_UINT8 r, TQ_UINT8 b, TQ_UINT8 g) + { + return (TQ_UINT8)( CLAMP_TO_8BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 128) ); + } +#undef CLAMP_TO_8BITCHANNEL + + static const TQ_UINT8 PIXEL_Y = 0; + static const TQ_UINT8 PIXEL_Cb = 1; + static const TQ_UINT8 PIXEL_Cr = 2; + static const TQ_UINT8 PIXEL_ALPHA = 3; + + struct Pixel { + TQ_UINT8 Y; + TQ_UINT8 Cb; + TQ_UINT8 Cr; + TQ_UINT8 alpha; + }; +}; + +class KisYCbCrU8ColorSpaceFactory : public KisColorSpaceFactory +{ + public: + /** + * Chalk definition for use in .kra files and internally: unchanging name + + * i18n'able description. + */ + virtual KisID id() const { return KisID("YCbCrAU8", i18n("YCbCr (8-bit integer/channel)")); }; + + /** + * lcms colorspace type definition. + */ + virtual TQ_UINT32 colorSpaceType() { return TYPE_YCbCr_8; }; + + virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; }; + + virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisYCbCrU8ColorSpace(tqparent, p); }; + + virtual TQString defaultProfile() { return ""; }; +}; + +#endif diff --git a/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc b/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc new file mode 100644 index 00000000..d1d19c32 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc @@ -0,0 +1,62 @@ +/* + * ycbcr_u8_plugin.cc -- Part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "ycbcr_u8_plugin.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_ycbcr_u8_colorspace.h" + +typedef KGenericFactory YCbCrU8PluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalk_ycbcr_u8_plugin, YCbCrU8PluginFactory( "chalk" ) ) + + +YCbCrU8Plugin::YCbCrU8Plugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(YCbCrU8PluginFactory::instance()); + + if ( tqparent->inherits("KisColorSpaceFactoryRegistry") ) + { + KisColorSpaceFactoryRegistry * f = dynamic_cast( tqparent ); + + KisColorSpace * colorSpaceYCbCrU8 = new KisYCbCrU8ColorSpace(f, 0); + KisColorSpaceFactory * csf = new KisYCbCrU8ColorSpaceFactory(); + Q_CHECK_PTR(colorSpaceYCbCrU8); + f->add(csf); + KisHistogramProducerFactoryRegistry::instance()->add( + new KisBasicHistogramProducerFactory + (KisID("YCBR8HISTO", i18n("YCBR8")), colorSpaceYCbCrU8) ); + } + +} + +YCbCrU8Plugin::~YCbCrU8Plugin() +{ +} + +#include "ycbcr_u8_plugin.moc" diff --git a/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h b/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h new file mode 100644 index 00000000..98274614 --- /dev/null +++ b/chalk/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef YCBCR_U8_PLUGIN_H_ +#define YCBCR_U8_PLUGIN_H_ + +#include + +/** + * A plugin wrapper around the YCbCr U8 colour space strategy. + */ +class YCbCrU8Plugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + YCbCrU8Plugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~YCbCrU8Plugin(); + +}; + + +#endif // YCBCR_U8_PLUGIN_H_ diff --git a/chalk/configure.in.bot b/chalk/configure.in.bot new file mode 100644 index 00000000..1f070ba8 --- /dev/null +++ b/chalk/configure.in.bot @@ -0,0 +1,19 @@ +if test -z "$LCMS_LIBS"; then + echo "" + echo "LittleCMS is missing, Chalk will not be built." + echo "" + echo "If you want to compile Chalk you should install:" + echo " * lcms 1.15 or newer (http://www.littlecms.com/)" + echo "" + all_tests=bad +else + if test -z "$GLLIB"; then + echo "" + echo "You're missing OpenGL libraries. chalk will" + echo "not be able to use OpenGL for hardware" + echo "accelerated rendering." + echo "" + fi +fi + + diff --git a/chalk/configure.in.in b/chalk/configure.in.in new file mode 100644 index 00000000..733abe21 --- /dev/null +++ b/chalk/configure.in.in @@ -0,0 +1,113 @@ +KDE_CHECK_LIB(Xi, XOpenDisplay, [ + LIB_XINPUTEXT="-lXi" + AC_DEFINE(HAVE_XINPUTEXT, 1, [Define if you have the X11 Input Extension]) + ]) +AC_SUBST(LIB_XINPUTEXT) + +# Check for lcms +AC_MSG_CHECKING([for lcms >= 1.15]) + +have_lcms_header='no' +KDE_CHECK_HEADER(lcms/lcms.h,have_lcms_header='yes',,) +if test "$have_lcms_header" = 'yes' +then + AC_DEFINE(LCMS_HEADER, , [The correct header]) + + echo "#include " > conftest.$ac_ext + echo "#if LCMS_VERSION < 115" >> conftest.$ac_ext + echo "#error Need lcms >= 1.15" >> conftest.$ac_ext + echo "#endif" >> conftest.$ac_ext + echo "int main() {}" >> conftest.$ac_ext + +else + # Alternative! Debian does it this way... + KDE_CHECK_HEADER(lcms.h,have_lcms_header='yes',,) + + if test "$have_lcms_header" = 'yes' + then + AC_DEFINE(LCMS_HEADER, , [The correct header]) + + echo "#include " > conftest.$ac_ext + echo "#if LCMS_VERSION < 115" >> conftest.$ac_ext + echo "#error Need lcms >= 1.15" >> conftest.$ac_ext + echo "#endif" >> conftest.$ac_ext + echo "int main() {}" >> conftest.$ac_ext + else + KDE_CHECK_HEADER(lcms.h,have_lcms_header='yes',,) + # and now debian also does it this way... can't they decide for one way of doing stuff ? + + AC_DEFINE(LCMS_HEADER, , [The correct header]) + + echo "#include " > conftest.$ac_ext + echo "#if LCMS_VERSION < 115" >> conftest.$ac_ext + echo "#error Need lcms >= 1.15" >> conftest.$ac_ext + echo "#endif" >> conftest.$ac_ext + echo "int main() {}" >> conftest.$ac_ext + + fi +fi + + +ac_link='$LIBTOOL_SHELL --mode=link ${CXX-g++} -o conftest $CXXFLAGS $all_includes $CPPFLAGS $LDFLAGS $all_libraries -ltqt conftest.$ac_ext -llcms 1>&5' + +if AC_TRY_EVAL(ac_link) && test -s conftest; then + AC_MSG_RESULT(yes) + HAVELCMS="yes" + LCMS_LIBS="-llcms" +else + AC_MSG_RESULT(no) + HAVELCMS="no" + LCMS_LIBS="" + DO_NOT_COMPILE="$DO_NOT_COMPILE chalk" +fi + +AC_SUBST(LCMS_LIBS) + +# IM 6.1.3 changed the number of arguments to GetMagickInfoList + +AC_MSG_CHECKING(if GetMagickInfoList has only 2 arguments) +CPPFLAGS_TMP="$CPPFLAGS" # Save preprocessor flags +CPPFLAGS="$LIBMAGICK_CPPFLAGS" +LDFLAGS_TMP="$LDFLAGS" +LDFLAGS="$LDFLAGS -ltqt" + +AC_TRY_COMPILE( + [#include + #if HAVE_SYS_TYPES_H + #include + #endif + #include "magick/api.h"], + [const char *pattern; unsigned long ncolors; (void)GetMagickInfoList(pattern, &ncolors)], + magick_info_list='yes', + magick_info_list='no') + +CPPFLAGS="$CPPFLAGS_TMP" # Restore preprocessor flags +LDFLAGS="$LDFLAGS_TMP" + +if test "$magick_info_list" = 'yes'; then + AC_MSG_RESULT(yes) + AC_DEFINE([HAVE_OLD_GETMAGICKINFOLIST], 1, [GetMagickInfoList has different number of arguments with versions >= 6.1.3]) +else + AC_MSG_RESULT(no) +fi + +# Check for kunittest +AC_MSG_CHECKING([for kunittest]) + +have_kunittest_header="no" +KDE_CHECK_HEADER(kunittest/tester.h, have_kunittest_header="yes", , ) +AM_CONDITIONAL(include_kunittest_tests, test "$have_kunittest_header" = "yes") + +# --- OpenGL check --- + +AC_HAVE_GL( [], [] ) + +# --- End of OpenGL check --- + +# Check for powf. + +AC_CHECK_FUNC(powf, [have_powf="yes"], [AC_CHECK_LIB(m, powf, [have_powf="yes"], [have_powf="no"])]) + +if test "$have_powf" = 'yes'; then + AC_DEFINE([HAVE_POWF], 1, [Define to 1 if your system has powf in ]) +fi\ diff --git a/chalk/core/Makefile.am b/chalk/core/Makefile.am new file mode 100644 index 00000000..30b1eb07 --- /dev/null +++ b/chalk/core/Makefile.am @@ -0,0 +1,59 @@ +# all_includes must remain last! +INCLUDES = \ + -I$(srcdir)/../sdk \ + -I$(srcdir)/tiles \ + -I$(srcdir)/../chalkcolor \ + $(KOFFICE_INCLUDES) \ + $(KOPAINTER_INCLUDES) \ + $(OPENEXR_CFLAGS) \ + $(all_includes) + +#CXXFLAGS = -shared -fPIC + +lib_LTLIBRARIES = libchalkimage.la + +libchalkimage_la_SOURCES = kis_adjustment_layer.cc kis_alpha_mask.cc \ + kis_autobrush_resource.cc kis_autogradient_resource.cc kis_background.cc kis_boundary.cc \ + kis_brush.cc kis_command.cc kis_convolution_painter.cc kis_fill_painter.cc \ + kis_filter.cc kis_filter_registry.cc kis_filter_strategy.cc \ + kis_filter_configuration.cc kis_filter_config_widget.cc kis_gradient.cc kis_gradient_painter.cc \ + kis_histogram.cc kis_image.cc kis_imagepipe_brush.cc kis_iterator.cc \ + kis_iterators_pixel.cc kis_layer.cc kis_group_layer.cc kis_paint_layer.cc kis_meta_registry.cc \ + kis_nameserver.cc kis_painter.cc kis_paintop.cc kis_paintop_registry.cc kis_palette.cc \ + kis_pattern.cc kis_rect.cc kis_resource.cc kis_rotate_visitor.cc \ + kis_selected_transaction.cc kis_selection.cc kis_strategy_move.cc kis_transaction.cc \ + kis_transform_worker.cc kis_vec.cc kis_paint_device.cc kis_paint_device_iface.cc \ + kis_paint_device_iface.skel kis_image_iface.cc kis_image_iface.skel kis_basic_math_toolbox.cpp \ + kis_math_toolbox.cpp kis_exif_info.cc kis_thread_pool.cc kis_exif_value.cc \ + kis_filter_strategy.h kis_random_accessor.cpp kis_random_sub_accessor.cpp \ + kis_perspective_grid.cpp kis_perspectivetransform_worker.cpp kis_perspective_math.cpp kis_scale_visitor.cc + +noinst_HEADERS = kis_rotate_visitor.h kis_selected_transaction.h \ + kis_strategy_move.h kis_transform_worker.h kis_datamanager.h kis_iteratorpixeltrait.h \ + kis_merge_visitor.h kis_thread.h kis_thread_pool.h kis_change_profile_visitor.h \ + kis_perspective_grid.h kis_perspectivetransform_worker.h + +include_HEADERS = kis_adjustment_layer.h kis_alpha_mask.h \ + kis_autobrush_resource.h kis_autogradient_resource.h kis_background.h kis_boundary.h kis_brush.h \ + kis_command.h kis_convolution_painter.h kis_fill_painter.h kis_filter.h \ + kis_filter_registry.h kis_gradient.h kis_gradient_painter.h kis_histogram.h kis_image.h \ + kis_image_iface.h kis_imagepipe_brush.h kis_iterator.h kis_iterators_pixel.h \ + kis_iteratorpixeltrait.h kis_layer.h kis_meta_registry.h kis_nameserver.h \ + kis_paint_device_iface.h kis_paint_device.h kis_painter.h kis_paintop.h kis_paintop_registry.h \ + kis_palette.h kis_pattern.h kis_point.h kis_rect.h kis_resource.h kis_selection.h \ + kis_transaction.h kis_types.h kis_vec.h kis_filter_config_widget.h \ + kis_filter_configuration.h kis_exif_info.h kis_exif_value.h kis_substrate.h kis_perspective_math.h kis_scale_visitor.h kis_paint_layer.h kis_layer_visitor.h kis_filter_strategy.h kis_transform_worker.h + +libchalkimage_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libchalkimage_la_LIBADD = ../sdk/libchalksdk.la ../chalkcolor/libchalkcolor.la tiles/libchalktile.la $(OPENEXR_LIBS) $(LCMS_LIBS) $(LIB_KOFFICECORE) $(LIB_KOPAINTER) $(LIB_KDECORE) $(LIB_QT) $(OPENEXR_LIBS) + +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = tiles . $(TESTSDIR) + +libchalkimage_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + diff --git a/chalk/core/createdcop.py b/chalk/core/createdcop.py new file mode 100755 index 00000000..bac48f33 --- /dev/null +++ b/chalk/core/createdcop.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python + +import os, sys + +dcopiface_header = """/* This file is part of the KDE project + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef %(classname_upper)sIFACE_H +#define %(classname_upper)sIFACE_H + +#include +#include + +#include + +class %(classname)s; + +class %(classname)sIface : virtual public DCOPObject +{ + K_DCOP +public: + %(classname)sIface( %(classname)s * tqparent ); +k_dcop: + +private: + + %(classname)s *m_parent; +}; + +#endif +""" + +dcopiface_template = """/* + * This file is part of the KDE project + * + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + + +#include "%(ifaceheader)s" + +#include "%(classheader)s" + +#include + +%(classname)sIface::%(classname)sIface( %(classname)s * tqparent ) + : DCOPObject() +{ + m_parent = tqparent; +} + +""" + +def parseHeader(headerfile, classname): + # parse the source class header to get a list of functions we're going to wrap + functions = [] + if (headerfile.tqfind("private:") > -1): + lines = headerfile[headerfile.tqfind(classname):headerfile.tqfind("private")].splitlines() + else: + lines = headerfile[headerfile.tqfind(classname):headerfile.tqfind("#endif")].splitlines() + i = 0 + while i < len(lines): + line = lines[i].strip() + if (line.startswith("/") or + line.startswith("public:") or + line.startswith("*") or + line.startswith(classname) or + line.startswith("class") or + line.startswith("Q_OBJECT") or + line.startswith("#") or + line.startswith("}") or + line.startswith("public Q_SLOTS:") or + line.tqfind("~") != -1 or + len(line) == 0 + ): + i+=1 + continue + if (line.startswith("protected")): + return functions + # by now we are reasonable sure that this is a function. We need to find the end of the function definition, and then + # if the return type is not primitive, replace it with dcopref. + function = line + complete = 0 + # strip the inline implementation + if (line.tqfind("{") > -1): + function = line[:line.tqfind("{")] + if function.tqfind("}") > -1: + function += line[line.tqfind("}") + 1:] + complete = 1 + else: + i += 1 + # search for the missing } on the next lines + while i < len(lines): + if (lines[i].tqfind("}") > -1): + function += lines[i][lines[i].tqfind("}") + 1:] + complete = 1 + i += 1 + else: + complete = 1 + + if complete == 0: + i+=1 + continue + + if (function.endswith("= 0;")): + function = function[:-4] + ";" + print "\t", function + i+=1 + + +def createDCOP(header): + + # Determine filenames and classnames + + implementation = header[:-1] + "cc" + classname = "" + classname_upper ="_" + for part in header[:-2].split("_"): + classname = classname + part.capitalize() + classname_upper = classname_upper + part.upper() + "_" + ifaceheader = header[:-2] + "_iface.h" + ifaceimplementation = header[:-2] + "_iface.cc" + ifaceclass = classname + "Iface" + + #print "with: ", implementation, classname, classname_upper, ifaceheader, ifaceimplementation, ifaceclass + file(ifaceheader, "w+").write(dcopiface_header % { "classname_upper" : classname_upper, + "classname" : classname}) + file(ifaceimplementation, "w+").write(dcopiface_template % {"ifaceheader" : ifaceheader, + "classheader" : header, + "classname" : classname }) + functions = parseHeader(open(header).read(), classname) + +def main(args): + for line in args[1:]: + print "Going to create a dcop interface for:", line[:-1] + createDCOP(line.strip()) + +if __name__=="__main__": + main(sys.argv) + + diff --git a/chalk/core/kis_adjustment_layer.cc b/chalk/core/kis_adjustment_layer.cc new file mode 100644 index 00000000..69e8b939 --- /dev/null +++ b/chalk/core/kis_adjustment_layer.cc @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#include +#include + +#include "kis_debug_areas.h" +#include "kis_group_layer.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_painter.h" +#include "kis_undo_adapter.h" +#include "kis_selection.h" +#include "kis_fill_painter.h" + +KisAdjustmentLayer::KisAdjustmentLayer(KisImageSP img, const TQString &name, KisFilterConfiguration * kfc, KisSelectionSP selection) + : KisLayer (img, name, OPACITY_OPAQUE) +{ + m_filterConfig = kfc; + setSelection( selection ); + m_cachedPaintDev = new KisPaintDevice( img->colorSpace(), name.latin1()); + m_showSelection = true; + Q_ASSERT(m_cachedPaintDev); + connect(img, TQT_SIGNAL(sigSelectionChanged(KisImageSP)), + this, TQT_SLOT(slotSelectionChanged(KisImageSP))); +} + +KisAdjustmentLayer::KisAdjustmentLayer(const KisAdjustmentLayer& rhs) + : KisLayer(rhs), KisLayerSupportsIndirectPainting(rhs) +{ + m_filterConfig = new KisFilterConfiguration(*rhs.m_filterConfig); + if (rhs.m_selection) { + m_selection = new KisSelection( *rhs.m_selection.data() ); + m_selection->setParentLayer(this); + m_selection->setInterestedInDirtyness(true); + connect(rhs.image(), TQT_SIGNAL(sigSelectionChanged(KisImageSP)), + this, TQT_SLOT(slotSelectionChanged(KisImageSP))); + } + m_cachedPaintDev = new KisPaintDevice( *rhs.m_cachedPaintDev.data() ); + m_showSelection = false; +} + + +KisAdjustmentLayer::~KisAdjustmentLayer() +{ + delete m_filterConfig; +} + + +KisLayerSP KisAdjustmentLayer::clone() const +{ + return new KisAdjustmentLayer(*this); +} + + +void KisAdjustmentLayer::resetCache() +{ + m_cachedPaintDev = new KisPaintDevice(image()->colorSpace(), name().latin1()); +} + +KisFilterConfiguration * KisAdjustmentLayer::filter() +{ + Q_ASSERT(m_filterConfig); + return m_filterConfig; +} + + +void KisAdjustmentLayer::setFilter(KisFilterConfiguration * filterConfig) +{ + Q_ASSERT(filterConfig); + m_filterConfig = filterConfig; +} + + +KisSelectionSP KisAdjustmentLayer::selection() +{ + return m_selection; +} + +void KisAdjustmentLayer::setSelection(KisSelectionSP selection) +{ + m_selection = new KisSelection(); + KisFillPainter gc(m_selection.data()); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + + if (selection) { + gc.bitBlt(0, 0, COMPOSITE_COPY, selection.data(), + 0, 0, image()->bounds().width(), image()->bounds().height()); + } else { + gc.fillRect(image()->bounds(), KisColor(TQt::white, cs), MAX_SELECTED); + } + + gc.end(); + + m_selection->setParentLayer(this); + m_selection->setInterestedInDirtyness(true); +} + +void KisAdjustmentLayer::clearSelection() +{ + KisFillPainter gc(m_selection.data()); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + + TQRect bounds = extent(); + bounds |= image()->bounds(); + gc.fillRect(bounds, KisColor(TQt::white, cs), MIN_SELECTED); + gc.end(); +} + + +TQ_INT32 KisAdjustmentLayer::x() const +{ + if (m_selection) + return m_selection->getX(); + else + return 0; +} + +void KisAdjustmentLayer::setX(TQ_INT32 x) +{ + if (m_selection) { + m_selection->setX(x); + resetCache(); + } + +} + +TQ_INT32 KisAdjustmentLayer::y() const +{ + if (m_selection) + return m_selection->getY(); + else + return 0; +} + +void KisAdjustmentLayer::setY(TQ_INT32 y) +{ + if (m_selection) { + m_selection->setY(y); + resetCache(); + } +} + +TQRect KisAdjustmentLayer::extent() const +{ + if (m_selection) + return m_selection->selectedRect(); + else if (image()) + return image()->bounds(); + else + return TQRect(); +} + +TQRect KisAdjustmentLayer::exactBounds() const +{ + if (m_selection) + return m_selection->selectedRect(); + else if (image()) + return image()->bounds(); + else + return TQRect(); +} + +bool KisAdjustmentLayer::accept(KisLayerVisitor & v) +{ + return v.visit( this ); +} + +void KisAdjustmentLayer::paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + if (showSelection() && selection()) + selection()->paintSelection(img, x, y, w, h); +} + +void KisAdjustmentLayer::paintSelection(TQImage &img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize) +{ + if (showSelection() && selection()) + selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); +} + +TQImage KisAdjustmentLayer::createThumbnail(TQ_INT32 w, TQ_INT32 h) +{ + if (!selection()) + return TQImage(); + + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const TQRect e = extent(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = TQ_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = TQ_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = TQ_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = TQ_INT32(double(srcw) / srch * h); + + TQColor c; + TQ_UINT8 opacity; + TQImage img(w,h,32); + + for (TQ_INT32 y=0; y < h; ++y) { + TQ_INT32 iY = (y * srch ) / h; + for (TQ_INT32 x=0; x < w; ++x) { + TQ_INT32 iX = (x * srcw ) / w; + m_selection->pixel(iX, iY, &c, &opacity); + img.setPixel(x, y, tqRgb(opacity, opacity, opacity)); + } + } + + return img; +} + +void KisAdjustmentLayer::slotSelectionChanged(KisImageSP image) { + image->setModified(); +} + +#include "kis_adjustment_layer.moc" diff --git a/chalk/core/kis_adjustment_layer.h b/chalk/core/kis_adjustment_layer.h new file mode 100644 index 00000000..b8b76437 --- /dev/null +++ b/chalk/core/kis_adjustment_layer.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_ADJUSTMENT_LAYER_H_ +#define KIS_ADJUSTMENT_LAYER_H_ + +#include +#include "kis_types.h" +#include "kis_layer_visitor.h" +#include "kis_composite_op.h" +#include + +class KNamedCommand; +class TQPainter; +class KisUndoAdapter; +class KisGroupLayer; +class KisFilterConfiguration; + +/** + * Class that contains a KisFilter and optionally a KisSelection. The combination + * is used by to influence the rendering of the layers under this layer in the + * layerstack + **/ +class KRITACORE_EXPORT KisAdjustmentLayer : public KisLayer, public KisLayerSupportsIndirectPainting +{ + Q_OBJECT + TQ_OBJECT + +public: + /** + * Create a new adjustment layer with the given configuration and selection. + * Note that the selection will be _copied_. + */ + KisAdjustmentLayer(KisImageSP img, const TQString &name, KisFilterConfiguration * kfc, KisSelectionSP selection); + KisAdjustmentLayer(const KisAdjustmentLayer& rhs); + virtual ~KisAdjustmentLayer(); + + /// Return a copy of this layer + virtual KisLayerSP clone() const; + +public: + + KisFilterConfiguration * filter(); + void setFilter(KisFilterConfiguration * filterConfig); + + KisSelectionSP selection(); + + /// Set the selction of this adjustment layer to a copy of selection. + void setSelection(KisSelectionSP selection); + + /// Clears the selection (doesn't call any of the update or dirty methods) + void clearSelection(); + + virtual void paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + virtual void paintSelection(TQImage &img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize); +public: + + virtual TQ_INT32 x() const; + virtual void setX(TQ_INT32); + + virtual TQ_INT32 y() const; + virtual void setY(TQ_INT32); + + /// Returns an approximation of where the bounds on actual data are in this layer + virtual TQRect extent() const; + + /// Returns the exact bounds of where the actual data resides in this layer + virtual TQRect exactBounds() const; + + virtual bool accept(KisLayerVisitor &); + + virtual void resetCache(); + virtual KisPaintDeviceSP cachedPaintDevice() { return m_cachedPaintDev; } + + bool showSelection() const { return m_showSelection; } + void setSelection(bool b) { m_showSelection = b; } + + virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h); + + // KisLayerSupportsIndirectPainting + virtual KisLayer* layer() { return this; } +private: + bool m_showSelection; + KisFilterConfiguration * m_filterConfig; + KisSelectionSP m_selection; + KisPaintDeviceSP m_cachedPaintDev; +private slots: + void slotSelectionChanged(KisImageSP image); +}; + +#endif // KIS_ADJUSTMENT_LAYER_H_ + diff --git a/chalk/core/kis_alpha_mask.cc b/chalk/core/kis_alpha_mask.cc new file mode 100644 index 00000000..1b40e806 --- /dev/null +++ b/chalk/core/kis_alpha_mask.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include + +#include "kis_global.h" +#include "kis_alpha_mask.h" + +KisAlphaMask::KisAlphaMask(const TQImage& img, bool hasColor) +{ + m_width = img.width(); + m_height = img.height(); + + if (hasColor) { + copyAlpha(img); + } + else { + computeAlpha(img); + } +} + +KisAlphaMask::KisAlphaMask(const TQImage& img) +{ + m_width = img.width(); + m_height = img.height(); + + if (!img.allGray()) { + copyAlpha(img); + } + else { + computeAlpha(img); + } +} + +KisAlphaMask::KisAlphaMask(TQ_INT32 width, TQ_INT32 height) +{ + m_width = width; + m_height = height; + + m_data.resize(width * height, OPACITY_TRANSPARENT); +} + +KisAlphaMask::~KisAlphaMask() +{ +} + +TQ_INT32 KisAlphaMask::width() const +{ + return m_width; +} + +TQ_INT32 KisAlphaMask::height() const +{ + return m_height; +} + +void KisAlphaMask::setAlphaAt(TQ_INT32 x, TQ_INT32 y, TQ_UINT8 alpha) +{ + if (y >= 0 && y < m_height && x >= 0 && x < m_width) { + m_data[(y * m_width) + x] = alpha; + } +} + +void KisAlphaMask::copyAlpha(const TQImage& img) +{ + for (int y = 0; y < img.height(); y++) { + for (int x = 0; x < img.width(); x++) { + TQRgb c = img.pixel(x,y); + TQ_UINT8 a = (tqGray(c) * tqAlpha(c)) / 255; + m_data.push_back(a); + + } + } +} + +void KisAlphaMask::computeAlpha(const TQImage& img) +{ + // The brushes are mostly grayscale on a white background, + // although some do have a colors. The alpha channel is seldom + // used, so we take the average gray value of this pixel of + // the brush as the setting for the opacitiy. We need to + // invert it, because 255, 255, 255 is white, which is + // completely transparent, but 255 corresponds to + // OPACITY_OPAQUE. + + for (int y = 0; y < img.height(); y++) { + for (int x = 0; x < img.width(); x++) { + m_data.push_back(255 - tqRed(img.pixel(x, y))); + } + } +} + +KisAlphaMaskSP KisAlphaMask::interpolate(KisAlphaMaskSP tqmask1, KisAlphaMaskSP tqmask2, double t) +{ + Q_ASSERT((tqmask1->width() == tqmask2->width()) && (tqmask1->height() == tqmask2->height())); + Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); + + int width = tqmask1->width(); + int height = tqmask1->height(); + KisAlphaMaskSP outputMask = new KisAlphaMask(width, height); + Q_CHECK_PTR(outputMask); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + TQ_UINT8 d = static_cast((1 - t) * tqmask1->alphaAt(x, y) + t * tqmask2->alphaAt(x, y)); + outputMask->setAlphaAt(x, y, d); + } + } + + return outputMask; +} + + diff --git a/chalk/core/kis_alpha_mask.h b/chalk/core/kis_alpha_mask.h new file mode 100644 index 00000000..4665857e --- /dev/null +++ b/chalk/core/kis_alpha_mask.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_ALPHA_MASK_ +#define KIS_ALPHA_MASK_ + +#include +#include + +#include + +#include "kis_global.h" +#include "kis_types.h" + +/** + * KisAlphaMask is intended to create alpha values from a TQImage for use + * in brush creation. It is not a generic alpha tqmask that can be used with + * KisPaintDevices: use a KisSelection for that. + */ +class KisAlphaMask : public KShared { + + public: + /** + Create an alpha tqmask based on the specified TQImage. If the image is + not a grayscale, the tqmask value is calculated from the effective grey + level and alpha value. + */ + KisAlphaMask(const TQImage& img); + + /** + As above except quicker as the image does not need to be scanned + to see if it has any colour pixels. + */ + KisAlphaMask(const TQImage& img, bool hasColor); + + /** + Create a transparent tqmask. + */ + KisAlphaMask(TQ_INT32 width, TQ_INT32 height); + + virtual ~KisAlphaMask(); + + /** + @return the number of alpha values in a scanline. + */ + TQ_INT32 height() const; + + /** + @return the number of lines in the tqmask. + */ + TQ_INT32 width() const; + + /** + @return the alpha value at the specified position. + + Returns TQ_UINT8 OPACITY_TRANSPARENT if the value is + outside the bounds of the tqmask. + + XXX: this is, of course, not the best way of tqmasking. + Better would be to let KisAlphaMask fill a chunk of memory + with the alpha values at the right position, something like + void applyMask(TQ_UINT8 *pixeldata, TQ_INT32 pixelWidth, + TQ_INT32 alphaPos). That would be fastest, or we could + provide an iterator over the tqmask, that would be nice, too. + */ + inline TQ_UINT8 alphaAt(TQ_INT32 x, TQ_INT32 y) const + { + if (y >= 0 && y < m_height && x >= 0 && x < m_width) { + return m_data[(y * m_width) + x]; + } + else { + return OPACITY_TRANSPARENT; + } + } + + void setAlphaAt(TQ_INT32 x, TQ_INT32 y, TQ_UINT8 alpha); + + // Create a new tqmask by interpolating between tqmask1 and tqmask2 as t + // goes from 0 to 1. + static KisAlphaMaskSP interpolate(KisAlphaMaskSP tqmask1, KisAlphaMaskSP tqmask2, double t); + +private: + void computeAlpha(const TQImage& img); + void copyAlpha(const TQImage& img); + + TQValueVector m_data; + TQ_INT32 m_width; + TQ_INT32 m_height; +}; + +#endif // KIS_ALPHA_MASK_ + diff --git a/chalk/core/kis_autobrush_resource.cc b/chalk/core/kis_autobrush_resource.cc new file mode 100644 index 00000000..9a09fe78 --- /dev/null +++ b/chalk/core/kis_autobrush_resource.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_autobrush_resource.h" +#include + +void KisAutobrushShape::createBrush( TQImage* img) +{ + img->create(m_w, m_h, 32); + for(int j = 0; j < m_h; j++) + { + for(int i = 0; i < m_w; i++) + { + TQ_INT8 v = valueAt(i,j); + img->setPixel( i, j, tqRgb(v,v,v)); + } + } +} + +KisAutobrushCircleShape::KisAutobrushCircleShape(TQ_INT32 w, TQ_INT32 h, double fh, double fv) + : KisAutobrushShape( w, h, w / 2.0 - fh, h / 2.0 - fv), + m_xcentre ( w / 2.0 ), + m_ycentre ( h / 2.0 ), + m_xcoef ( 2.0 / w ), + m_ycoef ( 2.0 / h ), + m_xfadecoef ( (m_fh == 0) ? 1 : ( 1.0 / m_fh)), + m_yfadecoef ( (m_fv == 0) ? 1 : ( 1.0 / m_fv)) +{ +} +TQ_INT8 KisAutobrushCircleShape::valueAt(TQ_INT32 x, TQ_INT32 y) +{ + double xr = (x - m_xcentre) + 0.5; + double yr = (y - m_ycentre) + 0.5; + double n = norme( xr * m_xcoef, yr * m_ycoef); + if( n > 1 ) + { + return 255; + } + else + { + double normeFade = norme( xr * m_xfadecoef, yr * m_yfadecoef ); + if( normeFade > 1) + { + double xle, yle; + // xle stands for x-coordinate limit exterior + // yle stands for y-coordinate limit exterior + // we are computing the coordinate on the external ellipse in order to compute + // the fade value + if( xr == 0 ) + { + xle = 0; + yle = yr > 0 ? 1/m_ycoef : -1/m_ycoef; + } else { + double c = yr / (double)xr; + xle = sqrt(1 / norme( m_xcoef, c * m_ycoef )); + xle = xr > 0 ? xle : -xle; + yle = xle * c; + } + // On the internal limit of the fade area, normeFade is equal to 1 + double normeFadeLimitE = norme( xle * m_xfadecoef, yle * m_yfadecoef ); + return (uchar)(255 * ( normeFade - 1 ) / ( normeFadeLimitE - 1 )); + } else { + return 0; + } + } +} + +KisAutobrushRectShape::KisAutobrushRectShape(TQ_INT32 w, TQ_INT32 h, double fh, double fv) + : KisAutobrushShape( w, h, w / 2.0 - fh, h / 2.0 - fv), + m_xcentre ( w / 2.0 ), + m_ycentre ( h / 2.0 ), + m_c( fv/fh) +{ +} +TQ_INT8 KisAutobrushRectShape::valueAt(TQ_INT32 x, TQ_INT32 y) +{ + double xr = TQABS(x - m_xcentre); + double yr = TQABS(y - m_ycentre); + if( xr > m_fh || yr > m_fv ) + { + if( yr <= ((xr - m_fh) * m_c + m_fv ) ) + { + return (uchar)(255 * (xr - m_fh) / (m_w - m_fh)); + } else { + return (uchar)(255 * (yr - m_fv) / (m_w - m_fv)); + } + } + else { + return 0; + } +} diff --git a/chalk/core/kis_autobrush_resource.h b/chalk/core/kis_autobrush_resource.h new file mode 100644 index 00000000..44708efa --- /dev/null +++ b/chalk/core/kis_autobrush_resource.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_AUTOBRUSH_RESOURCE_H_ +#define _KIS_AUTOBRUSH_RESOURCE_H_ + +#include "kis_brush.h" + +class KisAutobrushShape { + public: + KisAutobrushShape(TQ_INT32 w, TQ_INT32 h, double fh, double fv) : m_w(w), m_h(h), m_fh(fh), m_fv(fv) + { }; + void createBrush( TQImage* img); + protected: + virtual TQ_INT8 valueAt(TQ_INT32 x, TQ_INT32 y) =0; + TQ_INT32 m_w, m_h; + double m_fh, m_fv; +}; + +class KisAutobrushCircleShape : public KisAutobrushShape { + public: + KisAutobrushCircleShape(TQ_INT32 w, TQ_INT32 h, double fh, double fv); + public: + virtual TQ_INT8 valueAt(TQ_INT32 x, TQ_INT32 y); + private: + double norme(double a, double b) + { + return a*a + b * b; + } + private: + double m_xcentre, m_ycentre; + double m_xcoef, m_ycoef; + double m_xfadecoef, m_yfadecoef; +}; + +class KisAutobrushRectShape : public KisAutobrushShape { + public: + KisAutobrushRectShape(TQ_INT32 w, TQ_INT32 h, double fh, double fv); + protected: + virtual TQ_INT8 valueAt(TQ_INT32 x, TQ_INT32 y); + private: + double m_xcentre, m_ycentre, m_c; +}; + +class KisAutobrushResource : public KisBrush +{ + public: + KisAutobrushResource(TQImage& img) : KisBrush("") + { + setImage(img); + setBrushType(MASK); + }; + public: + virtual bool load() { return false; }; +}; +#endif // _KIS_AUTOBRUSH_RESOURCE_H_ diff --git a/chalk/core/kis_autogradient_resource.cc b/chalk/core/kis_autogradient_resource.cc new file mode 100644 index 00000000..671e8fc2 --- /dev/null +++ b/chalk/core/kis_autogradient_resource.cc @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_gradient.h" +#include "kis_autogradient_resource.h" + +// FIXME: use the same #define as in kis_gradient.cc, probably best customizable? +#define PREVIEW_WIDTH 64 +#define PREVIEW_HEIGHT 64 + + +void KisAutogradientResource::createSegment( int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, TQColor left, TQColor right ) +{ + pushSegment(new KisGradientSegment(interpolation, colorInterpolation, startOffset, middleOffset, endOffset, Color( left, 1 ), Color( right, 1 ))); + +} + +const TQValueVector KisAutogradientResource::getHandlePositions() const +{ + TQValueVector handlePositions; + + handlePositions.push_back(m_segments[0]->startOffset()); + for (uint i = 0; i < m_segments.count(); i++) + { + handlePositions.push_back(m_segments[i]->endOffset()); + } + return handlePositions; +} + +const TQValueVector KisAutogradientResource::getMiddleHandlePositions() const +{ + TQValueVector middleHandlePositions; + + for (uint i = 0; i < m_segments.count(); i++) + { + middleHandlePositions.push_back(m_segments[i]->middleOffset()); + } + return middleHandlePositions; +} + +void KisAutogradientResource::moveSegmentStartOffset( KisGradientSegment* segment, double t) +{ + TQValueVector::iterator it = tqFind( m_segments.begin(), m_segments.end(), segment ); + if ( it != m_segments.end() ) + { + if ( it == m_segments.begin() ) + { + segment->setStartOffset( 0.0 ); + return; + } + KisGradientSegment* previousSegment = (*(it-1)); + if ( t > segment->startOffset() ) + { + if( t > segment->middleOffset() ) + t = segment->middleOffset(); + } + else { + if( t < previousSegment->middleOffset() ) + t = previousSegment->middleOffset(); + } + previousSegment->setEndOffset( t ); + segment->setStartOffset( t ); + } +} + +void KisAutogradientResource::moveSegmentEndOffset( KisGradientSegment* segment, double t) +{ + TQValueVector::iterator it = tqFind( m_segments.begin(), m_segments.end(), segment ); + if ( it != m_segments.end() ) + { + if ( it+1 == m_segments.end() ) + { + segment->setEndOffset( 1.0 ); + return; + } + KisGradientSegment* followingSegment = (*(it+1)); + if ( t < segment->endOffset() ) + { + if( t < segment->middleOffset() ) + t = segment->middleOffset(); + } + else { + if( t > followingSegment->middleOffset() ) + t = followingSegment->middleOffset(); + } + followingSegment->setStartOffset( t ); + segment->setEndOffset( t ); + } +} + +void KisAutogradientResource::moveSegmentMiddleOffset( KisGradientSegment* segment, double t) +{ + if( segment ) + { + if( t > segment->endOffset() ) + segment->setMiddleOffset( segment->endOffset() ); + else if( t < segment->startOffset() ) + segment->setMiddleOffset( segment->startOffset() ); + else + segment->setMiddleOffset( t ); + } +} + +void KisAutogradientResource::splitSegment( KisGradientSegment* segment ) +{ + Q_ASSERT(segment != 0); + TQValueVector::iterator it = tqFind( m_segments.begin(), m_segments.end(), segment ); + if ( it != m_segments.end() ) + { + KisGradientSegment* newSegment = new KisGradientSegment( + segment->interpolation(), segment->colorInterpolation(), + segment ->startOffset(), + ( segment->middleOffset() - segment->startOffset() ) / 2 + segment->startOffset(), + segment->middleOffset(), + segment->startColor(), + segment->colorAt( segment->middleOffset() ) ); + m_segments.insert( it, newSegment ); + segment->setStartColor( segment->colorAt( segment->middleOffset() ) ); + segment->setStartOffset( segment->middleOffset() ); + segment->setMiddleOffset( ( segment->endOffset() - segment->startOffset() ) / 2 + segment->startOffset() ); + } +} + +void KisAutogradientResource::duplicateSegment( KisGradientSegment* segment ) +{ + Q_ASSERT(segment != 0); + TQValueVector::iterator it = tqFind( m_segments.begin(), m_segments.end(), segment ); + if ( it != m_segments.end() ) + { + double middlePostionPercentage = ( segment->middleOffset() - segment->startOffset() ) / segment->length(); + double center = segment->startOffset() + segment->length() / 2; + KisGradientSegment* newSegment = new KisGradientSegment( + segment->interpolation(), segment->colorInterpolation(), + segment ->startOffset(), + segment->length() / 2 * middlePostionPercentage + segment->startOffset(), + center, segment->startColor(), + segment->endColor() ); + m_segments.insert( it, newSegment ); + segment->setStartOffset( center ); + segment->setMiddleOffset( segment->length() * middlePostionPercentage + segment->startOffset() ); + } +} + +void KisAutogradientResource::mirrorSegment( KisGradientSegment* segment ) +{ + Q_ASSERT(segment != 0); + Color tmpColor = segment->startColor(); + segment->setStartColor( segment->endColor() ); + segment->setEndColor( tmpColor ); + segment->setMiddleOffset( segment->endOffset() - ( segment->middleOffset() - segment->startOffset() ) ); + + if( segment->interpolation() == INTERP_SPHERE_INCREASING ) + segment->setInterpolation( INTERP_SPHERE_DECREASING ); + else if( segment->interpolation() == INTERP_SPHERE_DECREASING ) + segment->setInterpolation( INTERP_SPHERE_INCREASING ); + + if( segment->colorInterpolation() == COLOR_INTERP_HSV_CW ) + segment->setColorInterpolation( COLOR_INTERP_HSV_CCW ); + else if( segment->colorInterpolation() == COLOR_INTERP_HSV_CCW ) + segment->setColorInterpolation( COLOR_INTERP_HSV_CW ); +} + +KisGradientSegment* KisAutogradientResource::removeSegment( KisGradientSegment* segment ) +{ + Q_ASSERT(segment != 0); + if( m_segments.count() < 2 ) + return 0; + TQValueVector::iterator it = tqFind( m_segments.begin(), m_segments.end(), segment ); + if ( it != m_segments.end() ) + { + double middlePostionPercentage; + KisGradientSegment* nextSegment; + if( it == m_segments.begin() ) + { + nextSegment = (*(it+1)); + middlePostionPercentage = ( nextSegment->middleOffset() - nextSegment->startOffset() ) / nextSegment->length(); + nextSegment->setStartOffset( segment->startOffset() ); + nextSegment->setMiddleOffset( middlePostionPercentage * nextSegment->length() + nextSegment->startOffset() ); + } + else + { + nextSegment = (*(it-1)); + middlePostionPercentage = ( nextSegment->middleOffset() - nextSegment->startOffset() ) / nextSegment->length(); + nextSegment->setEndOffset( segment->endOffset() ); + nextSegment->setMiddleOffset( middlePostionPercentage * nextSegment->length() + nextSegment->startOffset() ); + } + + delete segment; + m_segments.erase( it ); + return nextSegment; + } + return 0; +} + +bool KisAutogradientResource::removeSegmentPossible() const +{ + if( m_segments.count() < 2 ) + return false; + return true; +} + +void KisAutogradientResource::updatePreview() +{ + setImage( generatePreview( PREVIEW_WIDTH, PREVIEW_HEIGHT ) ); +} diff --git a/chalk/core/kis_autogradient_resource.h b/chalk/core/kis_autogradient_resource.h new file mode 100644 index 00000000..37546a02 --- /dev/null +++ b/chalk/core/kis_autogradient_resource.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_AUTOGRADIENT_RESOURCE_H_ +#define _KIS_AUTOGRADIENT_RESOURCE_H_ + +#include "kis_gradient.h" + +class KisAutogradientResource : public KisGradient +{ + +public: + KisAutogradientResource() : KisGradient("") {} + +public: + + void createSegment( int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, TQColor left, TQColor right ); + + const TQValueVector getHandlePositions() const; + const TQValueVector getMiddleHandlePositions() const; + + /** + * Moves the StartOffset of the specified segment to the specified value + * and corrects the endoffset of the previous segment. + * If the segment is the first Segment the startoffset will be set to 0.0 . + * The offset will maximally be moved till the middle of the current or the previous + * segment + */ + void moveSegmentStartOffset( KisGradientSegment* segment, double t); + + /** + * Moves the endoffset of the specified segment to the specified value + * and corrects the startoffset of the following segment. + * If the segment is the last segment the endoffset will be set to 1.0 . + * The offset will maximally be moved till the middle of the current or the following + * segment + */ + void moveSegmentEndOffset( KisGradientSegment* segment, double t); + + /** + * Moves the Middle of the specified segment to the specified value + * The offset will maximally be moved till the endoffset or startoffset of the segment + */ + void moveSegmentMiddleOffset( KisGradientSegment* segment, double t); + + + void splitSegment( KisGradientSegment* segment ); + void duplicateSegment( KisGradientSegment* segment ); + void mirrorSegment( KisGradientSegment* segment ); + + /** + * Removes the specific segment from the gradient. + * @return The segment which will be at the place of the old segment. + * 0 if the segment is not in the gradient or it is not possible to remove the segment. + */ + KisGradientSegment* removeSegment( KisGradientSegment* segment ); + + /** + * Checks if it's possible to remove an segment(at least two segments in the gradient) + * @return true if it's possible to remove an segment + */ + bool removeSegmentPossible() const; + + /** + * Recreates the preview of the gradient + */ + void updatePreview(); +public: + virtual bool load() { return false; }; +}; + +#endif // _KIS_AUTOGRADIENT_RESOURCE_H_ diff --git a/chalk/core/kis_background.cc b/chalk/core/kis_background.cc new file mode 100644 index 00000000..6f881d33 --- /dev/null +++ b/chalk/core/kis_background.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#include "kis_global.h" +#include "kis_background.h" +#include "kis_integer_maths.h" + +KisBackground::KisBackground() + : KShared() +{ + m_patternTile = TQImage(PATTERN_WIDTH, PATTERN_HEIGHT, 32); + m_patternTile.setAlphaBuffer(false); + + for (int y = 0; y < PATTERN_HEIGHT; y++) + { + for (int x = 0; x < PATTERN_WIDTH; x++) + { + TQ_UINT8 v = 128 + 63 * ((x / 16 + y / 16) % 2); + m_patternTile.setPixel(x, y, tqRgb(v, v, v)); + } + } +} + +KisBackground::~KisBackground() +{ +} + +const TQImage& KisBackground::patternTile() const +{ + return m_patternTile; +} + +void KisBackground::paintBackground(TQImage image, int imageLeftX, int imageTopY) +{ + int patternLeftX; + + if (imageLeftX >= 0) { + patternLeftX = imageLeftX % PATTERN_WIDTH; + } else { + patternLeftX = (PATTERN_WIDTH - (-imageLeftX % PATTERN_WIDTH)) % PATTERN_WIDTH; + } + + int patternTopY; + + if (imageTopY >= 0) { + patternTopY = imageTopY % PATTERN_HEIGHT; + } else { + patternTopY = (PATTERN_HEIGHT - (-imageTopY % PATTERN_HEIGHT)) % PATTERN_HEIGHT; + } + + int imageWidth = image.width(); + int imageHeight = image.height(); + + int patternY = patternTopY; + + for (int y = 0; y < imageHeight; y++) + { + TQRgb *imagePixelPtr = reinterpret_cast(image.scanLine(y)); + const TQRgb *patternScanLine = reinterpret_cast(m_patternTile.scanLine(patternY)); + int patternX = patternLeftX; + + for (int x = 0; x < imageWidth; x++) + { + TQRgb imagePixel = *imagePixelPtr; + TQ_UINT8 imagePixelAlpha = tqAlpha(imagePixel); + + if (imagePixelAlpha != 255) { + + TQRgb patternPixel = patternScanLine[patternX]; + TQ_UINT8 imageRed = UINT8_BLEND(tqRed(imagePixel), tqRed(patternPixel), imagePixelAlpha); + TQ_UINT8 imageGreen = UINT8_BLEND(tqGreen(imagePixel), tqGreen(patternPixel), imagePixelAlpha); + TQ_UINT8 imageBlue = UINT8_BLEND(tqBlue(imagePixel), tqBlue(patternPixel), imagePixelAlpha); + + *imagePixelPtr = tqRgba(imageRed, imageGreen, imageBlue, 255); + } + + ++imagePixelPtr; + ++patternX; + + if (patternX == PATTERN_WIDTH) { + patternX = 0; + } + } + + ++patternY; + + if (patternY == PATTERN_HEIGHT) { + patternY = 0; + } + } +} + +void KisBackground::paintBackground(TQImage img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize) +{ + if (scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) { + return; + } + + Q_ASSERT(img.size() == scaledImageRect.size()); + + if (img.size() != scaledImageRect.size()) { + return; + } + + TQ_INT32 imageWidth = imageSize.width(); + TQ_INT32 imageHeight = imageSize.height(); + + for (TQ_INT32 y = 0; y < scaledImageRect.height(); ++y) { + + TQ_INT32 scaledY = scaledImageRect.y() + y; + TQ_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height(); + TQ_INT32 patternY = srcY % PATTERN_HEIGHT; + + TQRgb *imagePixelPtr = reinterpret_cast(img.scanLine(y)); + const TQRgb *patternScanLine = reinterpret_cast(m_patternTile.scanLine(patternY)); + + for (TQ_INT32 x = 0; x < scaledImageRect.width(); ++x) { + + TQRgb imagePixel = *imagePixelPtr; + TQ_UINT8 imagePixelAlpha = tqAlpha(imagePixel); + + if (imagePixelAlpha != 255) { + + TQ_INT32 scaledX = scaledImageRect.x() + x; + TQ_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width(); + TQ_INT32 patternX = srcX % PATTERN_WIDTH; + + TQRgb patternPixel = patternScanLine[patternX]; + TQ_UINT8 imageRed = UINT8_BLEND(tqRed(imagePixel), tqRed(patternPixel), imagePixelAlpha); + TQ_UINT8 imageGreen = UINT8_BLEND(tqGreen(imagePixel), tqGreen(patternPixel), imagePixelAlpha); + TQ_UINT8 imageBlue = UINT8_BLEND(tqBlue(imagePixel), tqBlue(patternPixel), imagePixelAlpha); + + *imagePixelPtr = tqRgba(imageRed, imageGreen, imageBlue, 255); + } + + ++imagePixelPtr; + } + } +} + + diff --git a/chalk/core/kis_background.h b/chalk/core/kis_background.h new file mode 100644 index 00000000..f5b52903 --- /dev/null +++ b/chalk/core/kis_background.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_BACKGROUND_H_ +#define KIS_BACKGROUND_H_ + +#include + +#include + +class KisBackground : public KShared { + +public: + KisBackground(); + virtual ~KisBackground(); + + // Paint the background pattern into the image, 'behind' the image + // contents. The coordinates are for the image's top-left corner + // in image space. + void paintBackground(TQImage image, int leftX, int topY); + + void paintBackground(TQImage image, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize); + + // Returns the pattern tile. + const TQImage& patternTile() const; + +protected: + static const int PATTERN_WIDTH = 32; + static const int PATTERN_HEIGHT = 32; + + TQImage m_patternTile; +}; + +#endif // KIS_BACKGROUND_H_ + diff --git a/chalk/core/kis_basic_math_toolbox.cpp b/chalk/core/kis_basic_math_toolbox.cpp new file mode 100644 index 00000000..1b397ab5 --- /dev/null +++ b/chalk/core/kis_basic_math_toolbox.cpp @@ -0,0 +1,137 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_basic_math_toolbox.h" + +KisBasicMathToolbox::KisBasicMathToolbox() + : KisMathToolbox(KisID("Basic")) +{ +} + + +KisBasicMathToolbox::~KisBasicMathToolbox() +{ +} + + +void KisBasicMathToolbox::wavetrans(KisMathToolbox::KisWavelet* wav, KisMathToolbox::KisWavelet* buff, uint halfsize) +{ + uint l = (2*halfsize)*wav->depth*sizeof(float); + for(uint i = 0; i < halfsize; i++) + { + float * itLL = buff->coeffs + i*buff->size*buff->depth; + float * itHL = buff->coeffs + (i*buff->size + halfsize)*buff->depth; + float * itLH = buff->coeffs + (halfsize+i)*buff->size*buff->depth; + float * itHH = buff->coeffs + ( (halfsize+i)*buff->size + halfsize)*buff->depth; + float * itS11 = wav->coeffs + 2*i*wav->size*wav->depth; + float * itS12 = wav->coeffs + (2*i*wav->size+1)*wav->depth; + float * itS21 = wav->coeffs + (2*i+1)*wav->size*wav->depth; + float * itS22 = wav->coeffs + ((2*i+1)*wav->size+1)*wav->depth; + for(uint j = 0; j < halfsize; j++) + { + for( uint k = 0; k < wav->depth; k++) + { + *(itLL++) = (*itS11 + *itS12 + *itS21 + *itS22) * M_SQRT1_2; + *(itHL++) = (*itS11 - *itS12 + *itS21 - *itS22) * M_SQRT1_2; + *(itLH++) = (*itS11 + *itS12 - *itS21 - *itS22) * M_SQRT1_2; + *(itHH++) = (*(itS11++) - *(itS12++) - *(itS21++) + *(itS22++)) * M_SQRT1_2; + } + itS11 += wav->depth; itS12 += wav->depth; + itS21 += wav->depth; itS22 += wav->depth; + } + emit nextStep(); + } + for(uint i = 0; i < halfsize; i++) + { + uint p = i*wav->size*wav->depth; + memcpy(wav->coeffs + p, buff->coeffs + p, l); + p = (i + halfsize )*wav->size*wav->depth; + memcpy(wav->coeffs + p, buff->coeffs + p, l); + } + if(halfsize != 1) + { + wavetrans(wav, buff, halfsize/2); + } +} + +void KisBasicMathToolbox::waveuntrans(KisMathToolbox::KisWavelet* wav, KisMathToolbox::KisWavelet* buff, uint halfsize) +{ + uint l = (2*halfsize)*wav->depth*sizeof(float); + for(uint i = 0; i < halfsize; i++) + { + float * itLL = wav->coeffs + i*buff->size*buff->depth; + float * itHL = wav->coeffs + (i*buff->size + halfsize)*buff->depth; + float * itLH = wav->coeffs + (halfsize+i)*buff->size*buff->depth; + float * itHH = wav->coeffs + ( (halfsize+i)*buff->size + halfsize)*buff->depth; + float * itS11 = buff->coeffs + 2*i*wav->size*wav->depth; + float * itS12 = buff->coeffs + (2*i*wav->size+1)*wav->depth; + float * itS21 = buff->coeffs + (2*i+1)*wav->size*wav->depth; + float * itS22 = buff->coeffs + ((2*i+1)*wav->size+1)*wav->depth; + for(uint j = 0; j < halfsize; j++) + { + for( uint k = 0; k < wav->depth; k++) + { + *(itS11++) = (*itLL + *itHL + *itLH + *itHH)*0.25*M_SQRT2; + *(itS12++) = (*itLL - *itHL + *itLH - *itHH)*0.25*M_SQRT2; + *(itS21++) = (*itLL + *itHL - *itLH - *itHH)*0.25*M_SQRT2; + *(itS22++) = (*(itLL++) - *(itHL++) - *(itLH++) + *(itHH++))*0.25*M_SQRT2; + } + itS11 += wav->depth; itS12 += wav->depth; + itS21 += wav->depth; itS22 += wav->depth; + } + emit nextStep(); + } + for(uint i = 0; i < halfsize; i++) + { + uint p = i*wav->size*wav->depth; + memcpy(wav->coeffs + p, buff->coeffs + p, l); + p = (i + halfsize )*wav->size*wav->depth; + memcpy(wav->coeffs + p, buff->coeffs + p, l); + } + + if(halfsize != wav->size/2) + { + waveuntrans(wav, buff, halfsize*2); + } +} + +KisMathToolbox::KisWavelet* KisBasicMathToolbox::fastWaveletTransformation(KisPaintDeviceSP src, const TQRect& rect, KisWavelet* buff) +{ + if(buff == 0) + { + buff = initWavelet( src, rect ); + } + KisWavelet* wav = initWavelet( src, rect ); + transformToFR(src, wav, rect); + wavetrans(wav, buff, wav->size / 2); + + return wav; +} + +void KisBasicMathToolbox::fastWaveletUntransformation(KisPaintDeviceSP dst, const TQRect& rect, KisWavelet* wav, KisWavelet* buff) +{ + if(buff == 0) + { + buff = initWavelet( dst, rect ); + } + + waveuntrans(wav, buff, 1 ); + transformFromFR(dst, wav, rect); +} diff --git a/chalk/core/kis_basic_math_toolbox.h b/chalk/core/kis_basic_math_toolbox.h new file mode 100644 index 00000000..e5fa66cd --- /dev/null +++ b/chalk/core/kis_basic_math_toolbox.h @@ -0,0 +1,44 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_BASIC_MATH_TOOLBOX_H +#define KIS_BASIC_MATH_TOOLBOX_H + +#include "kis_math_toolbox.h" + +/** + * This class implement KisMathToolbox for most colorspaces, only colorspaces with "angular" + * channels need to reimplement the functions + */ +class KisBasicMathToolbox : public KisMathToolbox +{ + public: + KisBasicMathToolbox(); + ~KisBasicMathToolbox(); + public: + virtual KisWavelet* fastWaveletTransformation(KisPaintDeviceSP src, const TQRect&, KisWavelet* buff = 0); + virtual void fastWaveletUntransformation(KisPaintDeviceSP dst, const TQRect&, KisWavelet* wav, KisWavelet* buff = 0); + private: + void wavetrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); + void waveuntrans(KisWavelet* wav, KisWavelet* buff, uint halfsize); + +}; + +#endif diff --git a/chalk/core/kis_boundary.cc b/chalk/core/kis_boundary.cc new file mode 100644 index 00000000..0c9681c2 --- /dev/null +++ b/chalk/core/kis_boundary.cc @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "kis_colorspace.h" +#include "kis_iterators_pixel.h" +#include "kis_paint_device.h" +#include "kis_boundary.h" + +KisBoundary::KisBoundary(KisPaintDevice* dev) { + m_device = dev; + m_fuzzyness = 255 / 2; +} + +bool KisBoundary::isDark(TQ_UINT8 val) { + return val < m_fuzzyness; +} + +void KisBoundary::generateBoundary(int w, int h) { + if (!m_device) + return; + + KisColorSpace* cs = m_device->colorSpace(); + + //Qt::Horizontal + for (int currentY = - 1; currentY < h; currentY++) { + KisHLineIteratorPixel topIt = m_device->createHLineIterator(0, currentY, w, false); + KisHLineIteratorPixel botIt = m_device->createHLineIterator(0, currentY + 1, w, false); + bool darkTop; + bool darkBot; + + m_horSegments.append(TQValueList()); + + while (!topIt.isDone()) { + darkTop = cs->getAlpha(topIt.rawData()); + darkBot = cs->getAlpha(botIt.rawData()); + if (darkTop != darkBot) { + // detected a change + m_horSegments.back().append(tqMakePair(KisPoint(botIt.x(), botIt.y()), 1)); + } + ++topIt; + ++botIt; + } + } + + //Qt::Vertical + for (int currentX = - 1; currentX < w; currentX++) { + KisVLineIteratorPixel leftIt = m_device->createVLineIterator(currentX, 0, h, false); + KisVLineIteratorPixel rightIt = m_device->createVLineIterator(currentX + 1, 0, h, false); + bool darkLeft; + bool darkRight; + + m_vertSegments.append(TQValueList()); + + while (!leftIt.isDone()) { + darkLeft = cs->getAlpha(leftIt.rawData()); + darkRight = cs->getAlpha(rightIt.rawData()); + if (darkLeft != darkRight) { + // detected a change + m_vertSegments.back().append(tqMakePair(KisPoint(rightIt.x(), rightIt.y()), 1)); + } + ++leftIt; + ++rightIt; + } + } +} + diff --git a/chalk/core/kis_boundary.h b/chalk/core/kis_boundary.h new file mode 100644 index 00000000..6c5ce8c6 --- /dev/null +++ b/chalk/core/kis_boundary.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_BOUNDARY_H_ +#define _KIS_BOUNDARY_H_ + +#include +#include +#include + +#include "kis_point.h" + +class KisPaintDevice; + +/** + * Generates an 'outline' for a paint device. It should look a bit like the outline of a + * marching ants selection. You can use it to paint the outline of a KisBrush while painting. + * It's not really optimized, so it's not recommended to do big things with it and expect + * it to be fast. + * Usage: construct a KisBoundary, and then run a generateBoundary(w, h) on it. After that, + * you can use the KisBoundaryPainter::paint method to let it paint the outline, or get a pixmap. + **/ +class KRITACORE_EXPORT KisBoundary { +public: + KisBoundary(KisPaintDevice* dev); + void generateBoundary(int w, int h); + +private: + typedef TQPair PointPair; // int->length + bool isDark(TQ_UINT8 val); + KisPaintDevice* m_device; + int m_fuzzyness; + + typedef TQValueList PointPairList; + typedef TQValueList< PointPairList > PointPairListList; + + PointPairListList m_horSegments; + PointPairListList m_vertSegments; + + friend class KisBoundaryPainter; +}; + +#endif // _KIS_BOUNDARY_H_ diff --git a/chalk/core/kis_brush.cc b/chalk/core/kis_brush.cc new file mode 100644 index 00000000..9720a3e1 --- /dev/null +++ b/chalk/core/kis_brush.cc @@ -0,0 +1,1333 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include "kis_paint_device.h" +#include "kis_global.h" +#include "kis_brush.h" +#include "kis_alpha_mask.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_iterators_pixel.h" +#include "kis_image.h" + + +namespace { + struct GimpBrushV1Header { + TQ_UINT32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ + TQ_UINT32 version; /* brush file version # */ + TQ_UINT32 width; /* width of brush */ + TQ_UINT32 height; /* height of brush */ + TQ_UINT32 bytes; /* depth of brush in bytes */ + }; + + /// All fields are in MSB on disk! + struct GimpBrushHeader { + TQ_UINT32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ + TQ_UINT32 version; /* brush file version # */ + TQ_UINT32 width; /* width of brush */ + TQ_UINT32 height; /* height of brush */ + TQ_UINT32 bytes; /* depth of brush in bytes */ + + /* The following are only defined in version 2 */ + TQ_UINT32 magic_number; /* GIMP brush magic number */ + TQ_UINT32 spacing; /* brush spacing as % of width & height, 0 - 1000 */ + }; + + // Needed, or the GIMP won't open it! + TQ_UINT32 const GimpV2BrushMagic = ('G' << 24) + ('I' << 16) + ('M' << 8) + ('P' << 0); +} + +#define DEFAULT_SPACING 0.25 +#define MAXIMUM_SCALE 2 + +KisBrush::KisBrush(const TQString& filename) : super(filename) +{ + m_brushType = INVALID; + m_ownData = true; + m_useColorAsMask = false; + m_hasColor = false; + m_spacing = DEFAULT_SPACING; + m_boundary = 0; +} + +KisBrush::KisBrush(const TQString& filename, + const TQByteArray& data, + TQ_UINT32 & dataPos) : super(filename) +{ + m_brushType = INVALID; + m_ownData = false; + m_useColorAsMask = false; + m_hasColor = false; + m_spacing = DEFAULT_SPACING; + m_boundary = 0; + + m_data.setRawData(data.data() + dataPos, data.size() - dataPos); + init(); + m_data.resetRawData(data.data() + dataPos, data.size() - dataPos); + dataPos += m_header_size + (width() * height() * m_bytes); +} + +KisBrush::KisBrush(KisPaintDevice* image, int x, int y, int w, int h) + : super(TQString("")) +{ + m_brushType = INVALID; + m_ownData = true; + m_useColorAsMask = false; + m_hasColor = true; + m_spacing = DEFAULT_SPACING; + m_boundary = 0; + + initFromPaintDev(image, x, y, w, h); +} + +KisBrush::KisBrush(const TQImage& image, const TQString& name) + : super(TQString("")) +{ + m_ownData = false; + m_useColorAsMask = false; + m_hasColor = true; + m_spacing = DEFAULT_SPACING; + m_boundary = 0; + + setImage(image); + setName(name); + setBrushType(IMAGE); +} + + +KisBrush::~KisBrush() +{ + m_scaledBrushes.clear(); + delete m_boundary; +} + +bool KisBrush::load() +{ + if (m_ownData) { + TQFile file(filename()); + file.open(IO_ReadOnly); + m_data = file.readAll(); + file.close(); + } + return init(); +} + +bool KisBrush::init() +{ + GimpBrushHeader bh; + + if (sizeof(GimpBrushHeader) > m_data.size()) { + return false; + } + + memcpy(&bh, &m_data[0], sizeof(GimpBrushHeader)); + bh.header_size = ntohl(bh.header_size); + m_header_size = bh.header_size; + + bh.version = ntohl(bh.version); + m_version = bh.version; + + bh.width = ntohl(bh.width); + bh.height = ntohl(bh.height); + + bh.bytes = ntohl(bh.bytes); + m_bytes = bh.bytes; + + bh.magic_number = ntohl(bh.magic_number); + m_magic_number = bh.magic_number; + + if (bh.version == 1) { + // No spacing in version 1 files so use Gimp default + bh.spacing = static_cast(DEFAULT_SPACING * 100); + } + else { + bh.spacing = ntohl(bh.spacing); + + if (bh.spacing > 1000) { + return false; + } + } + + setSpacing(bh.spacing / 100.0); + + if (bh.header_size > m_data.size() || bh.header_size == 0) { + return false; + } + + TQString name; + + if (bh.version == 1) { + // Version 1 has no magic number or spacing, so the name + // is at a different offset. Character encoding is undefined. + const char *text = &m_data[sizeof(GimpBrushV1Header)]; + name = TQString::fromAscii(text, bh.header_size - sizeof(GimpBrushV1Header)); + } else { + // ### Version = 3->cinepaint; may be float16 data! + // Version >=2: UTF-8 encoding is used + name = TQString::fromUtf8(&m_data[sizeof(GimpBrushHeader)], + bh.header_size - sizeof(GimpBrushHeader)); + } + + setName(i18n(name.ascii())); // Ascii? And what with real UTF-8 chars? + + if (bh.width == 0 || bh.height == 0 || !m_img.create(bh.width, bh.height, 32)) { + return false; + } + + TQ_INT32 k = bh.header_size; + + if (bh.bytes == 1) { + // Grayscale + + if (static_cast(k + bh.width * bh.height) > m_data.size()) { + return false; + } + + m_brushType = MASK; + m_hasColor = false; + + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++, k++) { + TQ_INT32 val = 255 - static_cast(m_data[k]); + m_img.setPixel(x, y, tqRgb(val, val, val)); + } + } + } else if (bh.bytes == 4) { + // RGBA + + if (static_cast(k + (bh.width * bh.height * 4)) > m_data.size()) { + return false; + } + + m_brushType = IMAGE; + m_img.setAlphaBuffer(true); + m_hasColor = true; + + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++, k += 4) { + m_img.setPixel(x, y, tqRgba(m_data[k], + m_data[k+1], + m_data[k+2], + m_data[k+3])); + } + } + } else { + return false; + } + + setWidth(m_img.width()); + setHeight(m_img.height()); + //createScaledBrushes(); + if (m_ownData) { + m_data.resize(0); // Save some memory, we're using enough of it as it is. + } + + + if (m_img.width() == 0 || m_img.height() == 0) + setValid(false); + else + setValid(true); + + return true; +} + +bool KisBrush::initFromPaintDev(KisPaintDevice* image, int x, int y, int w, int h) { + // Forcefully convert to RGBA8 + // XXX profile and exposure? + setImage(image->convertToTQImage(0, x, y, w, h)); + setName(image->name()); + + m_brushType = IMAGE; + m_hasColor = true; + + return true; +} + +bool KisBrush::save() +{ + TQFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + bool ok = saveToDevice(TQT_TQIODEVICE(&file)); + file.close(); + return ok; +} + +bool KisBrush::saveToDevice(TQIODevice* dev) const +{ + GimpBrushHeader bh; + TQCString utf8Name = name().utf8(); // Names in v2 brushes are in UTF-8 + char const* name = utf8Name.data(); + int nameLength = tqstrlen(name); + int wrote; + + bh.header_size = htonl(sizeof(GimpBrushHeader) + nameLength); + bh.version = htonl(2); // Only RGBA8 data needed atm, no cinepaint stuff + bh.width = htonl(width()); + bh.height = htonl(height()); + // Hardcoded, 4 bytes RGBA or 1 byte GREY + if (!hasColor()) + bh.bytes = htonl(1); + else + bh.bytes = htonl(4); + bh.magic_number = htonl(GimpV2BrushMagic); + bh.spacing = htonl(static_cast(spacing() * 100.0)); + + // Write header: first bh, then the name + TQByteArray bytes; + bytes.setRawData(reinterpret_cast(&bh), sizeof(GimpBrushHeader)); + wrote = dev->writeBlock(bytes); + bytes.resetRawData(reinterpret_cast(&bh), sizeof(GimpBrushHeader)); + + if (wrote == -1) + return false; + + wrote = dev->writeBlock(name, nameLength); // No +1 for the trailing NULL it seems... + if (wrote == -1) + return false; + + int k = 0; + + if (!hasColor()) { + bytes.resize(width() * height()); + for (TQ_INT32 y = 0; y < height(); y++) { + for (TQ_INT32 x = 0; x < width(); x++) { + TQRgb c = m_img.pixel(x, y); + bytes[k++] = static_cast(255 - tqRed(c)); // red == blue == green + } + } + } else { + bytes.resize(width() * height() * 4); + for (TQ_INT32 y = 0; y < height(); y++) { + for (TQ_INT32 x = 0; x < width(); x++) { + // order for gimp brushes, v2 is: RGBA + TQRgb pixel = m_img.pixel(x,y); + bytes[k++] = static_cast(tqRed(pixel)); + bytes[k++] = static_cast(tqGreen(pixel)); + bytes[k++] = static_cast(tqBlue(pixel)); + bytes[k++] = static_cast(tqAlpha(pixel)); + } + } + } + + wrote = dev->writeBlock(bytes); + if (wrote == -1) + return false; + + return true; +} + +TQImage KisBrush::img() +{ + TQImage image = m_img; + + if (hasColor() && useColorAsMask()) { + image.detach(); + + for (int x = 0; x < image.width(); x++) { + for (int y = 0; y < image.height(); y++) { + TQRgb c = image.pixel(x, y); + int a = (tqGray(c) * tqAlpha(c)) / 255; + image.setPixel(x, y, tqRgba(a, 0, a, a)); + } + } + } + + return image; +} + +KisAlphaMaskSP KisBrush::tqmask(const KisPaintInformation& info, double subPixelX, double subPixelY) const +{ + if (m_scaledBrushes.isEmpty()) { + createScaledBrushes(); + } + + double scale = scaleForPressure(info.pressure); + + const ScaledBrush *aboveBrush = 0; + const ScaledBrush *belowBrush = 0; + + findScaledBrushes(scale, &aboveBrush, &belowBrush); + Q_ASSERT(aboveBrush != 0); + + KisAlphaMaskSP outputMask = 0; + + if (belowBrush != 0) { + // We're in between two tqmasks. Interpolate between them. + + KisAlphaMaskSP scaledAboveMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY); + KisAlphaMaskSP scaledBelowMask = scaleMask(belowBrush, scale, subPixelX, subPixelY); + + double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale()); + + outputMask = KisAlphaMask::interpolate(scaledBelowMask, scaledAboveMask, t); + } else { + if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) { + // Exact match. + outputMask = scaleMask(aboveBrush, scale, subPixelX, subPixelY); + } else { + // We are smaller than the smallest tqmask, which is always 1x1. + double s = scale / aboveBrush->scale(); + outputMask = scaleSinglePixelMask(s, aboveBrush->tqmask()->alphaAt(0, 0), subPixelX, subPixelY); + } + } + + return outputMask; +} + +KisPaintDeviceSP KisBrush::image(KisColorSpace * /*colorSpace*/, const KisPaintInformation& info, double subPixelX, double subPixelY) const +{ + if (m_scaledBrushes.isEmpty()) { + createScaledBrushes(); + } + + double scale = scaleForPressure(info.pressure); + + const ScaledBrush *aboveBrush = 0; + const ScaledBrush *belowBrush = 0; + + findScaledBrushes(scale, &aboveBrush, &belowBrush); + Q_ASSERT(aboveBrush != 0); + + TQImage outputImage; + + if (belowBrush != 0) { + // We're in between two brushes. Interpolate between them. + + TQImage scaledAboveImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY); + TQImage scaledBelowImage = scaleImage(belowBrush, scale, subPixelX, subPixelY); + + double t = (scale - belowBrush->scale()) / (aboveBrush->scale() - belowBrush->scale()); + + outputImage = interpolate(scaledBelowImage, scaledAboveImage, t); + } else { + if (fabs(scale - aboveBrush->scale()) < DBL_EPSILON) { + // Exact match. + outputImage = scaleImage(aboveBrush, scale, subPixelX, subPixelY); + } else { + // We are smaller than the smallest brush, which is always 1x1. + double s = scale / aboveBrush->scale(); + outputImage = scaleSinglePixelImage(s, aboveBrush->image().pixel(0, 0), subPixelX, subPixelY); + } + } + + int outputWidth = outputImage.width(); + int outputHeight = outputImage.height(); + + KisPaintDevice *layer = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "brush"); + + Q_CHECK_PTR(layer); + + for (int y = 0; y < outputHeight; y++) { + KisHLineIterator iter = layer->createHLineIterator( 0, y, outputWidth, true); + for (int x = 0; x < outputWidth; x++) { + TQ_UINT8 * p = iter.rawData(); + + TQRgb pixel = outputImage.pixel(x, y); + int red = tqRed(pixel); + int green = tqGreen(pixel); + int blue = tqBlue(pixel); + int alpha = tqAlpha(pixel); + + // Scaled images are in pre-multiplied alpha form so + // divide by alpha. + // channel order is BGRA + if (alpha != 0) { + p[2] = (red * 255) / alpha; + p[1] = (green * 255) / alpha; + p[0] = (blue * 255) / alpha; + p[3] = alpha; + } + + ++iter; + } + } + + return layer; +} + +void KisBrush::setHotSpot(KisPoint pt) +{ + double x = pt.x(); + double y = pt.y(); + + if (x < 0) + x = 0; + else if (x >= width()) + x = width() - 1; + + if (y < 0) + y = 0; + else if (y >= height()) + y = height() - 1; + + m_hotSpot = KisPoint(x, y); +} + +KisPoint KisBrush::hotSpot(const KisPaintInformation& info) const +{ + double scale = scaleForPressure(info.pressure); + double w = width() * scale; + double h = height() * scale; + + // The smallest brush we can produce is a single pixel. + if (w < 1) { + w = 1; + } + + if (h < 1) { + h = 1; + } + + // XXX: This should take m_hotSpot into account, though it + // isn't specified by gimp brushes so it would default to the centre + // anyway. + KisPoint p(w / 2, h / 2); + return p; +} + +enumBrushType KisBrush::brushType() const +{ + if (m_brushType == IMAGE && useColorAsMask()) { + return MASK; + } + else { + return m_brushType; + } +} + +bool KisBrush::hasColor() const +{ + return m_hasColor; +} + +void KisBrush::createScaledBrushes() const +{ + if (!m_scaledBrushes.isEmpty()) + m_scaledBrushes.clear(); + + // Construct a series of brushes where each one's dimensions are + // half the size of the previous one. + int width = m_img.width() * MAXIMUM_SCALE; + int height = m_img.height() * MAXIMUM_SCALE; + + TQImage scaledImage; + + while (true) { + + if (width >= m_img.width() && height >= m_img.height()) { + scaledImage = scaleImage(m_img, width, height); + } + else { + // Scale down the previous image once we're below 1:1. + scaledImage = scaleImage(scaledImage, width, height); + } + + KisAlphaMaskSP scaledMask = new KisAlphaMask(scaledImage, hasColor()); + Q_CHECK_PTR(scaledMask); + + double xScale = static_cast(width) / m_img.width(); + double yScale = static_cast(height) / m_img.height(); + double scale = xScale; + + m_scaledBrushes.append(ScaledBrush(scaledMask, hasColor() ? scaledImage : TQImage(), scale, xScale, yScale)); + + if (width == 1 && height == 1) { + break; + } + + // Round up so that we never have to scale an image by less than 1/2. + width = (width + 1) / 2; + height = (height + 1) / 2; + + } + +} + +double KisBrush::xSpacing(double pressure) const +{ + return width() * scaleForPressure(pressure) * m_spacing; +} + +double KisBrush::ySpacing(double pressure) const +{ + return height() * scaleForPressure(pressure) * m_spacing; +} + +double KisBrush::scaleForPressure(double pressure) +{ + double scale = pressure / PRESSURE_DEFAULT; + + if (scale < 0) { + scale = 0; + } + + if (scale > MAXIMUM_SCALE) { + scale = MAXIMUM_SCALE; + } + + return scale; +} + +TQ_INT32 KisBrush::tqmaskWidth(const KisPaintInformation& info) const +{ + // Add one for sub-pixel shift + return static_cast(ceil(width() * scaleForPressure(info.pressure)) + 1); +} + +TQ_INT32 KisBrush::tqmaskHeight(const KisPaintInformation& info) const +{ + // Add one for sub-pixel shift + return static_cast(ceil(height() * scaleForPressure(info.pressure)) + 1); +} + +KisAlphaMaskSP KisBrush::scaleMask(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const +{ + // Add one pixel for sub-pixel shifting + int dstWidth = static_cast(ceil(scale * width())) + 1; + int dstHeight = static_cast(ceil(scale * height())) + 1; + + KisAlphaMaskSP dstMask = new KisAlphaMask(dstWidth, dstHeight); + Q_CHECK_PTR(dstMask); + + KisAlphaMaskSP srcMask = srcBrush->tqmask(); + + // Compute scales to map the scaled brush onto the required scale. + double xScale = srcBrush->xScale() / scale; + double yScale = srcBrush->yScale() / scale; + + int srcWidth = srcMask->width(); + int srcHeight = srcMask->height(); + + for (int dstY = 0; dstY < dstHeight; dstY++) { + for (int dstX = 0; dstX < dstWidth; dstX++) { + + double srcX = (dstX - subPixelX + 0.5) * xScale; + double srcY = (dstY - subPixelY + 0.5) * yScale; + + srcX -= 0.5; + srcY -= 0.5; + + int leftX = static_cast(srcX); + + if (srcX < 0) { + leftX--; + } + + double xInterp = srcX - leftX; + + int topY = static_cast(srcY); + + if (srcY < 0) { + topY--; + } + + double yInterp = srcY - topY; + + TQ_UINT8 topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX, topY) : OPACITY_TRANSPARENT; + TQ_UINT8 bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX, topY + 1) : OPACITY_TRANSPARENT; + TQ_UINT8 topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcMask->alphaAt(leftX + 1, topY) : OPACITY_TRANSPARENT; + TQ_UINT8 bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcMask->alphaAt(leftX + 1, topY + 1) : OPACITY_TRANSPARENT; + + double a = 1 - xInterp; + double b = 1 - yInterp; + + // Bi-linear interpolation + int d = static_cast(a * b * topLeft + + a * (1 - b) * bottomLeft + + (1 - a) * b * topRight + + (1 - a) * (1 - b) * bottomRight + 0.5); + + if (d < OPACITY_TRANSPARENT) { + d = OPACITY_TRANSPARENT; + } + else + if (d > OPACITY_OPAQUE) { + d = OPACITY_OPAQUE; + } + + dstMask->setAlphaAt(dstX, dstY, static_cast(d)); + } + } + + return dstMask; +} + +TQImage KisBrush::scaleImage(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const +{ + // Add one pixel for sub-pixel shifting + int dstWidth = static_cast(ceil(scale * width())) + 1; + int dstHeight = static_cast(ceil(scale * height())) + 1; + + TQImage dstImage(dstWidth, dstHeight, 32); + dstImage.setAlphaBuffer(true); + + const TQImage srcImage = srcBrush->image(); + + // Compute scales to map the scaled brush onto the required scale. + double xScale = srcBrush->xScale() / scale; + double yScale = srcBrush->yScale() / scale; + + int srcWidth = srcImage.width(); + int srcHeight = srcImage.height(); + + for (int dstY = 0; dstY < dstHeight; dstY++) { + for (int dstX = 0; dstX < dstWidth; dstX++) { + + double srcX = (dstX - subPixelX + 0.5) * xScale; + double srcY = (dstY - subPixelY + 0.5) * yScale; + + srcX -= 0.5; + srcY -= 0.5; + + int leftX = static_cast(srcX); + + if (srcX < 0) { + leftX--; + } + + double xInterp = srcX - leftX; + + int topY = static_cast(srcY); + + if (srcY < 0) { + topY--; + } + + double yInterp = srcY - topY; + + TQRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : tqRgba(0, 0, 0, 0); + TQRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : tqRgba(0, 0, 0, 0); + TQRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : tqRgba(0, 0, 0, 0); + TQRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : tqRgba(0, 0, 0, 0); + + double a = 1 - xInterp; + double b = 1 - yInterp; + + // Bi-linear interpolation. Image is pre-multiplied by alpha. + int red = static_cast(a * b * tqRed(topLeft) + + a * (1 - b) * tqRed(bottomLeft) + + (1 - a) * b * tqRed(topRight) + + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5); + int green = static_cast(a * b * tqGreen(topLeft) + + a * (1 - b) * tqGreen(bottomLeft) + + (1 - a) * b * tqGreen(topRight) + + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5); + int blue = static_cast(a * b * tqBlue(topLeft) + + a * (1 - b) * tqBlue(bottomLeft) + + (1 - a) * b * tqBlue(topRight) + + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5); + int alpha = static_cast(a * b * tqAlpha(topLeft) + + a * (1 - b) * tqAlpha(bottomLeft) + + (1 - a) * b * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5); + + if (red < 0) { + red = 0; + } + else + if (red > 255) { + red = 255; + } + + if (green < 0) { + green = 0; + } + else + if (green > 255) { + green = 255; + } + + if (blue < 0) { + blue = 0; + } + else + if (blue > 255) { + blue = 255; + } + + if (alpha < 0) { + alpha = 0; + } + else + if (alpha > 255) { + alpha = 255; + } + + dstImage.setPixel(dstX, dstY, tqRgba(red, green, blue, alpha)); + } + } + + return dstImage; +} + +TQImage KisBrush::scaleImage(const TQImage& srcImage, int width, int height) +{ + TQImage scaledImage; + //TQString filename; + + int srcWidth = srcImage.width(); + int srcHeight = srcImage.height(); + + double xScale = static_cast(srcWidth) / width; + double yScale = static_cast(srcHeight) / height; + + if (xScale > 2 + DBL_EPSILON || yScale > 2 + DBL_EPSILON || xScale < 1 - DBL_EPSILON || yScale < 1 - DBL_EPSILON) { + // smoothScale gives better results when scaling an image up + // or scaling it to less than half size. + scaledImage = srcImage.smoothScale(width, height); + + //filename = TQString("smoothScale_%1x%2.png").tqarg(width).tqarg(height); + } + else { + scaledImage.create(width, height, 32); + scaledImage.setAlphaBuffer(srcImage.hasAlphaBuffer()); + + for (int dstY = 0; dstY < height; dstY++) { + for (int dstX = 0; dstX < width; dstX++) { + + double srcX = (dstX + 0.5) * xScale; + double srcY = (dstY + 0.5) * yScale; + + srcX -= 0.5; + srcY -= 0.5; + + int leftX = static_cast(srcX); + + if (srcX < 0) { + leftX--; + } + + double xInterp = srcX - leftX; + + int topY = static_cast(srcY); + + if (srcY < 0) { + topY--; + } + + double yInterp = srcY - topY; + + TQRgb topLeft = (leftX >= 0 && leftX < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX, topY) : tqRgba(0, 0, 0, 0); + TQRgb bottomLeft = (leftX >= 0 && leftX < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX, topY + 1) : tqRgba(0, 0, 0, 0); + TQRgb topRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY >= 0 && topY < srcHeight) ? srcImage.pixel(leftX + 1, topY) : tqRgba(0, 0, 0, 0); + TQRgb bottomRight = (leftX + 1 >= 0 && leftX + 1 < srcWidth && topY + 1 >= 0 && topY + 1 < srcHeight) ? srcImage.pixel(leftX + 1, topY + 1) : tqRgba(0, 0, 0, 0); + + double a = 1 - xInterp; + double b = 1 - yInterp; + + int red; + int green; + int blue; + int alpha; + + if (srcImage.hasAlphaBuffer()) { + red = static_cast(a * b * tqRed(topLeft) * tqAlpha(topLeft) + + a * (1 - b) * tqRed(bottomLeft) * tqAlpha(bottomLeft) + + (1 - a) * b * tqRed(topRight) * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqRed(bottomRight) * tqAlpha(bottomRight) + 0.5); + green = static_cast(a * b * tqGreen(topLeft) * tqAlpha(topLeft) + + a * (1 - b) * tqGreen(bottomLeft) * tqAlpha(bottomLeft) + + (1 - a) * b * tqGreen(topRight) * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqGreen(bottomRight) * tqAlpha(bottomRight) + 0.5); + blue = static_cast(a * b * tqBlue(topLeft) * tqAlpha(topLeft) + + a * (1 - b) * tqBlue(bottomLeft) * tqAlpha(bottomLeft) + + (1 - a) * b * tqBlue(topRight) * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqBlue(bottomRight) * tqAlpha(bottomRight) + 0.5); + alpha = static_cast(a * b * tqAlpha(topLeft) + + a * (1 - b) * tqAlpha(bottomLeft) + + (1 - a) * b * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5); + + if (alpha != 0) { + red /= alpha; + green /= alpha; + blue /= alpha; + } + } + else { + red = static_cast(a * b * tqRed(topLeft) + + a * (1 - b) * tqRed(bottomLeft) + + (1 - a) * b * tqRed(topRight) + + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5); + green = static_cast(a * b * tqGreen(topLeft) + + a * (1 - b) * tqGreen(bottomLeft) + + (1 - a) * b * tqGreen(topRight) + + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5); + blue = static_cast(a * b * tqBlue(topLeft) + + a * (1 - b) * tqBlue(bottomLeft) + + (1 - a) * b * tqBlue(topRight) + + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5); + alpha = 255; + } + + if (red < 0) { + red = 0; + } + else + if (red > 255) { + red = 255; + } + + if (green < 0) { + green = 0; + } + else + if (green > 255) { + green = 255; + } + + if (blue < 0) { + blue = 0; + } + else + if (blue > 255) { + blue = 255; + } + + if (alpha < 0) { + alpha = 0; + } + else + if (alpha > 255) { + alpha = 255; + } + + scaledImage.setPixel(dstX, dstY, tqRgba(red, green, blue, alpha)); + } + } + + //filename = TQString("bilinear_%1x%2.png").tqarg(width).tqarg(height); + } + + //scaledImage.save(filename, "PNG"); + + return scaledImage; +} + +void KisBrush::findScaledBrushes(double scale, const ScaledBrush **aboveBrush, const ScaledBrush **belowBrush) const +{ + uint current = 0; + + while (true) { + *aboveBrush = &(m_scaledBrushes[current]); + + if (fabs((*aboveBrush)->scale() - scale) < DBL_EPSILON) { + // Scale matches exactly + break; + } + + if (current == m_scaledBrushes.count() - 1) { + // This is the last one + break; + } + + if (scale > m_scaledBrushes[current + 1].scale() + DBL_EPSILON) { + // We fit in between the two. + *belowBrush = &(m_scaledBrushes[current + 1]); + break; + } + + current++; + } +} + +KisAlphaMaskSP KisBrush::scaleSinglePixelMask(double scale, TQ_UINT8 tqmaskValue, double subPixelX, double subPixelY) +{ + int srcWidth = 1; + int srcHeight = 1; + int dstWidth = 2; + int dstHeight = 2; + KisAlphaMaskSP outputMask = new KisAlphaMask(dstWidth, dstHeight); + Q_CHECK_PTR(outputMask); + + double a = subPixelX; + double b = subPixelY; + + for (int y = 0; y < dstHeight; y++) { + for (int x = 0; x < dstWidth; x++) { + + TQ_UINT8 topLeft = (x > 0 && y > 0) ? tqmaskValue : OPACITY_TRANSPARENT; + TQ_UINT8 bottomLeft = (x > 0 && y < srcHeight) ? tqmaskValue : OPACITY_TRANSPARENT; + TQ_UINT8 topRight = (x < srcWidth && y > 0) ? tqmaskValue : OPACITY_TRANSPARENT; + TQ_UINT8 bottomRight = (x < srcWidth && y < srcHeight) ? tqmaskValue : OPACITY_TRANSPARENT; + + // Bi-linear interpolation + int d = static_cast(a * b * topLeft + + a * (1 - b) * bottomLeft + + (1 - a) * b * topRight + + (1 - a) * (1 - b) * bottomRight + 0.5); + + // Multiply by the square of the scale because a 0.5x0.5 pixel + // has 0.25 the value of the 1x1. + d = static_cast(d * scale * scale + 0.5); + + if (d < OPACITY_TRANSPARENT) { + d = OPACITY_TRANSPARENT; + } + else + if (d > OPACITY_OPAQUE) { + d = OPACITY_OPAQUE; + } + + outputMask->setAlphaAt(x, y, static_cast(d)); + } + } + + return outputMask; +} + +TQImage KisBrush::scaleSinglePixelImage(double scale, TQRgb pixel, double subPixelX, double subPixelY) +{ + int srcWidth = 1; + int srcHeight = 1; + int dstWidth = 2; + int dstHeight = 2; + + TQImage outputImage(dstWidth, dstHeight, 32); + outputImage.setAlphaBuffer(true); + + double a = subPixelX; + double b = subPixelY; + + for (int y = 0; y < dstHeight; y++) { + for (int x = 0; x < dstWidth; x++) { + + TQRgb topLeft = (x > 0 && y > 0) ? pixel : tqRgba(0, 0, 0, 0); + TQRgb bottomLeft = (x > 0 && y < srcHeight) ? pixel : tqRgba(0, 0, 0, 0); + TQRgb topRight = (x < srcWidth && y > 0) ? pixel : tqRgba(0, 0, 0, 0); + TQRgb bottomRight = (x < srcWidth && y < srcHeight) ? pixel : tqRgba(0, 0, 0, 0); + + // Bi-linear interpolation. Images are in pre-multiplied form. + int red = static_cast(a * b * tqRed(topLeft) + + a * (1 - b) * tqRed(bottomLeft) + + (1 - a) * b * tqRed(topRight) + + (1 - a) * (1 - b) * tqRed(bottomRight) + 0.5); + int green = static_cast(a * b * tqGreen(topLeft) + + a * (1 - b) * tqGreen(bottomLeft) + + (1 - a) * b * tqGreen(topRight) + + (1 - a) * (1 - b) * tqGreen(bottomRight) + 0.5); + int blue = static_cast(a * b * tqBlue(topLeft) + + a * (1 - b) * tqBlue(bottomLeft) + + (1 - a) * b * tqBlue(topRight) + + (1 - a) * (1 - b) * tqBlue(bottomRight) + 0.5); + int alpha = static_cast(a * b * tqAlpha(topLeft) + + a * (1 - b) * tqAlpha(bottomLeft) + + (1 - a) * b * tqAlpha(topRight) + + (1 - a) * (1 - b) * tqAlpha(bottomRight) + 0.5); + + // Multiply by the square of the scale because a 0.5x0.5 pixel + // has 0.25 the value of the 1x1. + alpha = static_cast(alpha * scale * scale + 0.5); + + // Apply to the colour channels too since we are + // storing pre-multiplied by alpha. + red = static_cast(red * scale * scale + 0.5); + green = static_cast(green * scale * scale + 0.5); + blue = static_cast(blue * scale * scale + 0.5); + + if (red < 0) { + red = 0; + } + else + if (red > 255) { + red = 255; + } + + if (green < 0) { + green = 0; + } + else + if (green > 255) { + green = 255; + } + + if (blue < 0) { + blue = 0; + } + else + if (blue > 255) { + blue = 255; + } + + if (alpha < 0) { + alpha = 0; + } + else + if (alpha > 255) { + alpha = 255; + } + + outputImage.setPixel(x, y, tqRgba(red, green, blue, alpha)); + } + } + + return outputImage; +} + +TQImage KisBrush::interpolate(const TQImage& image1, const TQImage& image2, double t) +{ + Q_ASSERT((image1.width() == image2.width()) && (image1.height() == image2.height())); + Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); + + int width = image1.width(); + int height = image1.height(); + + TQImage outputImage(width, height, 32); + outputImage.setAlphaBuffer(true); + + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + TQRgb image1pixel = image1.pixel(x, y); + TQRgb image2pixel = image2.pixel(x, y); + + // Images are in pre-multiplied alpha format. + int red = static_cast((1 - t) * tqRed(image1pixel) + t * tqRed(image2pixel) + 0.5); + int green = static_cast((1 - t) * tqGreen(image1pixel) + t * tqGreen(image2pixel) + 0.5); + int blue = static_cast((1 - t) * tqBlue(image1pixel) + t * tqBlue(image2pixel) + 0.5); + int alpha = static_cast((1 - t) * tqAlpha(image1pixel) + t * tqAlpha(image2pixel) + 0.5); + + if (red < 0) { + red = 0; + } + else + if (red > 255) { + red = 255; + } + + if (green < 0) { + green = 0; + } + else + if (green > 255) { + green = 255; + } + + if (blue < 0) { + blue = 0; + } + else + if (blue > 255) { + blue = 255; + } + + if (alpha < 0) { + alpha = 0; + } + else + if (alpha > 255) { + alpha = 255; + } + + outputImage.setPixel(x, y, tqRgba(red, green, blue, alpha)); + } + } + + return outputImage; +} + +KisBrush::ScaledBrush::ScaledBrush() +{ + m_tqmask = 0; + m_image = TQImage(); + m_scale = 1; + m_xScale = 1; + m_yScale = 1; +} + +KisBrush::ScaledBrush::ScaledBrush(KisAlphaMaskSP scaledMask, const TQImage& scaledImage, double scale, double xScale, double yScale) +{ + m_tqmask = scaledMask; + m_image = scaledImage; + m_scale = scale; + m_xScale = xScale; + m_yScale = yScale; + + if (!m_image.isNull()) { + // Convert image to pre-multiplied by alpha. + + m_image.detach(); + + for (int y = 0; y < m_image.height(); y++) { + for (int x = 0; x < m_image.width(); x++) { + + TQRgb pixel = m_image.pixel(x, y); + + int red = tqRed(pixel); + int green = tqGreen(pixel); + int blue = tqBlue(pixel); + int alpha = tqAlpha(pixel); + + red = (red * alpha) / 255; + green = (green * alpha) / 255; + blue = (blue * alpha) / 255; + + m_image.setPixel(x, y, tqRgba(red, green, blue, alpha)); + } + } + } +} + +void KisBrush::setImage(const TQImage& img) +{ + m_img = img; + m_img.detach(); + + setWidth(img.width()); + setHeight(img.height()); + + m_scaledBrushes.clear(); + + setValid(true); +} + +TQ_INT32 KisBrush::width() const +{ + return m_width; +} + +void KisBrush::setWidth(TQ_INT32 w) +{ + m_width = w; +} + +TQ_INT32 KisBrush::height() const +{ + return m_height; +} + +void KisBrush::setHeight(TQ_INT32 h) +{ + m_height = h; +} + +/*TQImage KisBrush::outline(double pressure) { + KisLayerSP layer = image(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), + KisPaintInformation(pressure)); + KisBoundary bounds(layer.data()); + int w = tqmaskWidth(pressure); + int h = tqmaskHeight(pressure); + + bounds.generateBoundary(w, h); + TQPixmap pix(bounds.pixmap(w, h)); + TQImage result; + result = pix; + return result; +}*/ + +void KisBrush::generateBoundary() { + KisPaintDeviceSP dev; + int w = tqmaskWidth(KisPaintInformation()); + int h = tqmaskHeight(KisPaintInformation()); + + if (brushType() == IMAGE || brushType() == PIPE_IMAGE) { + dev = image(KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),""), KisPaintInformation()); + } else { + KisAlphaMaskSP atqmask = tqmask(KisPaintInformation()); + KisColorSpace* cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""); + dev = new KisPaintDevice(cs, "tmp for generateBoundary"); + for (int y = 0; y < h; y++) { + KisHLineIteratorPixel it = dev->createHLineIterator(0, y, w, true); + int x = 0; + + while(!it.isDone()) { + cs->setAlpha(it.rawData(), atqmask->alphaAt(x++, y), 1); + ++it; + } + } + } + + m_boundary = new KisBoundary(dev); + m_boundary->generateBoundary(w, h); +} + +KisBoundary KisBrush::boundary() { + if (!m_boundary) + generateBoundary(); + return *m_boundary; +} + +void KisBrush::makeMaskImage() { + if (!hasColor()) + return; + + TQImage img; + img.create(width(), height(), 32); + + if (m_img.width() == img.width() && m_img.height() == img.height()) { + for (int x = 0; x < width(); x++) { + for (int y = 0; y < height(); y++) { + TQRgb c = m_img.pixel(x, y); + int a = (tqGray(c) * tqAlpha(c)) / 255; // tqGray(black) = 0 + img.setPixel(x, y, tqRgba(a, a, a, 255)); + } + } + + m_img = img; + } + + m_brushType = MASK; + m_hasColor = false; + m_useColorAsMask = false; + delete m_boundary; + m_boundary = 0; + m_scaledBrushes.clear(); +} + +KisBrush* KisBrush::clone() const { + KisBrush* c = new KisBrush(""); + c->m_spacing = m_spacing; + c->m_useColorAsMask = m_useColorAsMask; + c->m_hasColor = m_useColorAsMask; + c->m_img = m_img; + c->m_width = m_width; + c->m_height = m_height; + c->m_ownData = false; + c->m_hotSpot = m_hotSpot; + c->m_brushType = m_brushType; + c->setValid(true); + + return c; +} + +#include "kis_brush.moc" + diff --git a/chalk/core/kis_brush.h b/chalk/core/kis_brush.h new file mode 100644 index 00000000..091cebde --- /dev/null +++ b/chalk/core/kis_brush.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_BRUSH_ +#define KIS_BRUSH_ + +#include +#include +#include +#include +#include + +#include + +#include "kis_resource.h" +#include "kis_types.h" +#include "kis_point.h" +#include "kis_alpha_mask.h" +#include "koffice_export.h" +#include "kis_boundary.h" +#include "kis_paintop.h" + +class TQPoint; +class TQPixmap; +class KisBoundary; +class KisColorSpace; +class TQIODevice; + +enum enumBrushType { + INVALID, + MASK, + IMAGE, + PIPE_MASK, + PIPE_IMAGE, + AIRBRUSH +}; + +class KRITACORE_EXPORT KisBrush : public KisResource { + typedef KisResource super; + Q_OBJECT + TQ_OBJECT + +public: + /// Construct brush to load filename later as brush + KisBrush(const TQString& filename); + /// Load brush from the specified data, at position dataPos, and set the filename + KisBrush(const TQString& filename, + const TQByteArray & data, + TQ_UINT32 & dataPos); + /// Load brush from the specified paint device, in the specified region + KisBrush(KisPaintDevice* image, int x, int y, int w, int h); + /// Load brush as a copy from the specified TQImage (handy when you need to copy a brush!) + KisBrush(const TQImage& image, const TQString& name = TQString("")); + + virtual ~KisBrush(); + + virtual bool load(); + /// synchronous, doesn't emit any signal (none defined!) + virtual bool save(); + virtual TQImage img(); + virtual bool saveToDevice(TQIODevice* dev) const; + + /** + @return a tqmask computed from the grey-level values of the + pixels in the brush. + */ + virtual KisAlphaMaskSP tqmask(const KisPaintInformation& info, + double subPixelX = 0, double subPixelY = 0) const; + // XXX: return non-tiled simple buffer + virtual KisPaintDeviceSP image(KisColorSpace * colorSpace, const KisPaintInformation& info, + double subPixelX = 0, double subPixelY = 0) const; + + void setHotSpot(KisPoint); + KisPoint hotSpot(const KisPaintInformation& info = KisPaintInformation()) const; + + void setSpacing(double s) { m_spacing = s; } + double spacing() const { return m_spacing; } + double xSpacing(double pressure = PRESSURE_DEFAULT) const; + double ySpacing(double pressure = PRESSURE_DEFAULT) const; + + // Dimensions in pixels of the tqmask/image at a given pressure. + TQ_INT32 tqmaskWidth(const KisPaintInformation& info) const; + TQ_INT32 tqmaskHeight(const KisPaintInformation& info) const; + + virtual void setUseColorAsMask(bool useColorAsMask) { m_useColorAsMask = useColorAsMask; } + virtual bool useColorAsMask() const { return m_useColorAsMask; } + virtual bool hasColor() const; + + virtual void makeMaskImage(); + TQ_INT32 width() const; + TQ_INT32 height() const; + + virtual enumBrushType brushType() const; + + //TQImage outline(double pressure = PRESSURE_DEFAULT); + virtual KisBoundary boundary(); + + /** + * Returns true if this brush can return something useful for the info. This is used + * by Pipe Brushes that can't paint sometimes + **/ + virtual bool canPaintFor(const KisPaintInformation& /*info*/) { return true; } + + virtual KisBrush* clone() const; + +protected: + void setWidth(TQ_INT32 w); + void setHeight(TQ_INT32 h); + void setImage(const TQImage& img); + void setBrushType(enumBrushType type) { m_brushType = type; }; + static double scaleForPressure(double pressure); + +private: + class ScaledBrush { + public: + ScaledBrush(); + ScaledBrush(KisAlphaMaskSP scaledMask, const TQImage& scaledImage, double scale, double xScale, double yScale); + + double scale() const { return m_scale; } + double xScale() const { return m_xScale; } + double yScale() const { return m_yScale; } + KisAlphaMaskSP tqmask() const { return m_tqmask; } + TQImage image() const { return m_image; } + + private: + KisAlphaMaskSP m_tqmask; + TQImage m_image; + double m_scale; + double m_xScale; + double m_yScale; + }; + + + bool init(); + bool initFromPaintDev(KisPaintDevice* image, int x, int y, int w, int h); + void createScaledBrushes() const; + + KisAlphaMaskSP scaleMask(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const; + TQImage scaleImage(const ScaledBrush *srcBrush, double scale, double subPixelX, double subPixelY) const; + + static TQImage scaleImage(const TQImage& srcImage, int width, int height); + static TQImage interpolate(const TQImage& image1, const TQImage& image2, double t); + + static KisAlphaMaskSP scaleSinglePixelMask(double scale, TQ_UINT8 tqmaskValue, double subPixelX, double subPixelY); + static TQImage scaleSinglePixelImage(double scale, TQRgb pixel, double subPixelX, double subPixelY); + + // Find the scaled brush(es) nearest to the given scale. + void findScaledBrushes(double scale, const ScaledBrush **aboveBrush, const ScaledBrush **belowBrush) const; + + // Initialize our boundary + void generateBoundary(); + + TQByteArray m_data; + bool m_ownData; + KisPoint m_hotSpot; + double m_spacing; + bool m_useColorAsMask; + bool m_hasColor; + TQImage m_img; + mutable TQValueVector m_scaledBrushes; + + TQ_INT32 m_width; + TQ_INT32 m_height; + + TQ_UINT32 m_header_size; /* header_size = sizeof (BrushHeader) + brush name */ + TQ_UINT32 m_version; /* brush file version # */ + TQ_UINT32 m_bytes; /* depth of brush in bytes */ + TQ_UINT32 m_magic_number; /* GIMP brush magic number */ + + enumBrushType m_brushType; + + KisBoundary* m_boundary; + +}; +#endif // KIS_BRUSH_ + diff --git a/chalk/core/kis_change_profile_visitor.h b/chalk/core/kis_change_profile_visitor.h new file mode 100644 index 00000000..dea0eb4b --- /dev/null +++ b/chalk/core/kis_change_profile_visitor.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt resetProjection(); + + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + layer->setDirty(); + return true; +} + +bool KisChangeProfileVisitor::visit(KisPaintLayer *layer) +{ + if (!layer) return false; + if (!layer->paintDevice()) return false; + if (!layer->paintDevice()->colorSpace()) return false; + + KisColorSpace * cs = layer->paintDevice()->colorSpace(); + + if (cs == m_oldColorSpace) { + + layer->paintDevice()->setProfile(m_dstColorSpace->getProfile()); + + layer->setDirty(); + } + return true; +} + +bool KisChangeProfileVisitor::visit(KisPartLayer *) +{ + return true; +} + + +bool KisChangeProfileVisitor::visit(KisAdjustmentLayer * layer) +{ + layer->resetCache(); + layer->setDirty(); + return true; +} + +#endif // KIS_CHANGE_PROFILE_VISITOR_H_ + diff --git a/chalk/core/kis_colorspace_convert_visitor.h b/chalk/core/kis_colorspace_convert_visitor.h new file mode 100644 index 00000000..e42c0893 --- /dev/null +++ b/chalk/core/kis_colorspace_convert_visitor.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLORSPACE_CONVERT_VISITOR_H_ +#define KIS_COLORSPACE_CONVERT_VISITOR_H_ + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_layer_visitor.h" +#include "kis_paint_layer.h" +#include "kis_paint_device.h" +#include "kis_adjustment_layer.h" +#include "kis_group_layer.h" + +class KisColorSpaceConvertVisitor :public KisLayerVisitor { +public: + KisColorSpaceConvertVisitor(KisColorSpace *dstColorSpace, TQ_INT32 renderingIntent); + virtual ~KisColorSpaceConvertVisitor(); + +public: + virtual bool visit(KisPaintLayer *layer); + virtual bool visit(KisGroupLayer *layer); + virtual bool visit(KisPartLayer *layer); + virtual bool visit(KisAdjustmentLayer* layer); + +private: + KisColorSpace *m_dstColorSpace; + TQ_INT32 m_renderingIntent; +}; + +KisColorSpaceConvertVisitor::KisColorSpaceConvertVisitor(KisColorSpace *dstColorSpace, TQ_INT32 renderingIntent) : + KisLayerVisitor(), + m_dstColorSpace(dstColorSpace), + m_renderingIntent(renderingIntent) +{ +} + +KisColorSpaceConvertVisitor::~KisColorSpaceConvertVisitor() +{ +} + +bool KisColorSpaceConvertVisitor::visit(KisGroupLayer * layer) +{ + // Clear the projection, we will have to re-render everything. + // The image is already set to the new colorspace, so this'll work. + layer->resetProjection(); + + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + layer->setDirty(); + return true; +} + +bool KisColorSpaceConvertVisitor::visit(KisPaintLayer *layer) +{ + layer->paintDevice()->convertTo(m_dstColorSpace, m_renderingIntent); + + layer->setDirty(); + return true; +} + +bool KisColorSpaceConvertVisitor::visit(KisPartLayer *) +{ + return true; +} + + +bool KisColorSpaceConvertVisitor::visit(KisAdjustmentLayer * layer) +{ + if (layer->filter()->name() == "perchannel") { + // Per-channel filters need to be reset because of different number + // of channels. This makes undo very tricky, but so be it. + // XXX: Make this more generic for after 1.6, when we'll have many + // channel-specific filters. + KisFilter * f = KisFilterRegistry::instance()->get("perchannel"); + layer->setFilter(f->configuration()); + } + layer->resetCache(); + layer->setDirty(); + return true; +} + +#endif // KIS_COLORSPACE_CONVERT_VISITOR_H_ + diff --git a/chalk/core/kis_command.cc b/chalk/core/kis_command.cc new file mode 100644 index 00000000..11da634b --- /dev/null +++ b/chalk/core/kis_command.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1999 Michael Koch + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_command.h" + +KisCommand::KisCommand(KisUndoAdapter *adapter) +{ + m_name = ""; + m_undoAdapter = adapter; +} + +KisCommand::KisCommand(const TQString& name, KisUndoAdapter *adapter) +{ + m_name = name; + m_undoAdapter = adapter; +} + +KisCommand::~KisCommand() +{ +} + +TQString KisCommand::name() const +{ + return m_name; +} + diff --git a/chalk/core/kis_command.h b/chalk/core/kis_command.h new file mode 100644 index 00000000..bc87bc5d --- /dev/null +++ b/chalk/core/kis_command.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1999 Michael Koch + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_COMMAND_H_ +#define KIS_COMMAND_H_ + +#include +#include + +class KisUndoAdapter; + +class KisCommand : public KCommand { + typedef KCommand super; + +public: + KisCommand(KisUndoAdapter *undoAdapter); + KisCommand(const TQString& name, KisUndoAdapter *undoAdapter); + virtual ~KisCommand(); + + virtual void execute() = 0; + virtual void unexecute() = 0; + virtual TQString name() const; + +protected: + KisUndoAdapter *adapter() const; + +private: + KisUndoAdapter *m_undoAdapter; + TQString m_name; +}; + +inline +KisUndoAdapter *KisCommand::adapter() const +{ + return m_undoAdapter; +} + +#endif // KIS_COMMAND_H_ + diff --git a/chalk/core/kis_convolution_painter.cc b/chalk/core/kis_convolution_painter.cc new file mode 100644 index 00000000..ea0351df --- /dev/null +++ b/chalk/core/kis_convolution_painter.cc @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "tqbrush.h" +#include "tqcolor.h" +#include "tqfontinfo.h" +#include "tqfontmetrics.h" +#include "tqpen.h" +#include "tqregion.h" +#include "tqwmatrix.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_iterators_pixel.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_pattern.h" +#include "kis_rect.h" +#include "kis_colorspace.h" +#include "kis_types.h" +#include "kis_vec.h" +#include "kis_selection.h" +#include "kis_convolution_painter.h" + + +KisKernelSP KisKernel::fromTQImage(const TQImage& img) +{ + KisKernelSP k = new KisKernel; + k->width = img.width(); + k->height = img.height(); + k->offset = 0; + uint count = k->width * k->height; + k->data = new TQ_INT32[count]; + TQ_INT32* itData = k->data; + TQ_UINT8* itImg = (TQ_UINT8*)img.bits(); + k->factor = 0; + for(uint i = 0; i < count; ++i , ++itData, itImg+=4) + { + *itData = 255 - ( *itImg + *(itImg+1) + *(itImg+2) ) / 3; + k->factor += *itData; + } + return k; +} + + +KisConvolutionPainter::KisConvolutionPainter() + : super() +{ +} + +KisConvolutionPainter::KisConvolutionPainter(KisPaintDeviceSP device) : super(device) +{ +} + +void KisConvolutionPainter::applyMatrix(KisKernelSP kernel, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, + KisConvolutionBorderOp borderOp, + KisChannelInfo::enumChannelFlags channelFlags ) +{ + // Make the area we cover as small as possible + if (m_device->hasSelection()) { + + TQRect r = m_device->selection()->selectedRect().intersect(TQRect(x, y, w, h)); + x = r.x(); + y = r.y(); + w = r.width(); + h = r.height(); + + } + + if ( w == 0 && h == 0 ) return; + + // Determine the kernel's extent from the center pixel + TQ_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh; + kw = kernel->width; + kh = kernel->height; + khalfWidth = (kw - 1) / 2; + khalfHeight = (kh - 1) / 2; + + xLastMinuskhw = x + (w - khalfWidth); + yLastMinuskhh = y + (h - khalfHeight); + + // Don't try to convolve on an area smaller than the kernel, or with a kernel that is not square or has no center pixel. + if (w < kw || h < kh || (kw&1) == 0 || (kh&1) == 0 || kernel->factor == 0 ) return; + + m_cancelRequested = false; + int lastProgressPercent = 0; + emit notifyProgress(0); + + KisColorSpace * cs = m_device->colorSpace(); + + // Determine whether we convolve border pixels, or not. + switch (borderOp) { + case BORDER_DEFAULT_FILL : + break; + case BORDER_REPEAT: + applyMatrixRepeat(kernel, x, y, w, h, channelFlags); + return; + case BORDER_WRAP: + case BORDER_AVOID: + default : + x += khalfWidth; + y += khalfHeight; + w -= kw - 1; + h -= kh - 1; + } + + // Iterate over all pixels in our rect, create a cache of pixels around the current pixel and convolve them in the colorstrategy. + + int cacheSize = kw * kh; + int cdepth = cs -> pixelSize(); + TQ_UINT8** pixelPtrCache = new TQ_UINT8*[cacheSize]; + for (int i = 0; i < cacheSize; i++) + pixelPtrCache[i] = new TQ_UINT8[cdepth]; +// pixelPtrCache.fill(0); + + // row == the y position of the pixel we want to change in the paint device + int row = y; + + for (; row < y + h; ++row) { + + // col = the x position of the pixel we want to change + int col = x; + + KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true); + bool needFull = true; + while (!hit.isDone()) { + + // Iterate over all contributing pixels that are covered by the kernel + // krow = the y position in the kernel matrix + if(needFull) + { + TQ_INT32 i = 0; + for (TQ_INT32 krow = 0; krow < kh; ++krow) { + + // col - khalfWidth = the left starting point of the kernel as centered on our pixel + // krow - khalfHeight = the offset for the top of the kernel as centered on our pixel + // kw = the width of the kernel + + // Fill the cache with pointers to the pixels under the kernel + KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, (row - khalfHeight) + krow, kw, false); + while (!kit.isDone()) { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + ++kit; + ++i; + } + } + needFull = false; + Q_ASSERT (i==kw*kh); + } else { + for (TQ_INT32 krow = 0; krow < kh; ++krow) { // shift the cache to the left + TQ_UINT8** d = pixelPtrCache + krow * kw; + //memmove( d, d + 1, (kw-1)*sizeof(TQ_UINT8*)); + for (int i = 0; i < (kw-1); i++) { + memcpy(d[i], d[i+1], cdepth); + } + } + TQ_INT32 i = kw - 1; + KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, row - khalfHeight, kh, false); + while (!kit.isDone()) { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + ++kit; + i += kw; + } + } + if (hit.isSelected()) { + cs->convolveColors(pixelPtrCache, kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh); +// pixelPtrCache.fill(0); + } + ++col; + ++hit; + } + + int progressPercent = 100 - ((((y + h) - row) * 100) / h); + + if (progressPercent > lastProgressPercent) { + emit notifyProgress(progressPercent); + lastProgressPercent = progressPercent; + + if (m_cancelRequested) { + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; + + return; + } + } + + } + + addDirtyRect(TQRect(x, y, w, h)); + + emit notifyProgressDone(); + + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; +} + +void KisConvolutionPainter::applyMatrixRepeat(KisKernelSP kernel, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, + KisChannelInfo::enumChannelFlags channelFlags) +{ + int lastProgressPercent = 0; + // Determine the kernel's extent from the center pixel + TQ_INT32 kw, kh, khalfWidth, khalfHeight, xLastMinuskhw, yLastMinuskhh; + kw = kernel->width; + kh = kernel->height; + khalfWidth = (kw - 1) / 2; + khalfHeight = (kh - 1) / 2; + + xLastMinuskhw = x + (w - khalfWidth); + yLastMinuskhh = y + (h - khalfHeight); + + KisColorSpace * cs = m_device->colorSpace(); + + // Iterate over all pixels in our rect, create a cache of pixels around the current pixel and convolve them in the colorstrategy. + + int cacheSize = kw * kh; + int cdepth = cs -> pixelSize(); + TQ_UINT8** pixelPtrCache = new TQ_UINT8*[cacheSize]; + for (int i = 0; i < cacheSize; i++) + pixelPtrCache[i] = new TQ_UINT8[cdepth]; + + // row == the y position of the pixel we want to change in the paint device + int row = y; + + for (; row < y + h; ++row) { + + // col = the x position of the pixel we want to change + int col = x; + + KisHLineIteratorPixel hit = m_device->createHLineIterator(x, row, w, true); + bool needFull = true; + + TQ_INT32 itStart = row - khalfHeight; + TQ_INT32 itH = kh; + if(itStart < 0) + { + itH += itStart; + itStart = 0; + } else if(itStart + kh > yLastMinuskhh) + { + itH -= itStart + kh - yLastMinuskhh; + } + KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, itStart, itH, false); + while (!hit.isDone()) { + + // Iterate over all contributing pixels that are covered by the kernel + // krow = the y position in the kernel matrix + if(needFull) // The cache has not been fill, so we need to fill it + { + TQ_INT32 i = 0; + TQ_INT32 krow = 0; + if( row < khalfHeight ) + { + // We are just outside the layer, all the row in the cache will be identical + // so we need to create them only once, and then to copy them + if( x < khalfWidth) + { // the left pixels are outside of the layer, in the corner + TQ_INT32 kcol = 0; + KisHLineIteratorPixel kit = m_device->createHLineIterator(0, 0, kw, false); + for(; kcol < (khalfWidth - x) + 1; ++kcol) + { // First copy the address of the topleft pixel + memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth); + } + for(; kcol < kw; ++kcol) + { // Then copy the address of the rest of the line + ++kit; + memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth); + } + } else { + uint kcol = 0; + KisHLineIteratorPixel kit = m_device->createHLineIterator(col - khalfWidth, 0, kw, false); + while (!kit.isDone()) { + memcpy(pixelPtrCache[kcol], kit.oldRawData(), cdepth); + ++kit; + ++kcol; + } + } + krow = 1; // we have allready done the first krow + for(;krow < (khalfHeight - row); ++krow) + { + // Copy the first line in the current line + for (int i = 0; i < kw; i++) + memcpy(pixelPtrCache[krow * kw + i], pixelPtrCache[i], cdepth); + } + i = krow * kw; + } + TQ_INT32 itH = kh; + if(row + khalfHeight > yLastMinuskhh) + { + itH += yLastMinuskhh - row - khalfHeight; + } + for (; krow < itH; ++krow) { + + // col - khalfWidth = the left starting point of the kernel as centered on our pixel + // krow - khalfHeight = the offset for the top of the kernel as centered on our pixel + // kw = the width of the kernel + + // Fill the cache with pointers to the pixels under the kernel + TQ_INT32 itHStart = col - khalfWidth; + TQ_INT32 itW = kw; + if(itHStart < 0) + { + itW += itHStart; + itHStart = 0; + } + KisHLineIteratorPixel kit = m_device->createHLineIterator(itHStart, (row - khalfHeight) + krow, itW, false); + if( col < khalfWidth ) + { + for(; i < krow * kw + ( kw - itW ); i+= 1) + { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + } + } + while (!kit.isDone()) { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + ++kit; + ++i; + } + } + TQ_INT32 lastvalid = i - kw; + for(; krow < kh; ++krow) { + // Copy the last valid line in the current line + for (int i = 0; i < kw; i++) + memcpy(pixelPtrCache[krow * kw + i], pixelPtrCache[lastvalid + i], + cdepth); + } + needFull = false; + } else { +/* for (TQ_INT32 krow = 0; krow < kh; ++krow) { // shift the cache to the left + TQ_UINT8** d = pixelPtrCache + krow * kw; +// memmove( d, d + 1, (kw-1)*sizeof(TQ_UINT8*)); + for (int i = 0; i < (kw-1); i++) { + memcpy(d[i], d[i+1], cdepth); + } + }*/ + TQ_UINT8* firstincache = pixelPtrCache[0]; + memmove(pixelPtrCache, pixelPtrCache + 1, (cacheSize - 1) * sizeof(TQ_UINT8*) ); + pixelPtrCache[cacheSize - 1] = firstincache; + if(col < xLastMinuskhw) + { + TQ_INT32 i = kw - 1; +// KisVLineIteratorPixel kit = m_device->createVLineIterator(col + khalfWidth, itStart, itH, false); + kit.nextCol(); + if( row < khalfHeight ) + { + for(; i < (khalfHeight- row ) * kw; i+=kw) + { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + } + } + while (!kit.isDone()) { + memcpy(pixelPtrCache[i], kit.oldRawData(), cdepth); + ++kit; + i += kw; + } + TQ_INT32 lastvalid = i - kw; + for(;i < kw*kh; i+=kw) + { + memcpy(pixelPtrCache[i], pixelPtrCache[lastvalid], cdepth); + } + } + } + if (hit.isSelected()) { + cs->convolveColors(pixelPtrCache, kernel->data, channelFlags, hit.rawData(), kernel->factor, kernel->offset, kw * kh); + } + ++col; + ++hit; + } + + int progressPercent = 100 - ((((y + h) - row) * 100) / h); + + if (progressPercent > lastProgressPercent) { + emit notifyProgress(progressPercent); + lastProgressPercent = progressPercent; + + if (m_cancelRequested) { + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; + return; + } + } + + } + + addDirtyRect(TQRect(x, y, w, h)); + + emit notifyProgressDone(); + for (int i = 0; i < cacheSize; i++) + delete[] pixelPtrCache[i]; + delete[] pixelPtrCache; +} diff --git a/chalk/core/kis_convolution_painter.h b/chalk/core/kis_convolution_painter.h new file mode 100644 index 00000000..8c0b2bba --- /dev/null +++ b/chalk/core/kis_convolution_painter.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_CONVOLUTION_PAINTER_H_ +#define KIS_CONVOLUTION_PAINTER_H_ + +#include + +#include "ksharedptr.h" +#include "kis_types.h" +#include "kis_painter.h" + +#include "koffice_export.h" + +enum KisConvolutionBorderOp { + BORDER_DEFAULT_FILL = 0, // Use the default pixel to make up for the missing pixels on the border or the pixel that lies beyond + // the rect we are convolving. + BORDER_WRAP = 1, // Use the pixel on the opposite side to make up for the missing pixels on the border. XXX: Not implemented yet + BORDER_REPEAT = 2, // Use the border for the missing pixels, too. + BORDER_AVOID = 3 // Skip convolving the border pixels at all. +}; + +class KisKernel; +typedef KSharedPtr KisKernelSP; + +class KisKernel : public KShared +{ + +public: + + TQ_UINT32 width; + TQ_UINT32 height; + TQ_INT32 offset; + TQ_INT32 factor; + TQ_INT32 * data; + + KisKernel() : width(0), height(0), offset(0), factor(0), data(0) {}; + + virtual ~KisKernel() { delete [] data; }; + + static KisKernelSP fromTQImage(const TQImage& img); + +}; + + +class KRITACORE_EXPORT KisConvolutionPainter : public KisPainter +{ + + typedef KisPainter super; + +public: + + KisConvolutionPainter(); + KisConvolutionPainter(KisPaintDeviceSP device); + + /** + * Convolve all channels in src using the specified kernel; there is only one kernel for all + * channels possible. By default the the border pixels are not convolved, that is, convolving + * starts with at (x + kernel.width/2, y + kernel.height/2) and stops at w - (kernel.width/2) + * and h - (kernel.height/2) + * + * The border op decides what to do with pixels too close to the edge of the rect as defined above. + * + * The channels flag determines which set out of color channels, alpha channels, substance or substrate + * channels we convolve. + * + * Note that we do not (currently) support different kernels for different channels _or_ channel types. + */ + void applyMatrix(KisKernelSP kernel, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, + KisConvolutionBorderOp borderOp = BORDER_AVOID, + KisChannelInfo::enumChannelFlags channelFlags = KisChannelInfo::FLAG_COLOR); +private: + /** + * This function is called by applyMatrix when borderOp == BORDER_REPEAT + */ + void applyMatrixRepeat(KisKernelSP kernel, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, + KisChannelInfo::enumChannelFlags channelFlags); + + +}; +#endif //KIS_CONVOLUTION_PAINTER_H_ diff --git a/chalk/core/kis_crop_visitor.h b/chalk/core/kis_crop_visitor.h new file mode 100644 index 00000000..0988a920 --- /dev/null +++ b/chalk/core/kis_crop_visitor.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_CROP_VISITOR_H_ +#define KIS_CROP_VISITOR_H_ + +#include "tqrect.h" + +#include "klocale.h" + +#include "kis_layer_visitor.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_transaction.h" +#include + +class KisProgressDisplayInterface; +class KisFilterStrategy; + +class KisCropVisitor : public KisLayerVisitor { + +public: + + KisCropVisitor( const TQRect & rc, bool movelayers = true) + : KisLayerVisitor() + , m_rect(rc), m_movelayers(movelayers) + { + } + + virtual ~KisCropVisitor() + { + } + + /** + * Crops the specified layer and adds the undo information to the undo adapter of the + * layer's image. + */ + bool visit(KisPaintLayer *layer) + { + KisPaintDeviceSP dev = layer->paintDevice(); + KisSelectedTransaction * t = 0; + if (layer->undoAdapter() && layer->undoAdapter()->undo()) + t = new KisSelectedTransaction(i18n("Crop"), dev.data()); + + dev->crop(m_rect); + + if (layer->undoAdapter() && layer->undoAdapter()->undo()) { + layer->undoAdapter()->addCommand(t); + } + + if(m_movelayers) { + if(layer->undoAdapter() && layer->undoAdapter()->undo()) { + KNamedCommand * cmd = dev->moveCommand(layer->x() - m_rect.x(), layer->y() - m_rect.y()); + layer->undoAdapter()->addCommand(cmd); + } + } + layer->setDirty(dev->image()->bounds()); + return true; + }; + + bool visit(KisGroupLayer *layer) + { + layer->resetProjection(); + + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + layer->setDirty(); + return true; + }; + + bool visit(KisPartLayer */*layer*/) + { + return true; + }; + + virtual bool visit(KisAdjustmentLayer* layer) + { + layer->resetCache(); + return true; + } + + +private: + TQRect m_rect; + bool m_movelayers; +}; + + +#endif diff --git a/chalk/core/kis_datamanager.h b/chalk/core/kis_datamanager.h new file mode 100644 index 00000000..79f7ddb8 --- /dev/null +++ b/chalk/core/kis_datamanager.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DATAMANAGER_H_ +#define KIS_DATAMANAGER_H_ + +#include +#include +#include + +class KoStore; + + +// Change the following two lines to switch (at compiletime) to another datamanager +#include "tiles/kis_tileddatamanager.h" +#define ACTUAL_DATAMGR KisTiledDataManager + +/** + * KisDataManager defines the interface that modules responsible for + * storing and retrieving data must inmplement. Data modules, like + * the tile manager, are responsible for: + * + * * Storing undo/redo data + * * Offering ordererd and unordered iterators over rects of pixels + * * (eventually) efficiently loading and saving data in a format + * that may allow deferred loading. + * + * A datamanager knows nothing about the type of pixel data except + * how many TQ_UINT8's a single pixel takes. + */ +class KisDataManager : public ACTUAL_DATAMGR { + +public: + KisDataManager(TQ_UINT32 pixelSize, const TQ_UINT8 *defPixel) : ACTUAL_DATAMGR(pixelSize, defPixel) {} + KisDataManager(const KisDataManager& dm) : ACTUAL_DATAMGR(dm) { } + +public: + /** + * Sets the default pixel. Note that this might change every occurrance, and it might not, but new data + * well be initialised with this pixel + */ + inline void setDefaultPixel(const TQ_UINT8 *defPixel) { return ACTUAL_DATAMGR::setDefaultPixel(defPixel); } + + /** + * Gets the default pixel. + */ + inline const TQ_UINT8 *defaultPixel() const { return ACTUAL_DATAMGR::defaultPixel(); } + + /** + * Reguests a memento from the data manager. There is only one memento active + * at any given moment for a given paint device and all and any + * write actions on the datamanger builds undo data into this memento + * necessary to rollback the transaction. + */ + inline KisMementoSP getMemento() { return ACTUAL_DATAMGR::getMemento(); } + + /** + * Restores the image data to the state at the time of the getMemento() call. + * + * Note that rollback should be performed with mementos in the reverse order of + * their creation, as mementos only store incremental changes + */ + inline void rollback(KisMementoSP memento) { ACTUAL_DATAMGR::rollback(memento); } + + /** + * Restores the image data to the state at the time of the rollback call of the memento. + * + * Note that rollforward must only be called when an rollback have previously been performed, and + * no intermittent actions have been performed (though it's ok to rollback other mementos and + * roll them forward again) + */ + inline void rollforward(KisMementoSP memento) { ACTUAL_DATAMGR::rollforward(memento); } + +public: + /** + * Reads and writes the tiles from/onto a KoStore (wich is simply a file within a zip file) + * + */ + inline bool write(KoStore *store) { return ACTUAL_DATAMGR::write(store); } + inline bool read(KoStore *store) { return ACTUAL_DATAMGR::read(store); } + +public: + + /** + * Returns the number of bytes a pixel takes + */ + inline TQ_UINT32 pixelSize() { return ACTUAL_DATAMGR::pixelSize(); } + + /** + * Return the extent of the data in x,y,w,h. + */ + inline void extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const + { return ACTUAL_DATAMGR::extent(x, y, w, h); } + + TQRect extent() const { return ACTUAL_DATAMGR::extent(); } + + +public: + + /** + * Crop or extend the data to x, y, w, h. + */ + inline void setExtent(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) + { return ACTUAL_DATAMGR::setExtent(x, y, w, h); } + + inline void setExtent(const TQRect & rect) { setExtent(rect.x(), rect.y(), rect.width(), rect.height()); } + +public: + + /** + * Clear the specified rect to the specified value. + */ + inline void clear(TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h, + TQ_UINT8 def) { ACTUAL_DATAMGR::clear(x, y, w, h, def); } + + /** + * Clear the specified rect to the specified pixel value. + */ + inline void clear(TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h, + const TQ_UINT8 * def) { ACTUAL_DATAMGR::clear(x, y, w, h, def); } + + /** + * Clear all back to default values. + */ + inline void clear() { ACTUAL_DATAMGR::clear(); } + + +public: + + /** + * Copy the specified rect from the specified data into this + * data. + */ + inline void paste(KisDataManagerSP data, TQ_INT32 sx, TQ_INT32 sy, TQ_INT32 dx, TQ_INT32 dy, + TQ_INT32 w, TQ_INT32 h) { ACTUAL_DATAMGR::paste(data, sx, sy, dx, dy, w, h); } + +public: + /** + * Get a read-only pointer to the specified pixel. + */ + inline KDE_DEPRECATED const TQ_UINT8* pixel(TQ_INT32 x, TQ_INT32 y) + { return ACTUAL_DATAMGR::pixel(x, y); } + + /** + * Get a read-write pointer to the specified pixel. + */ + inline KDE_DEPRECATED TQ_UINT8* writablePixel(TQ_INT32 x, TQ_INT32 y) + { return ACTUAL_DATAMGR::writablePixel(x, y); } + + /** + * Write the specified data to x, y. There is no checking on pixelSize! + */ + inline void setPixel(TQ_INT32 x, TQ_INT32 y, const TQ_UINT8 * data) + { ACTUAL_DATAMGR::setPixel(x, y, data);} + + + /** + * Copy the bytes in the specified rect to a chunk of memory. + * The pixelSize in bytes is w * h * pixelSize. XXX: Better + * use TQValueVector? + */ + inline void readBytes(TQ_UINT8 * data, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h) + { ACTUAL_DATAMGR::readBytes(data, x, y, w, h);} + + /** + * Copy the bytes to the specified rect. w * h * pixelSize bytes will be read, whether + * the caller prepared them or not. XXX: Better use TQValueVector? + */ + inline void writeBytes(const TQ_UINT8 * data, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h) + {ACTUAL_DATAMGR::writeBytes( data, x, y, w, h); } + + // Get the number of contiguous columns starting at x, valid for all values + // of y between minY and maxY. + inline TQ_INT32 numContiguousColumns(TQ_INT32 x, TQ_INT32 minY, TQ_INT32 maxY) + { return ACTUAL_DATAMGR::numContiguousColumns(x, minY, maxY); } + + + // Get the number of contiguous rows starting at y, valid for all values + // of x between minX and maxX. + inline TQ_INT32 numContiguousRows(TQ_INT32 y, TQ_INT32 minX, TQ_INT32 maxX) + { return ACTUAL_DATAMGR::numContiguousRows(y, minX, maxX); } + + + // Get the row stride at pixel (x, y). This is the number of bytes to add to a + // pointer to pixel (x, y) to access (x, y + 1). + inline TQ_INT32 rowStride(TQ_INT32 x, TQ_INT32 y) + { return ACTUAL_DATAMGR::rowStride(x, y); } + +protected: + friend class KisRectIterator; + friend class KisHLineIterator; + friend class KisVLineIterator; +}; + + +#endif // KIS_DATAMANAGER_H_ + diff --git a/chalk/core/kis_exif_info.cc b/chalk/core/kis_exif_info.cc new file mode 100644 index 00000000..5d54ed5e --- /dev/null +++ b/chalk/core/kis_exif_info.cc @@ -0,0 +1,66 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_exif_info.h" + +#include + +#include + +KisExifInfo::KisExifInfo() +{} + + +KisExifInfo::~KisExifInfo() +{} + + +bool KisExifInfo::load(const TQDomElement& elmt) +{ + if(elmt.tagName() != "ExifInfo") + return false; + for( TQDomNode node = elmt.firstChild(); !node.isNull(); node = node.nextSibling() ) + { + TQDomElement e = node.toElement(); + if ( !e.isNull() ) + { + if(e.tagName() == "ExifValue") + { + TQString key = e.attribute("name"); + ExifValue eV; + eV.load(e); + setValue(key, eV); + } + } + } + return true; +} + +TQDomElement KisExifInfo::save(TQDomDocument& doc) +{ + TQDomElement elmt = doc.createElement("ExifInfo"); + for( KisExifInfo::evMap::const_iterator it = begin(); it != end(); ++it) + { + ExifValue ev = it.data(); + TQDomElement evD = ev.save( doc); + evD.setAttribute("name", it.key()); + elmt.appendChild(evD); + } + return elmt; +} diff --git a/chalk/core/kis_exif_info.h b/chalk/core/kis_exif_info.h new file mode 100644 index 00000000..d3fa3428 --- /dev/null +++ b/chalk/core/kis_exif_info.h @@ -0,0 +1,58 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DOCUMENT_INFO_EXIF_H +#define KIS_DOCUMENT_INFO_EXIF_H + +#include "kis_exif_value.h" + +#include +#include + +class KisExifInfo +{ + public: + KisExifInfo(); + virtual ~KisExifInfo(); + + virtual bool load(const TQDomElement& elmt); + virtual TQDomElement save(TQDomDocument& doc); + + bool getValue(TQString name, ExifValue& value) + { + if ( m_values.tqfind( name ) == m_values.end() ) { + return false; + } + else { + value = m_values[name]; + return true; + } + } + void setValue(TQString name, ExifValue value) + { + m_values[name] = value; + } + typedef TQMap evMap; + evMap::const_iterator begin() const { return m_values.begin(); } + evMap::const_iterator end() const { return m_values.end(); } + private: + evMap m_values; +}; + +#endif diff --git a/chalk/core/kis_exif_value.cc b/chalk/core/kis_exif_value.cc new file mode 100644 index 00000000..1b7bcf32 --- /dev/null +++ b/chalk/core/kis_exif_value.cc @@ -0,0 +1,678 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_exif_value.h" + +#include +#include + +namespace { +void set16Bit (unsigned char *data, ExifValue::ByteOrder order, const TQ_UINT16* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + data[0] = (unsigned char) (*value >> 8); + data[1] = (unsigned char) *value; + break; + case ExifValue::BYTE_ORDER_INTEL: + data[0] = (unsigned char) *value; + data[1] = (unsigned char) (*value >> 8); + break; + } +} + +void get16Bit (const unsigned char *data, ExifValue::ByteOrder order, TQ_UINT16* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + *value = ((data[0] << 8) | data[1]); + break; + case ExifValue::BYTE_ORDER_INTEL: + *value = ((data[1] << 8) | data[0]); + break; + } +} + +void get32Bit (const unsigned char *data, ExifValue::ByteOrder order, TQ_UINT32* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + *value = ((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]); + break; + case ExifValue::BYTE_ORDER_INTEL: + *value = ((data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0]); + } +} + +void set32Bit(unsigned char *data, ExifValue::ByteOrder order, const TQ_UINT32* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + data[0] = (unsigned char) (*value >> 24); + data[1] = (unsigned char) (*value >> 16); + data[2] = (unsigned char) (*value >> 8); + data[3] = (unsigned char) *value; + break; + case ExifValue::BYTE_ORDER_INTEL: + data[3] = (unsigned char) (*value >> 24); + data[2] = (unsigned char) (*value >> 16); + data[1] = (unsigned char) (*value >> 8); + data[0] = (unsigned char) *value; + break; + } +} + +void get64Bit (const unsigned char *data, ExifValue::ByteOrder order, TQ_UINT64* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + *value = (((TQ_UINT64)data[0] << 56) | ((TQ_UINT64)data[1] << 48) | ((TQ_UINT64)data[2] << 40) | ((TQ_UINT64)data[3] << 32) | ((TQ_UINT64)data[4] << 24) | ((TQ_UINT64)data[5] << 16) | ((TQ_UINT64)data[6] << 8) | (TQ_UINT64)data[7]); + break; + case ExifValue::BYTE_ORDER_INTEL: + *value = (((TQ_UINT64)data[7] << 56) | ((TQ_UINT64)data[6] << 48) | ((TQ_UINT64)data[5] << 40) | ((TQ_UINT64)data[4] << 32) | ((TQ_UINT64)data[3] << 24) | ((TQ_UINT64)data[2] << 16) | ((TQ_UINT64)data[1] << 8) | (TQ_UINT64)data[0]); + } +} + +void set64Bit(unsigned char *data, ExifValue::ByteOrder order, const TQ_UINT64* value) +{ + switch (order) { + case ExifValue::BYTE_ORDER_MOTOROLA: + data[0] = (unsigned char) (*value >> 56); + data[1] = (unsigned char) (*value >> 48); + data[2] = (unsigned char) (*value >> 40); + data[3] = (unsigned char) (*value >> 32); + data[4] = (unsigned char) (*value >> 24); + data[5] = (unsigned char) (*value >> 16); + data[6] = (unsigned char) (*value >> 8); + data[7] = (unsigned char) *value; + break; + case ExifValue::BYTE_ORDER_INTEL: + data[7] = (unsigned char) (*value >> 56); + data[6] = (unsigned char) (*value >> 48); + data[5] = (unsigned char) (*value >> 40); + data[4] = (unsigned char) (*value >> 32); + data[3] = (unsigned char) (*value >> 24); + data[2] = (unsigned char) (*value >> 16); + data[1] = (unsigned char) (*value >> 8); + data[0] = (unsigned char) *value; + break; + } +} + + +} + +ExifValue::ExifValue(ExifType ntype, unsigned char *data, unsigned int size, int ifd, uint ncomponents, ExifValue::ByteOrder order ) : m_ifd(ifd), m_type(ntype), m_components(ncomponents), m_value(0) +{ + allocData(); + setValue(data, size, order); +} + +void ExifValue::allocData() +{ + if( type() != EXIF_TYPE_ASCII && type() != EXIF_TYPE_UNDEFINED) + { + m_value = new ExifNumber[components()]; + } else if ( type() == EXIF_TYPE_ASCII ) + { + m_value = new TQString(); + } else if ( type() == EXIF_TYPE_UNDEFINED) + { + m_value = new UByteArray(); + } +} + +bool ExifValue::load(const TQDomElement& elmt) +{ + TQString attr; + if( (attr = elmt.attribute("ifd")).isNull() ) + return false; + m_ifd = attr.toInt(); + if( (attr = elmt.attribute("components")).isNull() ) + return false; + m_components = attr.toInt(); + if( (attr = elmt.attribute("type")).isNull() ) + return false; + m_type = (ExifValue::ExifType)attr.toInt(); + allocData(); + switch(type()) + { + case EXIF_TYPE_BYTE: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_UINT8)0); + } else { + setValue(i, (TQ_UINT8) attr.toUInt()); + } + } + break; + case EXIF_TYPE_ASCII: + setAsAscii( elmt.attribute("value" ) ); + break; + case EXIF_TYPE_SHORT: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_UINT16)0); + } else { + setValue(i, (TQ_UINT16) attr.toUInt()); + } + } + break; + case EXIF_TYPE_LONG: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_UINT32)0); + } else { + setValue(i, (TQ_UINT32) attr.toUInt()); + } + } + break; + case EXIF_TYPE_RATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifRational r; + if( (attr = elmt.attribute(TQString("numerator%1").tqarg(i) ) ).isNull() ) + { + r.numerator = (TQ_UINT32)0; + } else { + r.numerator = (TQ_UINT32) attr.toUInt(); + } + if( (attr = elmt.attribute(TQString("denominator%1").tqarg(i) ) ).isNull() ) + { + r.denominator = (TQ_UINT32)0; + } else { + r.denominator = (TQ_UINT32) attr.toUInt(); + } + setValue(i, r); + } + break; + case EXIF_TYPE_SBYTE: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_INT8)0); + } else { + setValue(i, (TQ_INT8) attr.toInt()); + } + } + break; + case EXIF_TYPE_UNDEFINED: + { + TQString instr = elmt.attribute("value"); + TQByteArray out; + TQByteArray in = instr.utf8(); + KCodecs::base64Decode( in, out); + out.resize(out.size() - 2 ); + setAsUndefined((uchar*)out.data(), out.size() ); + } + break; + case EXIF_TYPE_SSHORT: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_INT16)0); + } else { + setValue(i, (TQ_INT16) attr.toInt()); + } + } + break; + case EXIF_TYPE_SLONG: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (TQ_INT32)0); + } else { + setValue(i, (TQ_INT32) attr.toInt()); + } + } + break; + case EXIF_TYPE_SRATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifSRational r; + if( (attr = elmt.attribute(TQString("numerator%1").tqarg(i) ) ).isNull() ) + { + r.numerator = (TQ_INT32)0; + } else { + r.numerator = (TQ_INT32) attr.toInt(); + } + if( (attr = elmt.attribute(TQString("denominator%1").tqarg(i) ) ).isNull() ) + { + r.denominator = (TQ_UINT32)0; + } else { + r.denominator = (TQ_UINT32) attr.toInt(); + } + setValue(i, r); + } + break; + case EXIF_TYPE_FLOAT: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (float)0); + } else { + setValue(i, (float) attr.toFloat()); + } + } + break; + case EXIF_TYPE_DOUBLE: + for(uint i = 0; i < components(); i++) + { + if( (attr = elmt.attribute(TQString("value%1").tqarg(i) ) ).isNull() ) + { + setValue(i, (double)0); + } else { + setValue(i, (double) attr.toDouble()); + } + } + break; + case EXIF_TYPE_UNKNOW: + break; + + } + return true; +} + +TQDomElement ExifValue::save(TQDomDocument& doc) +{ + TQDomElement elmt = doc.createElement("ExifValue"); + elmt.setAttribute("ifd", ifd()); + elmt.setAttribute("components", components() ); + elmt.setAttribute("type", type() ); + switch(type()) + { + case EXIF_TYPE_BYTE: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asByte( i ) ); + break; + case EXIF_TYPE_ASCII: + elmt.setAttribute("value", asAscii() ); + break; + case EXIF_TYPE_SHORT: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asShort( i ) ); + break; + case EXIF_TYPE_LONG: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asLong( i ) ); + break; + case EXIF_TYPE_RATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifRational r = asRational(i); + elmt.setAttribute(TQString("numerator%1").tqarg(i), r.numerator ); + elmt.setAttribute(TQString("denominator%1").tqarg(i), r.denominator ); + } + break; + case EXIF_TYPE_SBYTE: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asSByte( i ) ); + break; + case EXIF_TYPE_UNDEFINED: + { + UByteArray value = asUndefined(); + TQByteArray data; + data.setRawData((char*)value.data(), value.size()); + TQByteArray tqencodedData; + KCodecs::base64Encode( data, tqencodedData ); + data.resetRawData( (char*)value.data(), value.size()); + elmt.setAttribute("value", TQString(tqencodedData)); + } + break; + case EXIF_TYPE_SSHORT: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asSShort( i ) ); + break; + case EXIF_TYPE_SLONG: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asSLong( i ) ); + break; + case EXIF_TYPE_SRATIONAL: + for(uint i = 0; i < components(); i++) + { + KisExifSRational r = asSRational(i); + elmt.setAttribute(TQString("numerator%1").tqarg(i), r.numerator ); + elmt.setAttribute(TQString("denominator%1").tqarg(i), r.denominator ); + } + break; + case EXIF_TYPE_FLOAT: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asFloat( i ) ); + break; + case EXIF_TYPE_DOUBLE: + for(uint i = 0; i < components(); i++) + elmt.setAttribute(TQString("value%1").tqarg(i), asDouble( i ) ); + break; + case EXIF_TYPE_UNKNOW: + break; + } + return elmt; +} + + +void ExifValue::setValue(const unsigned char *data, unsigned int size, ExifValue::ByteOrder order) +{ + switch(type()) + { + case EXIF_TYPE_BYTE: + if( size == components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + n.m_byte = data[i]; + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_ASCII: + setAsAscii((char*) data); + break; + case EXIF_TYPE_SHORT: + if( size == 2*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get16Bit( data + 2 * i, order, &n.m_short); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_LONG: + if( size == 4*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get32Bit( data + 4 * i, order, &n.m_long); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_RATIONAL: + if( size == 8*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get32Bit( data + 8 * i, order, &n.m_rational.numerator); + get32Bit( data + 8 * i + 4, order, &n.m_rational.denominator); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_SBYTE: + if( size == components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + n.m_sbyte = ((TQ_INT8*)data)[i]; + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_UNDEFINED: + setAsUndefined(data, size); + break; + case EXIF_TYPE_SSHORT: + if( size == 2*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get16Bit( data + 2 * i, order, (TQ_UINT16*)&n.m_sshort); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_SLONG: + if( size == 4*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get32Bit( data + 4 * i, order, (TQ_UINT32*)&n.m_slong); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_SRATIONAL: + if( size == 8*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get32Bit( data + 8 * i, order, (TQ_UINT32*)&n.m_srational.numerator); + get32Bit( data + 8 * i + 4, order, (TQ_UINT32*)&n.m_srational.denominator); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_FLOAT: + if( size == 4*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get32Bit( data + 4 * i, order, (TQ_UINT32*)&n.m_float); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_DOUBLE: + if( size == 8*components() ) + { + ExifNumber n; + for(uint i = 0; i < components(); i++) + { + get64Bit( data + 8 * i, order, (TQ_UINT64*)&n.m_double); + setAsExifNumber( i, n); + } + } + break; + case EXIF_TYPE_UNKNOW: + break; + } +} + +void ExifValue::convertToData(unsigned char ** data, unsigned int* size, ExifValue::ByteOrder order) +{ + switch(type()) + { + case EXIF_TYPE_BYTE: + *size = components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + (*data)[i] = asExifNumber(i).m_byte; + } + return; + case EXIF_TYPE_ASCII: + { + TQString str = asAscii(); + *size = str.length(); + *data = new uchar[ *size ]; + uchar* ptr = *data; + memcpy(ptr, str.ascii(), (*size)*sizeof(uchar)); + } + return; + break; + case EXIF_TYPE_SHORT: + { + *size = 2*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set16Bit( (*data) + 2 * i, order, &asExifNumber(i).m_short); + } + return; + } + case EXIF_TYPE_LONG: + { + *size = 4*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set32Bit( (*data) + 4 * i, order, &asExifNumber(i).m_long); + } + return; + } + case EXIF_TYPE_RATIONAL: + *size = 8*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + ExifNumber n = asExifNumber(i); + set32Bit( (*data) + 8 * i, order, &n.m_rational.numerator); + set32Bit( (*data) + 8 * i + 4, order, &n.m_rational.denominator); + } + return; + case EXIF_TYPE_SBYTE: + *size = components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + *(((TQ_INT8*)*data) + i) = asExifNumber(i).m_sbyte; + } + return; + case EXIF_TYPE_UNDEFINED: + { + UByteArray array = asUndefined(); + *size = array.size(); + *data = new uchar[*size]; + memcpy( *data, array.data(), (*size)*sizeof(unsigned char)); + } + return; + case EXIF_TYPE_SSHORT: + *size = 2*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set16Bit( (*data) + 2 * i, order, (TQ_UINT16*)&asExifNumber(i).m_sshort); + } + return; + case EXIF_TYPE_SLONG: + *size = 4*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set32Bit( (*data) + 4 * i, order, (TQ_UINT32*)&asExifNumber(i).m_slong); + } + return; + case EXIF_TYPE_SRATIONAL: + *size = 8*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + ExifNumber n = asExifNumber(i); + set32Bit( (*data) + 4 * i, order, (TQ_UINT32*)&asExifNumber(i).m_srational.numerator); + set32Bit( (*data) + 4 * i + 4, order, (TQ_UINT32*)&asExifNumber(i).m_srational.denominator); + } + return; + case EXIF_TYPE_FLOAT: + *size = 4*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set32Bit( (*data) + 4 * i, order, (TQ_UINT32*)&asExifNumber(i).m_float); + } + return; + case EXIF_TYPE_DOUBLE: + *size = 8*components(); + *data = new uchar[*size]; + for(uint i = 0; i < components(); i++) + { + set64Bit( (*data) + 4 * i, order, (TQ_UINT64*)&asExifNumber(i).m_double); + } + return; + case EXIF_TYPE_UNKNOW: + break; + } +} + +TQString ExifValue::toString() +{ + switch(type()) + { + case EXIF_TYPE_ASCII: + return asAscii(); + case EXIF_TYPE_UNDEFINED: + { + TQString undefined = "undefined"; + UByteArray array = asUndefined(); + for(uint i = 0; i < components(); i++) + { + undefined += "\\" + TQString().setNum( array[i] ); + } + return undefined; + } + default: + { + TQString str = ""; + for(uint i = 0; i < components(); i++) + { + str += toString(i); + } + return str; + } + } +} + +TQString ExifValue::toString(uint i) +{ + switch(type()) + { + case EXIF_TYPE_BYTE: + return TQString("%1 ").tqarg( asExifNumber( i ).m_byte ); + case EXIF_TYPE_SHORT: + return TQString("%1 ").tqarg( asExifNumber( i ).m_short ); + case EXIF_TYPE_LONG: + return TQString("%1 ").tqarg( asExifNumber( i ).m_long ); + case EXIF_TYPE_RATIONAL: + return TQString("%1 / %2 ").tqarg( asExifNumber( i ).m_rational.numerator ).tqarg( asExifNumber( i ).m_rational.denominator ); + case EXIF_TYPE_SBYTE: + return TQString("%1 ").tqarg( asExifNumber( i ).m_sbyte ); + case EXIF_TYPE_SSHORT: + return TQString("%1 ").tqarg( asExifNumber( i ).m_sshort ); + case EXIF_TYPE_SLONG: + return TQString("%1 ").tqarg( asExifNumber( i ).m_slong ); + case EXIF_TYPE_SRATIONAL: + return TQString("%1 / %2 ").tqarg( asExifNumber( i ).m_srational.numerator ).tqarg( asExifNumber( i ).m_srational.denominator ); + case EXIF_TYPE_FLOAT: + return TQString("%1 ").tqarg( asExifNumber( i ).m_float ); + case EXIF_TYPE_DOUBLE: + return TQString("%1 ").tqarg( asExifNumber( i ).m_double ); + default: + return "unknow "; + } +} + diff --git a/chalk/core/kis_exif_value.h b/chalk/core/kis_exif_value.h new file mode 100644 index 00000000..44a3632b --- /dev/null +++ b/chalk/core/kis_exif_value.h @@ -0,0 +1,270 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_EXIF_VALUE_H +#define KIS_EXIF_VALUE_H + +#include + +#include +#include + +typedef TQMemArray UByteArray; + +struct KisExifRational { + TQ_UINT32 numerator; + TQ_UINT32 denominator; +}; + +struct KisExifSRational { + TQ_INT32 numerator; + TQ_INT32 denominator; +}; + +class ExifValue { + typedef union { + TQ_UINT8 m_byte; + TQ_UINT16 m_short; + TQ_UINT32 m_long; + KisExifRational m_rational; + TQ_INT8 m_sbyte; + TQ_INT16 m_sshort; + TQ_INT32 m_slong; + KisExifSRational m_srational; + float m_float; + double m_double; + } ExifNumber; + public: + enum ExifType { + EXIF_TYPE_BYTE = 1, + EXIF_TYPE_ASCII = 2, + EXIF_TYPE_SHORT = 3, + EXIF_TYPE_LONG = 4, + EXIF_TYPE_RATIONAL = 5, + EXIF_TYPE_SBYTE = 6, + EXIF_TYPE_UNDEFINED = 7, + EXIF_TYPE_SSHORT = 8, + EXIF_TYPE_SLONG = 9, + EXIF_TYPE_SRATIONAL = 10, + EXIF_TYPE_FLOAT = 11, + EXIF_TYPE_DOUBLE = 12, + EXIF_TYPE_UNKNOW = 13 + }; + enum ByteOrder { + BYTE_ORDER_MOTOROLA, + BYTE_ORDER_INTEL + }; + ExifValue() : m_ifd(-1), m_type(EXIF_TYPE_UNKNOW), m_components(0), m_value(0) { } + ExifValue(ExifType type, unsigned char *data, unsigned int size, int ifd, uint components, ExifValue::ByteOrder order); + + virtual bool load(const TQDomElement& elmt); + virtual TQDomElement save(TQDomDocument& doc); + + /** + * Return the type of the array + */ + inline ExifType type() { return m_type; } + inline const UByteArray asUndefined() { + if(m_type == EXIF_TYPE_UNDEFINED) + return *(UByteArray*) m_value; + return UByteArray(); + } + inline void setAsUndefined(const unsigned char *data, unsigned int size) + { + if(m_type == EXIF_TYPE_UNDEFINED) + { + ((UByteArray*)m_value)->duplicate(data, size); + m_components = size; + } + } + inline const TQString asAscii() { + if(m_type == EXIF_TYPE_ASCII) + return TQString(*(TQString*) m_value); + return TQString(); + } + inline void setAsAscii(char* data) + { + if(m_type == EXIF_TYPE_ASCII) + { + TQString str = TQString((char*) data); + *(TQString*)m_value = str; + m_components = str.length(); + } + } + inline void setAsAscii(TQString str) + { + *(TQString*)m_value = str; + m_components = str.length(); + } + void convertToData(unsigned char ** data, unsigned int* size, ExifValue::ByteOrder order); + /** + * Return the ifd number to which this ExifValue belongs. + */ + inline int ifd() { return m_ifd; } + /** + * Return the number of components of this ExifValue + */ + inline uint components() { return m_components; } + + /** + * This function return the value of a the ExifValue as a string. + */ + TQString toString(); + + inline TQ_UINT8 asByte(uint i) + { + if(m_type == EXIF_TYPE_BYTE) + return asExifNumber(i).m_byte; + return 0; + } + inline void setValue(uint i, TQ_UINT8 v) + { + ((ExifNumber*)m_value)[i].m_byte = v; + } + inline TQ_UINT8 asShort(uint i) + { + if(m_type == EXIF_TYPE_SHORT) + return asExifNumber(i).m_short; + return 0; + } + inline void setValue(uint i, TQ_UINT16 v) + { + ((ExifNumber*)m_value)[i].m_short = v; + } + inline TQ_UINT8 asLong(uint i) + { + if(m_type == EXIF_TYPE_LONG) + return asExifNumber(i).m_long; + return 0; + } + inline void setValue(uint i, TQ_UINT32 v) + { + ((ExifNumber*)m_value)[i].m_long = v; + } + inline KisExifRational asRational(uint i) + { + if(m_type == EXIF_TYPE_RATIONAL) + return asExifNumber(i).m_rational; + return KisExifRational(); + } + inline void setValue(uint i, TQ_UINT32 n, TQ_UINT32 d) + { + ((ExifNumber*)m_value)[i].m_rational.numerator = n; + ((ExifNumber*)m_value)[i].m_rational.denominator = d; + } + inline void setValue(uint i, KisExifRational r) + { + ((ExifNumber*)m_value)[i].m_rational = r; + } + inline TQ_INT8 asSByte(uint i) + { + if(m_type == EXIF_TYPE_SBYTE) + return asExifNumber(i).m_sbyte; + return 0; + } + inline void setValue(uint i, TQ_INT8 v) + { + ((ExifNumber*)m_value)[i].m_sbyte = v; + } + inline TQ_INT16 asSShort(uint i) + { + if(m_type == EXIF_TYPE_SSHORT) + return asExifNumber(i).m_sshort; + return 0; + } + inline void setValue(uint i, TQ_INT16 v) + { + ((ExifNumber*)m_value)[i].m_sshort = v; + } + inline TQ_INT32 asSLong(uint i) + { + if(m_type == EXIF_TYPE_SLONG) + return asExifNumber(i).m_slong; + return 0; + } + inline void setValue(uint i, TQ_INT32 v) + { + ((ExifNumber*)m_value)[i].m_slong = v; + } + inline KisExifSRational asSRational(uint i) + { + if(m_type == EXIF_TYPE_SRATIONAL) + return asExifNumber(i).m_srational; + return KisExifSRational(); + } + inline void setValue(uint i, KisExifSRational r) + { + ((ExifNumber*)m_value)[i].m_srational = r; + } + inline void setValue(uint i, TQ_INT32 n, TQ_INT32 d) + { + ((ExifNumber*)m_value)[i].m_srational.numerator = n; + ((ExifNumber*)m_value)[i].m_srational.denominator = d; + } + inline float asFloat(uint i) + { + if(m_type == EXIF_TYPE_FLOAT) + return asExifNumber(i).m_float; + return 0.; + } + inline void setValue(uint i, float v) + { + ((ExifNumber*)m_value)[i].m_float = v; + } + inline double asDouble(uint i) + { + if(m_type == EXIF_TYPE_DOUBLE) + return asExifNumber(i).m_double; + return 0.; + } + inline void setValue(uint i, double v) + { + ((ExifNumber*)m_value)[i].m_double = v; + } + private: + /** + * Return the ith component as a string. + */ + TQString toString(uint i); + void setValue(const unsigned char *data, unsigned int size, ExifValue::ByteOrder order); + /** + * Return the ExifValue as a number. + */ + inline const ExifNumber asExifNumber(uint index) + { + Q_ASSERT(index < m_components); + return ((ExifNumber*)m_value)[index]; + } + inline void setAsExifNumber(uint index, ExifNumber n) + { + Q_ASSERT(index < m_components); + ((ExifNumber*)m_value)[index] = n; + } + /** + * This function will allocate the memory used for storing the current data. + */ + void allocData(); + private: + int m_ifd; + ExifType m_type; + uint m_components; + void *m_value; +}; + +#endif diff --git a/chalk/core/kis_fill_painter.cc b/chalk/core/kis_fill_painter.cc new file mode 100644 index 00000000..5b8fdcc9 --- /dev/null +++ b/chalk/core/kis_fill_painter.cc @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include "tqbrush.h" +#include "tqfontinfo.h" +#include "tqfontmetrics.h" +#include "tqpen.h" +#include "tqregion.h" +#include "tqwmatrix.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_brush.h" +#include "kis_debug_areas.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_pattern.h" +#include "kis_rect.h" +#include "kis_colorspace.h" +#include "kis_transaction.h" +#include "kis_types.h" +#include "kis_vec.h" +#include "kis_selection.h" +#include "kis_fill_painter.h" +#include "kis_iterators_pixel.h" +#include "kis_iterator.h" +#include "kis_color.h" +#include "kis_selection.h" + +namespace { +} + +KisFillPainter::KisFillPainter() + : super() +{ + m_width = m_height = -1; + m_sampleMerged = false; + m_careForSelection = false; + m_fuzzy = false; +} + +KisFillPainter::KisFillPainter(KisPaintDeviceSP device) : super(device) +{ + m_width = m_height = -1; + m_sampleMerged = false; + m_careForSelection = false; + m_fuzzy = false; +} + +// 'regular' filling +// XXX: This also needs renaming, since filling ought to keep the opacity and the composite op in mind, +// this is more eraseToColor. +void KisFillPainter::fillRect(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h, const KisColor& kc, TQ_UINT8 opacity) +{ + if (w > 0 && h > 0) { + // Make sure we're in the right colorspace + + KisColor kc2(kc); // get rid of const + kc2.convertTo(m_device->colorSpace()); + TQ_UINT8 * data = kc2.data(); + m_device->colorSpace()->setAlpha(data, opacity, 1); + + m_device->fill(x1, y1, w, h, data); + + addDirtyRect(TQRect(x1, y1, w, h)); + } +} + +void KisFillPainter::fillRect(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h, KisPattern * pattern) { + if (!pattern) return; + if (!pattern->valid()) return; + if (!m_device) return; + + + KisPaintDeviceSP patternLayer = pattern->image(m_device->colorSpace()); + + int sx, sy, sw, sh; + + int y = y1; + + if (y >= 0) { + sy = y % pattern->height(); + } else { + sy = pattern->height() - (((-y - 1) % pattern->height()) + 1); + } + + while (y < y1 + h) { + sh = TQMIN((y1 + h) - y, pattern->height() - sy); + + int x = x1; + + if (x >= 0) { + sx = x % pattern->width(); + } else { + sx = pattern->width() - (((-x - 1) % pattern->width()) + 1); + } + + while (x < x1 + w) { + sw = TQMIN((x1 + w) - x, pattern->width() - sx); + + bitBlt(x, y, m_compositeOp, patternLayer.data(), m_opacity, sx, sy, sw, sh); + x += sw; sx = 0; + } + + y+=sh; sy = 0; + } + + addDirtyRect(TQRect(x1, y1, w, h)); +} + +// flood filling + +void KisFillPainter::fillColor(int startX, int startY) { + genericFillStart(startX, startY); + + // Now create a layer and fill it + KisPaintDeviceSP filled = new KisPaintDevice(m_device->colorSpace(), "filled"); + Q_CHECK_PTR(filled); + KisFillPainter painter(filled.data()); + painter.fillRect(0, 0, m_width, m_height, m_paintColor); + painter.end(); + + genericFillEnd(filled); +} + +void KisFillPainter::fillPattern(int startX, int startY) { + genericFillStart(startX, startY); + + // Now create a layer and fill it + KisPaintDeviceSP filled = new KisPaintDevice(m_device->colorSpace(), "filled"); + Q_CHECK_PTR(filled); + KisFillPainter painter(filled.data()); + painter.fillRect(0, 0, m_width, m_height, m_pattern); + painter.end(); + + genericFillEnd(filled); +} + +void KisFillPainter::genericFillStart(int startX, int startY) { + m_cancelRequested = false; + + if (m_width < 0 || m_height < 0) { + if (m_device->image()) { + m_width = m_device->image()->width(); + m_height = m_device->image()->height(); + } else { + m_width = m_height = 500; + } + } + + m_size = m_width * m_height; + + // Create a selection from the surrounding area + m_selection = createFloodSelection(startX, startY); +} + +void KisFillPainter::genericFillEnd(KisPaintDeviceSP filled) { + if (m_cancelRequested) { + m_width = m_height = -1; + return; + } + + TQRect rc = m_selection->selectedRect(); + + bltSelection(rc.x(), rc.y(), m_compositeOp, filled, m_selection, m_opacity, + rc.x(), rc.y(), rc.width(), rc.height()); + + emit notifyProgressDone(); + + m_width = m_height = -1; +} + +struct FillSegment { + FillSegment(int x, int y/*, FillSegment* tqparent*/) : x(x), y(y)/*, tqparent(tqparent)*/ {} + int x; + int y; +// FillSegment* tqparent; +}; + +typedef enum { None = 0, Added = 1, Checked = 2 } tqStatus; + +KisSelectionSP KisFillPainter::createFloodSelection(int startX, int startY) { + if (m_width < 0 || m_height < 0) { + if (m_device->hasSelection() && m_careForSelection) { + + TQRect rc = m_device->selection()->selectedRect(); + m_width = rc.width() - (startX - rc.x()); + m_height = rc.height() - (startY - rc.y()); + + } else if (m_device->image()) { + + m_width = m_device->image()->width(); + m_height = m_device->image()->height(); + + } else { + m_width = m_height = 500; + } + } + + // Don't try to fill if we start outside the borders, just return an empty 'fill' + if (startX < 0 || startY < 0 || startX >= m_width || startY >= m_height) + return new KisSelection(m_device); + + KisPaintDeviceSP sourceDevice = 0; + + // sample merged? + if (m_sampleMerged) { + if (!m_device->image()) { + return new KisSelection(m_device); + } + sourceDevice = m_device->image()->mergedImage(); + } else { + sourceDevice = m_device; + } + + m_size = m_width * m_height; + + KisSelectionSP selection = new KisSelection(m_device); + KisColorSpace * colorSpace = selection->colorSpace(); + KisColorSpace * devColorSpace = sourceDevice->colorSpace(); + + TQ_UINT8* source = new TQ_UINT8[sourceDevice->pixelSize()]; + KisHLineIteratorPixel pixelIt = sourceDevice->createHLineIterator(startX, startY, startX+1, false); + + memcpy(source, pixelIt.rawData(), sourceDevice->pixelSize()); + + std::stack stack; + + stack.push(new FillSegment(startX, startY/*, 0*/)); + + tqStatus* map = new tqStatus[m_size]; + + memset(map, None, m_size * sizeof(tqStatus)); + + int progressPercent = 0; int pixelsDone = 0; int currentPercent = 0; + emit notifyProgressStage(i18n("Making fill outline..."), 0); + + bool hasSelection = m_careForSelection && sourceDevice->hasSelection(); + KisSelectionSP srcSel = 0; + if (hasSelection) + srcSel = sourceDevice->selection(); + + while(!stack.empty()) { + FillSegment* segment = stack.top(); + stack.pop(); + if (map[m_width * segment->y + segment->x] == Checked) { + delete segment; + continue; + } + map[m_width * segment->y + segment->x] = Checked; + + int x = segment->x; + int y = segment->y; + + /* We need an iterator that is valid in the range (0,y) - (width,y). Therefore, + it is needed to start the iterator at the first position, and then skip to (x,y). */ + pixelIt = sourceDevice->createHLineIterator(0, y, m_width, false); + pixelIt += x; + TQ_UINT8 diff = devColorSpace->difference(source, pixelIt.rawData()); + + if (diff >= m_threshold + || (hasSelection && srcSel->selected(pixelIt.x(), pixelIt.y()) == MIN_SELECTED)) { + delete segment; + continue; + } + + // Here as well: start the iterator at (0,y) + KisHLineIteratorPixel selIt = selection->createHLineIterator(0, y, m_width, true); + selIt += x; + if (m_fuzzy) + colorSpace->fromTQColor(TQt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromTQColor(TQt::white, MAX_SELECTED, selIt.rawData()); + + if (y > 0 && (map[m_width * (y - 1) + x] == None)) { + map[m_width * (y - 1) + x] = Added; + stack.push(new FillSegment(x, y-1)); + } + if (y < (m_height - 1) && (map[m_width * (y + 1) + x] == None)) { + map[m_width * (y + 1) + x] = Added; + stack.push(new FillSegment(x, y+1)); + } + + ++pixelsDone; + + bool stop = false; + + --pixelIt; + --selIt; + --x; + + // go to the left + while(!stop && x >= 0 && (map[m_width * y + x] != Checked) ) { // FIXME optimizeable? + map[m_width * y + x] = Checked; + diff = devColorSpace->difference(source, pixelIt.rawData()); + if (diff >= m_threshold + || (hasSelection && srcSel->selected(pixelIt.x(), pixelIt.y()) == MIN_SELECTED)) { + stop = true; + continue; + } + + if (m_fuzzy) + colorSpace->fromTQColor(TQt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromTQColor(TQt::white, MAX_SELECTED, selIt.rawData()); + + if (y > 0 && (map[m_width * (y - 1) + x] == None)) { + map[m_width * (y - 1) + x] = Added; + stack.push(new FillSegment(x, y-1)); + } + if (y < (m_height - 1) && (map[m_width * (y + 1) + x] == None)) { + map[m_width * (y + 1) + x] = Added; + stack.push(new FillSegment(x, y+1)); + } + ++pixelsDone; + --pixelIt; + --selIt; + --x; + } + + x = segment->x + 1; + delete segment; + + if (map[m_width * y + x] == Checked) + continue; + + // and go to the right + pixelIt = sourceDevice->createHLineIterator(x, y, m_width, false); + selIt = selection->createHLineIterator(x, y, m_width, true); + + stop = false; + while(!stop && x < m_width && (map[m_width * y + x] != Checked) ) { + diff = devColorSpace->difference(source, pixelIt.rawData()); + map[m_width * y + x] = Checked; + + if (diff >= m_threshold + || (hasSelection && srcSel->selected(pixelIt.x(), pixelIt.y()) == MIN_SELECTED) ) { + stop = true; + continue; + } + + if (m_fuzzy) + colorSpace->fromTQColor(TQt::white, MAX_SELECTED - diff, selIt.rawData()); + else + colorSpace->fromTQColor(TQt::white, MAX_SELECTED, selIt.rawData()); + + if (y > 0 && (map[m_width * (y - 1) + x] == None)) { + map[m_width * (y - 1) + x] = Added; + stack.push(new FillSegment(x, y-1)); + } + if (y < (m_height - 1) && (map[m_width * (y + 1) + x] == None)) { + map[m_width * (y + 1) + x] = Added; + stack.push(new FillSegment(x, y+1)); + } + ++pixelsDone; + ++pixelIt; + ++selIt; + ++x; + } + + if (m_size > 0) { + progressPercent = (pixelsDone * 100) / m_size; + if (progressPercent > currentPercent) { + emit notifyProgress(progressPercent); + currentPercent = progressPercent; + } + } + } + + + delete[] map; + delete[] source; + + return selection; +} diff --git a/chalk/core/kis_fill_painter.h b/chalk/core/kis_fill_painter.h new file mode 100644 index 00000000..da244a67 --- /dev/null +++ b/chalk/core/kis_fill_painter.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_FILL_PAINTER_H_ +#define KIS_FILL_PAINTER_H_ + +#include + +#include "kis_meta_registry.h" +#include "kis_color.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_painter.h" +#include "kis_types.h" +#include + +class KisPattern; + +// XXX: Filling should set dirty rect. +/** + * This painter can be used to fill paint devices in different ways. This can also be used + * for flood filling related operations. + */ +class KRITACORE_EXPORT KisFillPainter : public KisPainter +{ + + typedef KisPainter super; + +public: + + /** + * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach + * to a paint device + */ + KisFillPainter(); + /** + * Start painting on the specified paint device + */ + KisFillPainter(KisPaintDeviceSP device); + + /** + * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA). + */ + void eraseRect(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h); + /** + * Overloaded version of the above function. + */ + void eraseRect(const TQRect& rc); + + /** + * Fill a rectangle with a certain color. + */ + void fillRect(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const KisColor& c); + /** + * Overloaded version of the above function. + */ + void fillRect(const TQRect& rc, const KisColor& c); + + /** + * Fill a rectangle with a certain color and opacity. + */ + void fillRect(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const KisColor& c, TQ_UINT8 opacity); + /** + * Overloaded version of the above function. + */ + void fillRect(const TQRect& rc, const KisColor& c, TQ_UINT8 opacity); + + /** + * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the + * entire rectangle. + */ + void fillRect(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h, KisPattern * pattern); + /** + * Overloaded version of the above function. + */ + void fillRect(const TQRect& rc, KisPattern * pattern); + + /** + * Fills the enclosed area around the point with the set color. If there is a + * selection, the whole selection is filled + **/ + void fillColor(int startX, int startY); + + /** + * Fills the enclosed area around the point with the set pattern. If there is a + * selection, the whole selection is filled + **/ + void fillPattern(int startX, int startY); + + /** + * Returns a selection tqmask for the floodfill starting at the specified position. + **/ + KisSelectionSP createFloodSelection(int startX, int startY); + + /** + * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only + * fill parts that are the exact same color, 255 means anything will be filled + */ + void setFillThreshold(int threshold); + /** Returns the fill threshold, see setFillThreshold for details */ + int fillThreshold() const { return m_threshold; } + + /** Sets the width of the layer */ + void setWidth(int w) { m_width = w; } + + /** Sets the height of the layer */ + void setHeight(int h) { m_height = h; } + + /** If sample merged is set to true, the paint device will get the bounds of the + * floodfill from the complete image instead of the layer */ + bool sampleMerged() const { return m_sampleMerged; } + /** Set sample merged. See sampleMerged() for details */ + void setSampleMerged(bool set) { m_sampleMerged = set; } + + /** If true, floodfill doesn't fill outside the selected area of a layer */ + bool careForSelection() const { return m_careForSelection; } + /** Set caring for selection. See careForSelection for details */ + void setCareForSelection(bool set) { m_careForSelection = set; } + + /** + * If true, the floodfill will be fuzzy. This means that the 'value' of selectedness + * will depend on the difference between the sampled color and the color at the current + * position. + */ + bool fuzzyFill() const { return m_fuzzy; } + /** Sets the fuzzyfill parameter. See fuzzyFill for details */ + void setFuzzyFill(bool set) { m_fuzzy = set; } + +private: + // for floodfill + void genericFillStart(int startX, int startY); + void genericFillEnd(KisPaintDeviceSP filled); + + KisSelectionSP m_selection; + + int m_threshold; + int m_size; + int m_width, m_height; + TQRect m_rect; + bool m_sampleMerged; + bool m_careForSelection; + bool m_fuzzy; +}; + + +inline +void KisFillPainter::fillRect(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const KisColor& c) +{ + fillRect(x, y, w, h, c, OPACITY_OPAQUE); +} + +inline +void KisFillPainter::fillRect(const TQRect& rc, const KisColor& c) +{ + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE); +} + +inline +void KisFillPainter::eraseRect(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + KisColor c(TQt::black, cs); + fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT); +} + +inline +void KisFillPainter::eraseRect(const TQRect& rc) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + KisColor c(TQt::black, cs); + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_TRANSPARENT); +} + +inline +void KisFillPainter::fillRect(const TQRect& rc, const KisColor& c, TQ_UINT8 opacity) +{ + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); +} + +inline +void KisFillPainter::fillRect(const TQRect& rc, KisPattern *pattern) +{ + fillRect(rc.x(), rc.y(), rc.width(), rc.height(), pattern); +} + +inline +void KisFillPainter::setFillThreshold(int threshold) +{ + m_threshold = threshold; +} + + +#endif //KIS_FILL_PAINTER_H_ diff --git a/chalk/core/kis_filter.cc b/chalk/core/kis_filter.cc new file mode 100644 index 00000000..ee396596 --- /dev/null +++ b/chalk/core/kis_filter.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_filter.h" + +#include + +#include "kis_types.h" +#include "kis_filter_configuration.h" + +KisFilter::KisFilter(const KisID& id, const TQString & category, const TQString & entry) + : KisProgressSubject(0, id.id().latin1()) + , m_id(id) + , m_progressDisplay(0) + , m_category(category) + , m_entry(entry) +{ +} + +KisFilterConfiguration * KisFilter::configuration(TQWidget*) +{ + return new KisFilterConfiguration(m_id.id(), 0); +} + +KisFilterConfiguration * KisFilter::configuration() +{ + return new KisFilterConfiguration(m_id.id(), 0); +} + +KisFilterConfigWidget * KisFilter::createConfigurationWidget(TQWidget *, KisPaintDeviceSP) +{ + return 0; +} + +void KisFilter::setProgressDisplay(KisProgressDisplayInterface * progressDisplay) +{ + m_progressDisplay = progressDisplay; +} + + +void KisFilter::enableProgress() { + m_progressEnabled = true; + m_cancelRequested = false; +} + +void KisFilter::disableProgress() { + m_progressEnabled = false; + m_cancelRequested = false; + m_progressDisplay = 0; +} + +void KisFilter::setProgressTotalSteps(TQ_INT32 totalSteps) +{ + if (m_progressEnabled) { + + m_progressTotalSteps = totalSteps; + m_lastProgressPerCent = 0; + m_progressSteps = 0; + emit notifyProgress(0); + } +} + +void KisFilter::setProgress(TQ_INT32 progress) +{ + if (m_progressEnabled) { + TQ_INT32 progressPerCent = (progress * 100) / m_progressTotalSteps; + m_progressSteps = progress; + + if (progressPerCent != m_lastProgressPerCent) { + + m_lastProgressPerCent = progressPerCent; + emit notifyProgress(progressPerCent); + } + } +} + +void KisFilter::incProgress() +{ + setProgress(++m_progressSteps); + +} + +void KisFilter::setProgressStage(const TQString& stage, TQ_INT32 progress) +{ + if (m_progressEnabled) { + + TQ_INT32 progressPerCent = (progress * 100) / m_progressTotalSteps; + + m_lastProgressPerCent = progressPerCent; + emit notifyProgressStage(stage, progressPerCent); + } +} + +void KisFilter::setProgressDone() +{ + if (m_progressEnabled) { + emit notifyProgressDone(); + } +} + + +bool KisFilter::autoUpdate() { + return m_autoUpdate; +} + +void KisFilter::setAutoUpdate(bool set) { + m_autoUpdate = set; +} + +TQRect KisFilter::enlargeRect(TQRect rect, KisFilterConfiguration* c) const { + int margin = overlapMarginNeeded(c); + rect.rLeft() -= margin; + rect.rTop() -= margin; + rect.rRight() += margin; + rect.rBottom() += margin; + return rect; +} + +#include "kis_filter.moc" diff --git a/chalk/core/kis_filter.h b/chalk/core/kis_filter.h new file mode 100644 index 00000000..807ecff8 --- /dev/null +++ b/chalk/core/kis_filter.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_FILTER_H_ +#define _KIS_FILTER_H_ + +#include + +#include + +#include +#include + +#include "kis_types.h" +#include "kis_filter_registry.h" +#include "kis_id.h" +#include "kis_paint_device.h" +#include "kis_progress_subject.h" +#include "kis_filter_configuration.h" +#include "kis_colorspace.h" +#include "koffice_export.h" + +class KisColorSpace; +class KisPreviewDialog; +class KisProgressDisplayInterface; +class KisFilterConfigWidget; +class TQWidget; + +/** + * Basic interface of a Chalk filter. + */ +class KRITACORE_EXPORT KisFilter : public KisProgressSubject, public KShared { + Q_OBJECT + TQ_OBJECT +public: + + /** + * Construct a Chalk filter + */ + KisFilter(const KisID& id, const TQString & category, const TQString & entry); + virtual ~KisFilter() {} + +public: + + virtual void setProgressDisplay(KisProgressDisplayInterface * progressDisplay); + + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&) = 0; + +public: + /** + * @return a new configuration derived from the widget. If the widget is NULL or not the correct type, + * a default configuration object will be returned + */ + virtual KisFilterConfiguration * configuration(TQWidget*); + + /** + * @return a default configuration object + * Normally this doesn't need to be overriden + */ + virtual KisFilterConfiguration * configuration(); + + /** + * If true, this filter can be used in painting tools as a paint operation + */ + virtual bool supportsPainting() { return false; }; + + /// This filter can be displayed in a preview dialog + virtual bool supportsPreview() { return false; }; + + /// This filter can be used in adjustment layers + // XXX: This uses supportsPreview() for backwards compatibility + virtual bool supportsAdjustmentLayers() { return supportsPreview(); }; + + /** + * Return a list of default configuration to demonstrates the use of the filter + * @return a list with a null element if the filter do not use a configuration + */ + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), 0); return list; } + + /** + * Can this filter work incrementally when painting, or do we need to work + * on the state as it was before painting started. The former is faster. + */ + virtual bool supportsIncrementalPainting() { return true; }; + + /** + * This filter supports cutting up the work area and filtering + * each chunk in a separate thread. Filters that need access to the + * whole area for correct computations should return false. + */ + virtual bool supportsThreading() { return true; }; + + /** + * Used when threading is used -- the overlap margin is passed to the + * filter to use to compute pixels, but the margin is not pasted into the + * resulting image. + */ + virtual int overlapMarginNeeded(KisFilterConfiguration* = 0) const { return 0; }; + + /** + * Similar to overlapMarginNeeded: some filters will alter a lot of pixels that are + * near to each other at the same time. So when you changed a single rectangle + * in a device, the actual rectangle that will feel the influence of this change + * might be bigger. Use this function to detirmine that rect. + * The default implementation makes a guess using overlapMarginNeeded. + */ + virtual TQRect enlargeRect(TQRect rect, KisFilterConfiguration* = 0) const; + + /** + * Determine the colorspace independence of this filter. + * @see ColorSpaceIndependence + * + * @return the degree of independence + */ + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_RGBA8; }; + + /** + * Determine if this filter can work with this colorSpace. For instance, some + * colorspaces don't depend on lcms, and cannot do certain tasks. The colorsfilters + * are problems here. + * BSAR: I'm still not convinced that this is the right approach. I think that every + * colorspace should implement the api fully; and that the filter should simply call + * that api. After all, you don't need lcms to desaturate. + * + * @param colorsSpace + */ + virtual bool workWith(KisColorSpace*) { return true; } + + virtual void enableProgress(); + virtual void disableProgress(); + + bool autoUpdate(); + + // Unique identification for this filter + inline const KisID id() const { return m_id; }; + // Which submenu in the filters menu does filter want to go? + + inline TQString menuCategory() const { return m_category; }; + // The i18n'ed string this filter wants to show itself in the menu + + inline TQString menuEntry() const { return m_entry; }; + + /** + * Create the configuration widget for this filter. + * + * @param tqparent the TQt owner widget of this widget + * @param dev the paintdevice this filter will act on +     * @return NULL if the filter does not use user-settable configuration settings. +     *         else return a pointer to the new configuration widget + */ + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget * tqparent, KisPaintDeviceSP dev); + + virtual void cancel() { m_cancelRequested = true; } + + virtual void setAutoUpdate(bool set); + bool progressEnabled() const { return m_progressEnabled; } + inline bool cancelRequested() const { return m_progressEnabled && m_cancelRequested; } + +protected slots: + + // Convenience functions for progress display. + void setProgressTotalSteps(TQ_INT32 totalSteps); + void setProgress(TQ_INT32 progress); + void incProgress(); + void setProgressStage(const TQString& stage, TQ_INT32 progress); + void setProgressDone(); + inline TQ_INT32 progress() { return m_progressSteps; } +private: + bool m_cancelRequested; + bool m_progressEnabled; + bool m_autoUpdate; + +protected: + TQ_INT32 m_progressTotalSteps; + TQ_INT32 m_lastProgressPerCent; + TQ_INT32 m_progressSteps; + + KisID m_id; + KisProgressDisplayInterface * m_progressDisplay; + TQString m_category; // The category in the filter menu this filter fits + TQString m_entry; // the i18n'ed accelerated menu text + +}; + + +#endif diff --git a/chalk/core/kis_filter_config_widget.cc b/chalk/core/kis_filter_config_widget.cc new file mode 100644 index 00000000..df7c13d5 --- /dev/null +++ b/chalk/core/kis_filter_config_widget.cc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_filter_config_widget.h" + + +KisFilterConfigWidget::KisFilterConfigWidget(TQWidget * tqparent, const char * name, WFlags f) + : TQWidget(tqparent, name, f) +{ +} + +KisFilterConfigWidget::~KisFilterConfigWidget() +{ +} + +#include "kis_filter_config_widget.moc" diff --git a/chalk/core/kis_filter_config_widget.h b/chalk/core/kis_filter_config_widget.h new file mode 100644 index 00000000..ddb600ab --- /dev/null +++ b/chalk/core/kis_filter_config_widget.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_FILTER_CONFIG_WIDGET_H_ +#define _KIS_FILTER_CONFIG_WIDGET_H_ + +#include +#include "kis_filter_configuration.h" + +/** + * Empty base class. Filters can build their own configuration widgets that + * inherit this class. The configuration widget can emit sigPleaseUpdatePreview + * when it wants the preview in the filter dialog to be updated. + */ +class KisFilterConfigWidget : public TQWidget { + + Q_OBJECT + TQ_OBJECT + +public: + + KisFilterConfigWidget(TQWidget * tqparent, const char * name = 0, WFlags f = 0 ); + virtual ~KisFilterConfigWidget(); + + virtual void setConfiguration(KisFilterConfiguration * config) = 0; + +signals: + + /** + * Subclasses should emit this signal whenever the preview should be + * be recalculated. + */ + void sigPleaseUpdatePreview(); +}; + +#endif diff --git a/chalk/core/kis_filter_configuration.cc b/chalk/core/kis_filter_configuration.cc new file mode 100644 index 00000000..b25dcb24 --- /dev/null +++ b/chalk/core/kis_filter_configuration.cc @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_filter.h" + +#include +#include +#include + +#include "kis_filter_registry.h" +#include "kis_transaction.h" +#include "kis_undo_adapter.h" +#include "kis_painter.h" +#include "kis_selection.h" +#include "kis_id.h" +#include "kis_canvas_subject.h" +#include "kis_progress_display_interface.h" +#include "kis_types.h" +#include "kis_filter_config_widget.h" + + +KisFilterConfiguration::KisFilterConfiguration(const KisFilterConfiguration & rhs) +{ + m_name = rhs.m_name; + m_version = rhs.m_version; + m_properties = rhs.m_properties; +} + +void KisFilterConfiguration::fromXML(const TQString & s ) +{ + m_properties.clear(); + + TQDomDocument doc; + doc.setContent( s ); + TQDomElement e = doc.documentElement(); + TQDomNode n = e.firstChild(); + + m_name = e.attribute("name"); + m_version = e.attribute("version").toInt(); + + while (!n.isNull()) { + // We don't nest elements in filter configuration. For now... + TQDomElement e = n.toElement(); + TQString name; + TQString type; + TQString value; + + if (!e.isNull()) { + if (e.tagName() == "property") { + name = e.attribute("name"); + type = e.attribute("type"); + value = e.text(); + // XXX Convert the variant pro-actively to the right type? + m_properties[name] = TQVariant(value); + } + } + n = n.nextSibling(); + } + //dump(); +} + +TQString KisFilterConfiguration::toString() +{ + TQDomDocument doc = TQDomDocument("filterconfig"); + TQDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", m_name ); + root.setAttribute( "version", m_version ); + + doc.appendChild( root ); + + TQMap::Iterator it; + for ( it = m_properties.begin(); it != m_properties.end(); ++it ) { + TQDomElement e = doc.createElement( "property" ); + e.setAttribute( "name", it.key().latin1() ); + TQVariant v = it.data(); + e.setAttribute( "type", v.typeName() ); + TQString s = v.asString(); + TQDomText text = doc.createCDATASection(v.asString() ); // XXX: Unittest this! + e.appendChild(text); + root.appendChild(e); + } + + return doc.toString(); +} + +const TQString & KisFilterConfiguration::name() const +{ + return m_name; +} + +TQ_INT32 KisFilterConfiguration::version() const +{ + return m_version; +} + +void KisFilterConfiguration::setProperty(const TQString & name, const TQVariant & value) +{ + if ( m_properties.tqfind( name ) == m_properties.end() ) { + m_properties.insert( name, value ); + } + else { + m_properties[name] = value; + } +} + +bool KisFilterConfiguration::getProperty(const TQString & name, TQVariant & value) +{ + if ( m_properties.tqfind( name ) == m_properties.end() ) { + return false; + } + else { + value = m_properties[name]; + return true; + } +} + +TQVariant KisFilterConfiguration::getProperty(const TQString & name) +{ + if ( m_properties.tqfind( name ) == m_properties.end() ) { + return TQVariant(); + } + else { + return m_properties[name]; + } +} + + +int KisFilterConfiguration::getInt(const TQString & name, int def) +{ + TQVariant v = getProperty(name); + if (v.isValid()) + return v.asInt(); + else + return def; + +} + +double KisFilterConfiguration::getDouble(const TQString & name, double def) +{ + TQVariant v = getProperty(name); + if (v.isValid()) + return v.asDouble(); + else + return def; +} + +bool KisFilterConfiguration::getBool(const TQString & name, bool def) +{ + TQVariant v = getProperty(name); + if (v.isValid()) + return v.asBool(); + else + return def; +} + +TQString KisFilterConfiguration::getString(const TQString & name, TQString def) +{ + TQVariant v = getProperty(name); + if (v.isValid()) + return v.asString(); + else + return def; +} + +void KisFilterConfiguration::dump() +{ + TQMap::Iterator it; + for ( it = m_properties.begin(); it != m_properties.end(); ++it ) { + } + +} diff --git a/chalk/core/kis_filter_configuration.h b/chalk/core/kis_filter_configuration.h new file mode 100644 index 00000000..8361861a --- /dev/null +++ b/chalk/core/kis_filter_configuration.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_FILTER_CONFIGURATION_H_ +#define _KIS_FILTER_CONFIGURATION_H_ + +#include +#include +#include +#include +#include "koffice_export.h" + +class KisPreviewDialog; +class KisProgressDisplayInterface; +class KisFilterConfigWidget; +class TQWidget; + +/** + * A KisFilterConfiguration is the serializable representation of + * the filter parameters. Filters can subclass this class to implement + * direct accessors to properties, but properties not in the map will + * not be serialized. + */ +class KRITACORE_EXPORT KisFilterConfiguration { + +public: + + /** + * Create a new filter config. + */ + KisFilterConfiguration(const TQString & name, TQ_INT32 version) + : m_name(name) + , m_version(version) {} + + /** + * Deep copy the filter configFile + */ + KisFilterConfiguration(const KisFilterConfiguration & rhs); + +public: + + /** + * Fill the filter configuration object from the XML encoded representation in s. + */ + virtual void fromXML(const TQString &); + + /** + * Create a serialized version of this filter config + */ + virtual TQString toString(); + + /** + * Get the unique, language independent name of the filter. + */ + const TQString & name() const; + + /** + * Get the version of the filter that has created this config + */ + TQ_INT32 version() const; + + /** + * Set the property with name to value. + */ + virtual void setProperty(const TQString & name, const TQVariant & value); + + /** + * Set value to the value associated with property name + * @return false if the specified property did not exist. + */ + virtual bool getProperty(const TQString & name, TQVariant & value); + + virtual TQVariant getProperty(const TQString & name); + + int getInt(const TQString & name, int def = 0); + double getDouble(const TQString & name, double def = 0.0); + bool getBool(const TQString & name, bool def = false); + TQString getString(const TQString & name, TQString def = TQString()); + +private: + void dump(); + +protected: + + TQString m_name; + TQ_INT32 m_version; + TQMap m_properties; + +}; + +#endif // _KIS_FILTER_CONFIGURATION_H_ diff --git a/chalk/core/kis_filter_registry.cc b/chalk/core/kis_filter_registry.cc new file mode 100644 index 00000000..b7c8383e --- /dev/null +++ b/chalk/core/kis_filter_registry.cc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "kis_debug_areas.h" +#include +#include "kis_types.h" +#include "kis_filter_registry.h" +#include "kis_paint_device.h" +#include "kis_filter.h" + +KisFilterRegistry *KisFilterRegistry::m_singleton = 0; + +KisFilterRegistry::KisFilterRegistry() +{ + Q_ASSERT(KisFilterRegistry::m_singleton == 0); + KisFilterRegistry::m_singleton = this; + + KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/Filter"), + TQString::tqfromLatin1("(Type == 'Service') and " + "([X-Chalk-Version] == 2)")); + + KTrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService ( service, this, 0, TQStringList(), &errCode); + if ( plugin ) + kdDebug(DBG_AREA_PLUGINS) << "found plugin " << service->property("Name").toString() << "\n"; + else { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n"; + if( errCode == KParts::ComponentFactory::ErrNoLibrary) + { + kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl; + } + } + + } + +} + +KisFilterRegistry::~KisFilterRegistry() +{ +} + +KisFilterRegistry* KisFilterRegistry::instance() +{ + if(KisFilterRegistry::m_singleton == 0) + { + KisFilterRegistry::m_singleton = new KisFilterRegistry(); + } + return KisFilterRegistry::m_singleton; +} + +#include "kis_filter_registry.moc" diff --git a/chalk/core/kis_filter_registry.h b/chalk/core/kis_filter_registry.h new file mode 100644 index 00000000..9ad9901d --- /dev/null +++ b/chalk/core/kis_filter_registry.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_FILTER_REGISTRY_H_ +#define KIS_FILTER_REGISTRY_H_ + +#include + +#include "kis_types.h" +#include "kis_generic_registry.h" + +#include + +class TQString; +class TQStringList; + +class KRITACORE_EXPORT KisFilterRegistry : public TQObject, public KisGenericRegistry +{ + + Q_OBJECT + TQ_OBJECT + +public: + virtual ~KisFilterRegistry(); + + static KisFilterRegistry* instance(); + +private: + KisFilterRegistry(); + KisFilterRegistry(const KisFilterRegistry&); + KisFilterRegistry operator=(const KisFilterRegistry&); + +private: + static KisFilterRegistry *m_singleton; +}; + +#endif // KIS_FILTERSPACE_REGISTRY_H_ diff --git a/chalk/core/kis_filter_strategy.cc b/chalk/core/kis_filter_strategy.cc new file mode 100644 index 00000000..f82e6cb5 --- /dev/null +++ b/chalk/core/kis_filter_strategy.cc @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2004 Michael Thaler + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include "kis_debug_areas.h" +#include "kis_filter_strategy.h" +#include + +double KisHermiteFilterStrategy::valueAt(double t) const { + /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ + if(t < 0.0) t = -t; + if(t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0); + return(0.0); +} + +TQ_UINT32 KisHermiteFilterStrategy::intValueAt(TQ_INT32 t) const { + /* f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 */ + if(t < 0) t = -t; + if(t < 256) + { + t =(2 * t - 3*256) * t * t +(256<<16); + + //go from .24 fixed point to .8 fixedpoint (hack only works with positve numbers, which it is) + t = (t + 0x8000) >> 16; + + // go from .8 fixed point to 8bitscale. ie t = (t*255)/256; + if(t >= 128) + return t - 1; + return t; + } + return(0); +} + +double KisCubicFilterStrategy::valueAt(double x) const { + if (x < -2.0) + return(0.0); + if (x < -1.0) + return((2.0+x)*(2.0+x)*(2.0+x)/6.0); + if (x < 0.0) + return((4.0+x*x*(-6.0-3.0*x))/6.0); + if (x < 1.0) + return((4.0+x*x*(-6.0+3.0*x))/6.0); + if (x < 2.0) + return((2.0-x)*(2.0-x)*(2.0-x)/6.0); + return(0.0); +} + +TQ_UINT32 KisCubicFilterStrategy::intValueAt(TQ_INT32 x) const { + if (x < 2) + return 0; + if (x < -1) + return (2 + x) * (2 + x) * ( 2 + x) / 6; + if ( x < 0) + return (4 + x * x * ( -6 - 3 * x)) / 6; + if (x < 1) + return (4 + x * x * ( -6 + 3 * x)) / 6; + if (x < 2) + return (2 - x) * ( 2 - x) * (2 - x) / 6; + return 0; +} + +double KisBoxFilterStrategy::valueAt(double t) const { + if((t > -0.5) && (t <= 0.5)) return(1.0); + return(0.0); +} + +TQ_UINT32 KisBoxFilterStrategy::intValueAt(TQ_INT32 t) const { + /* f(t) = 1, -0.5 < t <= 0.5 */ + if((t > -128) && (t <= 128)) + return 255; + return 0; +} + +double KisTriangleFilterStrategy::valueAt(double t) const { + if(t < 0.0) t = -t; + if(t < 1.0) return(1.0 - t); + return(0.0); +} + +TQ_UINT32 KisTriangleFilterStrategy::intValueAt(TQ_INT32 t) const { + /* f(t) = |t|, -1 <= t <= 1 */ + if(t < 0) t = -t; + if(t < 256) + { + // calc 256-1 but also go from .8 fixed point to 8bitscale. ie t = (t*255)/256; ie: if(t>=128) return t-1; + if(t>=128) return 256 - t; + return 255 - t; + } + return(0); +} + + +double KisBellFilterStrategy::valueAt(double t) const { + if(t < 0) t = -t; + if(t < .5) return(.75 - (t * t)); + if(t < 1.5) { + t = (t - 1.5); + return(.5 * (t * t)); + } + return(0.0); +} + +double KisBSplineFilterStrategy::valueAt(double t) const { + double tt; + + if(t < 0) t = -t; + if(t < 1) { + tt = t * t; + return((.5 * tt * t) - tt + (2.0 / 3.0)); + } else if(t < 2) { + t = 2 - t; + return((1.0 / 6.0) * (t * t * t)); + } + return(0.0); +} + +double KisLanczos3FilterStrategy::valueAt(double t) const { + if(t < 0) t = -t; + if(t < 3.0) return(sinc(t) * sinc(t/3.0)); + return(0.0); +} + +double KisLanczos3FilterStrategy::sinc(double x) const { + const double pi=3.1415926535897932385; + x *= pi; + if(x != 0) return(sin(x) / x); + return(1.0); +} + +double KisMitchellFilterStrategy::valueAt(double t) const { + const double B=1.0/3.0; + const double C=1.0/3.0; + double tt; + + tt = t * t; + if(t < 0) t = -t; + if(t < 1.0) { + t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt)) + ((-18.0 + 12.0 * B + 6.0 * C) * tt) + (6.0 - 2 * B)); + return(t / 6.0); + } else if(t < 2.0) { + t = (((-1.0 * B - 6.0 * C) * (t * tt)) + ((6.0 * B + 30.0 * C) * tt) + ((-12.0 * B - 48.0 * C) * t) + (8.0 * B + 24 * C)); + return(t / 6.0); + } + return(0.0); +} + +KisFilterStrategyRegistry *KisFilterStrategyRegistry::m_singleton = 0; + +KisFilterStrategyRegistry::KisFilterStrategyRegistry() +{ + Q_ASSERT(KisFilterStrategyRegistry::m_singleton == 0); + KisFilterStrategyRegistry::m_singleton = this; +} + +KisFilterStrategyRegistry::~KisFilterStrategyRegistry() +{ +} + +KisFilterStrategyRegistry* KisFilterStrategyRegistry::instance() +{ + if(KisFilterStrategyRegistry::m_singleton == 0) + { + KisFilterStrategyRegistry::m_singleton = new KisFilterStrategyRegistry(); + Q_CHECK_PTR(KisFilterStrategyRegistry::m_singleton); + m_singleton->add(new KisHermiteFilterStrategy); + m_singleton->add(new KisBoxFilterStrategy); + m_singleton->add(new KisTriangleFilterStrategy); + m_singleton->add(new KisBellFilterStrategy); + m_singleton->add(new KisBSplineFilterStrategy); +// m_singleton->add(new KisLanczos3FilterStrategy); + m_singleton->add(new KisMitchellFilterStrategy); +// m_singleton->add(new KisCubicFilterStrategy); + } + return KisFilterStrategyRegistry::m_singleton; +} + diff --git a/chalk/core/kis_filter_strategy.h b/chalk/core/kis_filter_strategy.h new file mode 100644 index 00000000..55ef3d06 --- /dev/null +++ b/chalk/core/kis_filter_strategy.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2004 Michael Thaler + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_FILTER_STRATEGY_H_ +#define KIS_FILTER_STRATEGY_H_ + +#include + +#include "kis_types.h" +#include "kis_generic_registry.h" +#include "kis_id.h" + +class KisFilterStrategy +{ + public: + KisFilterStrategy(KisID id) : m_id(id) {} + virtual ~KisFilterStrategy() {} + + KisID id() {return m_id;}; + virtual double valueAt(double /*t*/) const {return 0;}; + virtual TQ_UINT32 intValueAt(TQ_INT32 t) const {return TQ_UINT32(255*valueAt(t/256.0));}; + double support() { return supportVal;}; + TQ_UINT32 intSupport() { return intSupportVal;}; + virtual bool boxSpecial() { return false;}; + protected: + double supportVal; + TQ_UINT32 intSupportVal; + KisID m_id; +}; + +class KisHermiteFilterStrategy : public KisFilterStrategy +{ + public: + KisHermiteFilterStrategy() : KisFilterStrategy(KisID("Hermite", i18n("Hermite"))) + {supportVal = 1.0; intSupportVal = 256;} + virtual ~KisHermiteFilterStrategy() {} + + virtual TQ_UINT32 intValueAt(TQ_INT32 t) const; + virtual double valueAt(double t) const; +}; + +class KisCubicFilterStrategy : public KisFilterStrategy +{ + public: + KisCubicFilterStrategy() : KisFilterStrategy(KisID("Bicubic", i18n("Bicubic"))) + {supportVal = 1.0; intSupportVal = 256;} + virtual ~KisCubicFilterStrategy() {} + + virtual TQ_UINT32 intValueAt(TQ_INT32 t) const; + virtual double valueAt(double t) const; +}; + +class KisBoxFilterStrategy : public KisFilterStrategy +{ + public: + KisBoxFilterStrategy() : KisFilterStrategy(KisID("Box", i18n("Box"))) + {supportVal = 0.5; intSupportVal = 128;} + virtual ~KisBoxFilterStrategy() {} + + virtual TQ_UINT32 intValueAt(TQ_INT32 t) const; + virtual double valueAt(double t) const; + virtual bool boxSpecial() { return true;}; +}; + +class KisTriangleFilterStrategy : public KisFilterStrategy +{ + public: + KisTriangleFilterStrategy() : KisFilterStrategy(KisID("Triangle", i18n("Triangle aka (bi)linear"))) + {supportVal = 1.0; intSupportVal = 256;} + virtual ~KisTriangleFilterStrategy() {} + + virtual TQ_UINT32 intValueAt(TQ_INT32 t) const; + virtual double valueAt(double t) const; +}; + +class KisBellFilterStrategy : public KisFilterStrategy +{ + public: + KisBellFilterStrategy() : KisFilterStrategy(KisID("Bell", i18n("Bell"))) + {supportVal = 1.5; intSupportVal = 128+256;} + virtual ~KisBellFilterStrategy() {} + + virtual double valueAt(double t) const; +}; + +class KisBSplineFilterStrategy : public KisFilterStrategy +{ + public: + KisBSplineFilterStrategy() : KisFilterStrategy(KisID("BSpline", i18n("BSpline"))) + {supportVal = 2.0; intSupportVal = 512;} + virtual ~KisBSplineFilterStrategy() {} + + virtual double valueAt(double t) const; +}; + +class KisLanczos3FilterStrategy : public KisFilterStrategy +{ + public: + KisLanczos3FilterStrategy() : KisFilterStrategy(KisID("Lanczos3", i18n("Lanczos3"))) + {supportVal = 3.0; intSupportVal = 768;} + virtual ~KisLanczos3FilterStrategy() {} + + virtual double valueAt(double t) const; + private: + double sinc(double x) const; +}; + +class KisMitchellFilterStrategy : public KisFilterStrategy +{ + public: + KisMitchellFilterStrategy() : KisFilterStrategy(KisID("Mitchell", i18n("Mitchell"))) + {supportVal = 2.0; intSupportVal = 256;} + virtual ~KisMitchellFilterStrategy() {} + + virtual double valueAt(double t) const; +}; + +class KisFilterStrategyRegistry : public KisGenericRegistry +{ +public: + virtual ~KisFilterStrategyRegistry(); + + static KisFilterStrategyRegistry* instance(); + +private: + KisFilterStrategyRegistry(); + KisFilterStrategyRegistry(const KisFilterStrategyRegistry&); + KisFilterStrategyRegistry operator=(const KisFilterStrategyRegistry&); + +private: + static KisFilterStrategyRegistry *m_singleton; +}; + +#endif // KIS_FILTER_STRATEGY_H_ diff --git a/chalk/core/kis_gradient.cc b/chalk/core/kis_gradient.cc new file mode 100644 index 00000000..efc370bb --- /dev/null +++ b/chalk/core/kis_gradient.cc @@ -0,0 +1,639 @@ +/* + * kis_gradient.cc - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * 2001 John Califf + * 2004 Boudewijn Rempt + * 2004 Adrian Page + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include "kis_gradient.h" + +#define PREVIEW_WIDTH 64 +#define PREVIEW_HEIGHT 64 + +KisGradientSegment::RGBColorInterpolationStrategy *KisGradientSegment::RGBColorInterpolationStrategy::m_instance = 0; +KisGradientSegment::HSVCWColorInterpolationStrategy *KisGradientSegment::HSVCWColorInterpolationStrategy::m_instance = 0; +KisGradientSegment::HSVCCWColorInterpolationStrategy *KisGradientSegment::HSVCCWColorInterpolationStrategy::m_instance = 0; + +KisGradientSegment::LinearInterpolationStrategy *KisGradientSegment::LinearInterpolationStrategy::m_instance = 0; +KisGradientSegment::CurvedInterpolationStrategy *KisGradientSegment::CurvedInterpolationStrategy::m_instance = 0; +KisGradientSegment::SineInterpolationStrategy *KisGradientSegment::SineInterpolationStrategy::m_instance = 0; +KisGradientSegment::SphereIncreasingInterpolationStrategy *KisGradientSegment::SphereIncreasingInterpolationStrategy::m_instance = 0; +KisGradientSegment::SphereDecreasingInterpolationStrategy *KisGradientSegment::SphereDecreasingInterpolationStrategy::m_instance = 0; + +KisGradient::KisGradient(const TQString& file) : super(file) +{ +} + +KisGradient::~KisGradient() +{ + for (uint i = 0; i < m_segments.count(); i++) { + delete m_segments[i]; + m_segments[i] = 0; + } +} + +bool KisGradient::load() +{ + return init(); +} + +bool KisGradient::save() +{ + return false; +} + +TQImage KisGradient::img() +{ + return m_img; +} + +bool KisGradient::init() +{ + KoGradientManager gradLoader; + KoGradient* grad = gradLoader.loadGradient(filename()); + + if( !grad ) + return false; + + m_segments.clear(); + + if( grad->colorStops.count() > 1 ) { + KoColorStop *colstop; + for(colstop = grad->colorStops.first(); colstop; colstop = grad->colorStops.next()) { + KoColorStop *colstopNext = grad->colorStops.next(); + + if(colstopNext) { + KoColor leftRgb((int)(colstop->color1 * 255 + 0.5), (int)(colstop->color2 * 255 + 0.5), (int)(colstop->color3 * 255 + 0.5)); + KoColor rightRgb((int)(colstopNext->color1 * 255 + 0.5), (int)(colstopNext->color2 * 255 + 0.5), (int)(colstopNext->color3 * 255 + 0.5)); + + double midp = colstop->midpoint; + midp = colstop->offset + ((colstopNext->offset - colstop->offset) * midp); + + Color leftColor(leftRgb.color(), colstop->opacity); + Color rightColor(rightRgb.color(), colstopNext->opacity); + + KisGradientSegment *segment = new KisGradientSegment(colstop->interpolation, colstop->colorType, colstop->offset, midp, colstopNext->offset, leftColor, rightColor); + Q_CHECK_PTR(segment); + + if ( !segment->isValid() ) { + delete segment; + return false; + } + + m_segments.push_back(segment); + grad->colorStops.prev(); + } + else { + grad->colorStops.prev(); + break; + } + } + } + else + return false; + + if (!m_segments.isEmpty()) { + m_img = generatePreview(PREVIEW_WIDTH, PREVIEW_HEIGHT); + setValid(true); + return true; + } + else { + return false; + } +} + +void KisGradient::setImage(const TQImage& img) +{ + m_img = img; + m_img.detach(); + + setValid(true); +} + +KisGradientSegment *KisGradient::segmentAt(double t) const +{ + Q_ASSERT(t >= 0 || t <= 1); + Q_ASSERT(!m_segments.empty()); + + for(TQValueVector::const_iterator it = m_segments.begin(); it!= m_segments.end(); ++it) + { + if (t > (*it)->startOffset() - DBL_EPSILON && t < (*it)->endOffset() + DBL_EPSILON) { + return *it; + } + } + + return 0; +} + +void KisGradient::colorAt(double t, TQColor *color, TQ_UINT8 *opacity) const +{ + const KisGradientSegment *segment = segmentAt(t); + Q_ASSERT(segment != 0); + + if (segment) { + Color col = segment->colorAt(t); + *color = col.color(); + *opacity = static_cast(col.alpha() * OPACITY_OPAQUE + 0.5); + } +} + +TQImage KisGradient::generatePreview(int width, int height) const +{ + TQImage img(width, height, 32); + + for (int y = 0; y < img.height(); y++) { + for (int x = 0; x < img.width(); x++) { + + int backgroundRed = 128 + 63 * ((x / 4 + y / 4) % 2); + int backgroundGreen = backgroundRed; + int backgroundBlue = backgroundRed; + + TQColor color; + TQ_UINT8 opacity; + double t = static_cast(x) / (img.width() - 1); + + colorAt(t, &color, &opacity); + + double alpha = static_cast(opacity) / OPACITY_OPAQUE; + + int red = static_cast((1 - alpha) * backgroundRed + alpha * color.red() + 0.5); + int green = static_cast((1 - alpha) * backgroundGreen + alpha * color.green() + 0.5); + int blue = static_cast((1 - alpha) * backgroundBlue + alpha * color.blue() + 0.5); + + img.setPixel(x, y, tqRgb(red, green, blue)); + } + } + + return img; +} + +KisGradientSegment::KisGradientSegment(int interpolationType, int colorInterpolationType, double startOffset, double middleOffset, double endOffset, const Color& startColor, const Color& endColor) +{ + m_interpolator = 0; + + switch (interpolationType) { + case INTERP_LINEAR: + m_interpolator = LinearInterpolationStrategy::instance(); + break; + case INTERP_CURVED: + m_interpolator = CurvedInterpolationStrategy::instance(); + break; + case INTERP_SINE: + m_interpolator = SineInterpolationStrategy::instance(); + break; + case INTERP_SPHERE_INCREASING: + m_interpolator = SphereIncreasingInterpolationStrategy::instance(); + break; + case INTERP_SPHERE_DECREASING: + m_interpolator = SphereDecreasingInterpolationStrategy::instance(); + break; + } + + m_colorInterpolator = 0; + + switch (colorInterpolationType) { + case COLOR_INTERP_RGB: + m_colorInterpolator = RGBColorInterpolationStrategy::instance(); + break; + case COLOR_INTERP_HSV_CCW: + m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); + break; + case COLOR_INTERP_HSV_CW: + m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); + break; + } + + if (startOffset < DBL_EPSILON) { + m_startOffset = 0; + } + else + if (startOffset > 1 - DBL_EPSILON) { + m_startOffset = 1; + } + else { + m_startOffset = startOffset; + } + + if (middleOffset < m_startOffset + DBL_EPSILON) { + m_middleOffset = m_startOffset; + } + else + if (middleOffset > 1 - DBL_EPSILON) { + m_middleOffset = 1; + } + else { + m_middleOffset = middleOffset; + } + + if (endOffset < m_middleOffset + DBL_EPSILON) { + m_endOffset = m_middleOffset; + } + else + if (endOffset > 1 - DBL_EPSILON) { + m_endOffset = 1; + } + else { + m_endOffset = endOffset; + } + + m_length = m_endOffset - m_startOffset; + + if (m_length < DBL_EPSILON) { + m_middleT = 0.5; + } + else { + m_middleT = (m_middleOffset - m_startOffset) / m_length; + } + + m_startColor = startColor; + m_endColor = endColor; +} + +const Color& KisGradientSegment::startColor() const +{ + return m_startColor; +} + +const Color& KisGradientSegment::endColor() const +{ + return m_endColor; +} + +double KisGradientSegment::startOffset() const +{ + return m_startOffset; +} + +double KisGradientSegment::middleOffset() const +{ + return m_middleOffset; +} + +double KisGradientSegment::endOffset() const +{ + return m_endOffset; +} + +void KisGradientSegment::setStartOffset(double t) +{ + m_startOffset = t; + m_length = m_endOffset - m_startOffset; + + if (m_length < DBL_EPSILON) { + m_middleT = 0.5; + } + else { + m_middleT = (m_middleOffset - m_startOffset) / m_length; + } +} +void KisGradientSegment::setMiddleOffset(double t) +{ + m_middleOffset = t; + + if (m_length < DBL_EPSILON) { + m_middleT = 0.5; + } + else { + m_middleT = (m_middleOffset - m_startOffset) / m_length; + } +} + +void KisGradientSegment::setEndOffset(double t) +{ + m_endOffset = t; + m_length = m_endOffset - m_startOffset; + + if (m_length < DBL_EPSILON) { + m_middleT = 0.5; + } + else { + m_middleT = (m_middleOffset - m_startOffset) / m_length; + } +} + +int KisGradientSegment::interpolation() const +{ + return m_interpolator->type(); +} + +void KisGradientSegment::setInterpolation(int interpolationType) +{ + switch (interpolationType) { + case INTERP_LINEAR: + m_interpolator = LinearInterpolationStrategy::instance(); + break; + case INTERP_CURVED: + m_interpolator = CurvedInterpolationStrategy::instance(); + break; + case INTERP_SINE: + m_interpolator = SineInterpolationStrategy::instance(); + break; + case INTERP_SPHERE_INCREASING: + m_interpolator = SphereIncreasingInterpolationStrategy::instance(); + break; + case INTERP_SPHERE_DECREASING: + m_interpolator = SphereDecreasingInterpolationStrategy::instance(); + break; + } +} + +int KisGradientSegment::colorInterpolation() const +{ + return m_colorInterpolator->type(); +} + +void KisGradientSegment::setColorInterpolation(int colorInterpolationType) +{ + switch (colorInterpolationType) { + case COLOR_INTERP_RGB: + m_colorInterpolator = RGBColorInterpolationStrategy::instance(); + break; + case COLOR_INTERP_HSV_CCW: + m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); + break; + case COLOR_INTERP_HSV_CW: + m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); + break; + } +} + +Color KisGradientSegment::colorAt(double t) const +{ + Q_ASSERT(t > m_startOffset - DBL_EPSILON && t < m_endOffset + DBL_EPSILON); + + double segmentT; + + if (m_length < DBL_EPSILON) { + segmentT = 0.5; + } + else { + segmentT = (t - m_startOffset) / m_length; + } + + double colorT = m_interpolator->valueAt(segmentT, m_middleT); + + Color color = m_colorInterpolator->colorAt(colorT, m_startColor, m_endColor); + + return color; +} + +bool KisGradientSegment::isValid() const +{ + if (m_interpolator == 0 || m_colorInterpolator ==0) + return false; + return true; +} + +KisGradientSegment::RGBColorInterpolationStrategy *KisGradientSegment::RGBColorInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new RGBColorInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +Color KisGradientSegment::RGBColorInterpolationStrategy::colorAt(double t, Color start, Color end) const +{ + int startRed = start.color().red(); + int startGreen = start.color().green(); + int startBlue = start.color().blue(); + double startAlpha = start.alpha(); + int red = static_cast(startRed + t * (end.color().red() - startRed) + 0.5); + int green = static_cast(startGreen + t * (end.color().green() - startGreen) + 0.5); + int blue = static_cast(startBlue + t * (end.color().blue() - startBlue) + 0.5); + double alpha = startAlpha + t * (end.alpha() - startAlpha); + + return Color(TQColor(red, green, blue), alpha); +} + +KisGradientSegment::HSVCWColorInterpolationStrategy *KisGradientSegment::HSVCWColorInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new HSVCWColorInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +Color KisGradientSegment::HSVCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const +{ + KoColor sc = KoColor(start.color()); + KoColor ec = KoColor(end.color()); + + int s = static_cast(sc.S() + t * (ec.S() - sc.S()) + 0.5); + int v = static_cast(sc.V() + t * (ec.V() - sc.V()) + 0.5); + int h; + + if (ec.H() < sc.H()) { + h = static_cast(ec.H() + (1 - t) * (sc.H() - ec.H()) + 0.5); + } + else { + h = static_cast(ec.H() + (1 - t) * (360 - ec.H() + sc.H()) + 0.5); + + if (h > 359) { + h -= 360; + } + } + + double alpha = start.alpha() + t * (end.alpha() - start.alpha()); + + return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha); +} + +KisGradientSegment::HSVCCWColorInterpolationStrategy *KisGradientSegment::HSVCCWColorInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new HSVCCWColorInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +Color KisGradientSegment::HSVCCWColorInterpolationStrategy::colorAt(double t, Color start, Color end) const +{ + KoColor sc = KoColor(start.color()); + KoColor se = KoColor(end.color()); + + int s = static_cast(sc.S() + t * (se.S() - sc.S()) + 0.5); + int v = static_cast(sc.V() + t * (se.V() - sc.V()) + 0.5); + int h; + + if (sc.H() < se.H()) { + h = static_cast(sc.H() + t * (se.H() - sc.H()) + 0.5); + } + else { + h = static_cast(sc.H() + t * (360 - sc.H() + se.H()) + 0.5); + + if (h > 359) { + h -= 360; + } + } + + double alpha = start.alpha() + t * (end.alpha() - start.alpha()); + + return Color(KoColor(h, s, v, KoColor::csHSV).color(), alpha); +} + +KisGradientSegment::LinearInterpolationStrategy *KisGradientSegment::LinearInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new LinearInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +double KisGradientSegment::LinearInterpolationStrategy::calcValueAt(double t, double middle) +{ + Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); + Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); + + double value = 0; + + if (t <= middle) { + if (middle < DBL_EPSILON) { + value = 0; + } + else { + value = (t / middle) * 0.5; + } + } + else { + if (middle > 1 - DBL_EPSILON) { + value = 1; + } + else { + value = ((t - middle) / (1 - middle)) * 0.5 + 0.5; + } + } + + return value; +} + +double KisGradientSegment::LinearInterpolationStrategy::valueAt(double t, double middle) const +{ + return calcValueAt(t, middle); +} + +KisGradientSegment::CurvedInterpolationStrategy::CurvedInterpolationStrategy() +{ + m_logHalf = log(0.5); +} + +KisGradientSegment::CurvedInterpolationStrategy *KisGradientSegment::CurvedInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new CurvedInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +double KisGradientSegment::CurvedInterpolationStrategy::valueAt(double t, double middle) const +{ + Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); + Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); + + double value = 0; + + if (middle < DBL_EPSILON) { + middle = DBL_EPSILON; + } + + value = pow(t, m_logHalf / log(middle)); + + return value; +} + +KisGradientSegment::SineInterpolationStrategy *KisGradientSegment::SineInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new SineInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +double KisGradientSegment::SineInterpolationStrategy::valueAt(double t, double middle) const +{ + double lt = LinearInterpolationStrategy::calcValueAt(t, middle); + double value = (sin(-M_PI_2 + M_PI * lt) + 1.0) / 2.0; + + return value; +} + +KisGradientSegment::SphereIncreasingInterpolationStrategy *KisGradientSegment::SphereIncreasingInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new SphereIncreasingInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +double KisGradientSegment::SphereIncreasingInterpolationStrategy::valueAt(double t, double middle) const +{ + double lt = LinearInterpolationStrategy::calcValueAt(t, middle) - 1; + double value = sqrt(1 - lt * lt); + + return value; +} + +KisGradientSegment::SphereDecreasingInterpolationStrategy *KisGradientSegment::SphereDecreasingInterpolationStrategy::instance() +{ + if (m_instance == 0) { + m_instance = new SphereDecreasingInterpolationStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; +} + +double KisGradientSegment::SphereDecreasingInterpolationStrategy::valueAt(double t, double middle) const +{ + double lt = LinearInterpolationStrategy::calcValueAt(t, middle); + double value = 1 - sqrt(1 - lt * lt); + + return value; +} + +#include "kis_gradient.moc" + diff --git a/chalk/core/kis_gradient.h b/chalk/core/kis_gradient.h new file mode 100644 index 00000000..50bc0fd8 --- /dev/null +++ b/chalk/core/kis_gradient.h @@ -0,0 +1,265 @@ +/* + * kis_gradient.h - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * 2004 Boudewijn Rempt + * 2004 Adrian Page + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_GRADIENT_H +#define KIS_GRADIENT_H + +#include +#include + +#include + +#include "kis_resource.h" +#include "kis_global.h" + +class TQImage; + +enum { + INTERP_LINEAR = 0, + INTERP_CURVED, + INTERP_SINE, + INTERP_SPHERE_INCREASING, + INTERP_SPHERE_DECREASING +}; + +enum { + COLOR_INTERP_RGB, + COLOR_INTERP_HSV_CCW, + COLOR_INTERP_HSV_CW +}; + +// TODO: Replace TQColor with KisColor +class Color { + public: + Color() { m_alpha = 0; } + Color(const TQColor& color, double alpha) { m_color = color; m_alpha = alpha; } + + const TQColor& color() const { return m_color; } + double alpha() const { return m_alpha; } + + private: + TQColor m_color; + double m_alpha; +}; + +class KisGradientSegment { + public: + KisGradientSegment(int interpolationType, int colorInterpolationType, double startOffset, double middleOffset, double endOffset, const Color& startColor, const Color& endColor); + + // startOffset <= t <= endOffset + Color colorAt(double t) const; + + const Color& startColor() const; + const Color& endColor() const; + + void setStartColor(const Color& color) { m_startColor = color; } + void setEndColor(const Color& color) { m_endColor = color; } + + double startOffset() const; + double middleOffset() const; + double endOffset() const; + + void setStartOffset(double t); + void setMiddleOffset(double t); + void setEndOffset(double t); + + double length() { return m_length; } + + int interpolation() const; + int colorInterpolation() const; + + void setInterpolation(int interpolationType); + void setColorInterpolation(int colorInterpolationType); + + bool isValid() const; + protected: + + class ColorInterpolationStrategy { + public: + ColorInterpolationStrategy() {} + virtual ~ColorInterpolationStrategy() {} + + virtual Color colorAt(double t, Color start, Color end) const = 0; + virtual int type() const = 0; + }; + + class RGBColorInterpolationStrategy : public ColorInterpolationStrategy { + public: + static RGBColorInterpolationStrategy *instance(); + + virtual Color colorAt(double t, Color start, Color end) const; + virtual int type() const { return COLOR_INTERP_RGB; } + + private: + RGBColorInterpolationStrategy() {} + + static RGBColorInterpolationStrategy *m_instance; + }; + + class HSVCWColorInterpolationStrategy : public ColorInterpolationStrategy { + public: + static HSVCWColorInterpolationStrategy *instance(); + + virtual Color colorAt(double t, Color start, Color end) const; + virtual int type() const { return COLOR_INTERP_HSV_CW; } + private: + HSVCWColorInterpolationStrategy() {} + + static HSVCWColorInterpolationStrategy *m_instance; + }; + + class HSVCCWColorInterpolationStrategy : public ColorInterpolationStrategy { + public: + static HSVCCWColorInterpolationStrategy *instance(); + + virtual Color colorAt(double t, Color start, Color end) const; + virtual int type() const { return COLOR_INTERP_HSV_CCW; } + private: + HSVCCWColorInterpolationStrategy() {} + + static HSVCCWColorInterpolationStrategy *m_instance; + }; + + class InterpolationStrategy { + public: + InterpolationStrategy() {} + virtual ~InterpolationStrategy() {} + + virtual double valueAt(double t, double middle) const = 0; + virtual int type() const = 0; + }; + + class LinearInterpolationStrategy : public InterpolationStrategy { + public: + static LinearInterpolationStrategy *instance(); + + virtual double valueAt(double t, double middle) const; + virtual int type() const { return INTERP_LINEAR; } + + // This does the actual calculation and is made + // static as an optimisation for the other + // strategies that need this for their own calculation. + static double calcValueAt(double t, double middle); + + private: + LinearInterpolationStrategy() {} + + static LinearInterpolationStrategy *m_instance; + }; + + class CurvedInterpolationStrategy : public InterpolationStrategy { + public: + static CurvedInterpolationStrategy *instance(); + + virtual double valueAt(double t, double middle) const; + virtual int type() const { return INTERP_CURVED; } + private: + CurvedInterpolationStrategy(); + + static CurvedInterpolationStrategy *m_instance; + double m_logHalf; + }; + + class SphereIncreasingInterpolationStrategy : public InterpolationStrategy { + public: + static SphereIncreasingInterpolationStrategy *instance(); + + virtual double valueAt(double t, double middle) const; + virtual int type() const { return INTERP_SPHERE_INCREASING; } + private: + SphereIncreasingInterpolationStrategy() {} + + static SphereIncreasingInterpolationStrategy *m_instance; + }; + + class SphereDecreasingInterpolationStrategy : public InterpolationStrategy { + public: + static SphereDecreasingInterpolationStrategy *instance(); + + virtual double valueAt(double t, double middle) const; + virtual int type() const { return INTERP_SPHERE_DECREASING; } + private: + SphereDecreasingInterpolationStrategy() {} + + static SphereDecreasingInterpolationStrategy *m_instance; + }; + + class SineInterpolationStrategy : public InterpolationStrategy { + public: + static SineInterpolationStrategy *instance(); + + virtual double valueAt(double t, double middle) const; + virtual int type() const { return INTERP_SINE; } + private: + SineInterpolationStrategy() {} + + static SineInterpolationStrategy *m_instance; + }; + private: + InterpolationStrategy *m_interpolator; + ColorInterpolationStrategy *m_colorInterpolator; + + double m_startOffset; + double m_middleOffset; + double m_endOffset; + double m_length; + double m_middleT; + + Color m_startColor; + Color m_endColor; +}; + +class KisGradient : public KisResource { + typedef KisResource super; + Q_OBJECT + TQ_OBJECT + +public: + KisGradient(const TQString& file); + virtual ~KisGradient(); + + virtual bool load(); + virtual bool save(); + virtual TQImage img(); + virtual TQImage generatePreview(int width, int height) const; + + void colorAt(double t, TQColor *color, TQ_UINT8 *opacity) const; + + KisGradientSegment *segmentAt(double t) const; + +protected: + inline void pushSegment( KisGradientSegment* segment ) { m_segments.push_back(segment); }; + void setImage(const TQImage& img); + + TQValueVector m_segments; + +private: + bool init(); + +private: + TQByteArray m_data; + TQImage m_img; +}; + +#endif // KIS_GRADIENT_H + diff --git a/chalk/core/kis_gradient_painter.cc b/chalk/core/kis_gradient_painter.cc new file mode 100644 index 00000000..2258d899 --- /dev/null +++ b/chalk/core/kis_gradient_painter.cc @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "tqbrush.h" +#include "tqcolor.h" +#include "tqfontinfo.h" +#include "tqfontmetrics.h" +#include "tqpen.h" +#include "tqregion.h" +#include "tqwmatrix.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kis_brush.h" +#include "kis_debug_areas.h" +#include "kis_gradient.h" +#include "kis_image.h" +#include "kis_iterators_pixel.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_pattern.h" +#include "kis_rect.h" +#include "kis_colorspace.h" +#include "kis_types.h" +#include "kis_vec.h" +#include "kis_selection.h" +#include "kis_gradient_painter.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" + +namespace { + + class GradientShapeStrategy { + public: + GradientShapeStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + virtual ~GradientShapeStrategy() {} + + virtual double valueAt(double x, double y) const = 0; + + protected: + KisPoint m_gradientVectorStart; + KisPoint m_gradientVectorEnd; + }; + + GradientShapeStrategy::GradientShapeStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : m_gradientVectorStart(gradientVectorStart), m_gradientVectorEnd(gradientVectorEnd) + { + } + + + class LinearGradientStrategy : public GradientShapeStrategy { + typedef GradientShapeStrategy super; + public: + LinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + + protected: + double m_normalisedVectorX; + double m_normalisedVectorY; + double m_vectorLength; + }; + + LinearGradientStrategy::LinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + double dx = gradientVectorEnd.x() - gradientVectorStart.x(); + double dy = gradientVectorEnd.y() - gradientVectorStart.y(); + + m_vectorLength = sqrt((dx * dx) + (dy * dy)); + + if (m_vectorLength < DBL_EPSILON) { + m_normalisedVectorX = 0; + m_normalisedVectorY = 0; + } + else { + m_normalisedVectorX = dx / m_vectorLength; + m_normalisedVectorY = dy / m_vectorLength; + } + } + + double LinearGradientStrategy::valueAt(double x, double y) const + { + double vx = x - m_gradientVectorStart.x(); + double vy = y - m_gradientVectorStart.y(); + + // Project the vector onto the normalised gradient vector. + double t = vx * m_normalisedVectorX + vy * m_normalisedVectorY; + + if (m_vectorLength < DBL_EPSILON) { + t = 0; + } + else { + // Scale to 0 to 1 over the gradient vector length. + t /= m_vectorLength; + } + + return t; + } + + + class BiLinearGradientStrategy : public LinearGradientStrategy { + typedef LinearGradientStrategy super; + public: + BiLinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + }; + + BiLinearGradientStrategy::BiLinearGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + } + + double BiLinearGradientStrategy::valueAt(double x, double y) const + { + double t = super::valueAt(x, y); + + // Reflect + if (t < -DBL_EPSILON) { + t = -t; + } + + return t; + } + + + class RadialGradientStrategy : public GradientShapeStrategy { + typedef GradientShapeStrategy super; + public: + RadialGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + + protected: + double m_radius; + }; + + RadialGradientStrategy::RadialGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + double dx = gradientVectorEnd.x() - gradientVectorStart.x(); + double dy = gradientVectorEnd.y() - gradientVectorStart.y(); + + m_radius = sqrt((dx * dx) + (dy * dy)); + } + + double RadialGradientStrategy::valueAt(double x, double y) const + { + double dx = x - m_gradientVectorStart.x(); + double dy = y - m_gradientVectorStart.y(); + + double distance = sqrt((dx * dx) + (dy * dy)); + + double t; + + if (m_radius < DBL_EPSILON) { + t = 0; + } + else { + t = distance / m_radius; + } + + return t; + } + + + class SquareGradientStrategy : public GradientShapeStrategy { + typedef GradientShapeStrategy super; + public: + SquareGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + + protected: + double m_normalisedVectorX; + double m_normalisedVectorY; + double m_vectorLength; + }; + + SquareGradientStrategy::SquareGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + double dx = gradientVectorEnd.x() - gradientVectorStart.x(); + double dy = gradientVectorEnd.y() - gradientVectorStart.y(); + + m_vectorLength = sqrt((dx * dx) + (dy * dy)); + + if (m_vectorLength < DBL_EPSILON) { + m_normalisedVectorX = 0; + m_normalisedVectorY = 0; + } + else { + m_normalisedVectorX = dx / m_vectorLength; + m_normalisedVectorY = dy / m_vectorLength; + } + } + + double SquareGradientStrategy::valueAt(double x, double y) const + { + double px = x - m_gradientVectorStart.x(); + double py = y - m_gradientVectorStart.y(); + + double distance1 = 0; + double distance2 = 0; + + if (m_vectorLength > DBL_EPSILON) { + + // Point to line distance is: + // distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / m_vectorLength; + // + // Here l0 = (0, 0) and |l1 - l0| = 1 + + distance1 = -m_normalisedVectorY * px + m_normalisedVectorX * py; + distance1 = fabs(distance1); + + // Rotate point by 90 degrees and get the distance to the perpendicular + distance2 = -m_normalisedVectorY * -py + m_normalisedVectorX * px; + distance2 = fabs(distance2); + } + + double t = TQMAX(distance1, distance2) / m_vectorLength; + + return t; + } + + + class ConicalGradientStrategy : public GradientShapeStrategy { + typedef GradientShapeStrategy super; + public: + ConicalGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + + protected: + double m_vectorAngle; + }; + + ConicalGradientStrategy::ConicalGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + double dx = gradientVectorEnd.x() - gradientVectorStart.x(); + double dy = gradientVectorEnd.y() - gradientVectorStart.y(); + + // Get angle from 0 to 2 PI. + m_vectorAngle = atan2(dy, dx) + M_PI; + } + + double ConicalGradientStrategy::valueAt(double x, double y) const + { + double px = x - m_gradientVectorStart.x(); + double py = y - m_gradientVectorStart.y(); + + double angle = atan2(py, px) + M_PI; + + angle -= m_vectorAngle; + + if (angle < 0) { + angle += 2 * M_PI; + } + + double t = angle / (2 * M_PI); + + return t; + } + + + class ConicalSymetricGradientStrategy : public GradientShapeStrategy { + typedef GradientShapeStrategy super; + public: + ConicalSymetricGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd); + + virtual double valueAt(double x, double y) const; + + protected: + double m_vectorAngle; + }; + + ConicalSymetricGradientStrategy::ConicalSymetricGradientStrategy(const KisPoint& gradientVectorStart, const KisPoint& gradientVectorEnd) + : super(gradientVectorStart, gradientVectorEnd) + { + double dx = gradientVectorEnd.x() - gradientVectorStart.x(); + double dy = gradientVectorEnd.y() - gradientVectorStart.y(); + + // Get angle from 0 to 2 PI. + m_vectorAngle = atan2(dy, dx) + M_PI; + } + + double ConicalSymetricGradientStrategy::valueAt(double x, double y) const + { + double px = x - m_gradientVectorStart.x(); + double py = y - m_gradientVectorStart.y(); + + double angle = atan2(py, px) + M_PI; + + angle -= m_vectorAngle; + + if (angle < 0) { + angle += 2 * M_PI; + } + + double t; + + if (angle < M_PI) { + t = angle / M_PI; + } + else { + t = 1 - ((angle - M_PI) / M_PI); + } + + return t; + } + + + class GradientRepeatStrategy { + public: + GradientRepeatStrategy() {} + virtual ~GradientRepeatStrategy() {} + + virtual double valueAt(double t) const = 0; + }; + + + class GradientRepeatNoneStrategy : public GradientRepeatStrategy { + public: + static GradientRepeatNoneStrategy *instance(); + + virtual double valueAt(double t) const; + + private: + GradientRepeatNoneStrategy() {} + + static GradientRepeatNoneStrategy *m_instance; + }; + + GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::m_instance = 0; + + GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::instance() + { + if (m_instance == 0) { + m_instance = new GradientRepeatNoneStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; + } + + // Output is clamped to 0 to 1. + double GradientRepeatNoneStrategy::valueAt(double t) const + { + double value = t; + + if (t < DBL_EPSILON) { + value = 0; + } + else + if (t > 1 - DBL_EPSILON) { + value = 1; + } + + return value; + } + + + class GradientRepeatForwardsStrategy : public GradientRepeatStrategy { + public: + static GradientRepeatForwardsStrategy *instance(); + + virtual double valueAt(double t) const; + + private: + GradientRepeatForwardsStrategy() {} + + static GradientRepeatForwardsStrategy *m_instance; + }; + + GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::m_instance = 0; + + GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::instance() + { + if (m_instance == 0) { + m_instance = new GradientRepeatForwardsStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; + } + + // Output is 0 to 1, 0 to 1, 0 to 1... + double GradientRepeatForwardsStrategy::valueAt(double t) const + { + int i = static_cast(t); + + if (t < DBL_EPSILON) { + i--; + } + + double value = t - i; + + return value; + } + + + class GradientRepeatAlternateStrategy : public GradientRepeatStrategy { + public: + static GradientRepeatAlternateStrategy *instance(); + + virtual double valueAt(double t) const; + + private: + GradientRepeatAlternateStrategy() {} + + static GradientRepeatAlternateStrategy *m_instance; + }; + + GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::m_instance = 0; + + GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::instance() + { + if (m_instance == 0) { + m_instance = new GradientRepeatAlternateStrategy(); + Q_CHECK_PTR(m_instance); + } + + return m_instance; + } + + // Output is 0 to 1, 1 to 0, 0 to 1, 1 to 0... + double GradientRepeatAlternateStrategy::valueAt(double t) const + { + if (t < 0) { + t = -t; + } + + int i = static_cast(t); + + double value = t - i; + + if (i % 2 == 1) { + value = 1 - value; + } + + return value; + } +} + +KisGradientPainter::KisGradientPainter() + : super() +{ + m_gradient = 0; +} + +KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device) : super(device), m_gradient(0) +{ +} + +bool KisGradientPainter::paintGradient(const KisPoint& gradientVectorStart, + const KisPoint& gradientVectorEnd, + enumGradientShape tqshape, + enumGradientRepeat repeat, + double antiAliasThreshold, + bool reverseGradient, + TQ_INT32 startx, + TQ_INT32 starty, + TQ_INT32 width, + TQ_INT32 height) +{ + m_cancelRequested = false; + + if (!m_gradient) return false; + + GradientShapeStrategy *tqshapeStrategy = 0; + + switch (tqshape) { + case GradientShapeLinear: + tqshapeStrategy = new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeBiLinear: + tqshapeStrategy = new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeRadial: + tqshapeStrategy = new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeSquare: + tqshapeStrategy = new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeConical: + tqshapeStrategy = new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + case GradientShapeConicalSymetric: + tqshapeStrategy = new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd); + break; + } + Q_CHECK_PTR(tqshapeStrategy); + + GradientRepeatStrategy *repeatStrategy = 0; + + switch (repeat) { + case GradientRepeatNone: + repeatStrategy = GradientRepeatNoneStrategy::instance(); + break; + case GradientRepeatForwards: + repeatStrategy = GradientRepeatForwardsStrategy::instance(); + break; + case GradientRepeatAlternate: + repeatStrategy = GradientRepeatAlternateStrategy::instance(); + break; + } + Q_ASSERT(repeatStrategy != 0); + + + //If the device has a selection only iterate over that selection + TQRect r; + if( m_device->hasSelection() ) { + r = m_device->selection()->selectedExactRect(); + startx = r.x(); + starty = r.y(); + width = r.width(); + height = r.height(); + } + + TQ_INT32 endx = startx + width - 1; + TQ_INT32 endy = starty + height - 1; + + TQImage layer (width, height, 32); + layer.setAlphaBuffer(true); + + int pixelsProcessed = 0; + int lastProgressPercent = 0; + + emit notifyProgressStage(i18n("Rendering gradient..."), 0); + + int totalPixels = width * height; + + if (antiAliasThreshold < 1 - DBL_EPSILON) { + totalPixels *= 2; + } + + for (int y = starty; y <= endy; y++) { + for (int x = startx; x <= endx; x++) { + + double t = tqshapeStrategy->valueAt( x, y); + t = repeatStrategy->valueAt(t); + + if (reverseGradient) { + t = 1 - t; + } + + TQColor color; + TQ_UINT8 opacity; + + m_gradient->colorAt(t, &color, &opacity); + + layer.setPixel(x - startx, y - starty, + tqRgba(color.red(), color.green(), color.blue(), opacity)); + + pixelsProcessed++; + + int progressPercent = (pixelsProcessed * 100) / totalPixels; + + if (progressPercent > lastProgressPercent) { + emit notifyProgress(progressPercent); + lastProgressPercent = progressPercent; + + if (m_cancelRequested) { + break; + } + } + if (m_cancelRequested) { + break; + } + } + } + + if (!m_cancelRequested && antiAliasThreshold < 1 - DBL_EPSILON) { + + TQColor color; + emit notifyProgressStage(i18n("Anti-aliasing gradient..."), lastProgressPercent); + TQ_UINT8 * layerPointer = layer.bits(); + for (int y = starty; y <= endy; y++) { + for (int x = startx; x <= endx; x++) { + + double maxDistance = 0; + + TQ_UINT8 redThis = layerPointer[2]; + TQ_UINT8 greenThis = layerPointer[1]; + TQ_UINT8 blueThis = layerPointer[0]; + TQ_UINT8 thisPixelOpacity = layerPointer[3]; + + for (int yOffset = -1; yOffset < 2; yOffset++) { + for (int xOffset = -1; xOffset < 2; xOffset++) { + + if (xOffset != 0 || yOffset != 0) { + int sampleX = x + xOffset; + int sampleY = y + yOffset; + + if (sampleX >= startx && sampleX <= endx && sampleY >= starty && sampleY <= endy) { + uint x = sampleX - startx; + uint y = sampleY - starty; + TQ_UINT8 * pixelPos = layer.bits() + (y * width * 4) + (x * 4); + TQ_UINT8 red = *(pixelPos +2); + TQ_UINT8 green = *(pixelPos + 1); + TQ_UINT8 blue = *pixelPos; + TQ_UINT8 opacity = *(pixelPos + 3); + + double dRed = (red * opacity - redThis * thisPixelOpacity) / 65535.0; + double dGreen = (green * opacity - greenThis * thisPixelOpacity) / 65535.0; + double dBlue = (blue * opacity - blueThis * thisPixelOpacity) / 65535.0; + + #define SQRT_3 1.7320508 + + double distance =/* sqrt(*/dRed * dRed + dGreen * dGreen + dBlue * dBlue/*) / SQRT_3*/; + + if (distance > maxDistance) { + maxDistance = distance; + } + } + } + } + } + + if (maxDistance > 3.*antiAliasThreshold*antiAliasThreshold) { + const int numSamples = 4; + + int totalRed = 0; + int totalGreen = 0; + int totalBlue = 0; + int totalOpacity = 0; + + for (int ySample = 0; ySample < numSamples; ySample++) { + for (int xSample = 0; xSample < numSamples; xSample++) { + + double sampleWidth = 1.0 / numSamples; + + double sampleX = x - 0.5 + (sampleWidth / 2) + xSample * sampleWidth; + double sampleY = y - 0.5 + (sampleWidth / 2) + ySample * sampleWidth; + + double t = tqshapeStrategy->valueAt(sampleX, sampleY); + t = repeatStrategy->valueAt(t); + + if (reverseGradient) { + t = 1 - t; + } + + TQ_UINT8 opacity; + + m_gradient->colorAt(t, &color, &opacity); + + totalRed += color.red(); + totalGreen += color.green(); + totalBlue += color.blue(); + totalOpacity += opacity; + } + } + + int red = totalRed / (numSamples * numSamples); + int green = totalGreen / (numSamples * numSamples); + int blue = totalBlue / (numSamples * numSamples); + int opacity = totalOpacity / (numSamples * numSamples); + + layer.setPixel(x - startx, y - starty, tqRgba(red, green, blue, opacity)); + } + + pixelsProcessed++; + + int progressPercent = (pixelsProcessed * 100) / totalPixels; + + if (progressPercent > lastProgressPercent) { + emit notifyProgress(progressPercent); + lastProgressPercent = progressPercent; + + if (m_cancelRequested) { + break; + } + } + layerPointer += 4; + } + + if (m_cancelRequested) { + break; + } + } + } + + if (!m_cancelRequested) { + kdDebug() << "Have we got a selection? " << m_device->hasSelection() << endl; + KisPaintDeviceSP dev = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temporary device for gradient"); + dev->writeBytes(layer.bits(), startx, starty, width, height); + bltSelection(startx, starty, m_compositeOp, dev, m_opacity, startx, starty, width, height); + } + delete tqshapeStrategy; + + emit notifyProgressDone(); + + return !m_cancelRequested; +} diff --git a/chalk/core/kis_gradient_painter.h b/chalk/core/kis_gradient_painter.h new file mode 100644 index 00000000..fc31b117 --- /dev/null +++ b/chalk/core/kis_gradient_painter.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_GRADIENT_PAINTER_H_ +#define KIS_GRADIENT_PAINTER_H_ + +#include + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_point.h" +#include "kis_painter.h" +#include + +class KisGradient; + + +// XXX: Need to set dirtyRect in KisPainter +class KRITACORE_EXPORT KisGradientPainter : public KisPainter +{ + + typedef KisPainter super; + +public: + + KisGradientPainter(); + KisGradientPainter(KisPaintDeviceSP device); + + + enum enumGradientShape { + GradientShapeLinear, + GradientShapeBiLinear, + GradientShapeRadial, + GradientShapeSquare, + GradientShapeConical, + GradientShapeConicalSymetric + }; + + enum enumGradientRepeat { + GradientRepeatNone, + GradientRepeatForwards, + GradientRepeatAlternate + }; + + void setGradient(KisGradient& gradient) { m_gradient = &gradient; } + void setGradient(KisGradient* gradient) { m_gradient = gradient; } + + /** + * Paint a gradient in the rect between startx, starty, width and height. + * XXX: What does the returned bool mean? + * XXX: Make cs-independent + */ + bool paintGradient(const KisPoint& gradientVectorStart, + const KisPoint& gradientVectorEnd, + enumGradientShape tqshape, + enumGradientRepeat repeat, + double antiAliasThreshold, + bool reverseGradient, + TQ_INT32 startx, + TQ_INT32 starty, + TQ_INT32 width, + TQ_INT32 height); + + +private: + KisGradient *m_gradient; + + +}; +#endif //KIS_GRADIENT_PAINTER_H_ diff --git a/chalk/core/kis_group_layer.cc b/chalk/core/kis_group_layer.cc new file mode 100644 index 00000000..a3a35339 --- /dev/null +++ b/chalk/core/kis_group_layer.cc @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#include +#include +#include +#include + +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_layer_visitor.h" +#include "kis_debug_areas.h" +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_merge_visitor.h" +#include "kis_fill_painter.h" + +KisGroupLayer::KisGroupLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity) : + super(img, name, opacity), + m_x(0), + m_y(0) +{ + m_projection = new KisPaintDevice(this, img->colorSpace(), name.latin1()); +} + +KisGroupLayer::KisGroupLayer(const KisGroupLayer &rhs) : + super(rhs), + m_x(rhs.m_x), + m_y(rhs.m_y) +{ + for(vKisLayerSP_cit it = rhs.m_layers.begin(); it != rhs.m_layers.end(); ++it) + { + this->addLayer(it->data()->clone(), 0); + } + m_projection = new KisPaintDevice(*rhs.m_projection.data()); + m_projection->setParentLayer(this); +} + +KisLayerSP KisGroupLayer::clone() const +{ + return new KisGroupLayer(*this); +} + +KisGroupLayer::~KisGroupLayer() +{ + m_layers.clear(); +} + + +void KisGroupLayer::setDirty(bool propagate) +{ + KisLayer::setDirty(propagate); + if (propagate) emit (sigDirty(m_dirtyRect)); +} + +void KisGroupLayer::setDirty(const TQRect & rc, bool propagate) +{ + KisLayer::setDirty(rc, propagate); + if (propagate) emit sigDirty(rc); +} + +void KisGroupLayer::resetProjection(KisPaintDevice* to) +{ + if (to) + m_projection = new KisPaintDevice(*to); /// XXX ### look into Copy on Write here (CoW) + else + m_projection = new KisPaintDevice(this, image()->colorSpace(), name().latin1()); +} + +bool KisGroupLayer::paintLayerInducesProjectionOptimization(KisPaintLayer* l) { + return l && l->paintDevice()->colorSpace() == m_image->colorSpace() && l->visible() + && l->opacity() == OPACITY_OPAQUE && !l->temporaryTarget() && !l->hasMask(); +} + +KisPaintDeviceSP KisGroupLayer::projection(const TQRect & rect) +{ + // We don't have a tqparent, and we've got only one child: abuse the child's + // paint device as the projection if the child is visible and 100% opaque + if (tqparent() == 0 && childCount() == 1) { + KisPaintLayerSP l = dynamic_cast(firstChild().data()); + if (paintLayerInducesProjectionOptimization(l)) { + l->setClean(rect); + setClean(rect); + return l->paintDevice(); + } + } + // No need for updates, we're clean + if (!dirty()) { + return m_projection; + } + // No need for updates -- the desired area wasn't dirty + if (!rect.intersects(m_dirtyRect)) { + return m_projection; + } + + + // Okay, we need to update the intersection between + // what's dirty and what's asked us to be updated. + // XXX Nooo, that doesn't work, since the call to setClean following this, is actually: + // m_dirtyRect = TQRect(); So the non-intersecting part gets brilliantly lost otherwise. + const TQRect rc = m_dirtyRect;//rect.intersect(m_dirtyRect); + + updateProjection(rc); + setClean(rect); + + return m_projection; +} + +uint KisGroupLayer::childCount() const +{ + return m_layers.count(); +} + +KisLayerSP KisGroupLayer::firstChild() const +{ + return at(0); +} + +KisLayerSP KisGroupLayer::lastChild() const +{ + return at(childCount() - 1); +} + +KisLayerSP KisGroupLayer::at(int index) const +{ + if (childCount() && index >= 0 && kClamp(uint(index), uint(0), childCount() - 1) == uint(index)) + return m_layers.at(reverseIndex(index)); + return 0; +} + +int KisGroupLayer::index(KisLayerSP layer) const +{ + if (layer->tqparent().data() == this) + return layer->index(); + return -1; +} + +void KisGroupLayer::setIndex(KisLayerSP layer, int index) +{ + if (layer->tqparent().data() != this) + return; + //TODO optimize + removeLayer(layer); + addLayer(layer, index); +} + +bool KisGroupLayer::addLayer(KisLayerSP newLayer, int x) +{ + if (x < 0 || kClamp(uint(x), uint(0), childCount()) != uint(x) || + newLayer->tqparent() || m_layers.tqcontains(newLayer)) + { + kdWarning() << "invalid input to KisGroupLayer::addLayer(KisLayerSP newLayer, int x)!" << endl; + return false; + } + uint index(x); + if (index == 0) + m_layers.append(newLayer); + else + m_layers.insert(m_layers.begin() + reverseIndex(index) + 1, newLayer); + for (uint i = childCount() - 1; i > index; i--) + at(i)->m_index++; + newLayer->m_parent = this; + newLayer->m_index = index; + newLayer->setImage(image()); + newLayer->setDirty(newLayer->extent()); + setDirty(); + return true; +} + +bool KisGroupLayer::addLayer(KisLayerSP newLayer, KisLayerSP aboveThis) +{ + if (aboveThis && aboveThis->tqparent().data() != this) + { + kdWarning() << "invalid input to KisGroupLayer::addLayer(KisLayerSP newLayer, KisLayerSP aboveThis)!" << endl; + return false; + } + return addLayer(newLayer, aboveThis ? aboveThis->index() : childCount()); +} + +bool KisGroupLayer::removeLayer(int x) +{ + if (x >= 0 && kClamp(uint(x), uint(0), childCount() - 1) == uint(x)) + { + uint index(x); + for (uint i = childCount() - 1; i > index; i--) + at(i)->m_index--; + KisLayerSP removedLayer = at(index); + + removedLayer->m_parent = 0; + removedLayer->m_index = -1; + m_layers.erase(m_layers.begin() + reverseIndex(index)); + setDirty(removedLayer->extent()); + if (childCount() < 1) { + // No tqchildren, nothing to show for it. + m_projection->clear(); + setDirty(); + } + return true; + } + kdWarning() << "invalid input to KisGroupLayer::removeLayer()!" << endl; + return false; +} + +bool KisGroupLayer::removeLayer(KisLayerSP layer) +{ + if (layer->tqparent().data() != this) + { + kdWarning() << "invalid input to KisGroupLayer::removeLayer()!" << endl; + return false; + } + + return removeLayer(layer->index()); +} + +void KisGroupLayer::setImage(KisImage *image) +{ + super::setImage(image); + for (vKisLayerSP_it it = m_layers.begin(); it != m_layers.end(); ++it) + { + (*it)->setImage(image); + } +} + +TQRect KisGroupLayer::extent() const +{ + TQRect groupExtent; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + groupExtent |= (*it)->extent(); + } + + return groupExtent; +} + +TQRect KisGroupLayer::exactBounds() const +{ + TQRect groupExactBounds; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + groupExactBounds |= (*it)->exactBounds(); + } + + return groupExactBounds; +} + +TQ_INT32 KisGroupLayer::x() const +{ + return m_x; +} + +void KisGroupLayer::setX(TQ_INT32 x) +{ + TQ_INT32 delta = x - m_x; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + KisLayerSP layer = *it; + layer->setX(layer->x() + delta); + } + m_x = x; +} + +TQ_INT32 KisGroupLayer::y() const +{ + return m_y; +} + +void KisGroupLayer::setY(TQ_INT32 y) +{ + TQ_INT32 delta = y - m_y; + + for (vKisLayerSP_cit it = m_layers.begin(); it != m_layers.end(); ++it) + { + KisLayerSP layer = *it; + layer->setY(layer->y() + delta); + } + + m_y = y; +} + +TQImage KisGroupLayer::createThumbnail(TQ_INT32 w, TQ_INT32 h) +{ + return m_projection->createThumbnail(w, h); +} + +void KisGroupLayer::updateProjection(const TQRect & rc) +{ + if (!m_dirtyRect.isValid()) return; + + // Get the first layer in this group to start compositing with + KisLayerSP child = lastChild(); + + // No child -- clear the projection. Without tqchildren, a group layer is empty. + if (!child) m_projection->clear(); + + KisLayerSP startWith = 0; + KisAdjustmentLayerSP adjLayer = 0; + KisLayerSP tmpPaintLayer = 0; + + // If this is the rootlayer, don't do anything with adj. layers that are below the + // first paintlayer + bool gotPaintLayer = (tqparent() != 0); + + // Look through all the child layers, searching for the first dirty layer + // if it's found, and if we have found an adj. layer before the the dirty layer, + // composite from the first adjustment layer searching back from the first dirty layer + while (child) { + KisAdjustmentLayerSP tmpAdjLayer = dynamic_cast(child.data()); + if (tmpAdjLayer) { + if (gotPaintLayer) { + // If this adjustment layer is dirty, start compositing with the + // previous layer, if there's one. + if (tmpAdjLayer->dirty(rc) && adjLayer != 0 && adjLayer->visible()) { + startWith = adjLayer->prevSibling(); + break; + } + else if (tmpAdjLayer->visible() && !tmpAdjLayer->dirty(rc)) { + // This is the first adj. layer that is not dirty -- the perfect starting point + adjLayer = tmpAdjLayer; + } + else { + startWith = tmpPaintLayer; + } + } + } + else { + tmpPaintLayer = child; + gotPaintLayer = true; + // A non-adjustmentlayer that's dirty; if there's an adjustmentlayer + // with a cache, we'll start from there. + if (child->dirty(rc)) { + if (adjLayer != 0 && adjLayer->visible()) { + // the first layer on top of the adj. layer + startWith = adjLayer->prevSibling(); + } + else { + startWith = child; + } + // break here: if there's no adj layer, we'll start with the layer->lastChild + break; + } + } + child = child->prevSibling(); + } + + if (adjLayer != 0 && startWith == 0 && gotPaintLayer && adjLayer->prevSibling()) { + startWith = adjLayer->prevSibling(); + } + + // No adj layer -- all layers inside the group must be recomposited + if (adjLayer == 0) { + startWith = lastChild(); + } + + if (startWith == 0) { + return; + } + + bool first = true; // The first layer in a stack needs special compositing + + // Fill the projection either with the cached data, or erase it. + KisFillPainter gc(m_projection); + if (adjLayer != 0) { + gc.bitBlt(rc.left(), rc.top(), + COMPOSITE_COPY, adjLayer->cachedPaintDevice(), OPACITY_OPAQUE, + rc.left(), rc.top(), rc.width(), rc.height()); + first = false; + } + else { + gc.eraseRect(rc); + first = true; + } + gc.end(); + + KisMergeVisitor visitor(m_projection, rc); + + child = startWith; + + while(child) + { + if(first) + { + // Copy the lowest layer rather than compositing it with the background + // or an empty image. This means the layer's composite op is ignored, + // which is consistent with Photoshop and gimp. + const KisCompositeOp cop = child->compositeOp(); + const bool block = child->signalsBlocked(); + child->blockSignals(true); + // Composite op copy doesn't take a tqmask/selection into account, so we need + // to make a difference between a paintlayer with a tqmask, and one without + KisPaintLayer* l = dynamic_cast(child.data()); + if (l && l->hasMask()) + child->m_compositeOp = COMPOSITE_OVER; + else + child->m_compositeOp = COMPOSITE_COPY; + child->blockSignals(block); + child->accept(visitor); + child->blockSignals(true); + child->m_compositeOp = cop; + child->blockSignals(block); + first = false; + } + else + child->accept(visitor); + + child = child->prevSibling(); + } +} + +#include "kis_group_layer.moc" diff --git a/chalk/core/kis_group_layer.h b/chalk/core/kis_group_layer.h new file mode 100644 index 00000000..3a2e042a --- /dev/null +++ b/chalk/core/kis_group_layer.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_GROUP_LAYER_H_ +#define KIS_GROUP_LAYER_H_ + +#include + +#include "kis_layer.h" +#include "kis_types.h" + +#include "kis_paint_layer.h" + +class KisMergeVisitor; + +/** + * A KisLayer that bundles child layers into a single layer. + * The top layer is firstChild(), with index 0; the bottommost lastChild() with index childCount() - 1. + * KisLayer::nextSibling() moves towards higher indices, from the top to the bottom layer; prevSibling() the reverse. + * (Implementation detail: internally, the indices are reversed, for speed.) + **/ +class KisGroupLayer : public KisLayer { + typedef KisLayer super; + + Q_OBJECT + TQ_OBJECT + +public: + KisGroupLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity); + KisGroupLayer(const KisGroupLayer& rhs); + virtual ~KisGroupLayer(); + + virtual KisLayerSP clone() const; +public: + + /** + * Set the entire layer extent dirty; this percolates up to tqparent layers all the + * way to the root layer. + */ + virtual void setDirty(bool propagate = true); + + /** + * Add the given rect to the set of dirty rects for this layer; + * this percolates up to tqparent layers all the way to the root + * layer. + */ + virtual void setDirty(const TQRect & rect, bool propagate = true); + + virtual void activate() {}; + + virtual void deactivate() {}; + + virtual TQ_INT32 x() const; + virtual void setX(TQ_INT32); + + virtual TQ_INT32 y() const; + virtual void setY(TQ_INT32); + + // Sets this layer and all its descendants' owner image to the given image. + virtual void setImage(KisImage *image); + + virtual TQRect extent() const; + virtual TQRect exactBounds() const; + + virtual bool accept(KisLayerVisitor &v) + { +// kdDebug(41001) << "GROUP\t\t" << name() +// << " dirty: " << dirty() +// << ", " << m_layers.count() << " tqchildren " +// << ", projection: " << m_projection +// << "\n"; + return v.visit(this); + }; + + virtual void resetProjection(KisPaintDevice* to = 0); /// will copy from to, if !0, CoW!! + virtual KisPaintDeviceSP projection(const TQRect & rect); + + virtual uint childCount() const; + + virtual KisLayerSP firstChild() const; + virtual KisLayerSP lastChild() const; + + /// Returns the layer at the specified index. + virtual KisLayerSP at(int index) const; + + /// Returns the index of the layer if it's in this group, or -1 otherwise. + virtual int index(KisLayerSP layer) const; + + /// Moves the specified layer to the specified index in the group, if it's already a member of this group. + virtual void setIndex(KisLayerSP layer, int index); + + /** Adds the layer to this group at the specified index. childCount() is a valid index and appends to the end. + Fails and returns false if the layer is already in this group or any other (remove it first.) */ + virtual bool addLayer(KisLayerSP newLayer, int index); + + /** + * Add the specified layer above the specified layer (if aboveThis == 0, the bottom is used) */ + virtual bool addLayer(KisLayerSP newLayer, KisLayerSP aboveThis); + + /// Removes the layer at the specified index from the group. + virtual bool removeLayer(int index); + + /// Removes the layer from this group. Fails if there's no such layer in this group. + virtual bool removeLayer(KisLayerSP layer); + + virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h); + + /// Returns if the layer will induce the projection hack (if the only layer in this group) + virtual bool paintLayerInducesProjectionOptimization(KisPaintLayer* l); +signals: + + void sigDirty(TQRect rc); + +private: + + void updateProjection(const TQRect & rc); + + inline int reverseIndex(int index) const { return childCount() - 1 - index; }; + vKisLayerSP m_layers; // Contains the list of all layers + KisPaintDeviceSP m_projection; // The cached composition of all layers in this group + + TQ_INT32 m_x; + TQ_INT32 m_y; +}; + +#endif // KIS_GROUP_LAYER_H_ + diff --git a/chalk/core/kis_histogram.cc b/chalk/core/kis_histogram.cc new file mode 100644 index 00000000..bece7c9a --- /dev/null +++ b/chalk/core/kis_histogram.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include // ### Debug + +#include "kis_types.h" +#include "kis_histogram.h" +#include "kis_paint_layer.h" +#include "kis_iterators_pixel.h" +#include "kis_colorspace.h" +#include "kis_debug_areas.h" + +KisHistogram::KisHistogram(KisPaintLayerSP layer, + KisHistogramProducerSP producer, + const enumHistogramType type) +{ + m_dev = layer->paintDevice(); + m_type = type; + m_producer = producer; + m_selection = false; + m_channel = 0; + + updateHistogram(); +} + +KisHistogram::KisHistogram(KisPaintDeviceSP paintdev, + KisHistogramProducerSP producer, + const enumHistogramType type) +{ + m_dev = paintdev; + m_type = type; + m_producer = producer; + m_selection = false; + m_channel = 0; + + updateHistogram(); +} + +KisHistogram::~KisHistogram() +{ +} + +void KisHistogram::updateHistogram() +{ + TQ_INT32 x,y,w,h; + m_dev->exactBounds(x,y,w,h); + KisRectIteratorPixel srcIt = m_dev->createRectIterator(x,y,w,h, false); + KisColorSpace* cs = m_dev->colorSpace(); + + TQTime t; + t.start(); + + // Let the producer do it's work + m_producer->clear(); + int i; + // Handle degenerate case (this happens with the accumulating histogram, + // which has an empty device) + if (srcIt.isDone()) { + m_producer->addRegionToBin(0, 0, 0, cs); + } else { + while ( !srcIt.isDone() ) { + i = srcIt.nConseqPixels(); + m_producer->addRegionToBin(srcIt.rawData(), srcIt.selectionMask(), i, cs); + srcIt += i; + } + } + + computeHistogram(); +} + +void KisHistogram::computeHistogram() +{ + m_completeCalculations = calculateForRange(m_producer->viewFrom(), + m_producer->viewFrom() + m_producer->viewWidth()); + + if (m_selection) { + m_selectionCalculations = calculateForRange(m_selFrom, m_selTo); + } else { + m_selectionCalculations.clear(); + } + +#if 1 + dump(); +#endif +} + +KisHistogram::Calculations KisHistogram::calculations() { + return m_completeCalculations.at(m_channel); +} + +KisHistogram::Calculations KisHistogram::selectionCalculations() { + return m_selectionCalculations.at(m_channel); +} + +TQValueVector KisHistogram::calculateForRange(double from, double to) { + TQValueVector calculations; + uint count = m_producer->channels().count(); + + for (uint i = 0; i < count; i++) { + calculations.append(calculateSingleRange(i, from, to)); + } + + return calculations; +} + +KisHistogram::Calculations KisHistogram::calculateSingleRange(int channel, double from, double to) { + Calculations c; + + // XXX If from == to, we only want a specific bin, handle that properly! + + double max = from, min = to, total = 0.0, mean = 0.0; //, median = 0.0, stddev = 0.0; + TQ_UINT32 high = 0, low = (TQ_UINT32) -1, count = 0; + + if (m_producer->count() == 0) { + // We won't get anything, even if a range is specified + // XXX make sure all initial '0' values are correct here! + return c; + } + + TQ_INT32 totbins = m_producer->numberOfBins(); + TQ_UINT32 current; + + // convert the double range into actual bins: + double factor = static_cast(totbins) / m_producer->viewWidth(); + + TQ_INT32 fromBin = static_cast((from - m_producer->viewFrom()) * factor); + TQ_INT32 toBin = fromBin + static_cast((to - from) * factor); + + // Min, max, count, low, high + for (TQ_INT32 i = fromBin; i < toBin; i++) { + current = m_producer->getBinAt(channel, i); + double pos = static_cast(i) / factor + from; + if (current > high) + high = current; + if (current < low) + low = current; + if (current > 0) { + if (pos < min) + min = pos; + if (pos > max) + max = pos; + } + // We do the count here as well. + // we can't use m_producer->count() for this, because of the range + count += current; + total += current * pos; + } + + if (count > 0) + mean = total / count; + + c.m_high = high; + c.m_low = low; + c.m_count = count; + c.m_min = min; + c.m_max = max; + c.m_mean = mean; + c.m_total = total; + + return c; +} + + +void KisHistogram::dump() { + kdDebug(DBG_AREA_MATH) << "Histogram\n"; + + switch (m_type) { + case LINEAR: + kdDebug(DBG_AREA_MATH) << "Linear histogram\n"; + break; + case LOGARITHMIC: + kdDebug(DBG_AREA_MATH) << "Logarithmic histogram\n"; + } + + kdDebug(DBG_AREA_MATH) << "Dumping channel " << m_channel << endl; + Calculations c = calculations(); + +/* for( int i = 0; i <256; ++i ) { + kdDebug(DBG_AREA_MATH) << "Value " + << TQString().setNum(i) + << ": " + << TQString().setNum(m_values[i]) + << "\n"; + }*/ + kdDebug(DBG_AREA_MATH) << "\n"; + + kdDebug(DBG_AREA_MATH) << "Max: " << TQString(TQString().setNum(c.getMax())) << "\n"; + kdDebug(DBG_AREA_MATH) << "Min: " << TQString(TQString().setNum(c.getMin())) << "\n"; + kdDebug(DBG_AREA_MATH) << "High: " << TQString(TQString().setNum(c.getHighest())) << "\n"; + kdDebug(DBG_AREA_MATH) << "Low: " << TQString(TQString().setNum(c.getLowest())) << "\n"; + kdDebug(DBG_AREA_MATH) << "Mean: " << TQString(m_producer->positionToString(c.getMean())) << "\n"; + kdDebug(DBG_AREA_MATH) << "Total: " << TQString(TQString().setNum(c.getTotal())) << "\n"; +// kdDebug(DBG_AREA_MATH) << "Median: " << TQString().setNum(m_median) << "\n"; +// kdDebug(DBG_AREA_MATH) << "Stddev: " << TQString().setNum(m_stddev) << "\n"; +// kdDebug(DBG_AREA_MATH) << "percentile: " << TQString().setNum(m_percentile) << "\n"; + + kdDebug(DBG_AREA_MATH) << "\n"; +} diff --git a/chalk/core/kis_histogram.h b/chalk/core/kis_histogram.h new file mode 100644 index 00000000..3d315994 --- /dev/null +++ b/chalk/core/kis_histogram.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_HISTOGRAM_ +#define KIS_HISTOGRAM_ + +#include "kis_types.h" +#include "kis_colorspace.h" +#include "kis_histogram_producer.h" + +enum enumHistogramType { + LINEAR, + LOGARITHMIC +}; +/** + * The histogram class computes the histogram data from the specified layer + * for the specified channel, through the use of a KisHistogramProducer. + * This class is only for layers and paintdevices. KisImages are not supported, + * but you can use the mergedImage function to create a paintdevice and feed that to this class. + * + * A Histogram also can have a selection: this is a specific range in the current histogram + * that will get calculations done on it as well. If the range's begin and end are the same, + * it is supposed to specify a single bin in the histogram. + * + * The calculations are done in the range 0 - 1, instead of the native range that a pixel + * might have, so it's not always as precise as it could be. But you can't have it all... + */ +class KisHistogram : public KShared { + +public: + /** + * Class that stores the result of histogram calculations. + * Doubles are in the 0-1 range, use the producer's positionToString function to display it. + **/ + class Calculations { + + double m_max, m_min, m_mean, m_total, m_median, m_stddev; + + TQ_UINT32 m_high, m_low, m_count; + + friend class KisHistogram; + + public: + + Calculations() : m_max(0.0), m_min(0.0), m_mean(0.0), m_total(0.0), m_median(0.0), + m_stddev(0.0), m_high(0), m_low(0), m_count(0) {} + /** + * This function return the maximum bound of the histogram + * (values at greater position than the maximum are null) + */ + inline double getMax() { return m_max; } + /** + * This function return the minimum bound of the histogram + * (values at smaller position than the minimum are null) + */ + inline double getMin() { return m_min; } + /// This function return the highest value of the histogram + inline TQ_UINT32 getHighest() { return m_high; } + /// This function return the lowest value of the histogram + inline TQ_UINT32 getLowest() { return m_low; } + /// This function return the mean of value of the histogram + inline double getMean() { return m_mean; } + //double getMedian() { return m_median; } + //double getStandardDeviation() { return m_stddev; } + /// This function return the number of pixels used by the histogram + inline TQ_UINT32 getCount() { return m_count; } + /** The sum of (the contents of every bin * the double value of that bin)*/ + inline double getTotal() { return m_total; } + //TQ_UINT8 getPercentile() { return m_percentile; } // What is this exactly? XXX + }; + + KisHistogram(KisPaintLayerSP layer, + KisHistogramProducerSP producer, + const enumHistogramType type); + + KisHistogram(KisPaintDeviceSP paintdev, + KisHistogramProducerSP producer, + const enumHistogramType type); + + virtual ~KisHistogram(); + + /** Updates the information in the producer */ + void updateHistogram(); + + /** + * (Re)computes the mathematical information from the information currently in the producer. + * Needs to be called when you change the selection and want to get that information + **/ + void computeHistogram(); + + /** The information on the entire view for the current channel */ + Calculations calculations(); + /** The information on the current selection for the current channel */ + Calculations selectionCalculations(); + + inline TQ_UINT32 getValue(TQ_UINT8 i) { return m_producer->getBinAt(m_channel, i); } + + inline enumHistogramType getHistogramType() { return m_type; } + inline void setHistogramType(enumHistogramType type) { m_type = type; } + inline void setProducer(KisHistogramProducerSP producer) { m_producer = producer; } + inline void setChannel(TQ_INT32 channel) { m_channel = channel; } + inline KisHistogramProducerSP producer() { return m_producer; } + inline TQ_INT32 channel() { return m_channel; } + + inline bool hasSelection() { return m_selection; } + inline double selectionFrom() { return m_selFrom; } + inline double selectionTo() { return m_selTo; } + inline void setNoSelection() { m_selection = false; } + /** Sets the current selection */ + inline void setSelection(double from, double to) + { m_selection = true; m_selFrom = from; m_selTo = to; } + + +private: + // Dump the histogram to debug. + void dump(); + TQValueVector calculateForRange(double from, double to); + Calculations calculateSingleRange(int channel, double from, double to); + + KisPaintDeviceSP m_device; + KisHistogramProducerSP m_producer; + + enumHistogramType m_type; + + TQ_INT32 m_channel; + double m_selFrom, m_selTo; + bool m_selection; + + KisPaintDeviceSP m_dev; + + TQValueVector m_completeCalculations, m_selectionCalculations; +}; + + +#endif // KIS_HISTOGRAM_WIDGET_ diff --git a/chalk/core/kis_image.cc b/chalk/core/kis_image.cc new file mode 100644 index 00000000..30f3ad36 --- /dev/null +++ b/chalk/core/kis_image.cc @@ -0,0 +1,1702 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include LCMS_HEADER + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_image_iface.h" + +#include "kis_annotation.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_color.h" +#include "kis_command.h" +#include "kis_types.h" +//#include "kis_guide.h" +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_paint_device_action.h" +#include "kis_selection.h" +#include "kis_painter.h" +#include "kis_fill_painter.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_paint_layer.h" +#include "kis_colorspace_convert_visitor.h" +#include "kis_background.h" +#include "kis_substrate.h" +#include "kis_scale_visitor.h" +#include "kis_nameserver.h" +#include "kis_undo_adapter.h" +#include "kis_merge_visitor.h" +#include "kis_transaction.h" +#include "kis_crop_visitor.h" +#include "kis_transform_visitor.h" +#include "kis_filter_strategy.h" +#include "kis_profile.h" +#include "kis_paint_layer.h" +#include "kis_perspective_grid.h" +#include "kis_change_profile_visitor.h" +#include "kis_group_layer.h" +#include "kis_iterators_pixel.h" +#include "kis_shear_visitor.h" + +class KisImage::KisImagePrivate { +public: + KisColor backgroundColor; + TQ_UINT32 lockCount; + bool sizeChangedWhileLocked; + bool selectionChangedWhileLocked; + KisSubstrateSP substrate; + KisPerspectiveGrid* perspectiveGrid; +}; + + +namespace { + + class KisResizeImageCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisResizeImageCmd(KisUndoAdapter *adapter, + KisImageSP img, + TQ_INT32 width, + TQ_INT32 height, + TQ_INT32 oldWidth, + TQ_INT32 oldHeight) : super(i18n("Resize Image")) + { + m_adapter = adapter; + m_img = img; + m_before = TQSize(oldWidth, oldHeight); + m_after = TQSize(width, height); + } + + virtual ~KisResizeImageCmd() + { + } + + public: + virtual void execute() + { + m_adapter->setUndo(false); + m_img->resize(m_after.width(), m_after.height()); + m_adapter->setUndo(true); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + m_img->resize(m_before.width(), m_before.height()); + m_adapter->setUndo(true); + } + + private: + KisUndoAdapter *m_adapter; + KisImageSP m_img; + TQSize m_before; + TQSize m_after; + }; + + // ------------------------------------------------------- + + class KisChangeLayersCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisChangeLayersCmd(KisUndoAdapter *adapter, KisImageSP img, + KisGroupLayerSP oldRootLayer, KisGroupLayerSP newRootLayer, const TQString& name) + : super(name) + { + m_adapter = adapter; + m_img = img; + m_oldRootLayer = oldRootLayer; + m_newRootLayer = newRootLayer; + } + + virtual ~KisChangeLayersCmd() + { + } + + public: + virtual void execute() + { + m_adapter->setUndo(false); + m_img->setRootLayer(m_newRootLayer); + m_adapter->setUndo(true); + m_img->notifyLayersChanged(); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + m_img->setRootLayer(m_oldRootLayer); + m_adapter->setUndo(true); + m_img->notifyLayersChanged(); + } + + private: + KisUndoAdapter *m_adapter; + KisImageSP m_img; + KisGroupLayerSP m_oldRootLayer; + KisGroupLayerSP m_newRootLayer; + }; + + + // ------------------------------------------------------- + + class KisConvertImageTypeCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisConvertImageTypeCmd(KisUndoAdapter *adapter, KisImageSP img, + KisColorSpace * beforeColorSpace, KisColorSpace * afterColorSpace + ) : super(i18n("Convert Image Type")) + { + m_adapter = adapter; + m_img = img; + m_beforeColorSpace = beforeColorSpace; + m_afterColorSpace = afterColorSpace; + } + + virtual ~KisConvertImageTypeCmd() + { + } + + public: + virtual void execute() + { + m_adapter->setUndo(false); + + m_img->setColorSpace(m_afterColorSpace); + m_img->setProfile(m_afterColorSpace->getProfile()); + + m_adapter->setUndo(true); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + + m_img->setColorSpace(m_beforeColorSpace); + m_img->setProfile(m_beforeColorSpace->getProfile()); + + m_adapter->setUndo(true); + } + + private: + KisUndoAdapter *m_adapter; + KisImageSP m_img; + KisColorSpace * m_beforeColorSpace; + KisColorSpace * m_afterColorSpace; + }; + + + // ------------------------------------------------------- + + class KisImageCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisImageCommand(const TQString& name, KisImageSP image); + virtual ~KisImageCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisImageSP m_image; + }; + + KisImageCommand::KisImageCommand(const TQString& name, KisImageSP image) : + super(name), m_image(image) + { + } + + void KisImageCommand::setUndo(bool undo) + { + if (m_image->undoAdapter()) { + m_image->undoAdapter()->setUndo(undo); + } + } + + + // ------------------------------------------------------- + + class KisLayerPositionCommand : public KisImageCommand { + typedef KisImageCommand super; + + public: + KisLayerPositionCommand(const TQString& name, KisImageSP image, KisLayerSP layer, KisGroupLayerSP tqparent, KisLayerSP aboveThis) : super(name, image) + { + m_layer = layer; + m_oldParent = layer->tqparent(); + m_oldAboveThis = layer->nextSibling(); + m_newParent = tqparent; + m_newAboveThis = aboveThis; + } + + virtual void execute() + { + setUndo(false); + m_image->moveLayer(m_layer, m_newParent, m_newAboveThis); + setUndo(true); + } + + virtual void unexecute() + { + setUndo(false); + m_image->moveLayer(m_layer, m_oldParent, m_oldAboveThis); + setUndo(true); + } + + private: + KisLayerSP m_layer; + KisGroupLayerSP m_oldParent; + KisLayerSP m_oldAboveThis; + KisGroupLayerSP m_newParent; + KisLayerSP m_newAboveThis; + }; + + + // ------------------------------------------------------- + + class LayerAddCmd : public KisCommand { + typedef KisCommand super; + + public: + LayerAddCmd(KisUndoAdapter *adapter, KisImageSP img, KisLayerSP layer) : super(i18n("Add Layer"), adapter) + { + m_img = img; + m_layer = layer; + m_parent = layer->tqparent(); + m_aboveThis = layer->nextSibling(); + } + + virtual ~LayerAddCmd() + { + } + + virtual void execute() + { + adapter()->setUndo(false); + m_img->addLayer(m_layer, m_parent.data(), m_aboveThis); + adapter()->setUndo(true); + } + + virtual void unexecute() + { + adapter()->setUndo(false); + m_img->removeLayer(m_layer); + adapter()->setUndo(true); + } + + private: + KisImageSP m_img; + KisLayerSP m_layer; + KisGroupLayerSP m_parent; + KisLayerSP m_aboveThis; + }; + + // ------------------------------------------------------- + + class LayerRmCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + LayerRmCmd(KisUndoAdapter *adapter, KisImageSP img, + KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAbove) + : super(i18n("Remove Layer")) + { + m_adapter = adapter; + m_img = img; + m_layer = layer; + m_prevParent = wasParent; + m_prevAbove = wasAbove; + } + + virtual ~LayerRmCmd() + { + } + + virtual void execute() + { + m_adapter->setUndo(false); + m_img->removeLayer(m_layer); + m_adapter->setUndo(true); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + m_img->addLayer(m_layer, m_prevParent.data(), m_prevAbove); + m_adapter->setUndo(true); + } + + private: + KisUndoAdapter *m_adapter; + KisImageSP m_img; + KisLayerSP m_layer; + KisGroupLayerSP m_prevParent; + KisLayerSP m_prevAbove; + }; + + class LayerMoveCmd: public KNamedCommand { + typedef KNamedCommand super; + + public: + LayerMoveCmd(KisUndoAdapter *adapter, KisImageSP img, + KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAbove) + : super(i18n("Move Layer")) + { + m_adapter = adapter; + m_img = img; + m_layer = layer; + m_prevParent = wasParent; + m_prevAbove = wasAbove; + m_newParent = layer->tqparent(); + m_newAbove = layer->nextSibling(); + } + + virtual ~LayerMoveCmd() + { + } + + virtual void execute() + { + m_adapter->setUndo(false); + m_img->moveLayer(m_layer, m_newParent.data(), m_newAbove); + m_adapter->setUndo(true); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + m_img->moveLayer(m_layer, m_prevParent.data(), m_prevAbove); + m_adapter->setUndo(true); + } + + private: + KisUndoAdapter *m_adapter; + KisImageSP m_img; + KisLayerSP m_layer; + KisGroupLayerSP m_prevParent; + KisLayerSP m_prevAbove; + KisGroupLayerSP m_newParent; + KisLayerSP m_newAbove; + }; + + + // ------------------------------------------------------- + + class LayerPropsCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + LayerPropsCmd(KisLayerSP layer, + KisImageSP img, + KisUndoAdapter *adapter, + const TQString& name, + TQ_INT32 opacity, + const KisCompositeOp& compositeOp) : super(i18n("Layer Property Changes")) + { + m_layer = layer; + m_img = img; + m_adapter = adapter; + m_name = name; + m_opacity = opacity; + m_compositeOp = compositeOp; + } + + virtual ~LayerPropsCmd() + { + } + + public: + virtual void execute() + { + TQString name = m_layer->name(); + TQ_INT32 opacity = m_layer->opacity(); + KisCompositeOp compositeOp = m_layer->compositeOp(); + + m_adapter->setUndo(false); + m_img->setLayerProperties(m_layer, + m_opacity, + m_compositeOp, + m_name); + m_adapter->setUndo(true); + m_name = name; + m_opacity = opacity; + m_compositeOp = compositeOp; + m_layer->setDirty(); + } + + virtual void unexecute() + { + execute(); + } + + private: + KisUndoAdapter *m_adapter; + KisLayerSP m_layer; + KisImageSP m_img; + TQString m_name; + TQ_INT32 m_opacity; + KisCompositeOp m_compositeOp; + }; + + // ------------------------------------------------------- + + class LockImageCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + LockImageCommand(KisImageSP img, bool lockImage) : super("lock image") // Not for translation, this + { // is only ever used inside a macro command. + m_img = img; + m_lockImage = lockImage; + } + + virtual ~LockImageCommand() + { + } + + virtual void execute() + { + if (m_lockImage) { + m_img->lock(); + } else { + m_img->unlock(); + } + } + + virtual void unexecute() + { + if (m_lockImage) { + m_img->unlock(); + } else { + m_img->lock(); + } + } + + private: + KisImageSP m_img; + bool m_lockImage; + }; +} + +KisImage::KisImage(KisUndoAdapter *adapter, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorSpace, const TQString& name) + : TQObject(0, name.latin1()), KShared() +{ + init(adapter, width, height, colorSpace, name); + setName(name); + m_dcop = 0L; +} + +KisImage::KisImage(const KisImage& rhs) : TQObject(), KShared(rhs) +{ + m_dcop = 0L; + if (this != &rhs) { + m_private = new KisImagePrivate(*rhs.m_private); + m_private->perspectiveGrid = new KisPerspectiveGrid(*rhs.m_private->perspectiveGrid); + m_uri = rhs.m_uri; + m_name = TQString(); + m_width = rhs.m_width; + m_height = rhs.m_height; + m_xres = rhs.m_xres; + m_yres = rhs.m_yres; + m_unit = rhs.m_unit; + m_colorSpace = rhs.m_colorSpace; + m_dirty = rhs.m_dirty; + m_adapter = rhs.m_adapter; + + m_bkg = new KisBackground(); + Q_CHECK_PTR(m_bkg); + + m_rootLayer = static_cast(rhs.m_rootLayer->clone().data()); + connect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + + m_annotations = rhs.m_annotations; // XXX the annotations would probably need to be deep-copied + + m_nserver = new KisNameServer(i18n("Layer %1"), rhs.m_nserver->currentSeed() + 1); + Q_CHECK_PTR(m_nserver); + + //m_guides = rhs.m_guides; + + // Set this as the current image for the layers + m_rootLayer->setImage(this); + // Set the active paint layer + if(rhs.activeLayer() != NULL) { + TQString layerName = rhs.activeLayer()->name(); + // kdDebug(12345) << "KisImage::KisImage: active layer = " << layerName << "\n"; + KisLayerSP activeLayer = rootLayer()->findLayer(layerName); + Q_ASSERT(activeLayer); + activate(activeLayer); + } else { + activate(NULL); + } + } +} + + + +DCOPObject * KisImage::dcopObject() +{ + if (!m_dcop) { + m_dcop = new KisImageIface(this); + Q_CHECK_PTR(m_dcop); + } + return m_dcop; +} + +KisImage::~KisImage() +{ + delete m_private->perspectiveGrid; + delete m_private; + delete m_nserver; + delete m_dcop; +} + +TQString KisImage::name() const +{ + return m_name; +} + +void KisImage::setName(const TQString& name) +{ + if (!name.isEmpty()) + m_name = name; +} + +TQString KisImage::description() const +{ + return m_description; +} + +void KisImage::setDescription(const TQString& description) +{ + if (!description.isEmpty()) + m_description = description; +} + + +KisColor KisImage::backgroundColor() const +{ + return m_private->backgroundColor; +} + +void KisImage::setBackgroundColor(const KisColor & color) +{ + m_private->backgroundColor = color; +} + + +TQString KisImage::nextLayerName() const +{ + if (m_nserver->currentSeed() == 0) { + m_nserver->number(); + return i18n("background"); + } + + return m_nserver->name(); +} + +void KisImage::rollBackLayerName() +{ + m_nserver->rollback(); +} + +void KisImage::init(KisUndoAdapter *adapter, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorSpace, const TQString& name) +{ + Q_ASSERT(colorSpace); + + if (colorSpace == 0) { + colorSpace = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + kdWarning(41010) << "No colorspace specified: using RGBA\n"; + } + + m_private = new KisImagePrivate(); + m_private->backgroundColor = KisColor(TQt::white, colorSpace); + m_private->lockCount = 0; + m_private->sizeChangedWhileLocked = false; + m_private->selectionChangedWhileLocked = false; + m_private->substrate = 0; + m_private->perspectiveGrid = new KisPerspectiveGrid(); + + m_adapter = adapter; + + m_nserver = new KisNameServer(i18n("Layer %1"), 1); + m_name = name; + + m_colorSpace = colorSpace; + m_bkg = new KisBackground(); + + m_rootLayer = new KisGroupLayer(this,"root", OPACITY_OPAQUE); + connect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + + m_xres = 1.0; + m_yres = 1.0; + m_unit = KoUnit::U_PT; + m_dirty = false; + m_width = width; + m_height = height; +} + +bool KisImage::locked() const +{ + return m_private->lockCount != 0; +} + +void KisImage::lock() +{ + if (!locked()) { + if (m_rootLayer) disconnect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + m_private->sizeChangedWhileLocked = false; + m_private->selectionChangedWhileLocked = false; + } + m_private->lockCount++; +} + +void KisImage::unlock() +{ + Q_ASSERT(locked()); + + if (locked()) { + m_private->lockCount--; + + if (m_private->lockCount == 0) { + if (m_private->sizeChangedWhileLocked) { + // A size change implies a full image update so only send this. + emit sigSizeChanged(m_width, m_height); + } else { + if (m_rootLayer->dirty()) emit sigImageUpdated( m_rootLayer->dirtyRect() ); + } + + if (m_private->selectionChangedWhileLocked) { + emit sigActiveSelectionChanged(this); + } + + if (m_rootLayer) connect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + } + } +} + +void KisImage::emitSizeChanged() +{ + if (!locked()) { + emit sigSizeChanged(m_width, m_height); + } else { + m_private->sizeChangedWhileLocked = true; + } +} + +void KisImage::notifyLayerUpdated(KisLayerSP layer, TQRect rc) +{ + emit sigLayerUpdated(layer, rc); +} + +void KisImage::resize(TQ_INT32 w, TQ_INT32 h, TQ_INT32 x, TQ_INT32 y, bool cropLayers) +{ + if (w != width() || h != height()) { + + lock(); + + if (undo()) { + if (cropLayers) + m_adapter->beginMacro(i18n("Crop Image")); + else + m_adapter->beginMacro(i18n("Resize Image")); + + m_adapter->addCommand(new LockImageCommand(this, true)); + m_adapter->addCommand(new KisResizeImageCmd(m_adapter, this, w, h, width(), height())); + } + + m_width = w; + m_height = h; + + if (cropLayers) { + KisCropVisitor v(TQRect(x, y, w, h)); + m_rootLayer->accept(v); + } + + emitSizeChanged(); + + unlock(); + + if (undo()) { + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } + } +} + +void KisImage::resize(const TQRect& rc, bool cropLayers) +{ + resize(rc.width(), rc.height(), rc.x(), rc.y(), cropLayers); +} + + +void KisImage::scale(double sx, double sy, KisProgressDisplayInterface *progress, KisFilterStrategy *filterStrategy) +{ + if (nlayers() == 0) return; // Nothing to scale + + // New image size. XXX: Pass along to discourage rounding errors? + TQ_INT32 w, h; + w = (TQ_INT32)(( width() * sx) + 0.5); + h = (TQ_INT32)(( height() * sy) + 0.5); + + if (w != width() || h != height()) { + + lock(); + + if (undo()) { + m_adapter->beginMacro(i18n("Scale Image")); + m_adapter->addCommand(new LockImageCommand(this, true)); + } +#if 0 + if ( colorSpace()->id() == KisID("RGBA") || colorSpace()->id() == KisID("CMYK") || colorSpace()->id() == KisID("GRAYA")) { + KisScaleVisitor v (this, sx, sy, progress, filterStrategy); + m_rootLayer->accept( v ); + } + else { +#endif + KisTransformVisitor visitor (this, sx, sy, 0.0, 0.0, 0.0, 0, 0, progress, filterStrategy); + m_rootLayer->accept(visitor); +// } + + if (undo()) { + m_adapter->addCommand(new KisResizeImageCmd(m_adapter, this, w, h, width(), height())); + } + + m_width = w; + m_height = h; + + emitSizeChanged(); + + unlock(); + + if (undo()) { + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } + } +} + + + +void KisImage::rotate(double radians, KisProgressDisplayInterface *progress) +{ + lock(); + + TQ_INT32 w = width(); + TQ_INT32 h = height(); + TQ_INT32 tx = TQ_INT32((w*cos(radians) - h*sin(radians) - w) / 2 + 0.5); + TQ_INT32 ty = TQ_INT32((h*cos(radians) + w*sin(radians) - h) / 2 + 0.5); + w = (TQ_INT32)(width()*TQABS(cos(radians)) + height()*TQABS(sin(radians)) + 0.5); + h = (TQ_INT32)(height()*TQABS(cos(radians)) + width()*TQABS(sin(radians)) + 0.5); + + tx -= (w - width()) / 2; + ty -= (h - height()) / 2; + + if (undo()) { + m_adapter->beginMacro(i18n("Rotate Image")); + m_adapter->addCommand(new LockImageCommand(this, true)); + } + + KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->get(KisID("Triangle")); + KisTransformVisitor visitor (this, 1.0, 1.0, 0, 0, radians, -tx, -ty, progress, filter); + m_rootLayer->accept(visitor); + + if (undo()) m_adapter->addCommand(new KisResizeImageCmd(undoAdapter(), this, w, h, width(), height())); + + m_width = w; + m_height = h; + + emitSizeChanged(); + + unlock(); + + if (undo()) { + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } +} + +void KisImage::shear(double angleX, double angleY, KisProgressDisplayInterface *m_progress) +{ + const double pi=3.1415926535897932385; + + //new image size + TQ_INT32 w=width(); + TQ_INT32 h=height(); + + + if(angleX != 0 || angleY != 0){ + double deltaY=height()*TQABS(tan(angleX*pi/180)*tan(angleY*pi/180)); + w = (TQ_INT32) ( width() + TQABS(height()*tan(angleX*pi/180)) ); + //ugly fix for the problem of having two extra pixels if only a shear along one + //axis is done. This has to be fixed in the cropping code in KisRotateVisitor! + if (angleX == 0 || angleY == 0) + h = (TQ_INT32) ( height() + TQABS(w*tan(angleY*pi/180)) ); + else if (angleX > 0 && angleY > 0) + h = (TQ_INT32) ( height() + TQABS(w*tan(angleY*pi/180))- 2 * deltaY + 2 ); + else if (angleX < 0 && angleY < 0) + h = (TQ_INT32) ( height() + TQABS(w*tan(angleY*pi/180))- 2 * deltaY + 2 ); + else + h = (TQ_INT32) ( height() + TQABS(w*tan(angleY*pi/180)) ); + } + + if (w != width() || h != height()) { + + lock(); + + if (undo()) { + m_adapter->beginMacro(i18n("Shear Image")); + m_adapter->addCommand(new LockImageCommand(this, true)); + } + + KisShearVisitor v(angleX, angleY, m_progress); + v.setUndoAdapter(undoAdapter()); + rootLayer()->accept(v); + + if (undo()) m_adapter->addCommand(new KisResizeImageCmd(m_adapter, this, w, h, width(), height())); + + m_width = w; + m_height = h; + + emitSizeChanged(); + + unlock(); + + if (undo()) { + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } + } +} + +void KisImage::convertTo(KisColorSpace * dstColorSpace, TQ_INT32 renderingIntent) +{ + if ( m_colorSpace == dstColorSpace ) + { + return; + } + + lock(); + + KisColorSpace * oldCs = m_colorSpace; + + if (undo()) { + m_adapter->beginMacro(i18n("Convert Image Type")); + m_adapter->addCommand(new LockImageCommand(this, true)); + } + + setColorSpace(dstColorSpace); + + KisColorSpaceConvertVisitor visitor(dstColorSpace, renderingIntent); + m_rootLayer->accept(visitor); + + unlock(); + + emit sigLayerPropertiesChanged( m_activeLayer ); + + if (undo()) { + + m_adapter->addCommand(new KisConvertImageTypeCmd(undoAdapter(), this, + oldCs, dstColorSpace)); + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } +} + +KisProfile * KisImage::getProfile() const +{ + return colorSpace()->getProfile(); +} + +void KisImage::setProfile(const KisProfile * profile) +{ + if (profile == 0) return; + + KisColorSpace * dstCs= KisMetaRegistry::instance()->csRegistry()->getColorSpace( colorSpace()->id(), + profile); + if (dstCs) { + + lock(); + + KisColorSpace * oldCs = colorSpace(); + setColorSpace(dstCs); + emit(sigProfileChanged(const_cast(profile))); + + KisChangeProfileVisitor visitor(oldCs, dstCs); + m_rootLayer->accept(visitor); + + unlock(); + } +} + +double KisImage::xRes() +{ + return m_xres; +} + +double KisImage::yRes() +{ + return m_yres; +} + +void KisImage::setResolution(double xres, double yres) +{ + m_xres = xres; + m_yres = yres; +} + +TQ_INT32 KisImage::width() const +{ + return m_width; +} + +TQ_INT32 KisImage::height() const +{ + return m_height; +} + +KisPaintDeviceSP KisImage::activeDevice() +{ + if (KisPaintLayer* layer = dynamic_cast(m_activeLayer.data())) { + return layer->paintDeviceOrMask(); + } + else if (KisAdjustmentLayer* layer = dynamic_cast(m_activeLayer.data())) { + if (layer->selection()) { + return layer->selection().data(); + } + } + else if (KisGroupLayer * layer = dynamic_cast(m_activeLayer.data())) { + // Find first child + KisLayerSP child = layer->lastChild(); + while(child) + { + if (KisPaintLayer* layer = dynamic_cast(child.data())) { + return layer->paintDevice(); + } + child = child->prevSibling(); + } + KisLayerSP sibling = layer->nextSibling(); + while (sibling) { + if (KisPaintLayer* layer = dynamic_cast(sibling.data())) { + return layer->paintDevice(); + } + sibling = sibling->nextSibling(); + } + } + else if (KisLayerSP layer = m_activeLayer) { + // A weird layer -- let's not return it, but a sibling + KisLayerSP sibling = layer->nextSibling(); + while (sibling) { + if (KisPaintLayer* layer = dynamic_cast(sibling.data())) { + return layer->paintDevice(); + } + sibling = sibling->nextSibling(); + } + } + // XXX: We're buggered! + return 0; +} + +KisLayerSP KisImage::newLayer(const TQString& name, TQ_UINT8 opacity, const KisCompositeOp& compositeOp, KisColorSpace * colorstrategy) +{ + KisPaintLayer * layer; + if (colorstrategy) + layer = new KisPaintLayer(this, name, opacity, colorstrategy); + else + layer = new KisPaintLayer(this, name, opacity); + Q_CHECK_PTR(layer); + + if (compositeOp.isValid()) + layer->setCompositeOp(compositeOp); + layer->setVisible(true); + + if (m_activeLayer != 0) { + addLayer(layer, m_activeLayer->tqparent().data(), m_activeLayer->nextSibling()); + } + else { + addLayer(layer, m_rootLayer, 0); + } + activate(layer); + + return layer; +} + +void KisImage::setLayerProperties(KisLayerSP layer, TQ_UINT8 opacity, const KisCompositeOp& compositeOp, const TQString& name) +{ + if (layer && (layer->opacity() != opacity || layer->compositeOp() != compositeOp || layer->name() != name)) { + if (undo()) { + TQString oldname = layer->name(); + TQ_INT32 oldopacity = layer->opacity(); + KisCompositeOp oldCompositeOp = layer->compositeOp(); + layer->setName(name); + layer->setOpacity(opacity); + layer->setCompositeOp(compositeOp); + m_adapter->addCommand(new LayerPropsCmd(layer, this, m_adapter, oldname, oldopacity, oldCompositeOp)); + } else { + layer->setName(name); + layer->setOpacity(opacity); + layer->setCompositeOp(compositeOp); + } + } +} + +KisGroupLayerSP KisImage::rootLayer() const +{ + return m_rootLayer; +} + +KisLayerSP KisImage::activeLayer() const +{ + return m_activeLayer; +} + +KisPaintDeviceSP KisImage::projection() +{ + return m_rootLayer->projection(TQRect(0, 0, m_width, m_height)); +} + +KisLayerSP KisImage::activate(KisLayerSP layer) +{ + if (layer != m_activeLayer) { + if (m_activeLayer) m_activeLayer->deactivate(); + m_activeLayer = layer; + if (m_activeLayer) m_activeLayer->activate(); + emit sigLayerActivated(m_activeLayer); + emit sigMaskInfoChanged(); + } + + return layer; +} + +KisLayerSP KisImage::findLayer(const TQString& name) const +{ + return rootLayer()->findLayer(name); +} + +KisLayerSP KisImage::findLayer(int id) const +{ + return rootLayer()->findLayer(id); +} + + +bool KisImage::addLayer(KisLayerSP layer, KisGroupLayerSP tqparent) +{ + return addLayer(layer, tqparent, tqparent->firstChild()); +} + +bool KisImage::addLayer(KisLayerSP layer, KisGroupLayerSP tqparent, KisLayerSP aboveThis) +{ + if (!tqparent) + return false; + + const bool success = tqparent->addLayer(layer, aboveThis); + if (success) + { + KisPaintLayerSP player = dynamic_cast(layer.data()); + if (player != 0) { + + // XXX: This should also be done whenever a layer grows! + TQValueVector actions = KisMetaRegistry::instance() -> + csRegistry()->paintDeviceActionsFor(player->paintDevice()->colorSpace()); + for (uint i = 0; i < actions.count(); i++) { + actions.at(i)->act(player.data()->paintDevice(), width(), height()); + } + + connect(player, TQT_SIGNAL(sigMaskInfoChanged()), this, TQT_SIGNAL(sigMaskInfoChanged())); + } + + if (layer->extent().isValid()) layer->setDirty(); + + if (!layer->temporary()) { + emit sigLayerAdded(layer); + activate(layer); + } + + + if (!layer->temporary() && undo()) { + m_adapter->addCommand(new LayerAddCmd(m_adapter, this, layer)); + } + } + + return success; +} + +bool KisImage::removeLayer(KisLayerSP layer) +{ + if (!layer || layer->image() != this) + return false; + + if (KisGroupLayerSP tqparent = layer->tqparent()) { + // Adjustment layers should mark the layers underneath them, whose rendering + // they have cached, diryt on removal. Otherwise, the group won't be re-rendered. + KisAdjustmentLayer * al = dynamic_cast(layer.data()); + if (al) { + TQRect r = al->extent(); + lock(); // Lock the image, because we are going to dirty a lot of layers + KisLayerSP l = layer->nextSibling(); + while (l) { + KisAdjustmentLayer * al2 = dynamic_cast(l.data()); + l->setDirty(r, false); + if (al2 != 0) break; + l = l->nextSibling(); + } + unlock(); + } + KisPaintLayerSP player = dynamic_cast(layer.data()); + if (player != 0) { + disconnect(player, TQT_SIGNAL(sigMaskInfoChanged()), + this, TQT_SIGNAL(sigMaskInfoChanged())); + } + KisLayerSP l = layer->prevSibling(); + TQRect r = layer->extent(); + while (l) { + l->setDirty(r, false); + l = l->prevSibling(); + } + + KisLayerSP wasAbove = layer->nextSibling(); + KisLayerSP wasBelow = layer->prevSibling(); + const bool wasActive = layer == activeLayer(); + // sigLayerRemoved can set it to 0, we don't want that in the else of wasActive! + KisLayerSP actLayer = activeLayer(); + const bool success = tqparent->removeLayer(layer); + if (success) { + layer->setImage(0); + if (!layer->temporary() && undo()) { + m_adapter->addCommand(new LayerRmCmd(m_adapter, this, layer, tqparent, wasAbove)); + } + if (!layer->temporary()) { + emit sigLayerRemoved(layer, tqparent, wasAbove); + if (wasActive) { + if (wasBelow) + activate(wasBelow); + else if (wasAbove) + activate(wasAbove); + else if (tqparent != rootLayer()) + activate(tqparent.data()); + else + activate(rootLayer()->firstChild()); + } else { + activate(actLayer); + } + } + } + return success; + } + + return false; +} + +bool KisImage::raiseLayer(KisLayerSP layer) +{ + if (!layer) + return false; + return moveLayer(layer, layer->tqparent().data(), layer->prevSibling()); +} + +bool KisImage::lowerLayer(KisLayerSP layer) +{ + if (!layer) + return false; + if (KisLayerSP next = layer->nextSibling()) + return moveLayer(layer, layer->tqparent().data(), next->nextSibling()); + return false; +} + +bool KisImage::toTop(KisLayerSP layer) +{ + if (!layer) + return false; + return moveLayer(layer, rootLayer(), rootLayer()->firstChild()); +} + +bool KisImage::toBottom(KisLayerSP layer) +{ + if (!layer) + return false; + return moveLayer(layer, rootLayer(), 0); +} + +bool KisImage::moveLayer(KisLayerSP layer, KisGroupLayerSP tqparent, KisLayerSP aboveThis) +{ + if (!tqparent) + return false; + + KisGroupLayerSP wasParent = layer->tqparent(); + KisLayerSP wasAbove = layer->nextSibling(); + + if (wasParent.data() == tqparent.data() && wasAbove.data() == aboveThis.data()) + return false; + + lock(); + + if (!wasParent->removeLayer(layer)) { + unlock(); + return false; + } + + const bool success = tqparent->addLayer(layer, aboveThis); + + layer->setDirty(); + + unlock(); + + if (success) + { + emit sigLayerMoved(layer, wasParent, wasAbove); + if (undo()) + m_adapter->addCommand(new LayerMoveCmd(m_adapter, this, layer, wasParent, wasAbove)); + } + else //we already removed the layer above, but re-adding it failed, so... + { + emit sigLayerRemoved(layer, wasParent, wasAbove); + if (undo()) + m_adapter->addCommand(new LayerRmCmd(m_adapter, this, layer, wasParent, wasAbove)); + } + + return success; +} + +TQ_INT32 KisImage::nlayers() const +{ + return rootLayer()->numLayers() - 1; +} + +TQ_INT32 KisImage::nHiddenLayers() const +{ + return rootLayer()->numLayers(KisLayer::Hidden); +} + +void KisImage::flatten() +{ + KisGroupLayerSP oldRootLayer = m_rootLayer; + disconnect(oldRootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + + KisPaintLayer *dst = new KisPaintLayer(this, nextLayerName(), OPACITY_OPAQUE, colorSpace()); + Q_CHECK_PTR(dst); + + TQRect rc = mergedImage()->extent(); + + KisPainter gc(dst->paintDevice()); + gc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, mergedImage(), OPACITY_OPAQUE, rc.left(), rc.top(), rc.width(), rc.height()); + + m_rootLayer = new KisGroupLayer(this, "", OPACITY_OPAQUE); + connect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + + if (undo()) { + m_adapter->beginMacro(i18n("Flatten Image")); + m_adapter->addCommand(new LockImageCommand(this, true)); + m_adapter->addCommand(new KisChangeLayersCmd(m_adapter, this, oldRootLayer, m_rootLayer, "")); + } + + lock(); + + addLayer(dst, m_rootLayer, 0); + activate(dst); + + unlock(); + + notifyLayersChanged(); + + if (undo()) { + m_adapter->addCommand(new LockImageCommand(this, false)); + m_adapter->endMacro(); + } +} + + +void KisImage::mergeLayer(KisLayerSP layer) +{ + KisPaintLayer *player = new KisPaintLayer(this, layer->name(), OPACITY_OPAQUE, colorSpace()); + Q_CHECK_PTR(player); + + TQRect rc = layer->extent() | layer->nextSibling()->extent(); + + undoAdapter()->beginMacro(i18n("Merge with Layer Below")); + + //Abuse the merge visitor to only merge two layers (if either are groups they'll recursively merge) + KisMergeVisitor visitor(player->paintDevice(), rc); + layer->nextSibling()->accept(visitor); + layer->accept(visitor); + + removeLayer(layer->nextSibling()); + addLayer(player, layer->tqparent(), layer); + removeLayer(layer); + + undoAdapter()->endMacro(); +} + + +void KisImage::setModified() +{ + emit sigImageModified(); +} + +void KisImage::renderToPainter(TQ_INT32 x1, + TQ_INT32 y1, + TQ_INT32 x2, + TQ_INT32 y2, + TQPainter &painter, + KisProfile * monitorProfile, + PaintFlags paintFlags, + float exposure) +{ + + TQImage img = convertToTQImage(x1, y1, x2, y2, monitorProfile, exposure); + + TQ_INT32 w = x2 - x1 + 1; + TQ_INT32 h = y2 - y1 + 1; + + + if (paintFlags & PAINT_BACKGROUND) { + m_bkg->paintBackground(img, x1, y1); + img.setAlphaBuffer(false); + } + + if (paintFlags & PAINT_SELECTION) { + if (m_activeLayer != 0) { + m_activeLayer->paintSelection(img, x1, y1, w, h); + } + } + + if (paintFlags & PAINT_MASKINACTIVELAYERS) { + if (m_activeLayer != 0) { + m_activeLayer->paintMaskInactiveLayers(img, x1, y1, w, h); + } + } + + painter.drawImage(x1, y1, img, 0, 0, w, h); +} + +TQImage KisImage::convertToTQImage(TQ_INT32 x1, + TQ_INT32 y1, + TQ_INT32 x2, + TQ_INT32 y2, + KisProfile * profile, + float exposure) +{ + TQ_INT32 w = x2 - x1 + 1; + TQ_INT32 h = y2 - y1 + 1; + + KisPaintDeviceSP dev = m_rootLayer->projection(TQRect(x1, y1, w, h)); + TQImage img = dev->convertToTQImage(profile, x1, y1, w, h, exposure); + + if (!img.isNull()) { + +#ifdef __BIG_ENDIAN__ + uchar * data = img.bits(); + for (int i = 0; i < w * h; ++i) { + uchar r, g, b, a; + a = data[0]; + b = data[1]; + g = data[2]; + r = data[3]; + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + data += 4; + } +#endif + + return img; + } + + return TQImage(); +} + +TQImage KisImage::convertToTQImage(const TQRect& r, const TQSize& scaledImageSize, KisProfile *profile, PaintFlags paintFlags, float exposure) +{ + + if (r.isEmpty() || scaledImageSize.isEmpty()) { + return TQImage(); + } + + TQ_INT32 imageWidth = width(); + TQ_INT32 imageHeight = height(); + TQ_UINT32 pixelSize = colorSpace()->pixelSize(); + + double xScale = static_cast(imageWidth) / scaledImageSize.width(); + double yScale = static_cast(imageHeight) / scaledImageSize.height(); + + TQRect srcRect; + + srcRect.setLeft(static_cast(r.left() * xScale)); + srcRect.setRight(static_cast(ceil((r.right() + 1) * xScale)) - 1); + srcRect.setTop(static_cast(r.top() * yScale)); + srcRect.setBottom(static_cast(ceil((r.bottom() + 1) * yScale)) - 1); + + KisPaintDeviceSP mergedImage = m_rootLayer->projection(srcRect); + TQTime t; + t.start(); + + TQ_UINT8 *scaledImageData = new TQ_UINT8[r.width() * r.height() * pixelSize]; + + TQ_UINT8 *imageRow = new TQ_UINT8[srcRect.width() * pixelSize]; + const TQ_INT32 imageRowX = srcRect.x(); + + for (TQ_INT32 y = 0; y < r.height(); ++y) { + + TQ_INT32 dstY = r.y() + y; + TQ_INT32 dstX = r.x(); + TQ_INT32 srcY = (dstY * imageHeight) / scaledImageSize.height(); + + mergedImage->readBytes(imageRow, imageRowX, srcY, srcRect.width(), 1); + + TQ_UINT8 *dstPixel = scaledImageData + (y * r.width() * pixelSize); + TQ_UINT32 columnsRemaining = r.width(); + + while (columnsRemaining > 0) { + + TQ_INT32 srcX = (dstX * imageWidth) / scaledImageSize.width(); + + memcpy(dstPixel, imageRow + ((srcX - imageRowX) * pixelSize), pixelSize); + + ++dstX; + dstPixel += pixelSize; + --columnsRemaining; + } + } + kdDebug() << "Time elapsed scaling image: " << t.elapsed() << endl; + + delete [] imageRow; + + TQImage image = colorSpace()->convertToTQImage(scaledImageData, r.width(), r.height(), profile, INTENT_PERCEPTUAL, exposure); + delete [] scaledImageData; + +#ifdef __BIG_ENDIAN__ + uchar * data = image.bits(); + for (int i = 0; i < image.width() * image.height(); ++i) { + uchar r, g, b, a; + a = data[0]; + b = data[1]; + g = data[2]; + r = data[3]; + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + data += 4; + } +#endif + + if (paintFlags & PAINT_BACKGROUND) { + m_bkg->paintBackground(image, r, scaledImageSize, TQSize(imageWidth, imageHeight)); + image.setAlphaBuffer(false); + } + + if (paintFlags & PAINT_SELECTION) { + if (m_activeLayer != 0) { + m_activeLayer->paintSelection(image, r, scaledImageSize, TQSize(imageWidth, imageHeight)); + } + } + + /*if (paintFlags & PAINT_MASKINACTIVELAYERS) { + if (m_activeLayer != 0) { + m_activeLayer->paintMaskInactiveLayers(img, x1, y1, w, h); + } + }*/ + + return image; +} + +KisPaintDeviceSP KisImage::mergedImage() +{ + return m_rootLayer->projection(TQRect(0, 0, m_width, m_height)); +} + +KisColor KisImage::mergedPixel(TQ_INT32 x, TQ_INT32 y) +{ + return m_rootLayer->projection(TQRect(x, y, 1, 1))->colorAt(x, y); +} + +void KisImage::notifyLayersChanged() +{ + emit sigLayersChanged(rootLayer()); +} + +void KisImage::notifyPropertyChanged(KisLayerSP layer) +{ + emit sigLayerPropertiesChanged(layer); +} + +void KisImage::notifyImageLoaded() +{ +} + +TQRect KisImage::bounds() const +{ + return TQRect(0, 0, width(), height()); +} + + +void KisImage::setUndoAdapter(KisUndoAdapter * adapter) +{ + m_adapter = adapter; +} + + +KisUndoAdapter* KisImage::undoAdapter() const +{ + return m_adapter; +} + +bool KisImage::undo() const +{ + return (m_adapter && m_adapter->undo()); +} + +//KisGuideMgr *KisImage::guides() const +//{ +// return const_cast(&m_guides); +//} + +void KisImage::slotSelectionChanged() +{ + slotSelectionChanged(bounds()); +} + +void KisImage::slotSelectionChanged(const TQRect& r) +{ + TQRect r2(r.x() - 1, r.y() - 1, r.width() + 2, r.height() + 2); + + if (!locked()) { + emit sigActiveSelectionChanged(this); + emit sigSelectionChanged(this); + } else { + m_private->selectionChangedWhileLocked = true; + } +} + +KisColorSpace * KisImage::colorSpace() const +{ + return m_colorSpace; +} + +void KisImage::setColorSpace(KisColorSpace * colorSpace) +{ + m_colorSpace = colorSpace; + m_rootLayer->resetProjection(); + emit sigColorSpaceChanged(colorSpace); +} + +void KisImage::setRootLayer(KisGroupLayerSP rootLayer) +{ + disconnect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + + m_rootLayer = rootLayer; + + if (!locked()) { + connect(m_rootLayer, TQT_SIGNAL(sigDirty(TQRect)), this, TQT_SIGNAL(sigImageUpdated(TQRect))); + } + activate(m_rootLayer->firstChild()); +} + +void KisImage::addAnnotation(KisAnnotationSP annotation) +{ + // Find the icc annotation, if there is one + vKisAnnotationSP_it it = m_annotations.begin(); + while (it != m_annotations.end()) { + if ((*it)->type() == annotation->type()) { + *it = annotation; + return; + } + ++it; + } + m_annotations.push_back(annotation); +} + +KisAnnotationSP KisImage::annotation(TQString type) +{ + vKisAnnotationSP_it it = m_annotations.begin(); + while (it != m_annotations.end()) { + if ((*it)->type() == type) { + return *it; + } + ++it; + } + return 0; +} + +void KisImage::removeAnnotation(TQString type) +{ + vKisAnnotationSP_it it = m_annotations.begin(); + while (it != m_annotations.end()) { + if ((*it)->type() == type) { + m_annotations.erase(it); + return; + } + ++it; + } +} + +vKisAnnotationSP_it KisImage::beginAnnotations() +{ + KisProfile * profile = colorSpace()->getProfile(); + KisAnnotationSP annotation; + + if (profile) + annotation = profile->annotation(); + + if (annotation) + addAnnotation(annotation); + else + removeAnnotation("icc"); + + return m_annotations.begin(); +} + +vKisAnnotationSP_it KisImage::endAnnotations() +{ + return m_annotations.end(); +} + +KisBackgroundSP KisImage::background() const +{ + return m_bkg; +} + +KisPerspectiveGrid* KisImage::perspectiveGrid() +{ + return m_private->perspectiveGrid; +} + +#include "kis_image.moc" + diff --git a/chalk/core/kis_image.h b/chalk/core/kis_image.h new file mode 100644 index 00000000..4db23d3c --- /dev/null +++ b/chalk/core/kis_image.h @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2002 Patrick Julien + * 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_IMAGE_H_ +#define KIS_IMAGE_H_ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "KoUnit.h" + +#include "kis_composite_op.h" +#include "kis_global.h" +#include "kis_types.h" +#include "kis_annotation.h" +#include "kis_paint_device.h" + +#include + + +class DCOPObject; +class KCommand; + +class KoCommandHistory; + +class KisColorSpace; +class KisNameServer; +class KisUndoAdapter; +class KisPainter; +class KCommand; +class KisColor; +class KisFilterStrategy; +class KisImageIface; +class KisProfile; +class KisProgressDisplayInterface; +class KisPaintLayer; +class KisPerspectiveGrid; + +class KRITACORE_EXPORT KisImage : public TQObject, public KShared { + Q_OBJECT + TQ_OBJECT + +public: + KisImage(KisUndoAdapter * adapter, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorSpace, const TQString& name); + KisImage(const KisImage& rhs); + virtual ~KisImage(); + virtual DCOPObject *dcopObject(); + +public: + typedef enum enumPaintFlags { + PAINT_IMAGE_ONLY = 0, + PAINT_BACKGROUND = 1, + PAINT_SELECTION = 2, + PAINT_MASKINACTIVELAYERS = 4, + PAINT_EMBEDDED_RECT = 8 // If the current layer is an embedded part draw a rect around it + } PaintFlags; + + /// Paint the specified rect onto the painter, adjusting the colors using the + /// given profile. The exposure setting is used if the image has a high dynamic range. + virtual void renderToPainter(TQ_INT32 x1, + TQ_INT32 y1, + TQ_INT32 x2, + TQ_INT32 y2, + TQPainter &painter, + KisProfile *profile, + PaintFlags paintFlags, + float exposure = 0.0f); + /** + * Render the projection onto a TQImage. In contrast with the above method, the + * selection is not rendered. + */ + virtual TQImage convertToTQImage(TQ_INT32 x1, + TQ_INT32 y1, + TQ_INT32 x2, + TQ_INT32 y2, + KisProfile * profile, + float exposure = 0.0f); + + virtual TQImage convertToTQImage(const TQRect& r, const TQSize& fullImageSize, KisProfile *profile, PaintFlags paintFlags, float exposure = 0.0f); + + KisBackgroundSP background() const; + KisSubstrateSP substrate() const; + + +public: + + /** + * Lock the image to make sure no recompositing-causing signals get emitted + * while you're messing with the layers. Don't forget to unlock again. + */ + void lock(); + + /** + * Unlock the image to make sure the rest of Chalk learns about changes in the image + * again. If the rootLayer is dirty on unlocking, an imgUpdated signal is sent out + * immediately. + */ + void unlock(); + + /** + * Returns true if the image is locked. + */ + bool locked() const; + + KisColor backgroundColor() const; + void setBackgroundColor(const KisColor & color); + + TQString name() const; + void setName(const TQString& name); + + TQString description() const; + void setDescription(const TQString& description); + + TQString nextLayerName() const; + void rollBackLayerName(); + + KisPerspectiveGrid* perspectiveGrid(); + void createPerspectiveGrid(TQPoint topLeft, TQPoint topRight, TQPoint bottomRight, TQPoint bottomLeft); + /** + * Resize the image to the specified width and height. The resize + * method handles the creating on an undo step itself. + * + * @param w the new width of the image + * @param h the new height of the image + * @param x the x position of the crop on all layer if cropLayers is true + * @param y the y position of the crop on all layer if cropLayers is true + * @param cropLayers if true, all layers are cropped to the new size. + */ + void resize(TQ_INT32 w, TQ_INT32 h, TQ_INT32 x = 0, TQ_INT32 y = 0, bool cropLayers = false); + + /** + * Resize the image to the specified width and height. The resize + * method handles the creating on an undo step itself. + * + * @param rc the rect describing the new width and height of the image + * @param cropLayers if true, all layers are cropped to the new rect + */ + void resize(const TQRect& rc, bool cropLayers = false); + + void scale(double sx, double sy, KisProgressDisplayInterface *m_progress, KisFilterStrategy *filterStrategy); + void rotate(double radians, KisProgressDisplayInterface *m_progress); + void shear(double angleX, double angleY, KisProgressDisplayInterface *m_progress); + + /** + * Convert the image and all its layers to the dstColorSpace + */ + void convertTo(KisColorSpace * dstColorSpace, TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + // Get the profile associated with this image + KisProfile * getProfile() const; + + /** + * Set the profile of the image to the new profile and do the same for + * all layers that have the same colorspace and profile as the image. + * It doesn't do any pixel conversion. + * + * This is essential if you have loaded an image that didn't + * have an embedded profile to which you want to attach the right profile. + */ + + void setProfile(const KisProfile * profile); + + /** + * Replace the current undo adapter with the specified undo adapter. + * The current undo adapter will _not_ be deleted. + */ + void setUndoAdapter(KisUndoAdapter * undoAdapter); + + /** + * Returns the current undo adapter. You can add new commands to the + * undo stack using the adapter + */ + KisUndoAdapter *undoAdapter() const; + + /** + * Returns true if this image wants undo information, false otherwise + */ + bool undo() const; + /** + * Tell the image it's modified; this emits the sigImageModified signal. This happens + * when the image needs to be saved + */ + void setModified(); + + KisColorSpace * colorSpace() const; + + // Resolution of the image == XXX: per inch? + double xRes(); + double yRes(); + void setResolution(double xres, double yres); + + TQ_INT32 width() const; + TQ_INT32 height() const; + + bool empty() const; + + /** + * returns a paintdevice that contains the merged layers of this image, within + * the bounds of this image (with the colorspace and profile of this image) + */ + KisPaintDeviceSP mergedImage(); + + /* + * Returns the colour of the merged image at pixel (x, y). + */ + KisColor mergedPixel(TQ_INT32 x, TQ_INT32 y); + + /// Creates a new paint layer with the specified properties, adds it to the image, and returns it. + KisLayerSP newLayer(const TQString& name, TQ_UINT8 opacity, + const KisCompositeOp& compositeOp = KisCompositeOp(), KisColorSpace * colorstrategy = 0); + + /// Get the active painting device. Returns 0 if the active layer does not have a paint device. + KisPaintDeviceSP activeDevice(); + + void setLayerProperties(KisLayerSP layer, TQ_UINT8 opacity, const KisCompositeOp& compositeOp, const TQString& name); + + KisGroupLayerSP rootLayer() const; + KisLayerSP activeLayer() const; + + /// Return the projection; that is, the complete, composited representation + /// of this image. + KisPaintDeviceSP projection(); + + KisLayerSP activate(KisLayerSP layer); + KisLayerSP findLayer(const TQString& name) const; + KisLayerSP findLayer(int id) const; + + /// Move layer to specified position + bool moveLayer(KisLayerSP layer, KisGroupLayerSP tqparent, KisLayerSP aboveThis); + + /** + * Add an already existing layer to the image. The layer is put on top + * of the layers in the specified layergroup + * @param layer the layer to be added + * @param tqparent the tqparent layer + */ + bool addLayer(KisLayerSP layer, KisGroupLayerSP tqparent); + + /** + * Add already existing layer to image. + * + * @param layer the layer to be added + * @param tqparent the tqparent layer + * @param aboveThis in the list with child layers of the specified + * tqparent, add this layer above the specified sibling. + * if 0, the layer is put in the lowermost position in + * its group. + * @param notify If true, the image is immediately recomposited, if false, + * no recomposition is done yet. The added layer is all + * + * returns false if adding the layer didn't work, true if the layer got added + */ + bool addLayer(KisLayerSP layer, KisGroupLayerSP tqparent, KisLayerSP aboveThis); + + /// Remove layer + bool removeLayer(KisLayerSP layer); + + /// Move layer up one slot + bool raiseLayer(KisLayerSP layer); + + /// Move layer down one slot + bool lowerLayer(KisLayerSP layer); + + /// Move layer to top slot + bool toTop(KisLayerSP layer); + + /// Move layer to bottom slot + bool toBottom(KisLayerSP layer); + + TQ_INT32 nlayers() const; + TQ_INT32 nHiddenLayers() const; + + KCommand *raiseLayerCommand(KisLayerSP layer); + KCommand *lowerLayerCommand(KisLayerSP layer); + KCommand *topLayerCommand(KisLayerSP layer); + KCommand *bottomLayerCommand(KisLayerSP layer); + + /** + * Merge all visible layers and discard hidden ones. + * The resulting layer will be activated. + */ + void flatten(); + + /** + * Merge the specified layer with the layer + * below this layer, remove the specified layer. + */ + void mergeLayer(KisLayerSP l); + + TQRect bounds() const; + + /// use if the layers have changed _completely_ (eg. when flattening) + void notifyLayersChanged(); + + void notifyPropertyChanged(KisLayerSP layer); + + void notifyImageLoaded(); + + void notifyLayerUpdated(KisLayerSP layer, TQRect rc); + + void setColorSpace(KisColorSpace * colorSpace); + void setRootLayer(KisGroupLayerSP rootLayer); + + //KisGuideMgr *guides() const; + + /** + * Add an annotation for this image. This can be anything: Gamma, EXIF, etc. + * Note that the "icc" annotation is reserved for the colour strategies. + * If the annotation already exists, overwrite it with this one. + */ + void addAnnotation(KisAnnotationSP annotation); + + /** get the annotation with the given type, can return 0 */ + KisAnnotationSP annotation(TQString type); + + /** delete the annotation, if the image contains it */ + void removeAnnotation(TQString type); + + /** + * Start of an iteration over the annotations of this image (including the ICC Profile) + */ + vKisAnnotationSP_it beginAnnotations(); + + /** end of an iteration over the annotations of this image */ + vKisAnnotationSP_it endAnnotations(); + +signals: + + void sigActiveSelectionChanged(KisImageSP image); + void sigSelectionChanged(KisImageSP image); + void sigSelectionChanged(KisImageSP image, const TQRect& rect); + + /// Emitted after a different layer is made active. + void sigLayerActivated(KisLayerSP layer); + + /// Emitted after a layer is added: you can find out where by asking it for its tqparent(), et al. + void sigLayerAdded(KisLayerSP layer); + + /** Emitted after a layer is removed. + It's no longer in the image, but still exists, so @p layer is valid. + + @param layer the removed layer + @param tqparent the tqparent of the layer, before it was removed + @param wasAboveThis the layer it was above, before it was removed. + */ + void sigLayerRemoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAboveThis); + + /** Emitted after a layer is moved to a different position under its tqparent layer, or its tqparent changes. + + @param previousParent the tqparent of the layer, before it was moved + @param wasAboveThis the layer it was above, before it was moved. + */ + void sigLayerMoved(KisLayerSP layer, KisGroupLayerSP previousParent, KisLayerSP wasAboveThis); + + /// Emitted after a layer's properties (visible, locked, opacity, composite op, name, ...) change + void sigLayerPropertiesChanged(KisLayerSP layer); + + /** Emitted when the list of layers has changed completely. + This means e.g. when the image is flattened, but not when it is rotated, + as the layers only change internally then. + */ + void sigLayersChanged(KisGroupLayerSP rootLayer); + + /** + * Emitted whenever an action has caused the image to be recomposited. This happens + * after calls to recomposite(). + * + * @param rc The rect that has been recomposited. + */ + void sigImageUpdated(TQRect rc); + + /** + * Emitted whenever a layer is modified. + * + * @param layer The layer that has been modified. + * @param rc The rectangle that has been modified. + */ + void sigLayerUpdated(KisLayerSP layer, TQRect rc); + + /** + * Emitted whenever the image has been modified, so that it doesn't match with the version saved on disk. + */ + void sigImageModified(); + + void sigSizeChanged(TQ_INT32 w, TQ_INT32 h); + void sigProfileChanged(KisProfile * profile); + void sigColorSpaceChanged(KisColorSpace* cs); + + + /// Emitted when any layer's tqmask info got updated (or when the current layer changes) + void sigMaskInfoChanged(); +public slots: + void slotSelectionChanged(); + void slotSelectionChanged(const TQRect& r); + + +private: + KisImage& operator=(const KisImage& rhs); + void init(KisUndoAdapter * adapter, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorSpace, const TQString& name); + void emitSizeChanged(); + +private: + + KURL m_uri; + TQString m_name; + TQString m_description; + + TQ_INT32 m_width; + TQ_INT32 m_height; + + double m_xres; + double m_yres; + + KoUnit::Unit m_unit; + + KisColorSpace * m_colorSpace; + + bool m_dirty; + TQRect m_dirtyRect; + + KisBackgroundSP m_bkg; + + KisGroupLayerSP m_rootLayer; // The layers are contained in here + KisLayerSP m_activeLayer; + + KisNameServer *m_nserver; + KisUndoAdapter *m_adapter; + //KisGuideMgr m_guides; + + DCOPObject *m_dcop; + + vKisAnnotationSP m_annotations; + + class KisImagePrivate; + KisImagePrivate * m_private; + +}; + +#endif // KIS_IMAGE_H_ diff --git a/chalk/core/kis_image_iface.cc b/chalk/core/kis_image_iface.cc new file mode 100644 index 00000000..a52cc8a4 --- /dev/null +++ b/chalk/core/kis_image_iface.cc @@ -0,0 +1,97 @@ +/* + * This file is part of the KDE project + * + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_image_iface.h" +#include "kis_types.h" +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_paint_device_iface.h" +#include + +KisImageIface::KisImageIface( KisImage * img ) + : DCOPObject(img->name().utf8()) +{ + m_img = img; +} + +int KisImageIface::height() const +{ + return m_img->height(); +} + +int KisImageIface::width() const +{ + return m_img->width(); +} + +void KisImageIface::setName(const TQString& name) +{ + m_img->setName( name ); +} + +void KisImageIface::rotateCCW() +{ + // XXX: Add progress display if there is a view + m_img->rotate(270, 0); +} + +void KisImageIface::rotateCW() +{ + // XXX: Add progressdisplay if there is a view + m_img->rotate(90, 0); +} + +void KisImageIface::rotate180() +{ + // XXX: Add progressdisplay if there is a view + m_img->rotate(180, 0); +} + +void KisImageIface::rotate(double angle) +{ + // XXX: Add progressdisplay if there is a view + angle *= M_PI/180; + m_img->rotate(angle, 0); +} + +DCOPRef KisImageIface::activeDevice() +{ + KisPaintDeviceSP dev = m_img->activeDevice(); + + if( !dev ) + return DCOPRef(); + else + return DCOPRef( kapp->dcopClient()->appId(), + dev->dcopObject()->objId(), + "KisPaintDeviceIface"); + +} + +DCOPRef KisImageIface::colorSpace() const +{ + KisColorSpace * cs = m_img->colorSpace(); + if ( !cs ) + return DCOPRef(); + else + return DCOPRef( kapp->dcopClient()->appId(), + cs->dcopObject()->objId(), + "KisColorSpaceIface" ); +} diff --git a/chalk/core/kis_image_iface.h b/chalk/core/kis_image_iface.h new file mode 100644 index 00000000..acf36738 --- /dev/null +++ b/chalk/core/kis_image_iface.h @@ -0,0 +1,65 @@ +/* + * This file is part of the KDE project + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_IMAGE_IFACE_H +#define KIS_IMAGE_IFACE_H + +#include +#include + + +#include + +class KisImage; +class KisPaintDeviceIface; + +class KisImageIface : virtual public DCOPObject +{ + K_DCOP +public: + KisImageIface( KisImage *img_ ); +k_dcop: + + int height() const; + int width() const; + + void setName(const TQString& name); + + void rotateCCW(); + void rotateCW(); + void rotate180(); + void rotate(double angle); + + /** + * Get the active painting device. + */ + DCOPRef activeDevice(); + + /** + * Get the colorspace of this image + */ + DCOPRef colorSpace() const; + + +private: + + KisImage *m_img; +}; + +#endif diff --git a/chalk/core/kis_imagepipe_brush.cc b/chalk/core/kis_imagepipe_brush.cc new file mode 100644 index 00000000..5cef04d6 --- /dev/null +++ b/chalk/core/kis_imagepipe_brush.cc @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_imagepipe_brush.h" +#include "kis_brush.h" +#include "kis_alpha_mask.h" +#include "kis_layer.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" + + +KisPipeBrushParasite::KisPipeBrushParasite(const TQString& source) +{ + needsMovement = false; + TQRegExp basicSplitter(" ", true); + TQRegExp parasiteSplitter(":", true); + TQStringList parasites = TQStringList::split(basicSplitter, source); + for (uint i = 0; i < parasites.count(); i++) { + TQStringList splitted = TQStringList::split(parasiteSplitter, *parasites.at(i)); + if (splitted.count() != 2) { + kdWarning(41001) << "Wrong count for this parasite key/value:" << *parasites.at(i) << endl; + continue; + } + TQString index = *splitted.at(0); + if (index == "dim") { + dim = (*splitted.at(1)).toInt(); + if (dim < 1 || dim > MaxDim) { + dim = 1; + } + } else if (index.startsWith("sel")) { + int selIndex = index.mid(strlen("sel")).toInt(); + if (selIndex >= 0 && selIndex < dim) { + TQString selectionMode = *splitted.at(1); + if (selectionMode == "incremental") + selection[selIndex] = Incremental; + else if (selectionMode == "angular") { + selection[selIndex] = Angular; + needsMovement = true; + } else if (selectionMode == "random") + selection[selIndex] = Random; + else if (selectionMode == "pressure") + selection[selIndex] = Pressure; + else if (selectionMode == "xtilt") + selection[selIndex] = TiltX; + else if (selectionMode == "ytilt") + selection[selIndex] = TiltY; + else + selection[selIndex] = Constant; + } else { + kdWarning(41001)<< "Sel: wrong index: " << selIndex << "(dim = " << dim << ")" << endl; + } + } else if (index.startsWith("rank")) { + int rankIndex = index.mid(strlen("rank")).toInt(); + if (rankIndex < 0 || rankIndex > dim) { + kdWarning(41001) << "Rankindex out of range: " << rankIndex << endl; + continue; + } + rank[rankIndex] = (*splitted.at(1)).toInt(); + } else if (index == "ncells") { + ncells = (*splitted.at(1)).toInt(); + if (ncells < 1 ) { + kdWarning(41001) << "ncells out of range: " << ncells << endl; + ncells = 1; + } + } + } + + for (int i = 0; i < dim; i++) { + index[i] = 0; + } + + setBrushesCount(); +} + +void KisPipeBrushParasite::setBrushesCount() { + // I assume ncells is correct. If it isn't, complain to the parasite header. + brushesCount[0] = ncells / rank[0]; + for (int i = 1; i < dim; i++) { + brushesCount[i] = brushesCount[i-1] / rank[i]; + } +} + +bool KisPipeBrushParasite::saveToDevice(TQIODevice* dev) const { + // write out something like + // ncells: dim: rank0: sel0: <...> + + TQTextStream stream(dev); + /// FIXME things like step, placement and so are not added (nor loaded, as a matter of fact) + stream << ncells << " ncells:" << ncells << " dim:" << dim; + + for (int i = 0; i < dim; i++) { + stream << " rank" << i << ":" << rank[i] << " sel" << i << ":"; + switch (selection[i]) { + case Constant: stream << "constant"; break; + case Incremental: stream << "incremental"; break; + case Angular: stream << "angular"; break; + case Velocity: stream << "velocity"; break; + case Random: stream << "random"; break; + case Pressure: stream << "pressure"; break; + case TiltX: stream << "xtilt"; break; + case TiltY: stream << "ytilt"; break; + } + } + + return true; +} + +KisImagePipeBrush::KisImagePipeBrush(const TQString& filename) : super(filename) +{ + m_brushType = INVALID; + m_numOfBrushes = 0; + m_currentBrush = 0; +} + +KisImagePipeBrush::KisImagePipeBrush(const TQString& name, int w, int h, + TQValueVector< TQValueVector > devices, + TQValueVector modes) + : super("") +{ + Q_ASSERT(devices.count() == modes.count()); + Q_ASSERT(devices.count() > 0); + Q_ASSERT(devices.count() < 2); // XXX Multidimensionals not supported yet, change to MaxDim! + + setName(name); + + m_parasite.dim = devices.count(); + // XXX Change for multidim! : + m_parasite.ncells = devices.at(0).count(); + m_parasite.rank[0] = m_parasite.ncells; + m_parasite.selection[0] = modes.at(0); + // XXX needsmovement! + + m_parasite.setBrushesCount(); + + for (uint i = 0; i < devices.at(0).count(); i++) { + m_brushes.append(new KisBrush(devices.at(0).at(i), 0, 0, w, h)); + } + + setImage(m_brushes.at(0)->img()); + + m_brushType = PIPE_IMAGE; +} + +KisImagePipeBrush::~KisImagePipeBrush() +{ + m_brushes.setAutoDelete(true); + m_brushes.clear(); +} + +bool KisImagePipeBrush::load() +{ + TQFile file(filename()); + file.open(IO_ReadOnly); + m_data = file.readAll(); + file.close(); + return init(); +} + +bool KisImagePipeBrush::init() +{ + // XXX: this doesn't correctly load the image pipe brushes yet. + + // XXX: This stuff is in utf-8, too. + // The first line contains the name -- this means we look until we arrive at the first newline + TQValueVector line1; + + TQ_UINT32 i = 0; + + while (m_data[i] != '\n' && i < m_data.size()) { + line1.append(m_data[i]); + i++; + } + setName(i18n(TQString::fromUtf8(&line1[0], i).ascii())); + + i++; // Skip past the first newline + + // The second line contains the number of brushes, separated by a space from the parasite + + // XXX: This stuff is in utf-8, too. + TQValueVector line2; + while (m_data[i] != '\n' && i < m_data.size()) { + line2.append(m_data[i]); + i++; + } + + TQString paramline = TQString::fromUtf8((&line2[0]), line2.size()); + TQ_UINT32 m_numOfBrushes = paramline.left(paramline.tqfind(' ')).toUInt(); + m_parasite = paramline.mid(paramline.tqfind(' ') + 1); + i++; // Skip past the second newline + + TQ_UINT32 numOfBrushes = 0; + while (numOfBrushes < m_numOfBrushes && i < m_data.size()){ + KisBrush * brush = new KisBrush(name() + "_" + numOfBrushes, + m_data, + i); + Q_CHECK_PTR(brush); + + m_brushes.append(brush); + + numOfBrushes++; + } + + if (!m_brushes.isEmpty()) { + setValid(true); + if (m_brushes.at( 0 )->brushType() == MASK) { + m_brushType = PIPE_MASK; + } + else { + m_brushType = PIPE_IMAGE; + } + setSpacing(m_brushes.at(m_brushes.count() - 1)->spacing()); + setWidth(m_brushes.at(0)->width()); + setHeight(m_brushes.at(0)->height()); + } + + m_data.resize(0); + return true; +} + +bool KisImagePipeBrush::save() +{ + TQFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + bool ok = saveToDevice(TQT_TQIODEVICE(&file)); + file.close(); + return ok; +} + +bool KisImagePipeBrush::saveToDevice(TQIODevice* dev) const +{ + TQCString utf8Name = name().utf8(); // Names in v2 brushes are in UTF-8 + char const* name = utf8Name.data(); + int len = tqstrlen(name); + + if (parasite().dim != 1) { + kdWarning(41001) << "Save to file for pipe brushes with dim != not yet supported!" << endl; + return false; + } + + // Save this pipe brush: first the header, and then all individual brushes consecutively + // (this needs some care for when we have > 1 dimension), FIXME + + // Gimp Pipe Brush header format: Name\n \n + + // The name\n + if (dev->writeBlock(name, len) == -1) + return false; + + if (dev->putch('\n') == -1) + return false; + + // Write the parasite (also writes number of brushes) + if (!m_parasite.saveToDevice(dev)) + return false; + + if (dev->putch('\n') == -1) + return false; + + // + for (uint i = 0; i < m_brushes.count(); i++) + if (!m_brushes.at(i)->saveToDevice(dev)) + return false; + + return true; +} + +TQImage KisImagePipeBrush::img() +{ + if (m_brushes.isEmpty()) { + return 0; + } + else { + return m_brushes.at(0)->img(); + } +} + +KisAlphaMaskSP KisImagePipeBrush::tqmask(const KisPaintInformation& info, double subPixelX, double subPixelY) const +{ + if (m_brushes.isEmpty()) return 0; + selectNextBrush(info); + return m_brushes.at(m_currentBrush)->tqmask(info, subPixelX, subPixelY); +} + +KisPaintDeviceSP KisImagePipeBrush::image(KisColorSpace * colorSpace, const KisPaintInformation& info, double subPixelX, double subPixelY) const +{ + if (m_brushes.isEmpty()) return 0; + selectNextBrush(info); + return m_brushes.at(m_currentBrush)->image(colorSpace, info, subPixelX, subPixelY); +} + +void KisImagePipeBrush::setParasiteString(const TQString& parasite) +{ + m_parasiteString = parasite; + m_parasite = KisPipeBrushParasite(parasite); +} + + +enumBrushType KisImagePipeBrush::brushType() const +{ + if (m_brushType == PIPE_IMAGE && useColorAsMask()) { + return PIPE_MASK; + } + else { + return m_brushType; + } +} + +bool KisImagePipeBrush::useColorAsMask() const +{ + if (m_brushes.count() > 0) { + return m_brushes.at(0)->useColorAsMask(); + } + else { + return false; + } +} + +void KisImagePipeBrush::setUseColorAsMask(bool useColorAsMask) +{ + for (uint i = 0; i < m_brushes.count(); i++) { + m_brushes.at(i)->setUseColorAsMask(useColorAsMask); + } +} + +bool KisImagePipeBrush::hasColor() const +{ + if (m_brushes.count() > 0) { + return m_brushes.at(0)->hasColor(); + } + else { + return false; + } +} + +KisBoundary KisImagePipeBrush::boundary() { + Q_ASSERT(!m_brushes.isEmpty()); + return m_brushes.at(0)->boundary(); +} + +void KisImagePipeBrush::selectNextBrush(const KisPaintInformation& info) const { + m_currentBrush = 0; + double angle; + for (int i = 0; i < m_parasite.dim; i++) { + int index = m_parasite.index[i]; + switch (m_parasite.selection[i]) { + case KisPipeBrushParasite::Constant: break; + case KisPipeBrushParasite::Incremental: + index = (index + 1) % m_parasite.rank[i]; break; + case KisPipeBrushParasite::Random: + index = int(float(m_parasite.rank[i])*KApplication::random() / RAND_MAX); break; + case KisPipeBrushParasite::Pressure: + index = static_cast(info.pressure * (m_parasite.rank[i] - 1) + 0.5); break; + case KisPipeBrushParasite::Angular: + // + M_PI_2 to be compatible with the gimp + angle = atan2(info.movement.y(), info.movement.x()) + M_PI_2; + // We need to be in the [0..2*Pi[ interval so that we can more nicely select it + if (angle < 0) + angle += 2.0 * M_PI; + else if (angle > 2.0 * M_PI) + angle -= 2.0 * M_PI; + index = static_cast(angle / (2.0 * M_PI) * m_parasite.rank[i]); + break; + default: + kdWarning(41001) << "This parasite selectionMode has not been implemented. Reselecting" + << " to Incremental" << endl; + m_parasite.selection[i] = KisPipeBrushParasite::Incremental; + index = 0; + } + m_parasite.index[i] = index; + m_currentBrush += m_parasite.brushesCount[i] * index; + } +} + +bool KisImagePipeBrush::canPaintFor(const KisPaintInformation& info) { + if (info.movement.isNull() && m_parasite.needsMovement) + return false; + return true; +} + +void KisImagePipeBrush::makeMaskImage() { + for (uint i = 0; i < m_brushes.count(); i++) + m_brushes.at(i)->makeMaskImage(); + + setBrushType(PIPE_MASK); + setUseColorAsMask(false); +} + +KisImagePipeBrush* KisImagePipeBrush::clone() const { + // The obvious way of cloning each brush in this one doesn't work for some reason... + + // XXX Multidimensionals not supported yet, change together with the constructor... + TQValueVector< TQValueVector > devices; + TQValueVector modes; + + devices.push_back(TQValueVector()); + modes.push_back(m_parasite.selection[0]); + + for (uint i = 0; i < m_brushes.count(); i++) { + KisPaintDevice* pd = new KisPaintDevice( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), "clone pd" ); + pd->convertFromTQImage(m_brushes.at(i)->img(), ""); + devices.at(0).append(pd); + } + + KisImagePipeBrush* c = new KisImagePipeBrush(name(), width(), height(), devices, modes); + // XXX clean up devices + + return c; +} + +#include "kis_imagepipe_brush.moc" + diff --git a/chalk/core/kis_imagepipe_brush.h b/chalk/core/kis_imagepipe_brush.h new file mode 100644 index 00000000..bc54204b --- /dev/null +++ b/chalk/core/kis_imagepipe_brush.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_IMAGEPIPE_BRUSH_ +#define KIS_IMAGEPIPE_BRUSH_ + +#include +#include +#include +#include +#include + +#include + +#include "kis_resource.h" +#include "kis_brush.h" +#include "kis_global.h" + +class TQCString; +class TQImage; +class TQPoint; +class TQSize; + +/** + * The parasite info that gets loaded from the terribly documented gimp pipe brush parasite. + * We only store data we actually use. + * BC: How it seems the dimension stuff interacts with rank, selectionMode and the actual + * selection of a brush to be drawn. So apparantly you can have at most 4 'dimensions'. + * Each dimension has a number of brushes, the rank. Each dimension has an associated selection + * mode and placement mode (which we don't use). The selection mode says us in which way + * which of the brushes or brush sets will be selected. In the case of a 1-dimensional pipe + * brush it is easy. + * However, when there are more dimensions it is a bit harder. You can according to the gimp + * source maximally use 4 dimensions. When you want to select a brush, you first go to the + * first dimension. Say it has a rank of 2. The code chooses one of the 2 according to the + * selection mode. Say we choose 2. Then the currentBrush will skip over all the brushes + * from the first element in dimension 1. Then in dimension we pick again from the choices + * we have in dimension 2. We again add the appropriate amount to currentBrush. And so on, + * until we have reached dimension dim. Or at least, that is how it looks like, we'll know + * for sure when we can test it better with >1 dim brushes and Angular selectionMode. + **/ +class KisPipeBrushParasite { +public: + /// Set some default values + KisPipeBrushParasite() : ncells(0), dim(0), needsMovement(false) { + for (int i = 0; i < MaxDim; i++) { + rank[i] = index[i] = brushesCount[i] = 0; + selection[i] = Constant; + } + } + /// Initializes the brushesCount helper + void setBrushesCount(); + /// Load the parasite from the source string + KisPipeBrushParasite(const TQString& source); + /** + * Saves a GIMP-compatible representation of this parasite to the device. Also writes the + * number of brushes (== ncells) (no trailing '\n') */ + bool saveToDevice(TQIODevice* dev) const; + + /** Velocity won't be supported, atm Angular and Tilt aren't either, but have chances of implementation */ + enum SelectionMode { + Constant, Incremental, Angular, Velocity, Random, Pressure, TiltX, TiltY + }; + enum Placement { DefaultPlacement, ConstantPlacement, RandomPlacement }; + static int const MaxDim = 4; + //TQ_INT32 step; + TQ_INT32 ncells; + TQ_INT32 dim; + // Apparantly only used for editing a pipe brush, which we won't at the moment + // TQ_INT32 cols, rows; + // TQ_INT32 cellwidth, cellheight; + // Aparantly the gimp doesn't use this anymore? Anyway it is a bit weird to + // paint at someplace else than where your cursor displays it will... + //Placement placement; + TQ_INT32 rank[MaxDim]; + SelectionMode selection[MaxDim]; + /// The total count of brushes in each dimension (helper) + TQ_INT32 brushesCount[MaxDim]; + /// The current index in each dimension, so that the selection modes know where to start + TQ_INT32 index[MaxDim]; + /// If true, the brush won't be painted when there is no motion + bool needsMovement; +}; + + +class KisImagePipeBrush : public KisBrush { + typedef KisBrush super; + Q_OBJECT + TQ_OBJECT + +public: + KisImagePipeBrush(const TQString& filename); + /** + * Specialized constructor that makes a new pipe brush from a sequence of samesize + * devices. The fact that it's a vector of a vector, is to support multidimensional + * brushes (not yet supported!) */ + KisImagePipeBrush(const TQString& name, int w, int h, + TQValueVector< TQValueVector > devices, + TQValueVector modes); + virtual ~KisImagePipeBrush(); + + virtual bool load(); + virtual bool save(); + /// Will call KisBrush's saveToDevice as well + virtual bool saveToDevice(TQIODevice* dev) const; + + /** + @return the next image in the pipe. + */ + virtual TQImage img(); + + /** + @return the next tqmask in the pipe. + */ + virtual KisAlphaMaskSP tqmask(const KisPaintInformation& info, + double subPixelX = 0, double subPixelY = 0) const; + virtual KisPaintDeviceSP image(KisColorSpace * colorSpace, const KisPaintInformation& info, + double subPixelX = 0, double subPixelY = 0) const; + + virtual bool useColorAsMask() const; + virtual void setUseColorAsMask(bool useColorAsMask); + virtual bool hasColor() const; + + virtual enumBrushType brushType() const; + + virtual KisBoundary boundary(); + + KisPipeBrushParasite const& parasite() const { return m_parasite; } + + virtual bool canPaintFor(const KisPaintInformation& info); + + virtual void makeMaskImage(); + + virtual KisImagePipeBrush* clone() const; + +private: + bool init(); + void setParasiteString(const TQString& parasite); + void selectNextBrush(const KisPaintInformation& info) const; + + TQString m_name; + TQString m_parasiteString; // Contains instructions on how to use the brush + mutable KisPipeBrushParasite m_parasite; + TQ_UINT32 m_numOfBrushes; + mutable TQ_UINT32 m_currentBrush; + + TQByteArray m_data; + mutable TQPtrList m_brushes; + + enumBrushType m_brushType; + +}; + +#endif // KIS_IMAGEPIPE_BRUSH_ diff --git a/chalk/core/kis_iterator.cc b/chalk/core/kis_iterator.cc new file mode 100644 index 00000000..0e0c2d81 --- /dev/null +++ b/chalk/core/kis_iterator.cc @@ -0,0 +1,142 @@ +/* This file is part of the KDE project + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + + +#include + +#include + +#include "kis_iterator.h" +#include "kis_datamanager.h" +#include "kis_tilediterator.h" + +KisRectIterator::KisRectIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, bool writable) +{ + m_iter = new KisTiledRectIterator(dm, x, y, w, h, writable); +} +KisRectIterator::KisRectIterator(const KisRectIterator& rhs) +{ + m_iter = rhs.m_iter; +} + +KisRectIterator& KisRectIterator::operator=(const KisRectIterator& rhs) +{ + m_iter = rhs.m_iter; + return *this; +} + +KisRectIterator::~KisRectIterator() +{ +} + +TQ_UINT8 * KisRectIterator::rawData() const { return m_iter->rawData();} + +const TQ_UINT8 * KisRectIterator::oldRawData() const { return m_iter->oldRawData();} + +TQ_INT32 KisRectIterator::nConseqPixels() const { return m_iter->nConseqPixels(); } + +KisRectIterator & KisRectIterator::operator+=(int n) { m_iter->operator+=(n); return *this; } + +KisRectIterator & KisRectIterator::operator++() { m_iter->operator++(); return *this; } + +bool KisRectIterator::isDone() const { return m_iter->isDone(); } + +TQ_INT32 KisRectIterator::x() const { return m_iter->x(); } +TQ_INT32 KisRectIterator::y() const { return m_iter->y(); } + +//--------------------------------------------------------------------------------------- + +KisHLineIterator::KisHLineIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable) +{ + m_iter = new KisTiledHLineIterator(dm, x, y, w, writable); +} + +KisHLineIterator::KisHLineIterator(const KisHLineIterator& rhs) +{ + m_iter = rhs.m_iter; +} + +KisHLineIterator& KisHLineIterator::operator=(const KisHLineIterator& rhs) +{ + + m_iter=rhs.m_iter; + return *this; +} + +KisHLineIterator::~KisHLineIterator() +{ +} + +TQ_UINT8 *KisHLineIterator::rawData() const +{ + return m_iter->rawData(); +} + +const TQ_UINT8 *KisHLineIterator::oldRawData() const { return m_iter->oldRawData();} + +KisHLineIterator & KisHLineIterator::operator++() { m_iter->operator++(); return *this; } + +TQ_INT32 KisHLineIterator::nConseqHPixels() const { return m_iter->nConseqHPixels(); } + +KisHLineIterator & KisHLineIterator::operator+=(int n) { m_iter->operator+=(n); return *this; } + +KisHLineIterator & KisHLineIterator::operator--() { m_iter->operator--(); return *this; } + +bool KisHLineIterator::isDone() const { return m_iter->isDone(); } + +TQ_INT32 KisHLineIterator::x() const { return m_iter->x(); } + +TQ_INT32 KisHLineIterator::y() const { return m_iter->y(); } + +void KisHLineIterator::nextRow() { m_iter->nextRow(); } + +//--------------------------------------------------------------------------------------- + +KisVLineIterator::KisVLineIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable) +{ + m_iter = new KisTiledVLineIterator(dm, x, y, h, writable); +} + +KisVLineIterator::KisVLineIterator(const KisVLineIterator& rhs) +{ + m_iter = rhs.m_iter; +} + +KisVLineIterator& KisVLineIterator::operator=(const KisVLineIterator& rhs) +{ + m_iter = rhs.m_iter; + return *this; +} + +KisVLineIterator::~KisVLineIterator() +{ +} + +TQ_UINT8 *KisVLineIterator::rawData() const { return m_iter->rawData();} + +const TQ_UINT8 * KisVLineIterator::oldRawData() const { return m_iter->oldRawData();} + +KisVLineIterator & KisVLineIterator::operator++() { m_iter->operator++(); return *this; } + +bool KisVLineIterator::isDone() const { return m_iter->isDone(); } + +TQ_INT32 KisVLineIterator::x() const { return m_iter->x(); } + +TQ_INT32 KisVLineIterator::y() const { return m_iter->y(); } + +void KisVLineIterator::nextCol() { return m_iter->nextCol(); } diff --git a/chalk/core/kis_iterator.h b/chalk/core/kis_iterator.h new file mode 100644 index 00000000..893461a5 --- /dev/null +++ b/chalk/core/kis_iterator.h @@ -0,0 +1,173 @@ +/* This file is part of the KDE project + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#ifndef KIS_ITERATOR_H_ +#define KIS_ITERATOR_H_ + +#include +#include + +class KisTiledRectIterator; +typedef KSharedPtr KisTiledRectIteratorSP; + +class KisTiledVLineIterator; +typedef KSharedPtr KisTiledVLineIteratorSP; + +class KisTiledHLineIterator; +typedef KSharedPtr KisTiledHLineIteratorSP; + +class KisDataManager; + +/** + * The KisRectIterator iterators over a rectangular area in the most efficient order. That is, + * there is no guarantee that the iterator will work scanline by scanline. + */ +class KisRectIterator +{ + + +public: + KisRectIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, bool writable); + +public: + virtual ~KisRectIterator(); + KisRectIterator(const KisRectIterator& rhs); + KisRectIterator& operator=(const KisRectIterator& rhs); + + +public: + /// returns a pointer to the pixel data. Do NOT interpret the data - leave that to a colorstrategy + TQ_UINT8 * rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const TQ_UINT8 * oldRawData() const; + + /// Returns the number of consequtive pixels that we point at + /// This is useful for optimizing + TQ_INT32 nConseqPixels() const; + + /// Advances a number of pixels until it reaches the end of the rect + KisRectIterator & operator+=(int n); + + /// Advances one pixel going to the beginning of the next line when it reaches the end of a line + KisRectIterator & operator++(); + + /// returns true when iterators has reached the end + bool isDone() const; + + // current x position + TQ_INT32 x() const; + + // current y position + TQ_INT32 y() const; + +private: + + KisTiledRectIteratorSP m_iter; +}; + +class KisHLineIterator +{ + +public: + + KisHLineIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable); + +public: + + virtual ~KisHLineIterator(); + KisHLineIterator(const KisHLineIterator& rhs); + KisHLineIterator& operator=(const KisHLineIterator& rhs); + +public: + /// Returns a pointer to the pixel data. Do NOT interpret the data - leave that to a colorstrategy + TQ_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const TQ_UINT8 *oldRawData() const; + + /// Advances one pixel until it reaches the end of the line + KisHLineIterator & operator++(); + + /// Returns the number of consequtive horizontal pixels that we point at + /// This is useful for optimizing + TQ_INT32 nConseqHPixels() const; + + /// Advances a number of pixels until it reaches the end of the line + KisHLineIterator & operator+=(int n); + + /// Goes back one pixel until it reaches the beginning of the line + KisHLineIterator & operator--(); + + /// returns true when iterators has reached the end + bool isDone() const; + + /// current x position + TQ_INT32 x() const; + + /// current y position + TQ_INT32 y() const; + + /// increment to the next row and rewind to the begining + void nextRow(); + + +private: + + KisTiledHLineIteratorSP m_iter; +}; + +class KisVLineIterator +{ + +public: + KisVLineIterator ( KisDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable); +public: + ~KisVLineIterator(); + KisVLineIterator(const KisVLineIterator& rhs); + KisVLineIterator& operator=(const KisVLineIterator& rhs); + +public: + /// returns a pointer to the pixel data. Do NOT interpret the data - leave that to a colorstrategy + TQ_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment of the last memento creation. + const TQ_UINT8 * oldRawData() const; + + /// Advances one pixel until it reaches the end of the line + KisVLineIterator & operator++(); + + /// returns true when iterators has reached the end + bool isDone() const; + + /// current x position + TQ_INT32 x() const; + + /// current y position + TQ_INT32 y() const; + + /// increment to the next column and rewind to the begining + void nextCol(); + +private: + + KisTiledVLineIteratorSP m_iter; + +}; + +#endif diff --git a/chalk/core/kis_iteratorpixeltrait.h b/chalk/core/kis_iteratorpixeltrait.h new file mode 100644 index 00000000..5d2c957f --- /dev/null +++ b/chalk/core/kis_iteratorpixeltrait.h @@ -0,0 +1,131 @@ +/* This file is part of the KDE project + * Copyright (c) 2004 Cyrille Berger , the original iteratorpixel + * Copyright (c) 2005 Casper Boemann , made it into a trait + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef KIS_ITERATORPIXELTRAIT_H_ +#define KIS_ITERATORPIXELTRAIT_H_ + +#include "kis_iterator.h" +#include + +template< typename _iTp> +class KisIteratorPixelTrait +{ +public: + KisIteratorPixelTrait(KisPaintDevice * ndevice, _iTp *underlyingIterator) + : m_device(ndevice), + m_underlyingIterator(underlyingIterator) + { + m_selectionIterator = NULL; + }; + + ~KisIteratorPixelTrait() + { + delete m_selectionIterator; + }; + + KisIteratorPixelTrait(const KisIteratorPixelTrait& rhs) + { + if (this == &rhs) + return; + m_device = rhs.m_device; + m_underlyingIterator = rhs.m_underlyingIterator; + + if (rhs.m_selectionIterator) { + m_selectionIterator = new _iTp(*rhs.m_selectionIterator); + } else { + m_selectionIterator = 0; + } + } + + KisIteratorPixelTrait& operator=(const KisIteratorPixelTrait& rhs) + { + if (this == &rhs) + return *this; + m_device = rhs.m_device; + m_underlyingIterator = rhs.m_underlyingIterator; + + delete m_selectionIterator; + if (rhs.m_selectionIterator) { + m_selectionIterator = new _iTp(*rhs.m_selectionIterator); + } else { + m_selectionIterator = 0; + } + + return *this; + } + + +public: + /** + * Return one channel from the current kispixel. Does not check whether + * channel index actually exists in this colorspace. + */ + inline TQ_UINT8 operator[](int index) const + { return m_underlyingIterator->rawData()[index]; }; + + /** + * Returns if the pixel is selected or not. This is much faster than first building a KisPixel + */ + inline bool isSelected() const + { + if (m_selectionIterator) + return *(m_selectionIterator->rawData()) > SELECTION_THRESHOLD; + else + return true; + }; + + /** + * Returns the degree of selectedness of the pixel. + */ + inline TQ_UINT8 selectedness() const + { + if (m_selectionIterator) + return *(m_selectionIterator->rawData()); + else { + return MAX_SELECTED; + } + }; + + /** + * Returns the selectiontqmask from the current point; this is guaranteed + * to have the same number of consecutive pixels that the iterator has + * at a given point. It return a 0 if there is no selection. + */ + inline TQ_UINT8 * selectionMask() const + { + if ( m_selectionIterator ) + return m_selectionIterator->rawData(); + else + return 0; + } + + +protected: + KisPaintDevice *m_device; + + inline void advance(int n){if (m_selectionIterator) for(int i=0; i< n; i++) ++(*m_selectionIterator);}; + inline void retreat(){if (m_selectionIterator) --(*m_selectionIterator);}; + + void setSelectionIterator(_iTp *si){m_selectionIterator = si;}; + + _iTp *m_underlyingIterator; + _iTp *m_selectionIterator; +}; + +#endif diff --git a/chalk/core/kis_iterators_pixel.cc b/chalk/core/kis_iterators_pixel.cc new file mode 100644 index 00000000..3c5f1e44 --- /dev/null +++ b/chalk/core/kis_iterators_pixel.cc @@ -0,0 +1,59 @@ +/* + * This file is part of the Chalk project + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_iterators_pixel.h" +#include "kis_global.h" +#include "kis_paint_device.h" + +KisHLineIteratorPixel::KisHLineIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable) : + KisHLineIterator(dm, x - offsetx, y - offsety, w, writable), + KisIteratorPixelTrait ( ndevice, this ), + m_offsetx(offsetx), m_offsety(offsety) +{ + if(sel_dm) { + KisHLineIterator * i = new KisHLineIterator(sel_dm, x - offsetx, y - offsety, w, false); + Q_CHECK_PTR(i); + KisIteratorPixelTrait ::setSelectionIterator(i); + } +} + +KisVLineIteratorPixel::KisVLineIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable) : + KisVLineIterator(dm, x - offsetx, y - offsety, h, writable), + KisIteratorPixelTrait ( ndevice, this ), + m_offsetx(offsetx), m_offsety(offsety) +{ + if(sel_dm) { + KisVLineIterator * i = new KisVLineIterator(sel_dm, x - offsetx, y - offsety, h, false); + Q_CHECK_PTR(i); + KisIteratorPixelTrait ::setSelectionIterator(i); + } +} + +KisRectIteratorPixel::KisRectIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable) : + KisRectIterator(dm, x - offsetx, y - offsety, w, h, writable), + KisIteratorPixelTrait ( ndevice, this ), + m_offsetx(offsetx), m_offsety(offsety) +{ + if(sel_dm) { + KisRectIterator * i = new KisRectIterator(sel_dm, x - offsetx, y - offsety, w, h, false); + Q_CHECK_PTR(i); + KisIteratorPixelTrait ::setSelectionIterator(i); + } +} diff --git a/chalk/core/kis_iterators_pixel.h b/chalk/core/kis_iterators_pixel.h new file mode 100644 index 00000000..bd82f856 --- /dev/null +++ b/chalk/core/kis_iterators_pixel.h @@ -0,0 +1,154 @@ +/* This file is part of the KDE project + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef KIS_ITERATORS_PIXEL_H_ +#define KIS_ITERATORS_PIXEL_H_ + +#include "kis_iterator.h" +#include "kis_iteratorpixeltrait.h" + +/** + * The pixel iterators are high level iterarators. The lower level iterators merely return a pointer to some memory + * where a pixel begins; these iterators return KisPixels -- high-level representations of a pixel together with + * color model, profile and selectedness. You can access individual channels using the KisPixel [] operator, and . + */ + + +class KisHLineIteratorPixel : public KisHLineIterator, public KisIteratorPixelTrait +{ + +public: + + KisHLineIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, + TQ_INT32 x , TQ_INT32 y , TQ_INT32 w, TQ_INT32 offsetx, TQ_INT32 offsety, + bool writable); + + KisHLineIteratorPixel(const KisHLineIteratorPixel& rhs) : KisHLineIterator(rhs), KisIteratorPixelTrait(rhs) + { m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; } + + KisHLineIteratorPixel& operator=(const KisHLineIteratorPixel& rhs) + { + KisHLineIterator::operator=(rhs); + KisIteratorPixelTrait::operator=(rhs); + m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; + return *this; + } + + inline KisHLineIteratorPixel & operator ++() { KisHLineIterator::operator++(); advance(1); return *this;} + inline KisHLineIteratorPixel & operator --() { KisHLineIterator::operator--(); retreat(); return *this;} + + inline void nextRow() { + KisHLineIterator::nextRow(); + if (m_selectionIterator) m_selectionIterator->nextRow(); + } + + /// Advances a number of pixels until it reaches the end of the line + KisHLineIteratorPixel & operator+=(int n) { KisHLineIterator::operator+=(n); advance(n); return *this; }; + + TQ_INT32 x() const { return KisHLineIterator::x() + m_offsetx; } + + TQ_INT32 y() const { return KisHLineIterator::y() + m_offsety; } + + TQ_INT32 nConseqHPixels() const { + if (m_selectionIterator) { + TQ_INT32 tqparent = KisHLineIteratorPixel::nConseqHPixels(); + TQ_INT32 selection = m_selectionIterator->nConseqHPixels(); + if (tqparent < selection) + return tqparent; + return selection; + } + return KisHLineIteratorPixel::nConseqHPixels(); + } +protected: + + TQ_INT32 m_offsetx, m_offsety; +}; + +class KisVLineIteratorPixel : public KisVLineIterator, public KisIteratorPixelTrait +{ +public: + KisVLineIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, + TQ_INT32 xpos , TQ_INT32 ypos , TQ_INT32 height, TQ_INT32 offsetx, TQ_INT32 offsety, + bool writable); + + KisVLineIteratorPixel(const KisVLineIteratorPixel& rhs) : KisVLineIterator(rhs), KisIteratorPixelTrait(rhs) + { m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; } + + KisVLineIteratorPixel& operator=(const KisVLineIteratorPixel& rhs) + { + KisVLineIterator::operator=(rhs); + KisIteratorPixelTrait::operator=(rhs); + m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; + return *this; } + + inline KisVLineIteratorPixel & operator ++() { KisVLineIterator::operator++(); advance(1); return *this;} + + inline void nextRow() { + KisVLineIterator::nextCol(); + if (m_selectionIterator) m_selectionIterator->nextCol(); + } + + TQ_INT32 x() const { return KisVLineIterator::x() + m_offsetx; } + + TQ_INT32 y() const { return KisVLineIterator::y() + m_offsety; } + +protected: + + TQ_INT32 m_offsetx, m_offsety; +}; + +class KisRectIteratorPixel : public KisRectIterator, public KisIteratorPixelTrait +{ +public: + KisRectIteratorPixel( KisPaintDevice *ndevice, KisDataManager *dm, KisDataManager *sel_dm, + TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, TQ_INT32 offsetx, TQ_INT32 offsety, + bool writable); + + KisRectIteratorPixel(const KisRectIteratorPixel& rhs) : KisRectIterator(rhs), KisIteratorPixelTrait(rhs) + { m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; } + + KisRectIteratorPixel& operator=(const KisRectIteratorPixel& rhs) + { + KisRectIterator::operator=(rhs); + KisIteratorPixelTrait::operator=(rhs); + m_offsetx = rhs.m_offsetx; m_offsety = rhs.m_offsety; + return *this; } + + inline KisRectIteratorPixel & operator ++() { KisRectIterator::operator++(); advance(1); return *this;} + + TQ_INT32 x() const { return KisRectIterator::x() + m_offsetx; } + + TQ_INT32 y() const { return KisRectIterator::y() + m_offsety; } + + TQ_INT32 nConseqPixels() const { + if (m_selectionIterator) { + TQ_INT32 tqparent = KisRectIterator::nConseqPixels(); + TQ_INT32 selection = m_selectionIterator->nConseqPixels(); + if (tqparent < selection) + return tqparent; + return selection; + } + return KisRectIterator::nConseqPixels(); + } + +protected: + + TQ_INT32 m_offsetx, m_offsety; +}; + +#endif diff --git a/chalk/core/kis_layer.cc b/chalk/core/kis_layer.cc new file mode 100644 index 00000000..cac178e5 --- /dev/null +++ b/chalk/core/kis_layer.cc @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#include +#include + +#include "kis_debug_areas.h" +#include "kis_group_layer.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_painter.h" +#include "kis_undo_adapter.h" + +namespace { + + class KisLayerCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisLayerCommand(const TQString& name, KisLayerSP layer); + virtual ~KisLayerCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisLayerSP m_layer; + }; + + KisLayerCommand::KisLayerCommand(const TQString& name, KisLayerSP layer) : + super(name), m_layer(layer) + { + } + + void KisLayerCommand::setUndo(bool undo) + { + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(undo); + } + } + + class KisLayerLockedCommand : public KisLayerCommand { + typedef KisLayerCommand super; + + public: + KisLayerLockedCommand(KisLayerSP layer, bool newLocked); + + virtual void execute(); + virtual void unexecute(); + + private: + bool m_newLocked; + }; + + KisLayerLockedCommand::KisLayerLockedCommand(KisLayerSP layer, bool newLocked) : + super(i18n("Lock Layer"), layer) + { + m_newLocked = newLocked; + } + + void KisLayerLockedCommand::execute() + { + setUndo(false); + m_layer->setLocked(m_newLocked); + setUndo(true); + } + + void KisLayerLockedCommand::unexecute() + { + setUndo(false); + m_layer->setLocked(!m_newLocked); + setUndo(true); + } + + class KisLayerOpacityCommand : public KisLayerCommand { + typedef KisLayerCommand super; + + public: + KisLayerOpacityCommand(KisLayerSP layer, TQ_UINT8 oldOpacity, TQ_UINT8 newOpacity); + + virtual void execute(); + virtual void unexecute(); + + private: + TQ_UINT8 m_oldOpacity; + TQ_UINT8 m_newOpacity; + }; + + KisLayerOpacityCommand::KisLayerOpacityCommand(KisLayerSP layer, TQ_UINT8 oldOpacity, TQ_UINT8 newOpacity) : + super(i18n("Layer Opacity"), layer) + { + m_oldOpacity = oldOpacity; + m_newOpacity = newOpacity; + } + + void KisLayerOpacityCommand::execute() + { + setUndo(false); + m_layer->setOpacity(m_newOpacity); + setUndo(true); + } + + void KisLayerOpacityCommand::unexecute() + { + setUndo(false); + m_layer->setOpacity(m_oldOpacity); + setUndo(true); + } + + class KisLayerVisibilityCommand : public KisLayerCommand { + typedef KisLayerCommand super; + + public: + KisLayerVisibilityCommand(KisLayerSP layer, bool newVisibility); + + virtual void execute(); + virtual void unexecute(); + + private: + bool m_newVisibility; + }; + + KisLayerVisibilityCommand::KisLayerVisibilityCommand(KisLayerSP layer, bool newVisibility) : + super(i18n("Layer Visibility"), layer) + { + m_newVisibility = newVisibility; + } + + void KisLayerVisibilityCommand::execute() + { + setUndo(false); + m_layer->setVisible(m_newVisibility); + setUndo(true); + } + + void KisLayerVisibilityCommand::unexecute() + { + setUndo(false); + m_layer->setVisible(!m_newVisibility); + setUndo(true); + } + + class KisLayerCompositeOpCommand : public KisLayerCommand { + typedef KisLayerCommand super; + + public: + KisLayerCompositeOpCommand(KisLayerSP layer, const KisCompositeOp& oldCompositeOp, const KisCompositeOp& newCompositeOp); + + virtual void execute(); + virtual void unexecute(); + + private: + KisCompositeOp m_oldCompositeOp; + KisCompositeOp m_newCompositeOp; + }; + + KisLayerCompositeOpCommand::KisLayerCompositeOpCommand(KisLayerSP layer, const KisCompositeOp& oldCompositeOp, + const KisCompositeOp& newCompositeOp) : + super(i18n("Layer Composite Mode"), layer) + { + m_oldCompositeOp = oldCompositeOp; + m_newCompositeOp = newCompositeOp; + } + + void KisLayerCompositeOpCommand::execute() + { + setUndo(false); + m_layer->setCompositeOp(m_newCompositeOp); + setUndo(true); + } + + void KisLayerCompositeOpCommand::unexecute() + { + setUndo(false); + m_layer->setCompositeOp(m_oldCompositeOp); + setUndo(true); + } + + class KisLayerOffsetCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisLayerOffsetCommand(KisLayerSP layer, const TQPoint& oldpos, const TQPoint& newpos); + virtual ~KisLayerOffsetCommand(); + + virtual void execute(); + virtual void unexecute(); + + private: + void moveTo(const TQPoint& pos); + + private: + KisLayerSP m_layer; + TQRect m_updateRect; + TQPoint m_oldPos; + TQPoint m_newPos; + }; + + KisLayerOffsetCommand::KisLayerOffsetCommand(KisLayerSP layer, const TQPoint& oldpos, const TQPoint& newpos) : + super(i18n("Move Layer")) + { + m_layer = layer; + m_oldPos = oldpos; + m_newPos = newpos; + + TQRect currentBounds = m_layer->exactBounds(); + TQRect oldBounds = currentBounds; + oldBounds.moveBy(oldpos.x() - newpos.x(), oldpos.y() - newpos.y()); + + m_updateRect = currentBounds | oldBounds; + } + + KisLayerOffsetCommand::~KisLayerOffsetCommand() + { + } + + void KisLayerOffsetCommand::execute() + { + moveTo(m_newPos); + } + + void KisLayerOffsetCommand::unexecute() + { + moveTo(m_oldPos); + } + + void KisLayerOffsetCommand::moveTo(const TQPoint& pos) + { + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(false); + } + + m_layer->setX(pos.x()); + m_layer->setY(pos.y()); + + m_layer->setDirty(m_updateRect); + + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(true); + } + } +} + +static int getID() +{ + static int id = 1; + return id++; +} + + +KisLayer::KisLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity) : + TQObject(0, name.latin1()), + KShared(), + m_id(getID()), + m_index(-1), + m_opacity(opacity), + m_locked(false), + m_visible(true), + m_temporary(false), + m_name(name), + m_parent(0), + m_image(img), + m_compositeOp(COMPOSITE_OVER) +{ +} + +KisLayer::KisLayer(const KisLayer& rhs) : + TQObject(), + KShared(rhs) +{ + if (this != &rhs) { + m_id = getID(); + m_index = -1; + m_opacity = rhs.m_opacity; + m_locked = rhs.m_locked; + m_visible = rhs.m_visible; + m_temporary = rhs.m_temporary; + m_dirtyRect = rhs.m_dirtyRect; + m_name = rhs.m_name; + m_image = rhs.m_image; + m_parent = 0; + m_compositeOp = rhs.m_compositeOp; + } +} + +KisLayer::~KisLayer() +{ +} + +void KisLayer::setClean(const TQRect & rect) +{ + if (m_dirtyRect.isValid() && rect.isValid()) { + + // XXX: We should only set the parts clean that were actually cleaned. However, extent and exactBounds conspire + // to make that very hard atm. + //if (rect.tqcontains(m_dirtyRect)) m_dirtyRect = TQRect(); + m_dirtyRect = TQRect(); + } + +} + +bool KisLayer::dirty() +{ + return m_dirtyRect.isValid(); +} + + +bool KisLayer::dirty(const TQRect & rc) +{ + if (!m_dirtyRect.isValid() || !rc.isValid()) return false; + + return rc.intersects(m_dirtyRect); +} + +TQRect KisLayer::dirtyRect() const +{ + return m_dirtyRect; +} + +void KisLayer::setDirty(bool propagate) +{ + TQRect rc = extent(); + + if (rc.isValid()) m_dirtyRect = rc; + + // If we're dirty, our tqparent is dirty, if we've got a tqparent + if (propagate && m_parent && rc.isValid()) m_parent->setDirty(m_dirtyRect); + + if (m_image && rc.isValid()) { + m_image->notifyLayerUpdated(this, rc); + } +} + +void KisLayer::setDirty(const TQRect & rc, bool propagate) +{ + // If we're dirty, our tqparent is dirty, if we've got a tqparent + + if (rc.isValid()) + m_dirtyRect |= rc; + + if (propagate && m_parent && m_dirtyRect.isValid()) + m_parent->setDirty(m_dirtyRect); + + if (m_image && rc.isValid()) { + m_image->notifyLayerUpdated(this, rc); + } +} + +KisGroupLayerSP KisLayer::tqparent() const +{ + return m_parent; +} + +KisLayerSP KisLayer::prevSibling() const +{ + if (!tqparent()) + return 0; + return tqparent()->at(index() - 1); +} + +KisLayerSP KisLayer::nextSibling() const +{ + if (!tqparent()) + return 0; + return tqparent()->at(index() + 1); +} + +int KisLayer::index() const +{ + return m_index; +} + +void KisLayer::setIndex(int i) +{ + if (!tqparent()) + return; + tqparent()->setIndex(this, i); +} + +KisLayerSP KisLayer::findLayer(const TQString& n) const +{ + if (name() == n) + return const_cast(this); //HACK any less ugly way? findLayer() is conceptually const... + for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling()) + if (KisLayerSP found = layer->findLayer(n)) + return found; + return 0; +} + +KisLayerSP KisLayer::findLayer(int i) const +{ + if (id() == i) + return const_cast(this); //HACK + for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling()) + if (KisLayerSP found = layer->findLayer(i)) + return found; + return 0; +} + +int KisLayer::numLayers(int flags) const +{ + int num = 0; + if (matchesFlags(flags)) num++; + for (KisLayerSP layer = firstChild(); layer; layer = layer->nextSibling()) + num += layer->numLayers(flags); + return num; +} + +bool KisLayer::matchesFlags(int flags) const +{ + if ((flags & Visible) && !visible()) + return false; + if ((flags & Hidden) && visible()) + return false; + if ((flags & Locked) && !locked()) + return false; + if ((flags & Unlocked) && locked()) + return false; + return true; +} + +TQ_UINT8 KisLayer::opacity() const +{ + return m_opacity; +} + +void KisLayer::setOpacity(TQ_UINT8 val) +{ + if (m_opacity != val) + { + m_opacity = val; + setDirty(); + notifyPropertyChanged(); + } +} + +KNamedCommand *KisLayer::setOpacityCommand(TQ_UINT8 newOpacity) +{ + return new KisLayerOpacityCommand(this, opacity(), newOpacity); +} + +KNamedCommand *KisLayer::setOpacityCommand(TQ_UINT8 prevOpacity, TQ_UINT8 newOpacity) +{ + return new KisLayerOpacityCommand(this, prevOpacity, newOpacity); +} + +const bool KisLayer::visible() const +{ + return m_visible; +} + +void KisLayer::setVisible(bool v) +{ + if (m_visible != v) { + + m_visible = v; + notifyPropertyChanged(); + setDirty(); + + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(setVisibleCommand(v)); + } + } +} + +KNamedCommand *KisLayer::setVisibleCommand(bool newVisibility) +{ + return new KisLayerVisibilityCommand(this, newVisibility); +} + +bool KisLayer::locked() const +{ + return m_locked; +} + +void KisLayer::setLocked(bool l) +{ + if (m_locked != l) { + m_locked = l; + notifyPropertyChanged(); + + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(setLockedCommand(l)); + } + } +} + +bool KisLayer::temporary() const +{ + return m_temporary; +} + +void KisLayer::setTemporary(bool t) +{ + m_temporary = t; +} + +KNamedCommand *KisLayer::setLockedCommand(bool newLocked) +{ + return new KisLayerLockedCommand(this, newLocked); +} + +TQString KisLayer::name() const +{ + return m_name; +} + +void KisLayer::setName(const TQString& name) +{ + if (!name.isEmpty() && m_name != name) + { + m_name = name; + notifyPropertyChanged(); + } +} + +void KisLayer::setCompositeOp(const KisCompositeOp& compositeOp) +{ + if (m_compositeOp != compositeOp) + { + m_compositeOp = compositeOp; + notifyPropertyChanged(); + setDirty(); + + } +} + +KNamedCommand *KisLayer::setCompositeOpCommand(const KisCompositeOp& newCompositeOp) +{ + return new KisLayerCompositeOpCommand(this, compositeOp(), newCompositeOp); +} + +KNamedCommand *KisLayer::moveCommand(TQPoint oldPosition, TQPoint newPosition) +{ + return new KisLayerOffsetCommand(this, oldPosition, newPosition); +} + +KisUndoAdapter *KisLayer::undoAdapter() const +{ + if (m_image) { + return m_image->undoAdapter(); + } + return 0; +} + +void KisLayer::paintMaskInactiveLayers(TQImage &, TQ_INT32, TQ_INT32, TQ_INT32, TQ_INT32) +{ +} + +void KisLayer::paintSelection(TQImage &, TQ_INT32, TQ_INT32, TQ_INT32, TQ_INT32) +{ +} + +void KisLayer::paintSelection(TQImage &, const TQRect&, const TQSize&, const TQSize&) +{ +} + +TQImage KisLayer::createThumbnail(TQ_INT32, TQ_INT32) +{ + return 0; +} + +void KisLayer::notifyPropertyChanged() +{ + if(image() && !signalsBlocked()) + image()->notifyPropertyChanged(this); +} + +void KisLayerSupportsIndirectPainting::setTemporaryTarget(KisPaintDeviceSP t) { + m_temporaryTarget = t; +} + +void KisLayerSupportsIndirectPainting::setTemporaryCompositeOp(const KisCompositeOp& c) { + m_compositeOp = c; +} + +void KisLayerSupportsIndirectPainting::setTemporaryOpacity(TQ_UINT8 o) { + m_compositeOpacity = o; +} + +KisPaintDeviceSP KisLayerSupportsIndirectPainting::temporaryTarget() { + return m_temporaryTarget; +} + +KisCompositeOp KisLayerSupportsIndirectPainting::temporaryCompositeOp() const { + return m_compositeOp; +} + +TQ_UINT8 KisLayerSupportsIndirectPainting::temporaryOpacity() const { + return m_compositeOpacity; +} + +#include "kis_layer.moc" diff --git a/chalk/core/kis_layer.h b/chalk/core/kis_layer.h new file mode 100644 index 00000000..09ecd235 --- /dev/null +++ b/chalk/core/kis_layer.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_LAYER_H_ +#define KIS_LAYER_H_ + +#include +#include "kis_types.h" +#include "kis_layer_visitor.h" +#include "kis_composite_op.h" +#include + +class KNamedCommand; +class TQPainter; +class KisUndoAdapter; +class KisGroupLayer; + +/** + * Abstract class that represents the concept of a Layer in Chalk. This is not related + * to the paint devices: this is merely an abstraction of how layers can be stacked and + * rendered differently. + * Regarding the previous-, first-, next- and lastChild() calls, first means that it the layer + * is at the top of the group in the layerlist, using next will iterate to the bottom to last, + * whereas previous will go up to first again. + **/ +class KRITACORE_EXPORT KisLayer : public TQObject, public KShared +{ + Q_OBJECT + TQ_OBJECT + +public: + KisLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity); + KisLayer(const KisLayer& rhs); + virtual ~KisLayer(); + + + /** + * Set the specified rect to clean + */ + virtual void setClean(const TQRect & rect); + + /** + * If the layer has been changed and not been composited yet, this returns true + */ + virtual bool dirty(); + + /** + * Return true if the given rect intersects the dirty rect(s) of this layer + */ + virtual bool dirty(const TQRect & rc); + + + virtual TQRect dirtyRect() const; + + + /** + * Set the entire layer extent dirty; this percolates up to tqparent layers all the + * way to the root layer. + */ + virtual void setDirty(bool propagate = true); + + /** + * Add the given rect to the set of dirty rects for this layer; + * this percolates up to tqparent layers all the way to the root + * layer. + */ + virtual void setDirty(const TQRect & rect, bool propagate = true); + + /// Return a copy of this layer + virtual KisLayerSP clone() const = 0; + + /// Returns the ID of the layer, which is guaranteed to be unique among all KisLayers. + int id() const { return m_id; } + + /* Returns the index of the layer in its tqparent's list of child layers. Indices + * increase from 0, which is the topmost layer in the list, to the bottommost. + */ + virtual int index() const; + + /// Moves this layer to the specified index within its tqparent's list of child layers. + virtual void setIndex(int index); + + /** + * Returns the tqparent layer of a layer. This is 0 only for a root layer; otherwise + * this will be an actual GroupLayer */ + virtual KisGroupLayerSP tqparent() const; + + /** + * Returns the previous sibling of this layer in the tqparent's list. This is the layer + * *above* this layer. 0 is returned if there is no tqparent, or if this child has no more + * previous siblings (== firstChild()) + */ + virtual KisLayerSP prevSibling() const; + + /** + * Returns the next sibling of this layer in the tqparent's list. This is the layer *below* + * this layer. 0 is returned if there is no tqparent, or if this child has no more next + * siblings (== lastChild()) + */ + virtual KisLayerSP nextSibling() const; + + /** + * Returns the sibling above this layer in its tqparent's list. 0 is returned if there is no tqparent, + * or if this layer is the topmost layer in its group. This is the same as calling prevSibling(). + */ + KisLayerSP siblingAbove() const { return prevSibling(); } + + /** + * Returns the sibling below this layer in its tqparent's list. 0 is returned if there is no tqparent, + * or if this layer is the bottommost layer in its group. This is the same as calling nextSibling(). + */ + KisLayerSP siblingBelow() const { return nextSibling(); } + + /// Returns how many direct child layers this layer has (not recursive). + virtual uint childCount() const { return 0; } + + /// Returns the first child layer of this layer (if it supports that). + virtual KisLayerSP firstChild() const { return 0; } + + /// Returns the last child layer of this layer (if it supports that). + virtual KisLayerSP lastChild() const { return 0; } + + /// Recursively searches this layer and any child layers for a layer with the specified name. + virtual KisLayerSP findLayer(const TQString& name) const; + + /// Recursively searches this layer and any child layers for a layer with the specified ID. + virtual KisLayerSP findLayer(int id) const; + + enum { Visible = 1, Hidden = 2, Locked = 4, Unlocked = 8 }; + + /// Returns the total number of layers in this layer, its child layers, and their child layers recursively, optionally ones with the specified properties Visible or Locked, which you can OR together. + virtual int numLayers(int type = 0) const; + +public: + /// Called when the layer is made active + virtual void activate() {}; + + /// Called when another layer is made active + virtual void deactivate() {}; + +public: + virtual TQ_INT32 x() const = 0; + virtual void setX(TQ_INT32) = 0; + + virtual TQ_INT32 y() const = 0; + virtual void setY(TQ_INT32) = 0; + + virtual KNamedCommand *moveCommand(TQPoint oldPosition, TQPoint newPosition); + + /// Returns an approximation of where the bounds on actual data are in this layer + virtual TQRect extent() const = 0; + /// Returns the exact bounds of where the actual data resides in this layer + virtual TQRect exactBounds() const = 0; + + virtual const bool visible() const; + virtual void setVisible(bool v); + KNamedCommand *setVisibleCommand(bool visiblel); + + TQ_UINT8 opacity() const; + void setOpacity(TQ_UINT8 val); + KNamedCommand *setOpacityCommand(TQ_UINT8 val); + KNamedCommand *setOpacityCommand(TQ_UINT8 prevOpacity, TQ_UINT8 newOpacity); + + bool locked() const; + void setLocked(bool l); + KNamedCommand *setLockedCommand(bool locked); + + void notifyPropertyChanged(); + + bool temporary() const; + void setTemporary(bool t); + + virtual TQString name() const; + virtual void setName(const TQString& name); + + KisCompositeOp compositeOp() { return m_compositeOp; } + void setCompositeOp(const KisCompositeOp& compositeOp); + KNamedCommand *setCompositeOpCommand(const KisCompositeOp& compositeOp); + + KisImage *image() const { return m_image; } + virtual void setImage(KisImage *image) { m_image = image; } + + KisUndoAdapter *undoAdapter() const; + + /// paints a tqmask where the selection on this layer resides + virtual void paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + virtual void paintSelection(TQImage &img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize); + + /// paints where no data is on this layer. Useful when it is a transparent layer stacked on top of another one + virtual void paintMaskInactiveLayers(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /// Returns a thumbnail in requested size. The TQImage may have transparent parts. + /// May also return 0 + virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h); + + /// Accept the KisLayerVisitor (for the Visitor design pattern), should call the correct function on the KisLayerVisitor for this layer type + virtual bool accept(KisLayerVisitor &) = 0; + +private: + friend class KisGroupLayer; + + bool matchesFlags(int flags) const; + + int m_id; + int m_index; + TQ_UINT8 m_opacity; + bool m_locked; + bool m_visible; + bool m_temporary; + + // XXX: keep a list of dirty rects instead of always aggegrating them + TQRect m_dirtyRect; + TQString m_name; + KisGroupLayerSP m_parent; + KisImage *m_image; + + // Operation used to composite this layer with the layers _under_ this layer + KisCompositeOp m_compositeOp; +}; + +// For classes that support indirect painting +class KRITACORE_EXPORT KisLayerSupportsIndirectPainting { + // To simulate the indirect painting + KisPaintDeviceSP m_temporaryTarget; + KisCompositeOp m_compositeOp; + TQ_UINT8 m_compositeOpacity; +public: + // Indirect painting + void setTemporaryTarget(KisPaintDeviceSP t); + void setTemporaryCompositeOp(const KisCompositeOp& c); + void setTemporaryOpacity(TQ_UINT8 o); + KisPaintDeviceSP temporaryTarget(); + KisCompositeOp temporaryCompositeOp() const; + TQ_UINT8 temporaryOpacity() const; + + // Or I could make KisLayer a virtual base of KisLayerSupportsIndirectPainting and so, but + // I'm sure virtual diamond inheritance isn't as appreciated as this + virtual KisLayer* layer() = 0; +}; + +#endif // KIS_LAYER_H_ + diff --git a/chalk/core/kis_layer_visitor.h b/chalk/core/kis_layer_visitor.h new file mode 100644 index 00000000..4326bc54 --- /dev/null +++ b/chalk/core/kis_layer_visitor.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_LAYER_VISITOR_H_ +#define KIS_LAYER_VISITOR_H_ + +#include "kis_global.h" +#include "kis_types.h" + +class KisPaintLayer; +class KisGroupLayer; +class KisPartLayer; +class KisAdjustmentLayer; + +class KisLayerVisitor { +public: + KisLayerVisitor() {}; + virtual ~KisLayerVisitor() {}; + +public: + virtual bool visit(KisPaintLayer *layer) = 0; + virtual bool visit(KisGroupLayer *layer) = 0; + virtual bool visit(KisPartLayer *layer) = 0; + virtual bool visit(KisAdjustmentLayer *layer) = 0; +}; + + +#endif // KIS_LAYER_VISITOR_H_ + diff --git a/chalk/core/kis_math_toolbox.cpp b/chalk/core/kis_math_toolbox.cpp new file mode 100644 index 00000000..f4fdf88c --- /dev/null +++ b/chalk/core/kis_math_toolbox.cpp @@ -0,0 +1,166 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_math_toolbox.h" + +#ifdef HAVE_OPENEXR +#include +#endif + +#include "kis_basic_math_toolbox.h" +#include "kis_iterators_pixel.h" + + +KisMathToolbox::KisMathToolbox(KisID id) : m_id(id) +{ +} + +KisMathToolbox::~KisMathToolbox() +{ +} + +KisMathToolboxFactoryRegistry::KisMathToolboxFactoryRegistry() +{ + add(new KisBasicMathToolbox()); +} +KisMathToolboxFactoryRegistry::~KisMathToolboxFactoryRegistry() +{ +} +template +double toDouble(TQ_UINT8* data, int channelpos ) +{ + return (float)( *((T*)(data + channelpos)) ); +} + +typedef double (*PtrToDouble)(TQ_UINT8*, int); + +template +void fromDouble(TQ_UINT8* data, int channelpos, double v ) +{ + *((T*)(data + channelpos)) = (T)v; +} + +typedef void (*PtrFromDouble)(TQ_UINT8*, int, double); + + +void KisMathToolbox::transformToFR(KisPaintDeviceSP src, KisFloatRepresentation* fr, const TQRect& rect) +{ + TQ_INT32 depth = src->colorSpace()->nColorChannels(); + TQMemArray f(depth); + TQValueVector cis = src->colorSpace()->channels(); + for(TQ_INT32 k = 0; k < depth; k++) + { + switch( cis[k]->channelValueType() ) + { + case KisChannelInfo::UINT8: + f[k] = toDouble; + break; + case KisChannelInfo::UINT16: + f[k] = toDouble; + break; +#ifdef HAVE_OPENEXR + case KisChannelInfo::FLOAT16: + f[k] = toDouble; + break; +#endif + case KisChannelInfo::FLOAT32: + f[k] = toDouble; + break; + case KisChannelInfo::INT8: + f[k] = toDouble; + break; + case KisChannelInfo::INT16: + f[k] = toDouble; + break; + default: + kdWarning() << "Unsupported value type in KisMathToolbox" << endl; + return; + } + } + + for(int i = rect.y(); i < rect.height(); i++) + { + KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), i, rect.width(), false ); + float *dstIt = fr->coeffs + (i-rect.y()) * fr->size * fr->depth; + while( ! srcIt.isDone() ) + { + TQ_UINT8* v1 = srcIt.rawData(); + for( int k = 0; k < depth; k++) + { + *dstIt = f[k](v1, cis[k]->pos()); + ++dstIt; + } + ++srcIt; + } + } +} + +void KisMathToolbox::transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation* fr, const TQRect& rect) +{ + TQ_INT32 depth = dst->colorSpace()->nColorChannels(); + TQMemArray f(depth); + TQValueVector cis = dst->colorSpace()->channels(); + for(TQ_INT32 k = 0; k < depth; k++) + { + switch( cis[k]->channelValueType() ) + { + case KisChannelInfo::UINT8: + f[k] = fromDouble; + break; + case KisChannelInfo::UINT16: + f[k] = fromDouble; + break; +#ifdef HAVE_OPENEXR + case KisChannelInfo::FLOAT16: + f[k] = fromDouble; + break; +#endif + case KisChannelInfo::FLOAT32: + f[k] = fromDouble; + break; + case KisChannelInfo::INT8: + f[k] = fromDouble; + break; + case KisChannelInfo::INT16: + f[k] = fromDouble; + break; + default: + kdWarning() << "Unsupported value type in KisMathToolbox" << endl; + return; + } + } + for(int i = rect.y(); i < rect.height(); i++) + { + KisHLineIteratorPixel dstIt = dst->createHLineIterator(rect.x(), i, rect.width(), true ); + float *srcIt = fr->coeffs + (i-rect.y()) * fr->size * fr->depth; + while( ! dstIt.isDone() ) + { + TQ_UINT8* v1 = dstIt.rawData(); + for( int k = 0; k < depth; k++) + { + f[k](v1, cis[k]->pos(), *srcIt); + ++srcIt; + } + ++dstIt; + } + } +} + +#include "kis_math_toolbox.moc" diff --git a/chalk/core/kis_math_toolbox.h b/chalk/core/kis_math_toolbox.h new file mode 100644 index 00000000..8d5bef50 --- /dev/null +++ b/chalk/core/kis_math_toolbox.h @@ -0,0 +1,124 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_MATH_TOOLBOX_H +#define KIS_MATH_TOOLBOX_H + +#include + +// typedef unsigned int uint; + +#include +#include "kis_paint_device.h" +#include "kis_types.h" + +#include + +class KisMathToolbox : public TQObject { + Q_OBJECT + TQ_OBJECT + public: + struct KisFloatRepresentation { + KisFloatRepresentation(uint nsize, uint ndepth) throw(std::bad_alloc ) : coeffs(new float[nsize*nsize*ndepth]) ,size(nsize), depth(ndepth) + { + // XXX: Valgrind shows that these are being used without being initialised. + for (TQ_UINT32 i = 0; i < nsize*nsize*ndepth; ++i) { + coeffs[i] = 0; + } + } + ~KisFloatRepresentation() { if(coeffs) delete[] coeffs; } + float* coeffs; + uint size; + uint depth; + }; + typedef KisFloatRepresentation KisWavelet; + public: + KisMathToolbox(KisID id); + ~KisMathToolbox(); + public: + inline KisID id() { return m_id; }; + /** + * This function initialize a wavelet structure + * @param lay the layer that will be used for the transformation + */ + inline KisWavelet* initWavelet(KisPaintDeviceSP lay, const TQRect&) throw(std::bad_alloc ); + inline uint fastWaveletTotalSteps(const TQRect&); + /** + * This function reconstruct the layer from the information of a wavelet + * @param src layer from which the wavelet will be computed + * @param buff if set to 0, the buffer will be initialized by the function, + * you might want to give a buff to the function if you want to use the same buffer + * in transformToWavelet and in untransformToWavelet, use initWavelet to initialize + * the buffer + */ + virtual KisWavelet* fastWaveletTransformation(KisPaintDeviceSP src, const TQRect&, KisWavelet* buff = 0) =0; + /** + * This function reconstruct the layer from the information of a wavelet + * @param dst layer on which the wavelet will be untransform + * @param wav the wavelet + * @param buff if set to 0, the buffer will be initialized by the function, + * you might want to give a buff to the function if you want to use the same buffer + * in transformToWavelet and in untransformToWavelet, use initWavelet to initialize + * the buffer + */ + virtual void fastWaveletUntransformation(KisPaintDeviceSP dst, const TQRect&, KisWavelet* wav, KisWavelet* buff = 0) =0; + signals: + void nextStep(); + protected: + /** + * This function transform a paint device into a KisFloatRepresentation, this function is colorspace independant, + * for Wavelet, Pyramid and FFT the data is allways the exact value of the channel stored in a float. + */ + void transformToFR(KisPaintDeviceSP src, KisFloatRepresentation*, const TQRect&); + /** + * This function transform a KisFloatRepresentation into a paint device, this function is colorspace independant, + * for Wavelet, Pyramid and FFT the data is allways the exact value of the channel stored in a float. + */ + void transformFromFR(KisPaintDeviceSP dst, KisFloatRepresentation*, const TQRect&); + private: + KisID m_id; +}; + +class KisMathToolboxFactoryRegistry : public KisGenericRegistry { + public: + KisMathToolboxFactoryRegistry(); + ~KisMathToolboxFactoryRegistry(); +}; + + +inline KisMathToolbox::KisWavelet* KisMathToolbox::initWavelet(KisPaintDeviceSP src, const TQRect& rect) throw(std::bad_alloc ) +{ + int size; + int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); + for(size = 2; size < maxrectsize; size *= 2) ; + TQ_INT32 depth = src->colorSpace()->nColorChannels(); + return new KisWavelet(size, depth); +} + +inline uint KisMathToolbox::fastWaveletTotalSteps(const TQRect& rect) +{ + int size, steps; + int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); + steps = 0; + for(size = 2; size < maxrectsize; size *= 2) steps += size / 2; ; + return steps; +} + +#endif diff --git a/chalk/core/kis_merge_visitor.h b/chalk/core/kis_merge_visitor.h new file mode 100644 index 00000000..68053384 --- /dev/null +++ b/chalk/core/kis_merge_visitor.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_MERGE_H_ +#define KIS_MERGE_H_ + +#include + +#include "kis_types.h" +#include "kis_paint_device.h" +#include "kis_layer_visitor.h" +#include "kis_painter.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_paint_layer.h" +#include "kis_part_layer_iface.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_filter_registry.h" +#include "kis_selection.h" +#include "kis_transaction.h" +#include "kis_iterators_pixel.h" + +class KisMergeVisitor : public KisLayerVisitor { +public: + /** + * Don't even _think_ of creating a merge visitor without a projection; without a projection, + * the adjustmentlayers won't work. + */ + KisMergeVisitor(KisPaintDeviceSP projection, const TQRect& rc) : + KisLayerVisitor() + { + Q_ASSERT(projection); + + m_projection = projection; + m_rc = rc; + } + +private: + // Helper for the indirect painting (keep above to inhibit gcc-2.95 ICE) + template + KSharedPtr paintIndirect(KisPaintDeviceSP source, + KSharedPtr target, + KisLayerSupportsIndirectPainting* layer, + TQ_INT32 sx, TQ_INT32 sy, TQ_INT32 dx, TQ_INT32 dy, + TQ_INT32 w, TQ_INT32 h) { + KisPainter gc2(target.data()); + gc2.bitBlt(dx, dy, COMPOSITE_COPY, source, + OPACITY_OPAQUE, sx, sy, w, h); + gc2.bitBlt(dx, dy, layer->temporaryCompositeOp(), layer->temporaryTarget(), + layer->temporaryOpacity(), sx, sy, w, h); + gc2.end(); + return target; + } + +public: + virtual bool visit(KisPaintLayer *layer) + { + + if (m_projection == 0) { + return false; + } + + kdDebug(41010) << "Visiting on paint layer " << layer->name() << ", visible: " << layer->visible() + << ", temporary: " << layer->temporary() << ", extent: " + << layer->extent() << ", dirty: " << layer->dirtyRect() << ", paint rect: " << m_rc << endl; + if (!layer->visible()) + return true; + + TQ_INT32 sx, sy, dx, dy, w, h; + + TQRect rc = layer->paintDevice()->extent() & m_rc; + + // Indirect painting? + KisPaintDeviceSP tempTarget = layer->temporaryTarget(); + if (tempTarget) { + rc = (layer->paintDevice()->extent() | tempTarget->extent()) & m_rc; + } + + sx = rc.left(); + sy = rc.top(); + w = rc.width(); + h = rc.height(); + dx = sx; + dy = sy; + + KisPainter gc(m_projection); + KisPaintDeviceSP source = layer->paintDevice(); + + if (!layer->hasMask()) { + if (tempTarget) { + KisPaintDeviceSP temp = new KisPaintDevice(source->colorSpace()); + source = paintIndirect(source, temp, layer, sx, sy, dx, dy, w, h); + } + + gc.bitBlt(dx, dy, layer->compositeOp(), source, layer->opacity(), sx, sy, w, h); + } else { + if (layer->renderMask()) { + // To display the tqmask, we don't do things with composite op and opacity + // This is like the gimp does it, I guess that's ok? + + // Note that here we'll use m_rc, because even if the extent of the device is + // empty, we want a full tqmask to be drawn! (we don't change rc, since + // it'd mess with setClean). This is because KisPainter::bitBlt &'s with + // the source device's extent. This is ok in normal circumstances, but + // we changed the default tile. Fixing this properly would mean fixing it there. + sx = m_rc.left(); + sy = m_rc.top(); + w = m_rc.width(); + h = m_rc.height(); + dx = sx; + dy = sy; + + // The problem is that the extent of the layer tqmask might not be extended + // enough. Check if that is the case + KisPaintDeviceSP tqmask = layer->getMask(); + TQRect mextent = tqmask->extent(); + if ((mextent & m_rc) != m_rc) { + // Iterate over all pixels in the m_rc area. With just accessing the + // tiles in read-write mode, we ensure that the tiles get created if they + // do not exist. If they do, they'll remain untouched since we don't + // actually write data to it. + // XXX Admission: this is actually kind of a hack :-( + KisRectIteratorPixel it = tqmask->createRectIterator(sx, sy, w, h, true); + while (!it.isDone()) + ++it; + } + if (tempTarget) { + KisPaintDeviceSP temp = new KisPaintDevice(source->colorSpace()); + tqmask = paintIndirect(tqmask, temp, layer, sx, sy, dx, dy, w, h); + } + + gc.bitBlt(dx, dy, COMPOSITE_OVER, tqmask, OPACITY_OPAQUE, sx, sy, w, h); + } else { + KisSelectionSP tqmask = layer->getMaskAsSelection(); + // The indirect painting happens on the tqmask + if (tempTarget && layer->editMask()) { + KisPaintDeviceSP tqmaskSrc = layer->getMask(); + KisPaintDeviceSP temp = new KisPaintDevice(tqmaskSrc->colorSpace()); + temp = paintIndirect(tqmaskSrc, temp, layer, sx, sy, dx, dy, w, h); + // Blegh + KisRectIteratorPixel srcIt = temp->createRectIterator(sx, sy, w, h, false); + KisRectIteratorPixel dstIt = tqmask->createRectIterator(sx, sy, w, h, true); + + while(!dstIt.isDone()) { + // Same as in convertMaskToSelection + *dstIt.rawData() = *srcIt.rawData(); + ++srcIt; + ++dstIt; + } + } else if (tempTarget) { + // We have a tqmask, and paint indirect, but not on the tqmask + KisPaintDeviceSP temp = new KisPaintDevice(source->colorSpace()); + source = paintIndirect(source, temp, layer, sx, sy, dx, dy, w, h); + } + + gc.bltSelection(dx, dy, + layer->compositeOp(), + source, + tqmask, + layer->opacity(), sx, sy, w, h); + } + } + + layer->setClean( rc ); + return true; + } + + virtual bool visit(KisGroupLayer *layer) + { + + if (m_projection == 0) { + return false; + } + + kdDebug(41010) << "Visiting on group layer " << layer->name() << ", visible: " << layer->visible() << ", extent: " + << layer->extent() << ", dirty: " << layer->dirtyRect() << ", paint rect: " << m_rc << endl; + + if (!layer->visible()) + return true; + + TQ_INT32 sx, sy, dx, dy, w, h; + + // This automatically makes sure the projection is up-to-date for the specified rect. + KisPaintDeviceSP dev = layer->projection(m_rc); + TQRect rc = dev->extent() & m_rc; + + sx = rc.left(); + sy = rc.top(); + w = rc.width(); + h = rc.height(); + dx = sx; + dy = sy; + + KisPainter gc(m_projection); + gc.bitBlt(dx, dy, layer->compositeOp(), dev, layer->opacity(), sx, sy, w, h); + + return true; + } + + virtual bool visit(KisPartLayer* layer) + { + + kdDebug(41010) << "Visiting on part layer " << layer->name() << ", visible: " << layer->visible() << ", extent: " + << layer->extent() << ", dirty: " << layer->dirtyRect() << ", paint rect: " << m_rc << endl; + + if (m_projection == 0) { + return false; + } + if (!layer->visible()) + return true; + + KisPaintDeviceSP dev(layer->prepareProjection(m_projection, m_rc)); + if (!dev) + return true; + + TQ_INT32 sx, sy, dx, dy, w, h; + + TQRect rc = dev->extent() & m_rc; + + sx= rc.left(); + sy = rc.top(); + w = rc.width(); + h = rc.height(); + dx = sx; + dy = sy; + + KisPainter gc(m_projection); + gc.bitBlt(dx, dy, layer->compositeOp() , dev, layer->opacity(), sx, sy, w, h); + + layer->setClean(rc); + return true; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + kdDebug(41010) << "Visiting on adjustment layer " << layer->name() << ", visible: " << layer->visible() << ", extent: " + << layer->extent() << ", dirty: " << layer->dirtyRect() << ", paint rect: " << m_rc << endl; + + if (m_projection == 0) { + return true; + } + + if (!layer->visible()) + return true; + + KisPaintDeviceSP tempTarget = layer->temporaryTarget(); + if (tempTarget) { + m_rc = (layer->extent() | tempTarget->extent()) & m_rc; + } + + if (m_rc.width() == 0 || m_rc.height() == 0) // Don't even try + return true; + + KisFilterConfiguration * cfg = layer->filter(); + if (!cfg) return false; + + + KisFilter * f = KisFilterRegistry::instance()->get( cfg->name() ); + if (!f) return false; + + // Possibly enlarge the rect that changed (like for convolution filters) + // m_rc = f->enlargeRect(m_rc, cfg); + KisSelectionSP selection = layer->selection(); + + // Copy of the projection -- use the copy-on-write trick. XXX NO COPY ON WRITE YET =( + //KisPaintDeviceSP tmp = new KisPaintDevice(*m_projection); + KisPaintDeviceSP tmp = 0; + KisSelectionSP sel = selection; + // If there's a selection, only keep the selected bits + if (selection != 0) { + tmp = new KisPaintDevice(m_projection->colorSpace()); + + KisPainter gc(tmp); + TQRect selectedRect = selection->selectedRect(); + selectedRect &= m_rc; + + if (selectedRect.width() == 0 || selectedRect.height() == 0) // Don't even try + return true; + + // Don't forget that we need to take into account the extended sourcing area as well + //selectedRect = f->enlargeRect(selectedRect, cfg); + + //kdDebug() << k_funcinfo << selectedRect << endl; + tmp->setX(selection->getX()); + tmp->setY(selection->getY()); + + // Indirect painting + if (tempTarget) { + sel = new KisSelection(); + sel = paintIndirect(selection.data(), sel, layer, m_rc.left(), m_rc.top(), + m_rc.left(), m_rc.top(), m_rc.width(), m_rc.height()); + } + + gc.bitBlt(selectedRect.x(), selectedRect.y(), COMPOSITE_COPY, m_projection, + selectedRect.x(), selectedRect.y(), + selectedRect.width(), selectedRect.height()); + gc.end(); + } else { + tmp = new KisPaintDevice(*m_projection); + } + + // Some filters will require usage of oldRawData, which is not available without + // a transaction! + KisTransaction* cmd = new KisTransaction("", tmp); + + // Filter the temporary paint device -- remember, these are only the selected bits, + // if there was a selection. + f->process(tmp, tmp, cfg, m_rc); + + delete cmd; + + // Copy the filtered bits onto the projection + KisPainter gc(m_projection); + if (selection) + gc.bltSelection(m_rc.left(), m_rc.top(), + COMPOSITE_OVER, tmp, sel, layer->opacity(), + m_rc.left(), m_rc.top(), m_rc.width(), m_rc.height()); + else + gc.bitBlt(m_rc.left(), m_rc.top(), + COMPOSITE_OVER, tmp, layer->opacity(), + m_rc.left(), m_rc.top(), m_rc.width(), m_rc.height()); + gc.end(); + + // Copy the finished projection onto the cache + gc.begin(layer->cachedPaintDevice()); + gc.bitBlt(m_rc.left(), m_rc.top(), + COMPOSITE_COPY, m_projection, OPACITY_OPAQUE, + m_rc.left(), m_rc.top(), m_rc.width(), m_rc.height()); + layer->setClean(m_rc); + return true; + } + +private: + KisPaintDeviceSP m_projection; + TQRect m_rc; +}; + +#endif // KIS_MERGE_H_ + diff --git a/chalk/core/kis_meta_registry.cc b/chalk/core/kis_meta_registry.cc new file mode 100644 index 00000000..c6025869 --- /dev/null +++ b/chalk/core/kis_meta_registry.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include +#include LCMS_HEADER + +#include +#include +#include + +KisMetaRegistry * KisMetaRegistry::m_singleton = 0; + +KisMetaRegistry::KisMetaRegistry() +{ + // Create the colorspaces and load the profiles + + KGlobal::instance()->dirs()->addResourceType("kis_profiles", + KStandardDirs::kde_default("data") + "chalk/profiles/"); + + // Add those things here as well, since we are not yet using KisDoc's KisFactory instance (which inits these as well) + KGlobal::instance()->dirs()->addResourceType("kis_profiles", KStandardDirs::kde_default("data") + "chalk/profiles/"); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", "/usr/share/color/icc"); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", TQDir::homeDirPath() + TQString("/.icc/")); + KGlobal::instance()->dirs()->addResourceDir("kis_profiles", TQDir::homeDirPath() + TQString("/.color/icc/")); + + TQStringList profileFilenames; + profileFilenames += KGlobal::instance()->dirs()->findAllResources("kis_profiles", "*.icm", true /* recursive */); + profileFilenames += KGlobal::instance()->dirs()->findAllResources("kis_profiles", "*.ICM", true); + profileFilenames += KGlobal::instance()->dirs()->findAllResources("kis_profiles", "*.ICC", true); + profileFilenames += KGlobal::instance()->dirs()->findAllResources("kis_profiles", "*.icc", true); + // Set lcms to return NUll/false etc from failing calls, rather than aborting the app. + cmsErrorAction(LCMS_ERROR_SHOW); + + m_csRegistry = new KisColorSpaceFactoryRegistry(profileFilenames); + m_mtRegistry = new KisMathToolboxFactoryRegistry(); +} + +KisMetaRegistry::~KisMetaRegistry() +{ +} + +KisMetaRegistry * KisMetaRegistry::instance() +{ + if ( KisMetaRegistry::m_singleton == 0 ) { + KisMetaRegistry::m_singleton = new KisMetaRegistry(); + } + return KisMetaRegistry::m_singleton; +} + diff --git a/chalk/core/kis_meta_registry.h b/chalk/core/kis_meta_registry.h new file mode 100644 index 00000000..42aeee3d --- /dev/null +++ b/chalk/core/kis_meta_registry.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_META_REGISTRY_ +#define _KIS_META_REGISTRY_ + +class KisColorSpaceFactoryRegistry; +class KisMathToolboxFactoryRegistry; + +/** + * A single singleton that provides access to several registries. + * + * XXX: Maybe this should go into the SDK + */ +class KisMetaRegistry { + +public: + + virtual ~KisMetaRegistry(); + static KisMetaRegistry* instance(); + + KisColorSpaceFactoryRegistry * csRegistry() { return m_csRegistry; }; + KisMathToolboxFactoryRegistry* mtRegistry() { return m_mtRegistry; }; +private: + + KisMetaRegistry(); + KisMetaRegistry( const KisMetaRegistry& ); + KisMetaRegistry operator=( const KisMetaRegistry& ); + + static KisMetaRegistry * m_singleton; + + KisColorSpaceFactoryRegistry * m_csRegistry; + KisMathToolboxFactoryRegistry* m_mtRegistry; +}; +#endif diff --git a/chalk/core/kis_nameserver.cc b/chalk/core/kis_nameserver.cc new file mode 100644 index 00000000..ff66144d --- /dev/null +++ b/chalk/core/kis_nameserver.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_nameserver.h" + +KisNameServer::KisNameServer(const TQString& prefix, TQ_INT32 seed) +{ + m_prefix = prefix; + m_generator = seed; +} + +KisNameServer::~KisNameServer() +{ +} + +TQString KisNameServer::name() +{ + return m_prefix.tqarg(m_generator++); +} + +TQ_INT32 KisNameServer::currentSeed() const +{ + return m_generator; +} + +TQ_INT32 KisNameServer::number() +{ + return m_generator++; +} + +void KisNameServer::rollback() +{ + m_generator--; +} + diff --git a/chalk/core/kis_nameserver.h b/chalk/core/kis_nameserver.h new file mode 100644 index 00000000..a6989853 --- /dev/null +++ b/chalk/core/kis_nameserver.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_NAMESERVER_H_ +#define KIS_NAMESERVER_H_ + +#include +#include "kis_global.h" + +class KisNameServer { +public: + KisNameServer(const TQString& prefix, TQ_INT32 seed = 1); + ~KisNameServer(); + + TQString name(); + TQ_INT32 number(); + TQ_INT32 currentSeed() const; + void rollback(); + +private: + TQ_INT32 m_generator; + TQString m_prefix; +}; + +#endif // KIS_NAMESERVER_H_ + diff --git a/chalk/core/kis_paint_device.cc b/chalk/core/kis_paint_device.cc new file mode 100644 index 00000000..1ce2e98f --- /dev/null +++ b/chalk/core/kis_paint_device.cc @@ -0,0 +1,1285 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_painter.h" +#include "kis_fill_painter.h" +#include "kis_undo_adapter.h" +#include "kis_iterator.h" +#include "kis_iterators_pixel.h" +#include "kis_iteratorpixeltrait.h" +#include "kis_random_accessor.h" +#include "kis_random_sub_accessor.h" +#include "kis_transaction.h" +#include "kis_profile.h" +#include "kis_color.h" +#include "kis_integer_maths.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_selection.h" +#include "kis_layer.h" +#include "kis_paint_device_iface.h" +#include "kis_paint_device.h" +#include "kis_datamanager.h" +#include "kis_memento.h" +#include "kis_selection.h" + +#include "kis_exif_info.h" + +namespace { + + class KisPaintDeviceCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisPaintDeviceCommand(const TQString& name, KisPaintDeviceSP paintDevice); + virtual ~KisPaintDeviceCommand() {} + + virtual void execute() = 0; + virtual void unexecute() = 0; + + protected: + void setUndo(bool undo); + + KisPaintDeviceSP m_paintDevice; + }; + + KisPaintDeviceCommand::KisPaintDeviceCommand(const TQString& name, KisPaintDeviceSP paintDevice) : + super(name), m_paintDevice(paintDevice) + { + } + + void KisPaintDeviceCommand::setUndo(bool undo) + { + if (m_paintDevice->undoAdapter()) { + m_paintDevice->undoAdapter()->setUndo(undo); + } + } + + class MoveCommand : public KNamedCommand { + typedef KNamedCommand super; + + public: + MoveCommand(KisPaintDeviceSP device, const TQPoint& oldpos, const TQPoint& newpos); + virtual ~MoveCommand(); + + virtual void execute(); + virtual void unexecute(); + + private: + void moveTo(const TQPoint& pos); + void undoOff(); + void undoOn(); + + private: + KisPaintDeviceSP m_device; + TQPoint m_oldPos; + TQPoint m_newPos; + }; + + MoveCommand::MoveCommand(KisPaintDeviceSP device, const TQPoint& oldpos, const TQPoint& newpos) : + super(i18n("Move Layer")) + { + m_device = device; + m_oldPos = oldpos; + m_newPos = newpos; + } + + MoveCommand::~MoveCommand() + { + } + + void MoveCommand::undoOff() + { + if (m_device->undoAdapter()) { + m_device->undoAdapter()->setUndo(false); + } + } + + void MoveCommand::undoOn() + { + if (m_device->undoAdapter()) { + m_device->undoAdapter()->setUndo(true); + } + } + + void MoveCommand::execute() + { + undoOff(); + moveTo(m_newPos); + undoOn(); + } + + void MoveCommand::unexecute() + { + undoOff(); + moveTo(m_oldPos); + undoOn(); + } + + void MoveCommand::moveTo(const TQPoint& pos) + { + m_device->move(pos.x(), pos.y()); + } + + class KisConvertLayerTypeCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + KisConvertLayerTypeCmd(KisUndoAdapter *adapter, KisPaintDeviceSP paintDevice, + KisDataManagerSP beforeData, KisColorSpace * beforeColorSpace, + KisDataManagerSP afterData, KisColorSpace * afterColorSpace + ) : super(i18n("Convert Layer Type")) + { + m_adapter = adapter; + m_paintDevice = paintDevice; + m_beforeData = beforeData; + m_beforeColorSpace = beforeColorSpace; + m_afterData = afterData; + m_afterColorSpace = afterColorSpace; + } + + virtual ~KisConvertLayerTypeCmd() + { + } + + public: + virtual void execute() + { + m_adapter->setUndo(false); + m_paintDevice->setData(m_afterData, m_afterColorSpace); + m_adapter->setUndo(true); + } + + virtual void unexecute() + { + m_adapter->setUndo(false); + m_paintDevice->setData(m_beforeData, m_beforeColorSpace); + m_adapter->setUndo(true); + } + + private: + KisUndoAdapter *m_adapter; + + KisPaintDeviceSP m_paintDevice; + + KisDataManagerSP m_beforeData; + KisColorSpace * m_beforeColorSpace; + + KisDataManagerSP m_afterData; + KisColorSpace * m_afterColorSpace; + }; + +} + +KisPaintDevice::KisPaintDevice(KisColorSpace * colorSpace, const char * name) : + TQObject(0, name), KShared(), m_exifInfo(0), m_lock( false ) +{ + if (colorSpace == 0) { + kdWarning(41001) << "Cannot create paint device without colorstrategy!\n"; + return; + } + m_longRunningFilterTimer = 0; + m_dcop = 0; + + m_x = 0; + m_y = 0; + + m_pixelSize = colorSpace->pixelSize(); + m_nChannels = colorSpace->nChannels(); + + TQ_UINT8* defPixel = new TQ_UINT8 [ m_pixelSize ]; + colorSpace->fromTQColor(TQt::black, OPACITY_TRANSPARENT, defPixel); + + m_datamanager = new KisDataManager(m_pixelSize, defPixel); + delete [] defPixel; + + Q_CHECK_PTR(m_datamanager); + m_extentIsValid = true; + + m_parentLayer = 0; + + m_colorSpace = colorSpace; + + m_hasSelection = false; + m_selectionDeselected = false; + m_selection = 0; + +} + +KisPaintDevice::KisPaintDevice(KisLayer *tqparent, KisColorSpace * colorSpace, const char * name) : + TQObject(0, name), KShared(), m_exifInfo(0), m_lock( false ) +{ + + m_longRunningFilterTimer = 0; + m_dcop = 0; + + m_x = 0; + m_y = 0; + + m_hasSelection = false; + m_selectionDeselected = false; + m_selection = 0; + + m_parentLayer = tqparent; + + if (colorSpace == 0 && tqparent != 0 && tqparent->image() != 0) { + m_colorSpace = tqparent->image()->colorSpace(); + } + else { + m_colorSpace = colorSpace; + } + + Q_ASSERT( m_colorSpace ); + + m_pixelSize = m_colorSpace->pixelSize(); + m_nChannels = m_colorSpace->nChannels(); + + TQ_UINT8* defPixel = new TQ_UINT8[ m_pixelSize ]; + m_colorSpace->fromTQColor(TQt::black, OPACITY_TRANSPARENT, defPixel); + + m_datamanager = new KisDataManager(m_pixelSize, defPixel); + delete [] defPixel; + Q_CHECK_PTR(m_datamanager); + m_extentIsValid = true; + + if ( TQString ( name ) == TQString( "Layer 1" ) ) { + m_longRunningFilters = m_colorSpace->createBackgroundFilters(); + + if (!m_longRunningFilters.isEmpty()) { + m_longRunningFilterTimer = new TQTimer(this); + connect(m_longRunningFilterTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(runBackgroundFilters())); + m_longRunningFilterTimer->start(2000); + } + } +} + + +KisPaintDevice::KisPaintDevice(const KisPaintDevice& rhs) : TQObject(), KShared(rhs) +{ + if (this != &rhs) { + m_longRunningFilterTimer = 0; + m_parentLayer = 0; + m_dcop = rhs.m_dcop; + if (rhs.m_datamanager) { + m_datamanager = new KisDataManager(*rhs.m_datamanager); + Q_CHECK_PTR(m_datamanager); + } + else { + kdWarning() << "rhs " << rhs.name() << " has no datamanager\n"; + } + m_extentIsValid = rhs.m_extentIsValid; + m_x = rhs.m_x; + m_y = rhs.m_y; + m_colorSpace = rhs.m_colorSpace; + m_hasSelection = rhs.m_hasSelection; + + if ( m_hasSelection ) + m_selection = new KisSelection(*rhs.m_selection); + else + m_selection = 0; + + m_pixelSize = rhs.m_pixelSize; + m_nChannels = rhs.m_nChannels; + if(rhs.m_exifInfo) + { + m_exifInfo = new KisExifInfo(*rhs.m_exifInfo); + } + else { + m_exifInfo = 0; + } + } +} + +KisPaintDevice::~KisPaintDevice() +{ + delete m_dcop; + delete m_longRunningFilterTimer; + TQValueList::iterator it; + TQValueList::iterator end = m_longRunningFilters.end(); + for (it = m_longRunningFilters.begin(); it != end; ++it) { + KisFilter * f = (*it); + delete f; + } + m_longRunningFilters.clear(); + //delete m_exifInfo; +} + +DCOPObject *KisPaintDevice::dcopObject() +{ + if (!m_dcop) { + m_dcop = new KisPaintDeviceIface(this); + Q_CHECK_PTR(m_dcop); + } + return m_dcop; +} + +KisLayer *KisPaintDevice::tqparentLayer() const +{ + return m_parentLayer; +} + +void KisPaintDevice::setParentLayer(KisLayer *tqparentLayer) +{ + m_parentLayer = tqparentLayer; +} + +void KisPaintDevice::setDirty(const TQRect & rc) +{ + if (m_parentLayer) m_parentLayer->setDirty(rc); +} + +void KisPaintDevice::setDirty() +{ + if (m_parentLayer) m_parentLayer->setDirty(); +} + +KisImage *KisPaintDevice::image() const +{ + if (m_parentLayer) { + return m_parentLayer->image(); + } else { + return 0; + } +} + + +void KisPaintDevice::move(TQ_INT32 x, TQ_INT32 y) +{ + TQRect dirtyRect = extent(); + + m_x = x; + m_y = y; + + dirtyRect |= extent(); + + if(m_selection) + { + m_selection->setX(x); + m_selection->setY(y); + } + + setDirty(dirtyRect); + + emit positionChanged(this); +} + +void KisPaintDevice::move(const TQPoint& pt) +{ + move(pt.x(), pt.y()); +} + +KNamedCommand * KisPaintDevice::moveCommand(TQ_INT32 x, TQ_INT32 y) +{ + KNamedCommand * cmd = new MoveCommand(this, TQPoint(m_x, m_y), TQPoint(x, y)); + Q_CHECK_PTR(cmd); + cmd->execute(); + return cmd; +} + +void KisPaintDevice::extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const +{ + m_datamanager->extent(x, y, w, h); + x += m_x; + y += m_y; +} + +TQRect KisPaintDevice::extent() const +{ + TQ_INT32 x, y, w, h; + extent(x, y, w, h); + return TQRect(x, y, w, h); +} + +bool KisPaintDevice::extentIsValid() const +{ + return m_extentIsValid; +} + +void KisPaintDevice::setExtentIsValid(bool isValid) +{ + m_extentIsValid = isValid; +} + +void KisPaintDevice::exactBounds(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const +{ + TQRect r = exactBounds(); + x = r.x(); + y = r.y(); + w = r.width(); + h = r.height(); +} + +TQRect KisPaintDevice::exactBoundsOldMethod() const +{ + TQ_INT32 x, y, w, h, boundX, boundY, boundW, boundH; + extent(x, y, w, h); + + extent(boundX, boundY, boundW, boundH); + + const TQ_UINT8* defaultPixel = m_datamanager->defaultPixel(); + + bool found = false; + + for (TQ_INT32 y2 = y; y2 < y + h ; ++y2) { + KisHLineIterator it = const_cast(this)->createHLineIterator(x, y2, w, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundY = y2; + found = true; + break; + } + ++it; + } + if (found) break; + } + + found = false; + + for (TQ_INT32 y2 = y + h; y2 > y ; --y2) { + KisHLineIterator it = const_cast(this)->createHLineIterator(x, y2, w, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundH = y2 - boundY + 1; + found = true; + break; + } + ++it; + } + if (found) break; + } + found = false; + + for (TQ_INT32 x2 = x; x2 < x + w ; ++x2) { + KisVLineIterator it = const_cast(this)->createVLineIterator(x2, y, h, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundX = x2; + found = true; + break; + } + ++it; + } + if (found) break; + } + + found = false; + + // Look for right edge ) + for (TQ_INT32 x2 = x + w; x2 > x ; --x2) { + KisVLineIterator it = const_cast(this)->createVLineIterator(x2, y, h, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundW = x2 - boundX + 1; // XXX: I commented this + // +1 out, but why? It + // should be correct, since + // we've found the first + // pixel that should be + // included, and it should + // be added to the width. + found = true; + break; + } + ++it; + } + if (found) break; + } + + return TQRect(boundX, boundY, boundW, boundH); +} + +TQRect KisPaintDevice::exactBoundsImprovedOldMethod() const +{ + // Solution n°2 + TQ_INT32 x, y, w, h, boundX2, boundY2, boundW2, boundH2; + extent(x, y, w, h); + extent(boundX2, boundY2, boundW2, boundH2); + + const TQ_UINT8* defaultPixel = m_datamanager->defaultPixel(); + bool found = false; + { + KisHLineIterator it = const_cast(this)->createHLineIterator(x, y, w, false); + for (TQ_INT32 y2 = y; y2 < y + h ; ++y2) { + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundY2 = y2; + found = true; + break; + } + ++it; + } + if (found) break; + it.nextRow(); + } + } + + found = false; + + for (TQ_INT32 y2 = y + h; y2 > y ; --y2) { + KisHLineIterator it = const_cast(this)->createHLineIterator(x, y2, w, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundH2 = y2 - boundY2 + 1; + found = true; + break; + } + ++it; + } + if (found) break; + } + found = false; + + { + KisVLineIterator it = const_cast(this)->createVLineIterator(x, boundY2, boundH2, false); + for (TQ_INT32 x2 = x; x2 < x + w ; ++x2) { + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundX2 = x2; + found = true; + break; + } + ++it; + } + if (found) break; + it.nextCol(); + } + } + + found = false; + + // Look for right edge ) + { + for (TQ_INT32 x2 = x + w; x2 > x ; --x2) { + KisVLineIterator it = const_cast(this)->createVLineIterator(/*x + w*/ x2, boundY2, boundH2, false); + while (!it.isDone() && found == false) { + if (memcmp(it.rawData(), defaultPixel, m_pixelSize) != 0) { + boundW2 = x2 - boundX2 + 1; // XXX: I commented this + // +1 out, but why? It + // should be correct, since + // we've found the first + // pixel that should be + // included, and it should + // be added to the width. + found = true; + break; + } + ++it; + } + if (found) break; + } + } + return TQRect(boundX2, boundY2, boundW2, boundH2); +} + + +TQRect KisPaintDevice::exactBounds() const +{ + TQRect r2 = exactBoundsImprovedOldMethod(); + return r2; +} + +void KisPaintDevice::crop(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + m_datamanager->setExtent(x - m_x, y - m_y, w, h); +} + + +void KisPaintDevice::crop(TQRect r) +{ + r.moveBy(-m_x, -m_y); m_datamanager->setExtent(r); +} + +void KisPaintDevice::clear() +{ + m_datamanager->clear(); +} + +void KisPaintDevice::fill(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const TQ_UINT8 *fillPixel) +{ + m_datamanager->clear(x, y, w, h, fillPixel); +} + +void KisPaintDevice::mirrorX() +{ + TQRect r; + if (hasSelection()) { + r = selection()->selectedRect(); + } + else { + r = exactBounds(); + } + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + KisHLineIteratorPixel srcIt = createHLineIterator(r.x(), y, r.width(), false); + KisHLineIteratorPixel dstIt = createHLineIterator(r.x(), y, r.width(), true); + + dstIt += r.width() - 1; + + while (!srcIt.isDone()) { + if (srcIt.isSelected()) { + memcpy(dstIt.rawData(), srcIt.oldRawData(), m_pixelSize); + } + ++srcIt; + --dstIt; + + } + } + if (m_parentLayer) { + m_parentLayer->setDirty(r); + } +} + +void KisPaintDevice::mirrorY() +{ + /* Read a line from bottom to top and and from top to bottom and write their values to each other */ + TQRect r; + if (hasSelection()) { + r = selection()->selectedRect(); + } + else { + r = exactBounds(); + } + + + TQ_INT32 y1, y2; + for (y1 = r.top(), y2 = r.bottom(); y1 <= r.bottom(); ++y1, --y2) { + KisHLineIteratorPixel itTop = createHLineIterator(r.x(), y1, r.width(), true); + KisHLineIteratorPixel itBottom = createHLineIterator(r.x(), y2, r.width(), false); + while (!itTop.isDone() && !itBottom.isDone()) { + if (itBottom.isSelected()) { + memcpy(itTop.rawData(), itBottom.oldRawData(), m_pixelSize); + } + ++itBottom; + ++itTop; + } + } + + if (m_parentLayer) { + m_parentLayer->setDirty(r); + } +} + +KisMementoSP KisPaintDevice::getMemento() +{ + return m_datamanager->getMemento(); +} + +void KisPaintDevice::rollback(KisMementoSP memento) { m_datamanager->rollback(memento); } + +void KisPaintDevice::rollforward(KisMementoSP memento) { m_datamanager->rollforward(memento); } + +bool KisPaintDevice::write(KoStore *store) +{ + bool retval = m_datamanager->write(store); + emit ioProgress(100); + + return retval; +} + +bool KisPaintDevice::read(KoStore *store) +{ + bool retval = m_datamanager->read(store); + emit ioProgress(100); + + return retval; +} + +void KisPaintDevice::convertTo(KisColorSpace * dstColorSpace, TQ_INT32 renderingIntent) +{ + kdDebug(41004) << "Converting " << name() << " to " << dstColorSpace->id().id() << " from " + << m_colorSpace->id().id() << "\n"; + if ( colorSpace() == dstColorSpace ) + { + return; + } + + KisPaintDevice dst(dstColorSpace); + dst.setX(getX()); + dst.setY(getY()); + + TQ_INT32 x, y, w, h; + extent(x, y, w, h); + + for (TQ_INT32 row = y; row < y + h; ++row) { + + TQ_INT32 column = x; + TQ_INT32 columnsRemaining = w; + + while (columnsRemaining > 0) { + + TQ_INT32 numContiguousDstColumns = dst.numContiguousColumns(column, row, row); + TQ_INT32 numContiguousSrcColumns = numContiguousColumns(column, row, row); + + TQ_INT32 columns = TQMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = TQMIN(columns, columnsRemaining); + + //const TQ_UINT8 *srcData = pixel(column, row); + //TQ_UINT8 *dstData = dst.writablePixel(column, row); + KisHLineIteratorPixel srcIt = createHLineIterator(column, row, columns, false); + KisHLineIteratorPixel dstIt = dst.createHLineIterator(column, row, columns, true); + + const TQ_UINT8 *srcData = srcIt.rawData(); + TQ_UINT8 *dstData = dstIt.rawData(); + + + m_colorSpace->convertPixelsTo(srcData, dstData, dstColorSpace, columns, renderingIntent); + + column += columns; + columnsRemaining -= columns; + } + } + + KisDataManagerSP oldData = m_datamanager; + KisColorSpace *oldColorSpace = m_colorSpace; + + setData(dst.m_datamanager, dstColorSpace); + + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(new KisConvertLayerTypeCmd(undoAdapter(), this, oldData, oldColorSpace, m_datamanager, m_colorSpace)); + } +} + +void KisPaintDevice::setProfile(KisProfile * profile) +{ + if (profile == 0) return; + + KisColorSpace * dstSpace = + KisMetaRegistry::instance()->csRegistry()->getColorSpace( colorSpace()->id(), + profile); + if (dstSpace) + m_colorSpace = dstSpace; + +} + +void KisPaintDevice::setData(KisDataManagerSP data, KisColorSpace * colorSpace) +{ + m_datamanager = data; + m_colorSpace = colorSpace; + m_pixelSize = m_colorSpace->pixelSize(); + m_nChannels = m_colorSpace->nChannels(); + + if (m_parentLayer) { + m_parentLayer->setDirty(extent()); + m_parentLayer->notifyPropertyChanged(); + } +} + +KisUndoAdapter *KisPaintDevice::undoAdapter() const +{ + if (m_parentLayer && m_parentLayer->image()) { + return m_parentLayer->image()->undoAdapter(); + } + return 0; +} + +void KisPaintDevice::convertFromTQImage(const TQImage& image, const TQString &srcProfileName, + TQ_INT32 offsetX, TQ_INT32 offsetY) +{ + TQImage img = image; + + // Chalk is little-endian inside. + if (img.bitOrder() == TQImage::LittleEndian) { + img = img.convertBitOrder(TQImage::BigEndian); + } + kdDebug() << k_funcinfo << img.bitOrder()<< endl; + // Chalk likes bgra (convertDepth returns *this is the img is alread 32 bits) + img = img.convertDepth( 32 ); +#if 0 + // XXX: Apply import profile + if (colorSpace() == KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),"")) { + writeBytes(img.bits(), 0, 0, img.width(), img.height()); + } + else { +#endif + TQ_UINT8 * dstData = new TQ_UINT8[img.width() * img.height() * pixelSize()]; + KisMetaRegistry::instance()->csRegistry() + ->getColorSpace(KisID("RGBA",""),srcProfileName)-> + convertPixelsTo(img.bits(), dstData, colorSpace(), img.width() * img.height()); + writeBytes(dstData, offsetX, offsetY, img.width(), img.height()); +// } +} + +TQImage KisPaintDevice::convertToTQImage(KisProfile * dstProfile, float exposure) +{ + TQ_INT32 x1; + TQ_INT32 y1; + TQ_INT32 w; + TQ_INT32 h; + + x1 = - getX(); + y1 = - getY(); + + if (image()) { + w = image()->width(); + h = image()->height(); + } + else { + extent(x1, y1, w, h); + } + + return convertToTQImage(dstProfile, x1, y1, w, h, exposure); +} + +// XXX: is this faster than building the TQImage ourselves? It makes +TQImage KisPaintDevice::convertToTQImage(KisProfile * dstProfile, TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 w, TQ_INT32 h, float exposure) +{ + if (w < 0) + return TQImage(); + + if (h < 0) + return TQImage(); + + TQ_UINT8 * data = new TQ_UINT8 [w * h * m_pixelSize]; + Q_CHECK_PTR(data); + + // XXX: Is this really faster than converting line by line and building the TQImage directly? + // This copies potentially a lot of data. + readBytes(data, x1, y1, w, h); + TQImage image = colorSpace()->convertToTQImage(data, w, h, dstProfile, INTENT_PERCEPTUAL, exposure); + delete[] data; + + return image; +} + +KisPaintDeviceSP KisPaintDevice::createThumbnailDevice(TQ_INT32 w, TQ_INT32 h) +{ + KisPaintDeviceSP thumbnail = new KisPaintDevice(colorSpace(), "thumbnail"); + + thumbnail->clear(); + + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const TQRect e = exactBounds(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = TQ_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = TQ_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = TQ_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = TQ_INT32(double(srcw) / srch * h); + + for (TQ_INT32 y=0; y < h; ++y) { + TQ_INT32 iY = (y * srch ) / h; + for (TQ_INT32 x=0; x < w; ++x) { + TQ_INT32 iX = (x * srcw ) / w; + thumbnail->setPixel(x, y, colorAt(iX, iY)); + } + } + + return thumbnail; + +} + + +TQImage KisPaintDevice::createThumbnail(TQ_INT32 w, TQ_INT32 h) +{ + int srcw, srch; + if( image() ) + { + srcw = image()->width(); + srch = image()->height(); + } + else + { + const TQRect e = extent(); + srcw = e.width(); + srch = e.height(); + } + + if (w > srcw) + { + w = srcw; + h = TQ_INT32(double(srcw) / w * h); + } + if (h > srch) + { + h = srch; + w = TQ_INT32(double(srch) / h * w); + } + + if (srcw > srch) + h = TQ_INT32(double(srch) / srcw * w); + else if (srch > srcw) + w = TQ_INT32(double(srcw) / srch * h); + + TQColor c; + TQ_UINT8 opacity; + TQImage img(w,h,32); + + for (TQ_INT32 y=0; y < h; ++y) { + TQ_INT32 iY = (y * srch ) / h; + for (TQ_INT32 x=0; x < w; ++x) { + TQ_INT32 iX = (x * srcw ) / w; + pixel(iX, iY, &c, &opacity); + const TQRgb rgb = c.rgb(); + img.setPixel(x, y, tqRgba(tqRed(rgb), tqGreen(rgb), tqBlue(rgb), opacity)); + } + } + + return img; +} + +KisRectIteratorPixel KisPaintDevice::createRectIterator(TQ_INT32 left, TQ_INT32 top, TQ_INT32 w, TQ_INT32 h, bool writable) +{ + if(hasSelection()) + return KisRectIteratorPixel(this, m_datamanager, m_selection->m_datamanager, left, top, w, h, m_x, m_y, writable); + else + return KisRectIteratorPixel(this, m_datamanager, NULL, left, top, w, h, m_x, m_y, writable); +} + +KisHLineIteratorPixel KisPaintDevice::createHLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable) +{ + if(hasSelection()) + return KisHLineIteratorPixel(this, m_datamanager, m_selection->m_datamanager, x, y, w, m_x, m_y, writable); + else + return KisHLineIteratorPixel(this, m_datamanager, NULL, x, y, w, m_x, m_y, writable); +} + +KisVLineIteratorPixel KisPaintDevice::createVLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable) +{ + if(hasSelection()) + return KisVLineIteratorPixel(this, m_datamanager, m_selection->m_datamanager, x, y, h, m_x, m_y, writable); + else + return KisVLineIteratorPixel(this, m_datamanager, NULL, x, y, h, m_x, m_y, writable); + +} + +KisRandomAccessorPixel KisPaintDevice::createRandomAccessor(TQ_INT32 x, TQ_INT32 y, bool writable) { + if(hasSelection()) + return KisRandomAccessorPixel(m_datamanager, m_selection->m_datamanager, x, y, m_x, m_y, writable); + else + return KisRandomAccessorPixel(m_datamanager, NULL, x, y, m_x, m_y, writable); +} + +KisRandomSubAccessorPixel KisPaintDevice::createRandomSubAccessor() +{ + return KisRandomSubAccessorPixel(this); +} + +void KisPaintDevice::emitSelectionChanged() +{ + if (m_parentLayer && m_parentLayer->image()) { + m_parentLayer->image()->slotSelectionChanged(); + } +} + +void KisPaintDevice::emitSelectionChanged(const TQRect& r) +{ + if (m_parentLayer && m_parentLayer->image()) { + m_parentLayer->image()->slotSelectionChanged(r); + } +} + +KisSelectionSP KisPaintDevice::selection() +{ + if ( m_selectionDeselected && m_selection ) { + m_selectionDeselected = false; + } + else if (!m_selection) { + m_selection = new KisSelection(this); + Q_CHECK_PTR(m_selection); + m_selection->setX(m_x); + m_selection->setY(m_y); + } + m_hasSelection = true; + + return m_selection; +} + + +bool KisPaintDevice::hasSelection() +{ + return m_hasSelection; +} + +bool KisPaintDevice::selectionDeselected() +{ + return m_selectionDeselected; +} + + +void KisPaintDevice::deselect() +{ + if (m_selection && m_hasSelection) { + m_hasSelection = false; + m_selectionDeselected = true; + } +} + +void KisPaintDevice::reselect() +{ + m_hasSelection = true; + m_selectionDeselected = false; +} + +void KisPaintDevice::addSelection(KisSelectionSP selection) { + + KisPainter painter(this->selection().data()); + TQRect r = selection->selectedExactRect(); + painter.bitBlt(r.x(), r.y(), COMPOSITE_OVER, selection.data(), r.x(), r.y(), r.width(), r.height()); + painter.end(); +} + +void KisPaintDevice::subtractSelection(KisSelectionSP selection) { + KisPainter painter(this->selection().data()); + selection->invert(); + + TQRect r = selection->selectedExactRect(); + painter.bitBlt(r.x(), r.y(), COMPOSITE_ERASE, selection.data(), r.x(), r.y(), r.width(), r.height()); + + selection->invert(); + painter.end(); +} + +void KisPaintDevice::clearSelection() +{ + if (!hasSelection()) return; + + TQRect r = m_selection->selectedExactRect(); + + if (r.isValid()) { + + for (TQ_INT32 y = 0; y < r.height(); y++) { + + KisHLineIterator devIt = createHLineIterator(r.x(), r.y() + y, r.width(), true); + KisHLineIterator selectionIt = m_selection->createHLineIterator(r.x(), r.y() + y, r.width(), false); + + while (!devIt.isDone()) { + // XXX: Optimize by using stretches + + m_colorSpace->applyInverseAlphaU8Mask( devIt.rawData(), selectionIt.rawData(), 1); + + ++devIt; + ++selectionIt; + } + } + + if (m_parentLayer) { + m_parentLayer->setDirty(r); + } + } +} + +void KisPaintDevice::applySelectionMask(KisSelectionSP tqmask) +{ + TQRect r = tqmask->selectedRect(); + crop(r); + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + + KisHLineIterator pixelIt = createHLineIterator(r.x(), y, r.width(), true); + KisHLineIterator tqmaskIt = tqmask->createHLineIterator(r.x(), y, r.width(), false); + + while (!pixelIt.isDone()) { + // XXX: Optimize by using stretches + + m_colorSpace->applyAlphaU8Mask( pixelIt.rawData(), tqmaskIt.rawData(), 1); + + ++pixelIt; + ++tqmaskIt; + } + } +} + +KisSelectionSP KisPaintDevice::setSelection( KisSelectionSP selection) +{ + if (selection) { + KisSelectionSP oldSelection = m_selection; + m_selection = selection; + m_hasSelection = true; + return oldSelection; + } + else return 0; +} + +bool KisPaintDevice::pixel(TQ_INT32 x, TQ_INT32 y, TQColor *c, TQ_UINT8 *opacity) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + TQ_UINT8 *pix = iter.rawData(); + + if (!pix) return false; + + colorSpace()->toTQColor(pix, c, opacity); + + return true; +} + + +bool KisPaintDevice::pixel(TQ_INT32 x, TQ_INT32 y, KisColor * kc) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + TQ_UINT8 *pix = iter.rawData(); + + if (!pix) return false; + + kc->setColor(pix, m_colorSpace); + + return true; +} + +KisColor KisPaintDevice::colorAt(TQ_INT32 x, TQ_INT32 y) +{ + //return KisColor(m_datamanager->pixel(x - m_x, y - m_y), m_colorSpace); + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + return KisColor(iter.rawData(), m_colorSpace); +} + +bool KisPaintDevice::setPixel(TQ_INT32 x, TQ_INT32 y, const TQColor& c, TQ_UINT8 opacity) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + + colorSpace()->fromTQColor(c, opacity, iter.rawData()); + + return true; +} + +bool KisPaintDevice::setPixel(TQ_INT32 x, TQ_INT32 y, const KisColor& kc) +{ + TQ_UINT8 * pix; + if (kc.colorSpace() != m_colorSpace) { + KisColor kc2 (kc, m_colorSpace); + pix = kc2.data(); + } + else { + pix = kc.data(); + } + + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + memcpy(iter.rawData(), pix, m_colorSpace->pixelSize()); + + return true; +} + + +TQ_INT32 KisPaintDevice::numContiguousColumns(TQ_INT32 x, TQ_INT32 minY, TQ_INT32 maxY) +{ + return m_datamanager->numContiguousColumns(x - m_x, minY - m_y, maxY - m_y); +} + +TQ_INT32 KisPaintDevice::numContiguousRows(TQ_INT32 y, TQ_INT32 minX, TQ_INT32 maxX) +{ + return m_datamanager->numContiguousRows(y - m_y, minX - m_x, maxX - m_x); +} + +TQ_INT32 KisPaintDevice::rowStride(TQ_INT32 x, TQ_INT32 y) +{ + return m_datamanager->rowStride(x - m_x, y - m_y); +} + +const TQ_UINT8* KisPaintDevice::pixel(TQ_INT32 x, TQ_INT32 y) +{ + return m_datamanager->pixel(x - m_x, y - m_y); +} + +TQ_UINT8* KisPaintDevice::writablePixel(TQ_INT32 x, TQ_INT32 y) +{ + return m_datamanager->writablePixel(x - m_x, y - m_y); +} + +void KisPaintDevice::setX(TQ_INT32 x) +{ + m_x = x; + if(m_selection && m_selection != this) + m_selection->setX(x); +} + +void KisPaintDevice::setY(TQ_INT32 y) +{ + m_y = y; + if(m_selection && m_selection != this) + m_selection->setY(y); +} + + +void KisPaintDevice::readBytes(TQ_UINT8 * data, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + m_datamanager->readBytes(data, x - m_x, y - m_y, w, h); +} + +void KisPaintDevice::writeBytes(const TQ_UINT8 * data, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + m_datamanager->writeBytes( data, x - m_x, y - m_y, w, h); +} + + +KisDataManagerSP KisPaintDevice::dataManager() const +{ + return m_datamanager; +} + +KisExifInfo* KisPaintDevice::exifInfo() +{ + if(!m_exifInfo) + m_exifInfo = new KisExifInfo(); + return m_exifInfo; +} + +void KisPaintDevice::runBackgroundFilters() +{ + if ( m_lock ) return; + + KisTransaction * cmd = new KisTransaction("Running autofilters", this); + + TQRect rc = extent(); + if (!m_longRunningFilters.isEmpty()) { + TQValueList::iterator it; + TQValueList::iterator end = m_longRunningFilters.end(); + for (it = m_longRunningFilters.begin(); it != end; ++it) { + (*it)->process(this, this, 0, rc); + } + } + if (cmd && undoAdapter()) undoAdapter()->addCommand(cmd); + + if (m_parentLayer) m_parentLayer->setDirty(rc); +} + +#include "kis_paint_device.moc" diff --git a/chalk/core/kis_paint_device.h b/chalk/core/kis_paint_device.h new file mode 100644 index 00000000..6e804afe --- /dev/null +++ b/chalk/core/kis_paint_device.h @@ -0,0 +1,597 @@ +/* + * copyright (c) 2002 patrick julien + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_PAINT_DEVICE_IMPL_H_ +#define KIS_PAINT_DEVICE_IMPL_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_types.h" +#include "kdebug.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_colorspace.h" +#include "kis_canvas_controller.h" +#include "kis_color.h" +#include + +class DCOPObject; + +class TQImage; +class TQSize; +class TQPoint; +class TQWMatrix; +class TQTimer; + +class KNamedCommand; + +class KoStore; + +class KisExifInfo; +class KisHLineIteratorPixel; +class KisImage; +class KisRectIteratorPixel; +class KisVLineIteratorPixel; +class KisRandomAccessorPixel; +class KisRandomSubAccessorPixel; +class KisUndoAdapter; +class KisFilter; +class KisDataManager; +typedef KSharedPtr KisDataManagerSP; + +class KisMemento; +typedef KSharedPtr KisMementoSP; + + +/** + * A paint device contains the actual pixel data and offers methods + * to read and write pixels. A paint device has an integer x,y position + * (i.e., are not positioned on the image with sub-pixel accuracy). + * A KisPaintDevice doesn't have any fixed size, the size change dynamicaly + * when pixels are accessed by an iterator. + */ +class KRITACORE_EXPORT KisPaintDevice + : public TQObject + , public KShared +{ + + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Create a new paint device with the specified colorspace. + * + * @param colorSpace the colorspace of this paint device + * @param name for debugging purposes + */ + KisPaintDevice(KisColorSpace * colorSpace, const char * name = 0); + + /** + * Create a new paint device with the specified colorspace. The + * tqparentLayer will be notified of changes to this paint device. + * + * @param tqparentLayer the layer that contains this paint device. + * @param colorSpace the colorspace of this paint device + * @param name for debugging purposes + */ + KisPaintDevice(KisLayer *tqparentLayer, KisColorSpace * colorSpace, const char * name = 0); + + KisPaintDevice(const KisPaintDevice& rhs); + virtual ~KisPaintDevice(); + virtual DCOPObject *dcopObject(); + + void lock(bool lock) { m_lock = lock; } + +public: + + /** + * Write the pixels of this paint device into the specified file store. + */ + virtual bool write(KoStore *store); + + /** + * Fill this paint device with the pixels from the specified file store. + */ + virtual bool read(KoStore *store); + +public: + + /** + * Moves the device to these new coordinates (so no incremental move or so) + */ + virtual void move(TQ_INT32 x, TQ_INT32 y); + + /** + * Convenience method for the above + */ + virtual void move(const TQPoint& pt); + + /** + * Move the paint device to the specified location and make it possible to + * undo the move. + */ + virtual KNamedCommand * moveCommand(TQ_INT32 x, TQ_INT32 y); + + /** + * Returns true of x,y is within the extent of this paint device + */ + bool tqcontains(TQ_INT32 x, TQ_INT32 y) const; + + /** + * Convenience method for the above + */ + bool tqcontains(const TQPoint& pt) const; + + /** + * Retrieve the bounds of the paint device. The size is not exact, + * but may be larger if the underlying datamanager works that way. + * For instance, the tiled datamanager keeps the extent to the nearest + * multiple of 64. + */ + virtual void extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const; + virtual TQRect extent() const; + + /** + * XXX: This should be a temporay hack, awaiting a proper fix. + * + * Indicates whether the extent really represents the extent. For example, + * the KisBackground checkerboard pattern is generated by filling the + * default tile but it will return an empty extent. + */ + bool extentIsValid() const; + + /// Convience method for the above + void setExtentIsValid(bool isValid); + + /** + * Get the exact bounds of this paint device. This may be very slow, + * especially on larger paint devices because it does a linear scanline search. + */ + virtual void exactBounds(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const; + virtual TQRect exactBounds() const; + virtual TQRect exactBoundsOldMethod() const; + virtual TQRect exactBoundsImprovedOldMethod() const; + + /** + * Cut the paint device down to the specified rect + */ + void crop(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /// Convience method for the above + void crop(TQRect r); + + /** + * Complete erase the current paint device. Its size will become 0. + */ + virtual void clear(); + + /** + * Fill the given rectangle with the given pixel. + */ + void fill(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const TQ_UINT8 *fillPixel); + + /** + * Read the bytes representing the rectangle described by x, y, w, h into + * data. If data is not big enough, Chalk will gladly overwrite the rest + * of your precious memory. + * + * Since this is a copy, you need to make sure you have enough memory. + * + * Reading from areas not previously initialized will read the default + * pixel value into data but not initialize that region. + */ + virtual void readBytes(TQ_UINT8 * data, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /** + * Copy the bytes in data into the rect specified by x, y, w, h. If the + * data is too small or uninitialized, Chalk will happily read parts of + * memory you never wanted to be read. + * + * If the data is written to areas of the paint device not previously initialized, + * the paint device will grow. + */ + virtual void writeBytes(const TQ_UINT8 * data, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /** + * Get the number of contiguous columns starting at x, valid for all values + * of y between minY and maxY. + */ + TQ_INT32 numContiguousColumns(TQ_INT32 x, TQ_INT32 minY, TQ_INT32 maxY); + + /** + * Get the number of contiguous rows starting at y, valid for all values + * of x between minX and maxX. + */ + TQ_INT32 numContiguousRows(TQ_INT32 y, TQ_INT32 minX, TQ_INT32 maxX); + + /** + * Get the row stride at pixel (x, y). This is the number of bytes to add to a + * pointer to pixel (x, y) to access (x, y + 1). + */ + TQ_INT32 rowStride(TQ_INT32 x, TQ_INT32 y); + + /** + * Get a read-only pointer to pixel (x, y). + */ + KDE_DEPRECATED const TQ_UINT8* pixel(TQ_INT32 x, TQ_INT32 y); + + /** + * Get a read-write pointer to pixel (x, y). + */ + KDE_DEPRECATED TQ_UINT8* writablePixel(TQ_INT32 x, TQ_INT32 y); + + /** + * Converts the paint device to a different colorspace + */ + virtual void convertTo(KisColorSpace * dstColorSpace, TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + /** + * Changes the profile of the colorspace of this paint device to the given + * profile. If the given profile is 0, nothing happens. + */ + virtual void setProfile(KisProfile * profile); + + /** + * Fill this paint device with the data from img; starting at (offsetX, offsetY) + * @param srcProfileName name of the RGB profile to interpret the img as. "" is interpreted as sRGB + */ + virtual void convertFromTQImage(const TQImage& img, const TQString &srcProfileName, TQ_INT32 offsetX = 0, TQ_INT32 offsetY = 0); + + /** + * Create an RGBA TQImage from a rectangle in the paint device. + * + * @param x Left coordinate of the rectangle + * @param y Top coordinate of the rectangle + * @param w Width of the rectangle in pixels + * @param h Height of the rectangle in pixels + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the colour strategy to choose a profile (most + * like sRGB). + * @param exposure The exposure setting used to render a preview of a high dynamic range image. + */ + virtual TQImage convertToTQImage(KisProfile * dstProfile, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, float exposure = 0.0f); + + /** + * Create an RGBA TQImage from a rectangle in the paint device. The rectangle is defined by the tqparent image's bounds. + * + * @param dstProfile RGB profile to use in conversion. May be 0, in which + * case it's up to the colour strategy to choose a profile (most + * like sRGB). + * @param exposure The exposure setting used to render a preview of a high dynamic range image. + */ + virtual TQImage convertToTQImage(KisProfile * dstProfile, float exposure = 0.0f); + + /** + * Creates a paint device thumbnail of the paint device, retaining the aspect ratio. + * The width and height of the returned device won't exceed \p maxw and \p maxw, but they may be smaller. + */ + + KisPaintDeviceSP createThumbnailDevice(TQ_INT32 w, TQ_INT32 h); + + /** + * Creates a thumbnail of the paint device, retaining the aspect ratio. + * The width and height of the returned TQImage won't exceed \p maxw and \p maxw, but they may be smaller. + * The colors are not corrected for display! + */ + virtual TQImage createThumbnail(TQ_INT32 maxw, TQ_INT32 maxh); + + + /** + * Fill c and opacity with the values found at x and y. + * + * The color values will be transformed from the profile of + * this paint device to the display profile. + * + * @return true if the operation was succesful. + */ + bool pixel(TQ_INT32 x, TQ_INT32 y, TQColor *c, TQ_UINT8 *opacity); + + + /** + * Fill kc with the values found at x and y. This method differs + * from the above in using KisColor, which can be of any colorspace + * + * The color values will be transformed from the profile of + * this paint device to the display profile. + * + * @return true if the operation was succesful. + */ + bool pixel(TQ_INT32 x, TQ_INT32 y, KisColor * kc); + + /** + * Return the KisColor of the pixel at x,y. + */ + KisColor colorAt(TQ_INT32 x, TQ_INT32 y); + + /** + * Set the specified pixel to the specified color. Note that this + * bypasses KisPainter. the PaintDevice is here used as an equivalent + * to TQImage, not TQPixmap. This means that this is not undoable; also, + * there is no compositing with an existing value at this location. + * + * The color values will be transformed from the display profile to + * the paint device profile. + * + * Note that this will use 8-bit values and may cause a significant + * degradation when used on 16-bit or hdr quality images. + * + * @return true if the operation was succesful + * + */ + bool setPixel(TQ_INT32 x, TQ_INT32 y, const TQColor& c, TQ_UINT8 opacity); + + bool setPixel(TQ_INT32 x, TQ_INT32 y, const KisColor& kc); + + KisColorSpace * colorSpace() const; + + KisDataManagerSP dataManager() const; + + /** + * Replace the pixel data, color strategy, and profile. + */ + void setData(KisDataManagerSP data, KisColorSpace * colorSpace); + + /** + * The X offset of the paint device + */ + TQ_INT32 getX() const; + + /** + * The Y offset of the paint device + */ + TQ_INT32 getY() const; + + /** + * Return the X offset of the paint device + */ + void setX(TQ_INT32 x); + + /** + * Return the Y offset of the paint device + */ + void setY(TQ_INT32 y); + + + /** + * Return the number of bytes a pixel takes. + */ + virtual TQ_INT32 pixelSize() const; + + /** + * Return the number of channels a pixel takes + */ + virtual TQ_INT32 nChannels() const; + + /** + * Return the image that contains this paint device, or 0 if it is not + * part of an image. This is the same as calling tqparentLayer()->image(). + */ + KisImage *image() const; + + /** + * Returns the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + KisLayer *tqparentLayer() const; + + /** + * Set the KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + void setParentLayer(KisLayer *tqparentLayer); + + /** + * Add the specified rect top the tqparent layer (if present) + */ + virtual void setDirty(const TQRect & rc); + + /** + * Set the tqparent layer completely dirty, if this paint device has one. + */ + virtual void setDirty(); + + + /** + * Mirror the device along the X axis + */ + void mirrorX(); + /** + * Mirror the device along the Y axis + */ + void mirrorY(); + + KisMementoSP getMemento(); + void rollback(KisMementoSP memento); + void rollforward(KisMementoSP memento); + + /** + * This function return an iterator which points to the first pixel of an rectangle + */ + KisRectIteratorPixel createRectIterator(TQ_INT32 left, TQ_INT32 top, TQ_INT32 w, TQ_INT32 h, bool writable); + + /** + * This function return an iterator which points to the first pixel of a horizontal line + */ + KisHLineIteratorPixel createHLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable); + + /** + * This function return an iterator which points to the first pixel of a vertical line + */ + KisVLineIteratorPixel createVLineIterator(TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable); + + /** + * This function creates a random accessor which allow to randomly access any pixels on + * the paint device. + * Note: random access is way slower than iterators, allways use iterators whenever + * you can + */ + KisRandomAccessorPixel createRandomAccessor(TQ_INT32 x, TQ_INT32 y, bool writable); + + /** + * This function create a random accessor which can easily access to sub pixel values. + */ + KisRandomSubAccessorPixel createRandomSubAccessor(); + + /** Get the current selection or create one if this paintdevice hasn't got a selection yet. */ + KisSelectionSP selection(); + + /** Adds the specified selection to the currently active selection for this paintdevice */ + void addSelection(KisSelectionSP selection); + + /** Subtracts the specified selection from the currently active selection for this paindevice */ + void subtractSelection(KisSelectionSP selection); + + /** Whether there is a valid selection for this paintdevice. */ + bool hasSelection(); + + /** Whether the previous selection was deselected. */ + bool selectionDeselected(); + + /** Deselect the selection for this paintdevice. */ + void deselect(); + + /** Reinstates the old selection */ + void reselect(); + + /** Clear the selected pixels from the paint device */ + void clearSelection(); + + /** + * Apply a tqmask to the image data, i.e. multiply each pixel's opacity by its + * selectedness in the tqmask. + */ + void applySelectionMask(KisSelectionSP tqmask); + + /** + * Sets the selection of this paint device to the new selection, + * returns the old selection, if there was an old selection, + * otherwise 0 + */ + KisSelectionSP setSelection(KisSelectionSP selection); + + /** + * Notify the owning image that the current selection has changed. + */ + void emitSelectionChanged(); + + /** + * Notify the owning image that the current selection has changed. + * + * @param r the area for which the selection has changed + */ + void emitSelectionChanged(const TQRect& r); + + + KisUndoAdapter *undoAdapter() const; + + /** + * Return the exifInfo associated with this layer. If no exif infos are + * available, the function will create it. + */ + KisExifInfo* exifInfo(); + /** + * This function return true if the layer has exif info associated with it. + */ + bool hasExifInfo() { return m_exifInfo != 0; } +signals: + void positionChanged(KisPaintDeviceSP device); + void ioProgress(TQ_INT8 percentage); + void profileChanged(KisProfile * profile); + +private slots: + + void runBackgroundFilters(); + +private: + KisPaintDevice& operator=(const KisPaintDevice&); + +protected: + KisDataManagerSP m_datamanager; + +private: + /* The KisLayer that contains this paint device, or 0 if this is not + * part of a layer. + */ + KisLayer *m_parentLayer; + + bool m_extentIsValid; + + TQ_INT32 m_x; + TQ_INT32 m_y; + KisColorSpace * m_colorSpace; + // Cached for quick access + TQ_INT32 m_pixelSize; + TQ_INT32 m_nChannels; + + // Whether the selection is active + bool m_hasSelection; + bool m_selectionDeselected; + + // Contains the actual selection. For now, there can be only + // one selection per layer. XXX: is this a limitation? + KisSelectionSP m_selection; + + DCOPObject * m_dcop; + + KisExifInfo* m_exifInfo; + + TQValueList m_longRunningFilters; + TQTimer * m_longRunningFilterTimer; + + bool m_lock; +}; + +inline TQ_INT32 KisPaintDevice::pixelSize() const +{ + Q_ASSERT(m_pixelSize > 0); + return m_pixelSize; +} + +inline TQ_INT32 KisPaintDevice::nChannels() const +{ + Q_ASSERT(m_nChannels > 0); + return m_nChannels; +; +} + +inline KisColorSpace * KisPaintDevice::colorSpace() const +{ + Q_ASSERT(m_colorSpace != 0); + return m_colorSpace; +} + + +inline TQ_INT32 KisPaintDevice::getX() const +{ + return m_x; +} + +inline TQ_INT32 KisPaintDevice::getY() const +{ + return m_y; +} + +#endif // KIS_PAINT_DEVICE_IMPL_H_ + diff --git a/chalk/core/kis_paint_device_action.h b/chalk/core/kis_paint_device_action.h new file mode 100644 index 00000000..1e3d41f0 --- /dev/null +++ b/chalk/core/kis_paint_device_action.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PAINTDEV_ACTION_H_ +#define KIS_PAINTDEV_ACTION_H_ + +#include "kis_paint_device.h" +class TQString; + +/** + * Defines an action to do with a paint device. It can be force used by the gui on creation + * of a layer, for example. Or just appear in a list of actions to do. + */ +class KisPaintDeviceAction { +public: + virtual ~KisPaintDeviceAction() {} + /** + * Do something with the paint device. This can be anything, like, for example, popping + * up a dialog to choose a texture. The width and height are added because these may + * be needed in some cases. + */ + virtual void act(KisPaintDeviceSP paintDev, TQ_INT32 w = 0, TQ_INT32 h = 0) const = 0; + /// The name of the action, to be displayed in the GUI + virtual TQString name() const = 0; + /// A description of the action, to be displayed in the GUI + virtual TQString description() const = 0; +}; + +#endif // KIS_PAINTDEV_ACTION_H_ diff --git a/chalk/core/kis_paint_device_iface.cc b/chalk/core/kis_paint_device_iface.cc new file mode 100644 index 00000000..1aace538 --- /dev/null +++ b/chalk/core/kis_paint_device_iface.cc @@ -0,0 +1,74 @@ +/* + * This file is part of the KDE project + * + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include + +#include "kis_paint_device_iface.h" +#include "kis_colorspace_iface.h" +#include "kis_colorspace.h" + +#include "kis_paint_device.h" + +KisPaintDeviceIface::KisPaintDeviceIface( KisPaintDevice * tqparent ) + : DCOPObject("paintdevice") +{ + m_parent = tqparent; +} + +TQ_INT32 KisPaintDeviceIface::pixelSize() const +{ + return m_parent->pixelSize(); +} + +TQ_INT32 KisPaintDeviceIface::nChannels() const +{ + return m_parent->nChannels(); +} + +TQByteArray KisPaintDeviceIface::readBytes(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + TQByteArray b (w * h * m_parent->pixelSize()); + + m_parent->readBytes((TQ_UINT8*)b.data(), x, y, w, h); + return b; +} + +void KisPaintDeviceIface::writeBytes(TQByteArray bytes, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + m_parent->writeBytes((TQ_UINT8*)bytes.data(), x, y, w, h); +} + +DCOPRef KisPaintDeviceIface::colorSpace() const +{ + KisColorSpace * cs = m_parent->colorSpace(); + if ( !cs ) + return DCOPRef(); + else + return DCOPRef( kapp->dcopClient()->appId(), + cs->dcopObject()->objId(), + "KisColorSpaceIface" ); +} + +void KisPaintDeviceIface::setColorSpace(DCOPRef) +{ + // XXX: Figure out how to get the correct object from + // the dcopref +} diff --git a/chalk/core/kis_paint_device_iface.h b/chalk/core/kis_paint_device_iface.h new file mode 100644 index 00000000..df7c9372 --- /dev/null +++ b/chalk/core/kis_paint_device_iface.h @@ -0,0 +1,85 @@ +/* + * This file is part of the KDE project + * + * Copyright (C) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_PAINT_DEVICE_IFACE_H +#define _KIS_PAINT_DEVICE_IFACE_H + +#include +#include + +#include + +class KisPaintDevice; + +class KisPaintDeviceIface : virtual public DCOPObject +{ + K_DCOP +public: + KisPaintDeviceIface( KisPaintDevice * tqparent ); +k_dcop: + + /** + * Return the number of bytes a pixel takes. + */ + TQ_INT32 pixelSize() const; + + /** + * Return the number of channels a pixel takes + */ + TQ_INT32 nChannels() const; + + /** + * Read the bytes representing the rectangle described by x, y, w, h into + * data. If data is not big enough, Chalk will gladly overwrite the rest + * of your precious memory. + * + * Since this is a copy, you need to make sure you have enough memory. + * + * Reading from areas not previously initialized will read the default + * pixel value into data. + */ + TQByteArray readBytes(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /** + * Copy the bytes in data into the rect specified by x, y, w, h. If there + * data is too small or uninitialized, Chalk will happily read parts of + * memory you never wanted to be read. + * + * If the data is written to areas of the paint device not previously initialized, + * the paint device will grow. + */ + void writeBytes(TQByteArray bytes, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + /** + * Get the colorspace of this image + */ + DCOPRef colorSpace() const; + + /** + * Set the colorspace of this image + */ + void setColorSpace(DCOPRef colorSpace); + + +private: + + KisPaintDevice *m_parent; +}; + +#endif diff --git a/chalk/core/kis_paint_layer.cc b/chalk/core/kis_paint_layer.cc new file mode 100644 index 00000000..63663067 --- /dev/null +++ b/chalk/core/kis_paint_layer.cc @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2005 Casper Boemann + * Copyright (c) 2006 Bart Coppens + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#include +#include + +#include "kis_debug_areas.h" +#include "kis_image.h" +#include "kis_paint_layer.h" +#include "kis_selection.h" +#include "kis_painter.h" +#include "kis_undo_adapter.h" +#include "kis_iterators_pixel.h" +#include "kis_paint_device.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_datamanager.h" +#include "kis_undo_adapter.h" + +KisPaintLayer::KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity, KisPaintDeviceSP dev) + : super(img, name, opacity) +{ + Q_ASSERT(img); + Q_ASSERT(dev); + m_paintdev = dev; + m_tqmask = 0; + m_tqmaskAsSelection = 0; + m_paintdev->setParentLayer(this); + m_renderMask = false; + m_editMask = true; +} + + +KisPaintLayer::KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity) + : super(img, name, opacity) +{ + Q_ASSERT(img); + m_paintdev = new KisPaintDevice(this, img->colorSpace(), name.latin1()); + m_tqmask = 0; + m_tqmaskAsSelection = 0; + m_renderMask = false; + m_editMask = true; +} + +KisPaintLayer::KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity, KisColorSpace * colorSpace) + : super(img, name, opacity) +{ + Q_ASSERT(img); + Q_ASSERT(colorSpace); + m_paintdev = new KisPaintDevice(this, colorSpace, name.latin1()); + m_tqmask = 0; + m_tqmaskAsSelection = 0; + m_renderMask = false; + m_editMask = true; +} + +KisPaintLayer::KisPaintLayer(const KisPaintLayer& rhs) : + KisLayer(rhs), KisLayerSupportsIndirectPainting(rhs) +{ + m_paintdev = new KisPaintDevice( *rhs.m_paintdev.data() ); + m_paintdev->setParentLayer(this); + if (rhs.hasMask()) { + m_tqmask = new KisPaintDevice(*rhs.m_tqmask.data()); + m_tqmask->setParentLayer(this); + } + m_renderMask = rhs.m_renderMask; + m_editMask = rhs.m_editMask; +} + +KisLayerSP KisPaintLayer::clone() const +{ + return new KisPaintLayer(*this); +} + +KisPaintLayer::~KisPaintLayer() +{ + if (m_paintdev != 0) { + m_paintdev->setParentLayer(0); + } + if (m_tqmask != 0) { + m_tqmask->setParentLayer(0); + } +} + +void KisPaintLayer::paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + if (m_paintdev && m_paintdev->hasSelection()) { + m_paintdev->selection()->paintSelection(img, x, y, w, h); + } else if (m_tqmask && m_editMask && m_tqmask->hasSelection()) { + m_tqmask->selection()->paintSelection(img, x, y, w, h); + } +} + +void KisPaintLayer::paintSelection(TQImage &img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize) +{ + if (m_paintdev && m_paintdev->hasSelection()) { + m_paintdev->selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); + } else if (m_tqmask && m_editMask && m_tqmask->hasSelection()) { + m_tqmask->selection()->paintSelection(img, scaledImageRect, scaledImageSize, imageSize); + } +} + +void KisPaintLayer::paintMaskInactiveLayers(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + uchar *j = img.bits(); + + KisColorSpace *cs = m_paintdev->colorSpace(); + + for (TQ_INT32 y2 = y; y2 < h + y; ++y2) { + KisHLineIteratorPixel it = m_paintdev->createHLineIterator(x, y2, w, false); + while ( ! it.isDone()) { + TQ_UINT8 s = cs->getAlpha(it.rawData()); + if(s==0) + { + TQ_UINT8 g = (*(j + 0) + *(j + 1 ) + *(j + 2 )) / 9; + + *(j+0) = 128+g ; + *(j+1) = 165+g; + *(j+2) = 128+g; + } + j+=4; + ++it; + } + } +} + +TQImage KisPaintLayer::createThumbnail(TQ_INT32 w, TQ_INT32 h) +{ + if (m_paintdev) + return m_paintdev->createThumbnail(w, h); + else + return TQImage(); +} + + +TQ_INT32 KisPaintLayer::x() const { + if (m_paintdev) + return m_paintdev->getX(); + else return 0; +} + +void KisPaintLayer::setX(TQ_INT32 x) +{ + if (m_paintdev) + m_paintdev->setX(x); +} + +TQ_INT32 KisPaintLayer::y() const { + if (m_paintdev) + return m_paintdev->getY(); + else + return 0; +} + +void KisPaintLayer::setY(TQ_INT32 y) { + if (m_paintdev) + m_paintdev->setY(y); +} + +TQRect KisPaintLayer::extent() const { + if (m_paintdev) + return m_paintdev->extent(); + else + return TQRect(); +} + +TQRect KisPaintLayer::exactBounds() const { + if (m_paintdev) + return m_paintdev->exactBounds(); + else + return TQRect(); +} + +void KisPaintLayer::removeMask() { + if (!hasMask()) + return; + + m_tqmask->setParentLayer(0); + m_tqmask = 0; + m_tqmaskAsSelection = 0; + setDirty(); + + emit sigMaskInfoChanged(); +} + +// ### XXX Do we apply the tqmask outside the image boundaries too? I'd say no, but I'm not sure +void KisPaintLayer::applyMask() { + if (!hasMask()) + return; + + int x, y, w, h; + m_paintdev->extent(x, y, w, h); + + // A bit slow; but it works + KisPaintDeviceSP temp = new KisPaintDevice(m_paintdev->colorSpace()); + KisPainter gc(temp); + gc.bltSelection(x, y, COMPOSITE_OVER, m_paintdev, m_tqmaskAsSelection, OPACITY_OPAQUE, x, y, w, h); + gc.end(); + gc.begin(m_paintdev); + gc.bitBlt(x, y, COMPOSITE_COPY, temp, OPACITY_OPAQUE, x, y, w, h); + gc.end(); + + removeMask(); +} + +KisPaintDeviceSP KisPaintLayer::createMask() { + if (hasMask()) + return m_tqmask; + + kdDebug() << k_funcinfo << endl; + // Grey8 nicely fits our needs of being intuitively comparable to other apps' + // tqmask layer interfaces. It does have an alpha component though, which is a bit + // less appropriate in this context. + m_tqmask = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry() + ->getColorSpace(KisID("GRAYA"), 0)); + + genericMaskCreationHelper(); + + return m_tqmask; +} + +// FIXME If from is a paint device is not grey8!! +void KisPaintLayer::createMaskFromPaintDevice(KisPaintDeviceSP from) { + if (hasMask()) + return; // Or overwrite? XXX + + kdDebug() << k_funcinfo << endl; + m_tqmask = from; // KisPaintDevice(*from); XXX + + genericMaskCreationHelper(); +} + +void KisPaintLayer::createMaskFromSelection(KisSelectionSP from) { + kdDebug() << k_funcinfo << endl; + m_tqmask = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry() + ->getColorSpace(KisID("GRAYA"), 0)); + m_tqmask->setParentLayer(this); + + m_tqmaskAsSelection = new KisSelection(); // Anonymous selection is good enough + + // Default pixel is opaque white == don't tqmask? + TQ_UINT8 const defPixel[] = { 255, 255 }; + m_tqmask->dataManager()->setDefaultPixel(defPixel); + + if (from) { + TQRect r(extent()); + + int w = r.width(); + int h = r.height(); + for (int y = r.y(); y < h; y++) { + KisHLineIteratorPixel srcIt = from->createHLineIterator(r.x(), y, w, false); + KisHLineIteratorPixel dstIt = m_tqmask->createHLineIterator(r.x(), y, w, true); + + while(!dstIt.isDone()) { + // XXX same remark as in convertMaskToSelection + *dstIt.rawData() = *srcIt.rawData(); + ++srcIt; + ++dstIt; + } + } + } + + convertMaskToSelection(extent()); + m_paintdev->deselect(); + + setDirty(); + emit sigMaskInfoChanged(); +} + +KisPaintDeviceSP KisPaintLayer::getMask() { + createMask(); + kdDebug() << k_funcinfo << endl; + return m_tqmask; +} + +KisSelectionSP KisPaintLayer::getMaskAsSelection() { + createMask(); + kdDebug() << k_funcinfo << endl; + return m_tqmaskAsSelection; +} + +void KisPaintLayer::setEditMask(bool b) { + m_editMask = b; + emit sigMaskInfoChanged(); +} + +void KisPaintLayer::setRenderMask(bool b) { + m_renderMask = b; + + if (hasMask()) + setDirty(); + + emit sigMaskInfoChanged(); +} + +void KisPaintLayer::convertMaskToSelection(const TQRect& r) { + KisRectIteratorPixel srcIt = m_tqmask->createRectIterator(r.x(), r.y(), + r.width(), r.height(), false); + KisRectIteratorPixel dstIt = m_tqmaskAsSelection->createRectIterator(r.x(), r.y(), + r.width(), r.height(), true); + + while(!dstIt.isDone()) { + // src is grey8 (grey + alpha), dst is alpha8. We convert the grey value to + // alpha8 manually and ignore the alpha (that's why we don't convert using default + // functions, and interpret the data raw!) [ XXX ] + *dstIt.rawData() = *srcIt.rawData(); + ++srcIt; + ++dstIt; + } +} + +void KisPaintLayer::genericMaskCreationHelper() { + m_tqmask->setParentLayer(this); + + m_tqmaskAsSelection = new KisSelection(); // Anonymous selection is good enough + + // Default pixel is opaque white == don't tqmask? + TQ_UINT8 const defPixel[] = { 255, 255 }; + m_tqmask->dataManager()->setDefaultPixel(defPixel); + + setDirty(); + emit sigMaskInfoChanged(); +} + +void KisPaintLayer::setDirty(bool propagate) { + if (hasMask()) + convertMaskToSelection(extent()); + super::setDirty(propagate); +} + +void KisPaintLayer::setDirty(const TQRect & rect, bool propagate) { + if (hasMask()) + convertMaskToSelection(rect); + super::setDirty(rect, propagate); +} + +// Undoable versions code +namespace { + class KisCreateMaskCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_tqmask; + public: + KisCreateMaskCommand(const TQString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) {} + virtual void execute() { + kdDebug() << k_funcinfo << endl; + if (!m_tqmask) + m_tqmask = m_layer->createMask(); + else + m_layer->createMaskFromPaintDevice(m_tqmask); + } + virtual void unexecute() { + m_layer->removeMask(); + } + }; + + class KisMaskFromSelectionCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_tqmaskBefore; + KisPaintDeviceSP m_tqmaskAfter; + KisSelectionSP m_selection; + public: + KisMaskFromSelectionCommand(const TQString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + if (m_layer->hasMask()) + m_tqmaskBefore = m_layer->getMask(); + else + m_tqmaskBefore = 0; + m_tqmaskAfter = 0; + if (m_layer->paintDevice()->hasSelection()) + m_selection = m_layer->paintDevice()->selection(); + else + m_selection = 0; + } + virtual void execute() { + if (!m_tqmaskAfter) { + m_layer->createMaskFromSelection(m_selection); + m_tqmaskAfter = m_layer->getMask(); + } else { + m_layer->paintDevice()->deselect(); + m_layer->createMaskFromPaintDevice(m_tqmaskAfter); + } + } + virtual void unexecute() { + m_layer->paintDevice()->setSelection(m_selection); + if (m_tqmaskBefore) + m_layer->createMaskFromPaintDevice(m_tqmaskBefore); + else + m_layer->removeMask(); + } + }; + + class KisMaskToSelectionCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_tqmask; + KisSelectionSP m_selection; + public: + KisMaskToSelectionCommand(const TQString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_tqmask = m_layer->getMask(); + if (m_layer->paintDevice()->hasSelection()) + m_selection = m_layer->paintDevice()->selection(); + else + m_selection = 0; + } + virtual void execute() { + m_layer->paintDevice()->setSelection(m_layer->getMaskAsSelection()); + m_layer->removeMask(); + } + virtual void unexecute() { + if (m_selection) + m_layer->paintDevice()->setSelection(m_selection); + else + m_layer->paintDevice()->deselect(); + m_layer->createMaskFromPaintDevice(m_tqmask); + } + }; + + class KisRemoveMaskCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_tqmask; + public: + KisRemoveMaskCommand(const TQString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_tqmask = m_layer->getMask(); + } + virtual void execute() { + kdDebug() << k_funcinfo << endl; + m_layer->removeMask(); + } + virtual void unexecute() { + // I hope that if the undo stack unwinds, it will end up here in the right + // state again; taking a deep-copy sounds like wasteful to me + m_layer->createMaskFromPaintDevice(m_tqmask); + } + }; + + class KisApplyMaskCommand : public KNamedCommand { + typedef KNamedCommand super; + KisPaintLayerSP m_layer; + KisPaintDeviceSP m_tqmask; + KisPaintDeviceSP m_original; + public: + KisApplyMaskCommand(const TQString& name, KisPaintLayer* layer) + : super(name), m_layer(layer) { + m_tqmask = m_layer->getMask(); + m_original = new KisPaintDevice(*m_layer->paintDevice()); + } + virtual void execute() { + m_layer->applyMask(); + } + virtual void unexecute() { + // I hope that if the undo stack unwinds, it will end up here in the right + // state again; taking a deep-copy sounds like wasteful to me + KisPainter gc(m_layer->paintDevice()); + int x, y, w, h; + m_layer->paintDevice()->extent(x, y, w, h); + + gc.bitBlt(x, y, COMPOSITE_COPY, m_original, OPACITY_OPAQUE, x, y, w, h); + gc.end(); + + m_layer->createMaskFromPaintDevice(m_tqmask); + } + }; +} + +KNamedCommand* KisPaintLayer::createMaskCommand() { + return new KisCreateMaskCommand(i18n("Create Layer Mask"), this); +} + +KNamedCommand* KisPaintLayer::tqmaskFromSelectionCommand() { + return new KisMaskFromSelectionCommand(i18n("Mask From Selection"), this); +} + +KNamedCommand* KisPaintLayer::tqmaskToSelectionCommand() { + return new KisMaskToSelectionCommand(i18n("Mask to Selection"), this); +} + + +KNamedCommand* KisPaintLayer::removeMaskCommand() { + return new KisRemoveMaskCommand(i18n("Remove Layer Mask"), this); +} + +KNamedCommand* KisPaintLayer::applyMaskCommand() { + return new KisApplyMaskCommand(i18n("Apply Layer Mask"), this); +} + + +#include "kis_paint_layer.moc" diff --git a/chalk/core/kis_paint_layer.h b/chalk/core/kis_paint_layer.h new file mode 100644 index 00000000..9e598e7a --- /dev/null +++ b/chalk/core/kis_paint_layer.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_PAINT_LAYER_H_ +#define KIS_PAINT_LAYER_H_ + +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_colorspace.h" +/** + * This layer is of a type that can be painted on. + */ +class KisPaintLayer : public KisLayer, public KisLayerSupportsIndirectPainting { + typedef KisLayer super; + + Q_OBJECT + TQ_OBJECT + +public: + KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity, KisPaintDeviceSP dev); + KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity); + KisPaintLayer(KisImage *img, const TQString& name, TQ_UINT8 opacity, KisColorSpace * colorSpace); + KisPaintLayer(const KisPaintLayer& rhs); + virtual ~KisPaintLayer(); + + virtual KisLayerSP clone() const; +public: + + // Called when the layer is made active + virtual void activate() {} + + // Called when another layer is made active + virtual void deactivate() {} + + virtual TQ_INT32 x() const; + virtual void setX(TQ_INT32 x); + + virtual TQ_INT32 y() const; + virtual void setY(TQ_INT32 y); + + virtual TQRect extent() const; + virtual TQRect exactBounds() const; + + virtual void paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + virtual void paintSelection(TQImage &img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize); + + virtual void paintMaskInactiveLayers(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h); + + virtual bool accept(KisLayerVisitor &v) + { +// kdDebug(41001) << "\tPAINT\t" << name() +// << " dirty: " << dirty() << "\n"; + return v.visit(this); + } + + + inline KisPaintDeviceSP paintDevice() const { return m_paintdev; } + + /// Returns the paintDevice that accompanies this layer (or tqmask, see editMask) + inline KisPaintDeviceSP paintDeviceOrMask() const { + if (hasMask() && editMask()) + return m_tqmask; + return m_paintdev; + } + + // Mask Layer + + /// Does this layer have a layer tqmask? + bool hasMask() const { return m_tqmask != 0; } + // XXX TODO: Make these undo-able! + /// Create a tqmask if it does not yet exist, and return it + KisPaintDeviceSP createMask(); + /// Convert the from argument to the tqmask + void createMaskFromPaintDevice(KisPaintDeviceSP from); + /** + * Convert the from selection to a paint device (should convert the getMaskAsSelection + * result back to the tqmask). Overwrites the current tqmask, if any. Also removes the selection + */ + void createMaskFromSelection(KisSelectionSP from); + /// Remove the layer tqmask + void removeMask(); + /// Apply the layer tqmask to the paint device, this removes the tqmask afterwards + void applyMask(); + /// Returns the layer tqmask's device. Creates one if there is currently none + KisPaintDeviceSP getMask(); + /// Returns the layer tqmask's device, converted to a selection. Creates one if there is currently none + KisSelectionSP getMaskAsSelection(); + + /// Undoable version of createMask + KNamedCommand* createMaskCommand(); + /// Undoable version of createMaskFromSelection + KNamedCommand* tqmaskFromSelectionCommand(); + /// Undoable, removes the current tqmask, but converts it to the current selection + KNamedCommand* tqmaskToSelectionCommand(); + /// Undoable version of removeMask + KNamedCommand* removeMaskCommand(); + /// Undoable version of applyMask + KNamedCommand* applyMaskCommand(); + + /// Returns true if the tqmasked part of the tqmask will be rendered instead of being transparent + bool renderMask() const { return m_renderMask; } + /// Set the renderMask property + void setRenderMask(bool b); + + /** + * When this returns true, the KisPaintDevice returned in paintDevice will actually + * be the layer tqmask (if there is one). This is so that tools can draw on the tqmask + * without needing to know its existance. + */ + bool editMask() const { return m_editMask; } + /// Sets the editMask property + void setEditMask(bool b); + + /// Overridden to call the private convertMaskToSelection + virtual void setDirty(bool propagate = true); + /// Same as above + virtual void setDirty(const TQRect & rect, bool propagate = true); + + // KisLayerSupportsIndirectPainting + virtual KisLayer* layer() { return this; } +signals: + /// When the tqmask is created/destroyed or the edittqmask or rendertqmask is changed + void sigMaskInfoChanged(); + +private: + void convertMaskToSelection(const TQRect& r); + void genericMaskCreationHelper(); + KisPaintDeviceSP m_paintdev; + // Layer tqmask related: + // XXX It would be nice to merge the next 2 devices... + KisPaintDeviceSP m_tqmask; // The tqmask that we can edit and display easily + KisSelectionSP m_tqmaskAsSelection; // The tqmask as selection, to apply and render easily + bool m_renderMask; + bool m_editMask; +}; + +typedef KSharedPtr KisPaintLayerSP; + +#endif // KIS_PAINT_LAYER_H_ + diff --git a/chalk/core/kis_painter.cc b/chalk/core/kis_painter.cc new file mode 100644 index 00000000..b8353918 --- /dev/null +++ b/chalk/core/kis_painter.cc @@ -0,0 +1,928 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include + +#include "tqbrush.h" +#include "tqfontinfo.h" +#include "tqfontmetrics.h" +#include "tqpen.h" +#include "tqregion.h" +#include "tqwmatrix.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_brush.h" +#include "kis_debug_areas.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_pattern.h" +#include "kis_rect.h" +#include "kis_colorspace.h" +#include "kis_transaction.h" +#include "kis_types.h" +#include "kis_vec.h" +#include "kis_iterators_pixel.h" +#include "kis_paintop.h" +#include "kis_selection.h" +#include "kis_fill_painter.h" +#include "kis_color.h" + +// Maximum distance from a Bezier control point to the line through the start +// and end points for the curve to be considered flat. +#define BEZIER_FLATNESS_THRESHOLD 0.5 + +KisPainter::KisPainter() +{ + init(); +} + +KisPainter::KisPainter(KisPaintDeviceSP device) +{ + init(); + Q_ASSERT(device); + begin(device); +} + +void KisPainter::init() +{ + m_transaction = 0; + m_paintOp = 0; + m_filter = 0; + m_brush = 0; + m_pattern= 0; + m_opacity = OPACITY_OPAQUE; + m_compositeOp = COMPOSITE_OVER; + m_dab = 0; + m_fillStyle = FillStyleNone; + m_strokeStyle = StrokeStyleBrush; + m_pressure = PRESSURE_MIN; + m_duplicateHealing = false; + m_duplicateHealingRadius = 10; + m_duplicatePerspectiveCorrection = false; + m_varyBrushSpacingWithPressureWhenDrawingALine = true; +} + +KisPainter::~KisPainter() +{ + m_brush = 0; + delete m_paintOp; + end(); +} + +void KisPainter::begin(KisPaintDeviceSP device) +{ + if (!device) return; + + if (m_transaction) + delete m_transaction; + + m_device = device; + m_colorSpace = device->colorSpace(); + m_pixelSize = device->pixelSize(); +} + +KCommand *KisPainter::end() +{ + return endTransaction(); +} + +void KisPainter::beginTransaction(const TQString& customName) +{ + if (m_transaction) + delete m_transaction; + m_transaction = new KisTransaction(customName, m_device); + Q_CHECK_PTR(m_transaction); +} + +void KisPainter::beginTransaction( KisTransaction* command) +{ + if (m_transaction) + delete m_transaction; + m_transaction = command; +} + + +KCommand *KisPainter::endTransaction() +{ + KCommand *command = m_transaction; + m_transaction = 0; + return command; +} + + +TQRect KisPainter::dirtyRect() { + TQRect r = m_dirtyRect; + m_dirtyRect = TQRect(); + return r; +} + +void KisPainter::bitBlt(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP srcdev, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh) +{ + if (srcdev == 0) { + return; + } + + TQRect srcRect = TQRect(sx, sy, sw, sh); + + if (srcdev->extentIsValid() && op != COMPOSITE_COPY) { + srcRect &= srcdev->extent(); + } + + if (srcRect.isEmpty()) { + return; + } + + dx += srcRect.x() - sx; + dy += srcRect.y() - sy; + + sx = srcRect.x(); + sy = srcRect.y(); + sw = srcRect.width(); + sh = srcRect.height(); + + addDirtyRect(TQRect(dx, dy, sw, sh)); + + KisColorSpace * srcCs = srcdev->colorSpace(); + + TQ_INT32 dstY = dy; + TQ_INT32 srcY = sy; + TQ_INT32 rowsRemaining = sh; + + while (rowsRemaining > 0) { + + TQ_INT32 dstX = dx; + TQ_INT32 srcX = sx; + TQ_INT32 columnsRemaining = sw; + TQ_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1); + TQ_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1); + + TQ_INT32 rows = TQMIN(numContiguousDstRows, numContiguousSrcRows); + rows = TQMIN(rows, rowsRemaining); + + while (columnsRemaining > 0) { + + TQ_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1); + TQ_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1); + + TQ_INT32 columns = TQMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = TQMIN(columns, columnsRemaining); + + TQ_INT32 srcRowStride = srcdev->rowStride(srcX, srcY); + //const TQ_UINT8 *srcData = srcdev->pixel(srcX, srcY); + KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false); + const TQ_UINT8 *srcData = srcIt.rawData(); + + //TQ_UINT8 *dstData = m_device->writablePixel(dstX, dstY); + TQ_INT32 dstRowStride = m_device->rowStride(dstX, dstY); + KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true); + TQ_UINT8 *dstData = dstIt.rawData(); + + + m_colorSpace->bitBlt(dstData, + dstRowStride, + srcCs, + srcData, + srcRowStride, + 0, + 0, + opacity, + rows, + columns, + op); + + srcX += columns; + dstX += columns; + columnsRemaining -= columns; + } + + srcY += rows; + dstY += rows; + rowsRemaining -= rows; + } +} + +void KisPainter::bltSelection(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP srcdev, + KisSelectionSP seldev, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh) +{ + // Better use a probablistic method than a too slow one + if (seldev->isProbablyTotallyUnselected(TQRect(dx, dy, sw, sh))) { +/* + kdDebug() << "Blitting outside selection rect\n"; + + kdDebug() << "srcdev: " << srcdev << " (" << srcdev->name() << ")" + << ", seldev: " << seldev << " (" << seldev->name() << ")" + << ". dx, dy " << dx << "," << dy + << ". sx, sy : sw, sy " << sx << "," << sy << " : " << sw << "," << sh << endl; +*/ + return; + } + bltMask(dx,dy,op,srcdev,seldev.data(),opacity,sx,sy,sw,sh); +} + +void KisPainter::bltMask(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP srcdev, + KisPaintDeviceSP seldev, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh) + +{ + if (srcdev == 0) return; + + if (seldev == 0) return; + + if (m_device == 0) return; + + + TQRect srcRect = TQRect(sx, sy, sw, sh); + + if (srcdev->extentIsValid() && op != COMPOSITE_COPY) { + srcRect &= srcdev->extent(); + } + + if (srcRect.isEmpty()) { + return; + } + + dx += srcRect.x() - sx; + dy += srcRect.y() - sy; + + sx = srcRect.x(); + sy = srcRect.y(); + sw = srcRect.width(); + sh = srcRect.height(); + + addDirtyRect(TQRect(dx, dy, sw, sh)); + + KisColorSpace * srcCs = srcdev->colorSpace(); + + TQ_INT32 dstY = dy; + TQ_INT32 srcY = sy; + TQ_INT32 rowsRemaining = sh; + + while (rowsRemaining > 0) { + + TQ_INT32 dstX = dx; + TQ_INT32 srcX = sx; + TQ_INT32 columnsRemaining = sw; + TQ_INT32 numContiguousDstRows = m_device->numContiguousRows(dstY, dstX, dstX + sw - 1); + TQ_INT32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1); + TQ_INT32 numContiguousSelRows = seldev->numContiguousRows(dstY, dstX, dstX + sw - 1); + + TQ_INT32 rows = TQMIN(numContiguousDstRows, numContiguousSrcRows); + rows = TQMIN(numContiguousSelRows, rows); + rows = TQMIN(rows, rowsRemaining); + + while (columnsRemaining > 0) { + + TQ_INT32 numContiguousDstColumns = m_device->numContiguousColumns(dstX, dstY, dstY + rows - 1); + TQ_INT32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1); + TQ_INT32 numContiguousSelColumns = seldev->numContiguousColumns(dstX, dstY, dstY + rows - 1); + + TQ_INT32 columns = TQMIN(numContiguousDstColumns, numContiguousSrcColumns); + columns = TQMIN(numContiguousSelColumns, columns); + columns = TQMIN(columns, columnsRemaining); + + //TQ_UINT8 *dstData = m_device->writablePixel(dstX, dstY); + TQ_INT32 dstRowStride = m_device->rowStride(dstX, dstY); + KisHLineIteratorPixel dstIt = m_device->createHLineIterator(dstX, dstY, columns, true); + TQ_UINT8 *dstData = dstIt.rawData(); + + //const TQ_UINT8 *srcData = srcdev->pixel(srcX, srcY); + TQ_INT32 srcRowStride = srcdev->rowStride(srcX, srcY); + KisHLineIteratorPixel srcIt = srcdev->createHLineIterator(srcX, srcY, columns, false); + const TQ_UINT8 *srcData = srcIt.rawData(); + + //const TQ_UINT8 *selData = seldev->pixel(dstX, dstY); + TQ_INT32 selRowStride = seldev->rowStride(dstX, dstY); + KisHLineIteratorPixel selIt = seldev->createHLineIterator(dstX, dstY, columns, false); + const TQ_UINT8 *selData = selIt.rawData(); + + m_colorSpace->bitBlt(dstData, + dstRowStride, + srcCs, + srcData, + srcRowStride, + selData, + selRowStride, + opacity, + rows, + columns, + op); + + srcX += columns; + dstX += columns; + columnsRemaining -= columns; + } + + srcY += rows; + dstY += rows; + rowsRemaining -= rows; + } +} + + +void KisPainter::bltSelection(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP srcdev, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh) +{ + if (m_device == 0) return; + if (!m_device->hasSelection()) { + bitBlt(dx, dy, op, srcdev, opacity, sx, sy, sw, sh); + } + else + bltSelection(dx,dy,op,srcdev, m_device->selection(),opacity,sx,sy,sw,sh); +} + +double KisPainter::paintLine(const KisPoint & pos1, + const double pressure1, + const double xTilt1, + const double yTilt1, + const KisPoint & pos2, + const double pressure2, + const double xTilt2, + const double yTilt2, + const double inSavedDist) +{ + if (!m_device) return 0; + if (!m_paintOp) return 0; + if (!m_brush) return 0; + + double savedDist = inSavedDist; + KisVector2D end(pos2); + KisVector2D start(pos1); + + KisVector2D dragVec = end - start; + KisVector2D movement = dragVec; + + if (savedDist < 0) { + m_paintOp->paintAt(pos1, KisPaintInformation(pressure1, xTilt1, yTilt1, movement)); + savedDist = 0; + } + + double xSpacing = 0; + double ySpacing = 0; + + if ( m_varyBrushSpacingWithPressureWhenDrawingALine ) { + // XXX: The spacing should vary as the pressure changes along the + // line. + // This is a quick simplification. + xSpacing = m_brush->xSpacing((pressure1 + pressure2) / 2); + ySpacing = m_brush->ySpacing((pressure1 + pressure2) / 2); + } + else { + xSpacing = m_brush->xSpacing( PRESSURE_DEFAULT ); + ySpacing = m_brush->ySpacing( PRESSURE_DEFAULT ); + } + + if (xSpacing < 0.5) { + xSpacing = 0.5; + } + if (ySpacing < 0.5) { + ySpacing = 0.5; + } + + double xScale = 1; + double yScale = 1; + double spacing; + // Scale x or y so that we effectively have a square brush + // and calculate distance in that coordinate space. We reverse this scaling + // before drawing the brush. This produces the correct spacing in both + // x and y directions, even if the brush's aspect ratio is not 1:1. + if (xSpacing > ySpacing) { + yScale = xSpacing / ySpacing; + spacing = xSpacing; + } + else { + xScale = ySpacing / xSpacing; + spacing = ySpacing; + } + + dragVec.setX(dragVec.x() * xScale); + dragVec.setY(dragVec.y() * yScale); + + double newDist = dragVec.length(); + double dist = savedDist + newDist; + double l_savedDist = savedDist; + + if (dist < spacing) { + return dist; + } + + dragVec.normalize(); + KisVector2D step(0, 0); + + while (dist >= spacing) { + if (l_savedDist > 0) { + step += dragVec * (spacing - l_savedDist); + l_savedDist -= spacing; + } + else { + step += dragVec * spacing; + } + + KisPoint p(start.x() + (step.x() / xScale), start.y() + (step.y() / yScale)); + + double distanceMoved = step.length(); + double t = 0; + + if (newDist > DBL_EPSILON) { + t = distanceMoved / newDist; + } + + double pressure = (1 - t) * pressure1 + t * pressure2; + double xTilt = (1 - t) * xTilt1 + t * xTilt2; + double yTilt = (1 - t) * yTilt1 + t * yTilt2; + + m_paintOp->paintAt(p, KisPaintInformation(pressure, xTilt, yTilt, movement)); + dist -= spacing; + } + + if (dist > 0) + return dist; + else + return 0; +} + +void KisPainter::paintPolyline (const vKisPoint &points, + int index, int numPoints) +{ + if (index >= (int) points.count ()) + return; + + if (numPoints < 0) + numPoints = points.count (); + + if (index + numPoints > (int) points.count ()) + numPoints = points.count () - index; + + + for (int i = index; i < index + numPoints - 1; i++) + { + paintLine (points [index], 0/*pressure*/, 0, 0, points [index + 1], + 0/*pressure*/, 0, 0); + } +} + +void KisPainter::getBezierCurvePoints(const KisPoint &pos1, + const KisPoint &control1, + const KisPoint &control2, + const KisPoint &pos2, + vKisPoint& points) +{ + double d1 = pointToLineDistance(control1, pos1, pos2); + double d2 = pointToLineDistance(control2, pos1, pos2); + + if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) { + points.push_back(pos1); + } else { + // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508 + KisVector2D p1 = pos1; + KisVector2D p2 = control1; + KisVector2D p3 = control2; + KisVector2D p4 = pos2; + + KisVector2D l2 = (p1 + p2) / 2; + KisVector2D h = (p2 + p3) / 2; + KisVector2D l3 = (l2 + h) / 2; + KisVector2D r3 = (p3 + p4) / 2; + KisVector2D r2 = (h + r3) / 2; + KisVector2D l4 = (l3 + r2) / 2; + KisVector2D r1 = l4; + KisVector2D l1 = p1; + KisVector2D r4 = p4; + + getBezierCurvePoints(l1.toKisPoint(), l2.toKisPoint(), l3.toKisPoint(), l4.toKisPoint(), points); + getBezierCurvePoints(r1.toKisPoint(), r2.toKisPoint(), r3.toKisPoint(), r4.toKisPoint(), points); + } +} + +double KisPainter::paintBezierCurve(const KisPoint &pos1, + const double pressure1, + const double xTilt1, + const double yTilt1, + const KisPoint &control1, + const KisPoint &control2, + const KisPoint &pos2, + const double pressure2, + const double xTilt2, + const double yTilt2, + const double savedDist) +{ + double newDistance; + double d1 = pointToLineDistance(control1, pos1, pos2); + double d2 = pointToLineDistance(control2, pos1, pos2); + + if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) { + newDistance = paintLine(pos1, pressure1, xTilt1, yTilt1, pos2, pressure2, xTilt2, yTilt2, savedDist); + } else { + // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508 + KisVector2D p1 = pos1; + KisVector2D p2 = control1; + KisVector2D p3 = control2; + KisVector2D p4 = pos2; + + KisVector2D l2 = (p1 + p2) / 2; + KisVector2D h = (p2 + p3) / 2; + KisVector2D l3 = (l2 + h) / 2; + KisVector2D r3 = (p3 + p4) / 2; + KisVector2D r2 = (h + r3) / 2; + KisVector2D l4 = (l3 + r2) / 2; + KisVector2D r1 = l4; + KisVector2D l1 = p1; + KisVector2D r4 = p4; + + double midPressure = (pressure1 + pressure2) / 2; + double midXTilt = (xTilt1 + xTilt2) / 2; + double midYTilt = (yTilt1 + yTilt2) / 2; + + newDistance = paintBezierCurve(l1.toKisPoint(), pressure1, xTilt1, yTilt1, + l2.toKisPoint(), l3.toKisPoint(), + l4.toKisPoint(), midPressure, midXTilt, midYTilt, + savedDist); + newDistance = paintBezierCurve(r1.toKisPoint(), midPressure, midXTilt, midYTilt, + r2.toKisPoint(), + r3.toKisPoint(), + r4.toKisPoint(), pressure2, xTilt2, yTilt2, newDistance); + } + + return newDistance; +} + +void KisPainter::paintRect (const KisPoint &startPoint, + const KisPoint &endPoint, + const double /*pressure*/, + const double /*xTilt*/, + const double /*yTilt*/) +{ + KoRect normalizedRect = KisRect (startPoint, endPoint).normalize (); + + vKisPoint points; + + points.push_back(normalizedRect.topLeft()); + points.push_back(normalizedRect.bottomLeft()); + points.push_back(normalizedRect.bottomRight()); + points.push_back(normalizedRect.topRight()); + + paintPolygon(points); +} + +void KisPainter::paintEllipse (const KisPoint &startPoint, + const KisPoint &endPoint, + const double /*pressure*/, + const double /*xTilt*/, + const double /*yTilt*/) +{ + KisRect r = KisRect(startPoint, endPoint).normalize(); + + // See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation. + // kappa = (4/3*(sqrt(2)-1)) + const double kappa = 0.5522847498; + const double lx = (r.width() / 2) * kappa; + const double ly = (r.height() / 2) * kappa; + + KisPoint center = r.center(); + + KisPoint p0(r.left(), center.y()); + KisPoint p1(r.left(), center.y() - ly); + KisPoint p2(center.x() - lx, r.top()); + KisPoint p3(center.x(), r.top()); + + vKisPoint points; + + getBezierCurvePoints(p0, p1, p2, p3, points); + + KisPoint p4(center.x() + lx, r.top()); + KisPoint p5(r.right(), center.y() - ly); + KisPoint p6(r.right(), center.y()); + + getBezierCurvePoints(p3, p4, p5, p6, points); + + KisPoint p7(r.right(), center.y() + ly); + KisPoint p8(center.x() + lx, r.bottom()); + KisPoint p9(center.x(), r.bottom()); + + getBezierCurvePoints(p6, p7, p8, p9, points); + + KisPoint p10(center.x() - lx, r.bottom()); + KisPoint p11(r.left(), center.y() + ly); + + getBezierCurvePoints(p9, p10, p11, p0, points); + + paintPolygon(points); +} + +void KisPainter::paintAt(const KisPoint & pos, + const double pressure, + const double xTilt, + const double yTilt) +{ + if (!m_paintOp) return; + m_paintOp->paintAt(pos, KisPaintInformation(pressure, xTilt, yTilt, KisVector2D())); +} + +double KisPainter::pointToLineDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1) +{ + double lineLength = sqrt((l1.x() - l0.x()) * (l1.x() - l0.x()) + (l1.y() - l0.y()) * (l1.y() - l0.y())); + double distance = 0; + + if (lineLength > DBL_EPSILON) { + distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / lineLength; + distance = fabs(distance); + } + + return distance; +} + +/* + * Concave Polygon Scan Conversion + * by Paul Heckbert + * from "Graphics Gems", Academic Press, 1990 + */ + +/* + * concave: scan convert nvert-sided concave non-simple polygon with vertices at + * (point[i].x, point[i].y) for i in [0..nvert-1] within the window win by + * calling spanproc for each visible span of pixels. + * Polygon can be clockwise or counterclockwise. + * Algorithm does uniform point sampling at pixel centers. + * Inside-outside test done by Jordan's rule: a point is considered inside if + * an emanating ray intersects the polygon an odd number of times. + * drawproc should fill in pixels from xl to xr inclusive on scanline y, + * e.g: + * drawproc(y, xl, xr) + * int y, xl, xr; + * { + * int x; + * for (x=xl; x<=xr; x++) + * pixel_write(x, y, pixelvalue); + * } + * + * Paul Heckbert 30 June 81, 18 Dec 89 + */ + +typedef struct { /* a polygon edge */ + double x; /* x coordinate of edge's intersection with current scanline */ + double dx; /* change in x with respect to y */ + int i; /* edge number: edge i goes from pt[i] to pt[i+1] */ +} Edge; + +static int n; /* number of vertices */ +static const KisPoint *pt; /* vertices */ + +static int nact; /* number of active edges */ +static Edge *active; /* active edge list:edges crossing scanline y */ + +/* comparison routines for qsort */ +static int compare_ind(const void *pu, const void *pv) +{ + const int *u = static_cast(pu); + const int *v = static_cast(pv); + + return pt[*u].y() <= pt[*v].y() ? -1 : 1; +} + +static int compare_active(const void *pu, const void *pv) +{ + const Edge *u = static_cast(pu); + const Edge *v = static_cast(pv); + + return u->x <= v->x ? -1 : 1; +} + +static void cdelete(int i) /* remove edge i from active list */ +{ + int j; + + for (j=0; j=nact) return; /* edge not in active list; happens at win->y0*/ + nact--; + bcopy(&active[j+1], &active[j], (nact-j)*sizeof active[0]); +} + +static void cinsert(int i, int y) /* append edge i to end of active list */ +{ + int j; + double dx; + const KisPoint *p, *q; + + j = ix()-p->x())/(q->y()-p->y()); + active[nact].x = dx*(y+.5-p->y())+p->x(); + active[nact].i = i; + nact++; +} + +void KisPainter::fillPolygon(const vKisPoint& points, FillStyle fillStyle) +{ + int nvert = points.count(); + int k, y0, y1, y, i, j, xl, xr; + int *ind; /* list of vertex indices, sorted by pt[ind[j]].y */ + + n = nvert; + pt = &(points[0]); + if (n<3) return; + if (fillStyle == FillStyleNone) { + return; + } + + ind = new int[n]; + Q_CHECK_PTR(ind); + active = new Edge[n]; + Q_CHECK_PTR(active); + + /* create y-sorted array of indices ind[k] into vertex list */ + for (k=0; k(ceil(pt[ind[0]].y()-.5)); /* ymin of polygon */ + y1 = static_cast(floor(pt[ind[n-1]].y()-.5)); /* ymax of polygon */ + + int x0 = INT_MAX; + int x1 = INT_MIN; + + for (int i = 0; i < nvert; i++) { + int pointHighX = static_cast(ceil(points[i].x() - 0.5)); + int pointLowX = static_cast(floor(points[i].x() - 0.5)); + + if (pointLowX < x0) { + x0 = pointLowX; + } + if (pointHighX > x1) { + x1 = pointHighX; + } + } + + // Fill the polygon bounding rectangle with the required contents then we'll + // create a tqmask for the actual polygon coverage. + + KisPaintDeviceSP polygon = new KisPaintDevice(m_device->colorSpace(), "polygon"); + Q_CHECK_PTR(polygon); + + KisFillPainter fillPainter(polygon); + TQRect boundingRectangle(x0, y0, x1 - x0 + 1, y1 - y0 + 1); + + // Clip to the image bounds. + if (m_device->image()) { + boundingRectangle &= m_device->image()->bounds(); + } + + switch (fillStyle) { + default: + // Fall through + case FillStyleGradient: + // Currently unsupported, fall through + case FillStyleStrokes: + // Currently unsupported, fall through + kdWarning(DBG_AREA_CORE) << "Unknown or unsupported fill style in fillPolygon\n"; + case FillStyleForegroundColor: + fillPainter.fillRect(boundingRectangle, paintColor(), OPACITY_OPAQUE); + break; + case FillStyleBackgroundColor: + fillPainter.fillRect(boundingRectangle, backgroundColor(), OPACITY_OPAQUE); + break; + case FillStylePattern: + Q_ASSERT(m_pattern != 0); + fillPainter.fillRect(boundingRectangle, m_pattern); + break; + } + + KisSelectionSP polygonMask = new KisSelection(polygon); + + for (y=y0; y<=y1; y++) { /* step through scanlines */ + /* scanline y is at y+.5 in continuous coordinates */ + + /* check vertices between previous scanline and current one, if any */ + for (; k0 ? i-1 : n-1; /* vertex previous to i */ + if (pt[j].y() <= y-.5) /* old edge, remove from active list */ + cdelete(j); + else if (pt[j].y() > y+.5) /* new edge, add to active list */ + cinsert(j, y); + j = i y+.5) /* new edge, add to active list */ + cinsert(i, y); + } + + /* sort active edge list by active[j].x */ + qsort(active, nact, sizeof active[0], compare_active); + + /* draw horizontal segments for scanline y */ + for (j=0; j(ceil(active[j].x-.5)); /* left end of span */ + xr = static_cast(floor(active[j+1].x-.5)); /* right end of span */ + + if (xl<=xr) { + KisHLineIterator it = polygonMask->createHLineIterator(xl, y, xr - xl + 1, true); + + while (!it.isDone()) { + // We're using a selection here, that means alpha colorspace, that means one byte. + it.rawData()[0] = MAX_SELECTED; + ++it; + } + } + + active[j].x += active[j].dx; /* increment edge coords */ + active[j+1].x += active[j+1].dx; + } + } + delete [] ind; + delete [] active; + + polygon->applySelectionMask(polygonMask); + + TQRect r = polygon->extent(); + + // The strokes for the outline may have already added updated the dirtyrect, but it can't hurt, + // and if we're painting without outlines, then there will be no dirty rect. Let's do it ourselves... + // addDirtyRect( r ); // XXX the bltSelection will add to the dirtyrect + + bltSelection(r.x(), r.y(), compositeOp(), polygon, opacity(), r.x(), r.y(), r.width(), r.height()); +} + +void KisPainter::paintPolygon(const vKisPoint& points) +{ + if (m_fillStyle != FillStyleNone) { + fillPolygon(points, m_fillStyle); + } + + if (m_strokeStyle != StrokeStyleNone) { + if (points.count() > 1) { + double distance = -1; + + for (uint i = 0; i < points.count() - 1; i++) { + distance = paintLine(points[i], PRESSURE_DEFAULT, 0, 0, points[i + 1], PRESSURE_DEFAULT, 0, 0, distance); + } + paintLine(points[points.count() - 1], PRESSURE_DEFAULT, 0, 0, points[0], PRESSURE_DEFAULT, 0, 0, distance); + } + } +} + diff --git a/chalk/core/kis_painter.h b/chalk/core/kis_painter.h new file mode 100644 index 00000000..abfd8b17 --- /dev/null +++ b/chalk/core/kis_painter.h @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PAINTER_H_ +#define KIS_PAINTER_H_ + +#include + +#include "kis_color.h" +#include "kis_global.h" +#include "kis_types.h" +#include "kis_paint_device.h" +#include "kis_point.h" +#include "kis_filter.h" +#include "kis_progress_subject.h" +#include "kis_paintop.h" +#include "kis_color.h" + +#include + +class TQRect; +class KisTransaction; +class KisBrush; +class KisPattern; + +/** + * KisPainter contains the graphics primitives necessary to draw on a + * KisPaintDevice. This is the same kind of abstraction as used in TQt + * itself, where you have TQPainter and TQPaintDevice. + * + * However, KisPainter works on a tiled image and supports different + * colour models, and that's a lot more complicated. + * + * KisPainter supports transactions that can group various paint operations + * in one undoable step. + * + * For more complex operations, you might want to have a look at the subclasses + * of KisPainter: KisConvolutionPainter, KisFillPainter and KisGradientPainter + */ +class KRITACORE_EXPORT KisPainter : public KisProgressSubject { + typedef KisProgressSubject super; + +public: + /// Construct painter without a device + KisPainter(); + /// Construct a painter, and begin painting on the device + KisPainter(KisPaintDeviceSP device); + virtual ~KisPainter(); + +private: + // Implement KisProgressSubject + virtual void cancel() { m_cancelRequested = true; } + +public: + /** + * Start painting on the specified device. Not undoable. + */ + void begin(KisPaintDeviceSP device); + + /** + * Finish painting on the current device + */ + KCommand *end(); + + /// Begin an undoable paint operation + void beginTransaction(const TQString& customName = TQString()); + + /// Finish the undoable paint operation + KCommand *endTransaction(); + + /// begin a transaction with the given command + void beginTransaction( KisTransaction* command); + + /// Return the current transcation + KisTransaction * transaction() { return m_transaction; } + + + /// Returns the current paint device. + KisPaintDeviceSP device() const { return m_device; } + + + // ----------------------------------------------------------------- + // Native paint methods that are undo/redo-able, + // use the color strategies and the composite operations. + + /** + * Blast the specified region from src onto the current paint device. + */ + void bitBlt(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP src, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh) + { + bitBlt(dx, dy, op, src, OPACITY_OPAQUE, sx, sy, sw, sh); + } + + /** + * Overloaded version of the previous, differs in that it is possible to specify + * a value for opacity + */ + void bitBlt(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp& op, + KisPaintDeviceSP src, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh); + + /** + * A version of bitBlt that renders using an external tqmask, ignoring + * the src device's own selection, if it has one. + */ + void bltMask(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + KisPaintDeviceSP selMask, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh); + + /** + * A version of bitBlt that renders using an external selection tqmask, ignoring + * the src device's own selection, if it has one. + */ + void bltSelection(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + KisSelectionSP selMask, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh); + + + /** + * A version of bitBlt that renders using the src device's selection tqmask, if it has one. + */ + void bltSelection(TQ_INT32 dx, TQ_INT32 dy, + const KisCompositeOp &op, + KisPaintDeviceSP src, + TQ_UINT8 opacity, + TQ_INT32 sx, TQ_INT32 sy, + TQ_INT32 sw, TQ_INT32 sh); + + + /** + * The methods below are 'higher' level than the above methods. They need brushes, colors + * etc. set before they can be called. The methods do not directly tell the image to + * update, but you can call dirtyRect() to get the rect that needs to be notified by your + * painting code. + * + * Call will RESET the dirtyRect! + */ + TQRect dirtyRect(); + + /** + * Add the r to the current dirty rect, and return the dirtyRect after adding r to it. + */ + TQRect addDirtyRect(TQRect r) { m_dirtyRect |= r; return m_dirtyRect; } + + + + /** + * Paint a line that connects the dots in points + */ + void paintPolyline(const TQValueVector &points, + int index = 0, int numPoints = -1); + + /** + * Draw a line between pos1 and pos2 using the currently set brush and color. + * If savedDist is less than zero, the brush is painted at pos1 before being + * painted along the line using the spacing setting. + * @return the drag distance, that is the remains of the distance between p1 and p2 not covered + * because the currenlty set brush has a spacing greater than that distance. + */ + double paintLine(const KisPoint &pos1, + const double pressure1, + const double xTilt1, + const double yTilt1, + const KisPoint &pos2, + const double pressure2, + const double xTilt2, + const double yTilt2, + const double savedDist = -1); + + /** + * Draw a Bezier curve between pos1 and pos2 using control points 1 and 2. + * If savedDist is less than zero, the brush is painted at pos1 before being + * painted along the curve using the spacing setting. + * @return the drag distance, that is the remains of the distance between p1 and p2 not covered + * because the currenlty set brush has a spacing greater than that distance. + */ + double paintBezierCurve(const KisPoint &pos1, + const double pressure1, + const double xTilt1, + const double yTilt1, + const KisPoint &control1, + const KisPoint &control2, + const KisPoint &pos2, + const double pressure2, + const double xTilt2, + const double yTilt2, + const double savedDist = -1); + + /** + * Fill the given vector points with the points needed to draw the Bezier curve between + * pos1 and pos2 using control points 1 and 2, excluding the final pos2. + */ + void getBezierCurvePoints(const KisPoint &pos1, + const KisPoint &control1, + const KisPoint &control2, + const KisPoint &pos2, + vKisPoint& points); + + + /** + * Paint the rectangle with given begin and end points + */ + void paintRect(const KisPoint &startPoint, + const KisPoint &endPoint, + const double pressure, + const double xTilt, + const double yTilt); + + + /** + * Paint the ellipse with given begin and end points + */ + void paintEllipse(const KisPoint &startPoint, + const KisPoint &endPoint, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/); + + /** + * Paint the polygon with the points given in points. It automatically closes the polygon + * by drawing the line from the last point to the first. + */ + void paintPolygon(const vKisPoint& points); + + /** Draw a spot at pos using the currently set paint op, brush and color */ + void paintAt(const KisPoint &pos, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/); + + + // ------------------------------------------------------------------------ + // Set the parameters for the higher level graphics primitives. + + /// Determines whether the brush spacing should vary when drawing + /// lines with the pressure + void setVaryBrushSpacingWithPressureWhenDrawingALine( bool varyBrushSpacingWithPressureWhenDrawingALine ) + { m_varyBrushSpacingWithPressureWhenDrawingALine = varyBrushSpacingWithPressureWhenDrawingALine; } + bool varyBrushSpacingWithPressureWhenDrawingALine() { return m_varyBrushSpacingWithPressureWhenDrawingALine; } + + /// Set the current brush + void setBrush(KisBrush* brush) { m_brush = brush; } + /// Returns the currently set brush + KisBrush * brush() const { return m_brush; } + + /// Set the current pattern + void setPattern(KisPattern * pattern) { m_pattern = pattern; } + /// Returns the currently set pattern + KisPattern * pattern() const { return m_pattern; } + + /// Set the color that will be used to paint with + void setPaintColor(const KisColor& color) { m_paintColor = color;} + + /// Returns the color that will be used to paint with + KisColor paintColor() const { return m_paintColor; } + + /// Set the current background color + void setBackgroundColor(const KisColor& color) {m_backgroundColor = color; } + /// Returns the current background color + KisColor backgroundColor() const { return m_backgroundColor; } + + /// Set the current fill color + void setFillColor(const KisColor& color) { m_fillColor = color; } + /// Returns the current fill color + KisColor fillColor() const { return m_fillColor; } + + + /// This enum contains the styles with which we can fill things like polygons and ellipses + enum FillStyle { + FillStyleNone, + FillStyleForegroundColor, + FillStyleBackgroundColor, + FillStylePattern, + FillStyleGradient, + FillStyleStrokes + }; + + /// Set the current style with which to fill + void setFillStyle(FillStyle fillStyle) { m_fillStyle = fillStyle; } + /// Returns the current fill style + FillStyle fillStyle() const { return m_fillStyle; } + + /// The style of the brush stroke around polygons and so + enum StrokeStyle { + StrokeStyleNone, + StrokeStyleBrush + }; + + /// Set the current brush stroke style + void setStrokeStyle(StrokeStyle strokeStyle) { m_strokeStyle = strokeStyle; } + /// Returns the current brush stroke style + StrokeStyle strokeStyle() const { return m_strokeStyle; } + + /// Set the opacity which is used in painting (like filling polygons) + void setOpacity(TQ_UINT8 opacity) { m_opacity = opacity; } + /// Returns the opacity that is used in painting + TQ_UINT8 opacity() const { return m_opacity; } + + /** + * Sets the current composite operation. Everything painted will be composited on + * the destination layer with this composite op. + **/ + void setCompositeOp(const KisCompositeOp& op) { m_compositeOp = op; } + /// Returns the current composite operation + KisCompositeOp compositeOp() const { return m_compositeOp; } + + /// Sets the current KisFilter, used by the paintops that support it (like KisFilterOp) + void setFilter(KisFilterSP filter) { m_filter = filter; } + /// Returns the current KisFilter + KisFilterSP filter() { return m_filter; } + + /** + * The offset for paint operations that use it (like KisDuplicateOp). It will use as source + * the part of the layer that is at its paintedPosition - duplicateOffset + */ + // TODO: this is an hack ! it must be fix, the following functions have nothing to do here + void setDuplicateOffset(const KisPoint& offset) { m_duplicateOffset = offset; } + /// Returns the offset for duplication + KisPoint duplicateOffset(){ return m_duplicateOffset; } + + inline void setDuplicateHealing(bool v) { m_duplicateHealing = v; } + inline bool duplicateHealing() { return m_duplicateHealing; } + + inline void setDuplicateHealingRadius(int r) { m_duplicateHealingRadius = r; } + inline int duplicateHealingRadius() { return m_duplicateHealingRadius; } + + inline void setDuplicatePerspectiveCorrection(bool v) { m_duplicatePerspectiveCorrection = v; } + inline bool duplicatePerspectiveCorrection() { return m_duplicatePerspectiveCorrection; } + + void setDuplicateStart(const KisPoint start) { m_duplicateStart = start;} + KisPoint duplicateStart() { return m_duplicateStart;} + + /// Sets the current pressure for things that like to use this + void setPressure(double pressure) { m_pressure = pressure; } + /// Returns the current pressure + double pressure() { return m_pressure; } + + /** + * Set the current paint operation. This is used for all drawing functions. + * The painter will DELETE the paint op itself!! + * That means no that you should not delete it yourself (or put it on the stack) + */ + void setPaintOp(KisPaintOp * paintOp) { delete m_paintOp; m_paintOp = paintOp; } + /// Returns the current paint operation + KisPaintOp * paintOp() const { return m_paintOp; } + + /// Set a current 'dab'. This usually is a paint device containing a rendered brush + void setDab(KisPaintDeviceSP dab) { m_dab = dab; } + /// Get the currently set dab + KisPaintDeviceSP dab() const { return m_dab; } + + /// Is cancel Requested by the KisProgressSubject for this painter + bool cancelRequested() const { return m_cancelRequested; } + +protected: + /// Initialize, set everything to '0' or defaults + void init(); + KisPainter(const KisPainter&); + KisPainter& operator=(const KisPainter&); + + /// Calculate the distance that point p is from the line made by connecting l0 and l1 + static double pointToLineDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1); + + /// Fill the polygon defined by points with the fillStyle + void fillPolygon(const vKisPoint& points, FillStyle fillStyle); + +protected: + KisPaintDeviceSP m_device; + KisTransaction *m_transaction; + + TQRect m_dirtyRect; + + KisColor m_paintColor; + KisColor m_backgroundColor; + KisColor m_fillColor; + FillStyle m_fillStyle; + StrokeStyle m_strokeStyle; + KisBrush *m_brush; + KisPattern *m_pattern; + KisPoint m_duplicateOffset; + KisPoint m_duplicateStart; + bool m_duplicateHealing; + int m_duplicateHealingRadius; + bool m_duplicatePerspectiveCorrection; + TQ_UINT8 m_opacity; + KisCompositeOp m_compositeOp; + KisFilterSP m_filter; + KisPaintOp * m_paintOp; + double m_pressure; + bool m_cancelRequested; + TQ_INT32 m_pixelSize; + KisColorSpace * m_colorSpace; + KisProfile * m_profile; + KisPaintDeviceSP m_dab; + bool m_varyBrushSpacingWithPressureWhenDrawingALine; + +}; + + +#endif // KIS_PAINTER_H_ + diff --git a/chalk/core/kis_paintop.cc b/chalk/core/kis_paintop.cc new file mode 100644 index 00000000..71989bd9 --- /dev/null +++ b/chalk/core/kis_paintop.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "tqwidget.h" +#include "kis_painter.h" +#include "kis_layer.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_alpha_mask.h" +#include "kis_point.h" +#include "kis_colorspace.h" +#include "kis_global.h" +#include "kis_iterators_pixel.h" +#include "kis_color.h" + +KisPaintOp::KisPaintOp(KisPainter * painter) + : m_dab(0) +{ + m_painter = painter; + setSource(painter->device()); +} + +KisPaintOp::~KisPaintOp() +{ +} + +KisPaintDeviceSP KisPaintOp::computeDab(KisAlphaMaskSP tqmask) { + return computeDab(tqmask, m_painter->device()->colorSpace()); +} + +KisPaintDeviceSP KisPaintOp::computeDab(KisAlphaMaskSP tqmask, KisColorSpace *cs) +{ + // XXX: According to the SeaShore source, the Gimp uses a + // temporary layer the size of the layer that is being painted + // on. This layer is cleared between painting actions. Our + // temporary layer, dab, is for every paintAt, composited with + // the target layer. We only use a real temporary layer for things + // like filter tools. + + if(!m_dab || m_dab->colorSpace() != cs) + m_dab = new KisPaintDevice(cs, "dab"); + Q_CHECK_PTR(m_dab); + + KisColor kc = m_painter->paintColor(); + + KisColorSpace * colorSpace = m_dab->colorSpace(); + + TQ_INT32 pixelSize = colorSpace->pixelSize(); + + TQ_INT32 tqmaskWidth = tqmask->width(); + TQ_INT32 tqmaskHeight = tqmask->height(); + + // Convert the kiscolor to the right colorspace. + kc.convertTo(colorSpace); + + KisHLineIteratorPixel hiter = m_dab->createHLineIterator(0, 0, tqmaskWidth, true); + for (int y = 0; y < tqmaskHeight; y++) + { + int x=0; + while(! hiter.isDone()) + { + // XXX: Set tqmask + colorSpace->setAlpha(kc.data(), tqmask->alphaAt(x++, y), 1); + memcpy(hiter.rawData(), kc.data(), pixelSize); + ++hiter; + } + hiter.nextRow(); + } + + return m_dab; +} + +void KisPaintOp::splitCoordinate(double coordinate, TQ_INT32 *whole, double *fraction) +{ + TQ_INT32 i = static_cast(coordinate); + + if (coordinate < 0) { + // We always want the fractional part to be positive. + // E.g. -1.25 becomes -2 and +0.75 + i--; + } + + double f = coordinate - i; + + *whole = i; + *fraction = f; +} + +void KisPaintOp::setSource(KisPaintDeviceSP p) { + Q_ASSERT(p); + m_source = p; +} + + +KisPaintOpSettings* KisPaintOpFactory::settings(TQWidget* /*tqparent*/, const KisInputDevice& /*inputDevice*/) { return 0; } diff --git a/chalk/core/kis_paintop.h b/chalk/core/kis_paintop.h new file mode 100644 index 00000000..8e8587ea --- /dev/null +++ b/chalk/core/kis_paintop.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PAINTOP_H_ +#define KIS_PAINTOP_H_ + +#include + +#include +#include + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_id.h" +#include "kis_vec.h" +#include "kis_colorspace.h" + +#include + +class KisPoint; +class KisAlphaMask; +class KisPainter; +class KisColorSpace; +class KisInputDevice; +class TQWidget; + +/** + * This class keeps information that can be used in the painting process, for example by + * brushes. + **/ +class KRITACORE_EXPORT KisPaintInformation { +public: + KisPaintInformation(double pressure = PRESSURE_DEFAULT, + double xTilt = 0.0, double yTilt = 0.0, + KisVector2D movement = KisVector2D()) + : pressure(pressure), xTilt(xTilt), yTilt(yTilt), movement(movement) {} + double pressure; + double xTilt; + double yTilt; + KisVector2D movement; +}; + +class KRITACORE_EXPORT KisPaintOp : public KShared +{ + +public: + + KisPaintOp(KisPainter * painter); + virtual ~KisPaintOp(); + + virtual void paintAt(const KisPoint &pos, const KisPaintInformation& info) = 0; + void setSource(KisPaintDeviceSP p); + + /** + * Whether this paintop wants to deposit paint even when not moving, i.e. the + * tool needs to activate its timer. + */ + virtual bool incremental() { return false; } + + +protected: + + virtual KisPaintDeviceSP computeDab(KisAlphaMaskSP tqmask); + virtual KisPaintDeviceSP computeDab(KisAlphaMaskSP tqmask, KisColorSpace *cs); + + + /** + * Split the coordinate into whole + fraction, where fraction is always >= 0. + */ + virtual void splitCoordinate(double coordinate, TQ_INT32 *whole, double *fraction); + + KisPainter * m_painter; + KisPaintDeviceSP m_source; // use this layer as source layer for the operation +private: + KisPaintDeviceSP m_dab; +}; + +class KisPaintOpSettings { + +public: + KisPaintOpSettings(TQWidget *tqparent) { Q_UNUSED(tqparent); } + virtual ~KisPaintOpSettings() {} + + virtual TQWidget *widget() const { return 0; } +}; + +/** + * The paintop factory is responsible for creating paintops of the specified class. + * If there is an optionWidget, the derived paintop itself must support settings, + * and it's up to the factory to do that. + */ +class KisPaintOpFactory : public KShared +{ + +public: + KisPaintOpFactory() {} + virtual ~KisPaintOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter) = 0; + virtual KisID id() { return KisID("abstractpaintop", i18n("Abstract PaintOp")); } + + /** + * The filename of the pixmap we can use to represent this paintop in the ui. + */ + virtual TQString pixmap() { return ""; } + + /** + * Whether this paintop is internal to a certain tool or can be used + * in various tools. If false, it won't show up in the toolchest. + * The KisColorSpace argument can be used when certain paintops only support a specific cs + */ + virtual bool userVisible(KisColorSpace * cs = 0) { return cs->id() != KisID("WET", ""); } + + /** + * Create and return an (abstracted) widget with options for this paintop when used with the + * specified input device. Return 0 if there are no settings available for the given + * device. + */ + virtual KisPaintOpSettings* settings(TQWidget* tqparent, const KisInputDevice& inputDevice); + +}; +#endif // KIS_PAINTOP_H_ diff --git a/chalk/core/kis_paintop_registry.cc b/chalk/core/kis_paintop_registry.cc new file mode 100644 index 00000000..3651f35d --- /dev/null +++ b/chalk/core/kis_paintop_registry.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_generic_registry.h" +#include "kis_types.h" +#include "kis_paintop_registry.h" +#include "kis_paintop.h" +#include "kis_id.h" +#include "kis_debug_areas.h" +#include "kis_colorspace.h" + +KisPaintOpRegistry * KisPaintOpRegistry::m_singleton = 0; + +KisPaintOpRegistry::KisPaintOpRegistry() +{ + Q_ASSERT(KisPaintOpRegistry::m_singleton == 0); + KisPaintOpRegistry::m_singleton = this; + + KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/Paintop"), + TQString::tqfromLatin1("(Type == 'Service') and " + "([X-Chalk-Version] == 2)")); + + KTrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService ( service, this, 0, TQStringList(), &errCode); + if ( plugin ) + kdDebug(41006) << "found plugin " << service->property("Name").toString() << "\n"; + else { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n"; + if( errCode == KParts::ComponentFactory::ErrNoLibrary) + { + kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl; + } + } + + } + +} + +KisPaintOpRegistry::~KisPaintOpRegistry() +{ +} + +KisPaintOpRegistry* KisPaintOpRegistry::instance() +{ + if(KisPaintOpRegistry::m_singleton == 0) + { + KisPaintOpRegistry::m_singleton = new KisPaintOpRegistry(); + Q_CHECK_PTR(KisPaintOpRegistry::m_singleton); + } + return KisPaintOpRegistry::m_singleton; +} + +KisPaintOp * KisPaintOpRegistry::paintOp(const KisID & id, const KisPaintOpSettings * settings, KisPainter * painter) const +{ + if (painter == 0) { + kdWarning() << " KisPaintOpRegistry::paintOp painter is null"; + return 0; + } + KisPaintOpFactorySP f = get(id); + if (f) { + return f->createOp(settings, painter); + } + else { + return 0; + } +} + +KisPaintOp * KisPaintOpRegistry::paintOp(const TQString & id, const KisPaintOpSettings * settings, KisPainter * painter) const +{ + return paintOp(KisID(id, ""), settings, painter); +} + +KisPaintOpSettings * KisPaintOpRegistry::settings(const KisID& id, TQWidget * tqparent, const KisInputDevice& inputDevice) const +{ + KisPaintOpFactory* f = get(id); + if (f) + return f->settings( tqparent, inputDevice ); + + return 0; +} + +bool KisPaintOpRegistry::userVisible(const KisID & id, KisColorSpace* cs) const +{ + + KisPaintOpFactorySP f = get(id); + if (!f) { + kdDebug(DBG_AREA_REGISTRY) << "No paintop " << id.id() << "\n"; + return false; + } + return f->userVisible(cs); + +} + +TQString KisPaintOpRegistry::pixmap(const KisID & id) const +{ + KisPaintOpFactorySP f = get(id); + + if (!f) { + kdDebug(DBG_AREA_REGISTRY) << "No paintop " << id.id() << "\n"; + return ""; + } + + return f->pixmap(); +} + +#include "kis_paintop_registry.moc" diff --git a/chalk/core/kis_paintop_registry.h b/chalk/core/kis_paintop_registry.h new file mode 100644 index 00000000..c61105b6 --- /dev/null +++ b/chalk/core/kis_paintop_registry.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PAINTOP_REGISTRY_H_ +#define KIS_PAINTOP_REGISTRY_H_ + +#include + +#include "kis_types.h" +#include "kis_generic_registry.h" +#include + +class TQWidget; +class TQStringList; + +class KisPaintOp; +class KisPaintOpSettings; +class KisPainter; +class KisColorSpace; +class KisInputDevice; + +class KRITACORE_EXPORT KisPaintOpRegistry : public TQObject, public KisGenericRegistry +{ + + Q_OBJECT + TQ_OBJECT + +public: + virtual ~KisPaintOpRegistry(); + + /** + * Return a newly created paintop + */ + KisPaintOp * paintOp(const KisID& id, const KisPaintOpSettings * settings, KisPainter * painter) const; + + /** + * Return a newly created paintopd + */ + KisPaintOp * paintOp(const TQString& id, const KisPaintOpSettings * settings, KisPainter * painter) const; + + /** + * Create and return an (abstracted) configuration widget + * for using the specified paintop with the specified input device, + * with the specified tqparent as widget tqparent. Returns 0 if there + * are no settings available for the given device. + */ + KisPaintOpSettings * settings(const KisID& id, TQWidget * tqparent, const KisInputDevice& inputDevice) const; + + // Whether we should show this paintop in the toolchest + bool userVisible(const KisID & id, KisColorSpace* cs) const; + + // Get the name of the icon to show in the toolchest + TQString pixmap(const KisID & id) const; + + +public: + static KisPaintOpRegistry* instance(); + +private: + KisPaintOpRegistry(); + KisPaintOpRegistry(const KisPaintOpRegistry&); + KisPaintOpRegistry operator=(const KisPaintOpRegistry&); + +private: + static KisPaintOpRegistry *m_singleton; +}; + +#endif // KIS_PAINTOP_REGISTRY_H_ + diff --git a/chalk/core/kis_palette.cc b/chalk/core/kis_palette.cc new file mode 100644 index 00000000..daf8d84d --- /dev/null +++ b/chalk/core/kis_palette.cc @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "kis_debug_areas.h" +#include "kis_palette.h" +#include "kis_iterators_pixel.h" + + +namespace { + enum enumPaletteType { + FORMAT_UNKNOWN, + FORMAT_GPL, // Gimp palette + FORMAT_PAL, // RIFF palette + FORMAT_ACT // Photoshop binary color palette + }; + +} + + +KisPalette::KisPalette(const TQImage * img, TQ_INT32 nColors, const TQString & name) + : super(TQString("")), + m_name(name) +{ + Q_ASSERT(nColors > 0); + Q_ASSERT(!img->isNull()); + + // XXX: Implement + + m_columns = 0; // Set the default value that the GIMP uses... +} + +KisPalette::KisPalette(const KisPaintDeviceSP device, TQ_INT32 nColors, const TQString & name) + : super(TQString("")), + m_name(name) +{ + Q_ASSERT(nColors > 0); + Q_ASSERT(device != 0); + + + // XXX: Implement + m_columns = 0; // Set the default value that the GIMP uses... +} + + +KisPalette::KisPalette(const KisGradient * gradient, TQ_INT32 nColors, const TQString & name) + : super(TQString("")), + m_name(name) +{ + Q_ASSERT(nColors > 0); + Q_ASSERT(gradient != 0); + + double dx, cur_x; + TQColor c; + TQ_INT32 i; + TQ_UINT8 opacity; + dx = 1.0 / (nColors - 1); + + KisPaletteEntry e; + for (i = 0, cur_x = 0; i < nColors; i++, cur_x += dx) { + gradient->colorAt(cur_x, &e.color, &opacity); + e.name = "Untitled"; + add(e); + } + + m_columns = 0; // Set the default value that the GIMP uses... +} + +KisPalette::KisPalette(const TQString& filename) + : super(filename) +{ + // Implemented in super class + m_columns = 0; // Set the default value that the GIMP uses... +} + +KisPalette::KisPalette() + : super("") +{ + m_columns = 0; // Set the default value that the GIMP uses... +} + +/// Create an copied palette +KisPalette::KisPalette(const KisPalette& rhs) + : super("") +{ + setFilename(rhs.filename()); + m_ownData = false; + m_img = rhs.m_img; + m_name = rhs.m_name; + m_comment = rhs.m_comment; + m_columns = rhs.m_columns; + m_colors = rhs.m_colors; + setValid(true); +} + +KisPalette::~KisPalette() +{ +} + +bool KisPalette::load() +{ + TQFile file(filename()); + file.open(IO_ReadOnly); + m_data = file.readAll(); + file.close(); + return init(); +} + + +bool KisPalette::save() +{ + TQFile file(filename()); + if (!file.open(IO_WriteOnly | IO_Truncate)) { + return false; + } + + TQTextStream stream(&file); + // Header: Magic\nName: \nColumns: + // In any case, we don't use Columns... + stream << "GIMP Palette\nName: " << name() << "\nColumns: " << m_columns << "\n#\n"; + + for (uint i = 0; i < m_colors.size(); i++) { + const KisPaletteEntry& entry = m_colors.at(i); + TQColor c = entry.color; + stream << c.red() << " " << c.green() << " " << c.blue() << "\t"; + if (entry.name.isEmpty()) + stream << "Untitled\n"; + else + stream << entry.name << "\n"; + } + + file.close(); + return true; +} + +TQImage KisPalette::img() +{ + return m_img; +} + +TQ_INT32 KisPalette::nColors() +{ + return m_colors.count(); +} + +bool KisPalette::init() +{ + enumPaletteType format = FORMAT_UNKNOWN; + + TQString s = TQString::fromUtf8(m_data.data(), m_data.count()); + + if (s.isEmpty() || s.isNull() || s.length() < 50) { + kdWarning(DBG_AREA_FILE) << "Illegal Gimp palette file: " << filename() << "\n"; + return false; + } + + + if (s.startsWith("RIFF") || s.startsWith("PAL data")) + { + format = FORMAT_PAL; + } + else if (s.startsWith("GIMP Palette")) + { + // XXX: No checks for wrong input yet! + TQ_UINT32 index = 0; + + TQStringList lines = TQStringList::split("\n", s); + + if (lines.size() < 3) { + return false; + } + + TQString entry, channel, columns; + TQStringList c; + TQ_INT32 r, g, b; + TQColor color; + KisPaletteEntry e; + + format = FORMAT_GPL; + + // Read name + if (!lines[1].startsWith("Name: ") || !lines[0].startsWith("GIMP") ) + { + kdWarning(DBG_AREA_FILE) << "Illegal Gimp palette file: " << filename() << "\n"; + return false; + } + + setName(i18n(lines[1].mid(strlen("Name: ")).stripWhiteSpace().ascii())); + + index = 2; + + // Read columns + if (lines[index].startsWith("Columns: ")) { + columns = lines[index].mid(strlen("Columns: ")).stripWhiteSpace();; + m_columns = columns.toInt(); + index = 3; + } + + for (TQ_UINT32 i = index; i < lines.size(); i++) { + if (lines[i].startsWith("#")) { + m_comment += lines[i].mid(1).stripWhiteSpace() + " "; + } + else if (!lines[i].isEmpty()) + { + TQStringList a = TQStringList::split(" ", lines[i].tqreplace(TQChar('\t'), " ")); + + if (a.count() < 3) + { + break; + } + + r = a[0].toInt(); + a.pop_front(); + g = a[0].toInt(); + a.pop_front(); + b = a[0].toInt(); + a.pop_front(); + + if (r < 0 || r > 255 || + g < 0 || g > 255 || + b < 0 || b > 255) + { + break; + } + + color = TQColor(r, g, b); + e.color = color; + + TQString name = a.join(" "); + e.name = name.isEmpty() ? i18n("Untitled") : name; + + add(e); + } + } + setValid(true); + return true; + } + else if (s.length() == 768) { + kdWarning(DBG_AREA_FILE) << "Photoshop format palette file. Not implemented yet\n"; + format = FORMAT_ACT; + } + return false; +} + + +void KisPalette::add(const KisPaletteEntry & c) +{ + m_colors.push_back(c); +} + +void KisPalette::remove(const KisPaletteEntry & c) +{ + TQValueVector::iterator it = m_colors.begin(); + TQValueVector::iterator end = m_colors.end(); + + while (it != end) { + if ((*it) == c) { + m_colors.erase(it); + return; + } + ++it; + } +} + +KisPaletteEntry KisPalette::getColor(TQ_UINT32 index) +{ + return m_colors[index]; +} + +#include "kis_palette.moc" diff --git a/chalk/core/kis_palette.h b/chalk/core/kis_palette.h new file mode 100644 index 00000000..ed49849f --- /dev/null +++ b/chalk/core/kis_palette.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PALETTE_ +#define KIS_PALETTE_ + +#include +#include +#include + +#include +#include + +#include "kis_types.h" +#include "kis_resource.h" +#include "kis_global.h" +#include "kis_gradient.h" +#include "kis_alpha_mask.h" + +class TQPoint; +class TQPixmap; +class KisPaintDevice; + +struct KisPaletteEntry { + TQColor color; + TQString name; + bool operator==(const KisPaletteEntry& rhs) const { + return color == rhs.color && name == rhs.name; + } +}; + +/** + * Open Gimp, Photoshop or RIFF palette files. This is a straight port + * from the Gimp. + */ +class KisPalette : public KisResource { + typedef KisResource super; + + Q_OBJECT + TQ_OBJECT + +public: + /** + * Create a palette from the colours in an image + */ + KisPalette(const TQImage * img, TQ_INT32 nColors, const TQString & name); + + /** + * Create a palette from the colours in a paint device + */ + KisPalette(const KisPaintDeviceSP device, TQ_INT32 nColors, const TQString & name); + + /** + * Create a palette from the colours in a gradient + */ + KisPalette(const KisGradient * gradient, TQ_INT32 nColors, const TQString & name); + + /** + * Load a palette from a file. This can be a Gimp + * palette, a RIFF palette or a Photoshop palette. + */ + KisPalette(const TQString& filename); + + /// Create an empty palette + KisPalette(); + + /// Explicit copy constructor (KisResource copy constructor is private) + KisPalette(const KisPalette& rhs); + + virtual ~KisPalette(); + + virtual bool load(); + virtual bool save(); + virtual TQImage img(); + + +public: + + void add(const KisPaletteEntry &); + void remove(const KisPaletteEntry &); + KisPaletteEntry getColor(TQ_UINT32 index); + TQ_INT32 nColors(); + +private: + bool init(); + +private: + + TQByteArray m_data; + bool m_ownData; + TQImage m_img; + TQString m_name; + TQString m_comment; + TQ_INT32 m_columns; + TQValueVector m_colors; + +}; +#endif // KIS_PALETTE_ + diff --git a/chalk/core/kis_part_layer_iface.h b/chalk/core/kis_part_layer_iface.h new file mode 100644 index 00000000..1d4f7b99 --- /dev/null +++ b/chalk/core/kis_part_layer_iface.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PART_LAYER_IFACE_ +#define KIS_PART_LAYER_IFACE_ + +#include +#include "kis_types.h" + +/** + * An interface for the Part Layer so that we can use it in core/, but can implement it in ui/ + */ +class KisPartLayer : public KisLayer { + typedef KisLayer super; +public: + KisPartLayer(KisImage *img, const TQString &name, TQ_UINT8 opacity) + : super(img, name, opacity) {} + virtual KisPaintDeviceSP prepareProjection(KisPaintDeviceSP projection, const TQRect& r) = 0; + virtual bool saveToXML(TQDomDocument doc, TQDomElement elem) = 0; +}; + +#endif // KIS_PART_IFACE_LAYER_IFACE_ diff --git a/chalk/core/kis_pattern.cc b/chalk/core/kis_pattern.cc new file mode 100644 index 00000000..516d3d8b --- /dev/null +++ b/chalk/core/kis_pattern.cc @@ -0,0 +1,335 @@ +/* + * kis_pattern.cc - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * 2001 John Califf + * 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_pattern.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kis_color.h" +#include "kis_layer.h" +#include "kis_paint_device.h" + +namespace { + struct GimpPatternHeader { + TQ_UINT32 header_size; /* header_size = sizeof (PatternHeader) + brush name */ + TQ_UINT32 version; /* pattern file version # */ + TQ_UINT32 width; /* width of pattern */ + TQ_UINT32 height; /* height of pattern */ + TQ_UINT32 bytes; /* depth of pattern in bytes : 1, 2, 3 or 4*/ + TQ_UINT32 magic_number; /* GIMP brush magic number */ + }; + + // Yes! This is _NOT_ what my pat.txt file says. It's really not 'GIMP', but 'GPAT' + TQ_UINT32 const GimpPatternMagic = (('G' << 24) + ('P' << 16) + ('A' << 8) + ('T' << 0)); +} + +KisPattern::KisPattern(const TQString& file) : super(file), m_hasFile(true) +{ +} + +KisPattern::KisPattern(KisPaintDevice* image, int x, int y, int w, int h) + : super(""), m_hasFile(false) +{ + // Forcefully convert to RGBA8 + // XXX profile and exposure? + setImage(image->convertToTQImage(0, x, y, w, h)); + setName(image->name()); +} + +KisPattern::~KisPattern() +{ +} + +bool KisPattern::load() +{ + if (!m_hasFile) + return true; + + TQFile file(filename()); + file.open(IO_ReadOnly); + TQByteArray data = file.readAll(); + if (!data.isEmpty()) { + TQ_INT32 startPos = m_data.size(); + + m_data.resize(m_data.size() + data.count()); + memcpy(&m_data[startPos], data.data(), data.count()); + } + file.close(); + return init(); +} + +bool KisPattern::save() +{ + TQFile file(filename()); + file.open(IO_WriteOnly | IO_Truncate); + + TQTextStream stream(&file); + // Header: header_size (24+name length),version,width,height,colourdepth of brush,magic,name + // depth: 1 = greyscale, 2 = greyscale + A, 3 = RGB, 4 = RGBA + // magic = "GPAT", as a single uint32, the docs are wrong here! + // name is UTF-8 (\0-terminated! The docs say nothing about this!) + // _All_ data in network order, it seems! (not mentioned in gimp-2.2.8/devel-docs/pat.txt!!) + // We only save RGBA at the moment + // Version is 1 for now... + + GimpPatternHeader ph; + TQCString utf8Name = name().utf8(); + char const* name = utf8Name.data(); + int nameLength = tqstrlen(name); + + ph.header_size = htonl(sizeof(GimpPatternHeader) + nameLength + 1); // trailing 0 + ph.version = htonl(1); + ph.width = htonl(width()); + ph.height = htonl(height()); + ph.bytes = htonl(4); + ph.magic_number = htonl(GimpPatternMagic); + + TQByteArray bytes; + bytes.setRawData(reinterpret_cast(&ph), sizeof(GimpPatternHeader)); + int wrote = file.writeBlock(bytes); + bytes.resetRawData(reinterpret_cast(&ph), sizeof(GimpPatternHeader)); + + if (wrote == -1) + return false; + + wrote = file.writeBlock(name, nameLength + 1); // Trailing 0 apparantly! + if (wrote == -1) + return false; + + int k = 0; + bytes.resize(width() * height() * 4); + for (TQ_INT32 y = 0; y < height(); y++) { + for (TQ_INT32 x = 0; x < width(); x++) { + // RGBA only + TQRgb pixel = m_img.pixel(x,y); + bytes[k++] = static_cast(tqRed(pixel)); + bytes[k++] = static_cast(tqGreen(pixel)); + bytes[k++] = static_cast(tqBlue(pixel)); + bytes[k++] = static_cast(tqAlpha(pixel)); + } + } + + wrote = file.writeBlock(bytes); + if (wrote == -1) + return false; + + file.close(); + + return true; +} + +TQImage KisPattern::img() +{ + return m_img; +} + +bool KisPattern::init() +{ + // load Gimp patterns + GimpPatternHeader bh; + TQ_INT32 k; + TQValueVector name; + + if (sizeof(GimpPatternHeader) > m_data.size()) { + return false; + } + + memcpy(&bh, &m_data[0], sizeof(GimpPatternHeader)); + bh.header_size = ntohl(bh.header_size); + bh.version = ntohl(bh.version); + bh.width = ntohl(bh.width); + bh.height = ntohl(bh.height); + bh.bytes = ntohl(bh.bytes); + bh.magic_number = ntohl(bh.magic_number); + + if (bh.header_size > m_data.size() || bh.header_size == 0) { + return false; + } + + name.resize(bh.header_size - sizeof(GimpPatternHeader)); + memcpy(&name[0], &m_data[sizeof(GimpPatternHeader)], name.size()); + + if (name[name.size() - 1]) { + return false; + } + + setName(i18n(&name[0])); + + if (bh.width == 0 || bh.height == 0 || !m_img.create(bh.width, bh.height, 32)) { + return false; + } + + k = bh.header_size; + + if (bh.bytes == 1) { + // Grayscale + TQ_INT32 val; + + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++, k++) { + if (static_cast(k) > m_data.size()) { + kdDebug(DBG_AREA_FILE) << "failed in gray\n"; + return false; + } + + val = m_data[k]; + m_img.setPixel(x, y, tqRgb(val, val, val)); + m_img.setAlphaBuffer(false); + } + } + } else if (bh.bytes == 2) { + // Grayscale + A + TQ_INT32 val; + TQ_INT32 alpha; + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++, k++) { + if (static_cast(k + 2) > m_data.size()) { + kdDebug(DBG_AREA_FILE) << "failed in grayA\n"; + return false; + } + + val = m_data[k]; + alpha = m_data[k++]; + m_img.setPixel(x, y, tqRgba(val, val, val, alpha)); + m_img.setAlphaBuffer(true); + } + } + } else if (bh.bytes == 3) { + // RGB without alpha + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++) { + if (static_cast(k + 3) > m_data.size()) { + kdDebug(DBG_AREA_FILE) << "failed in RGB\n"; + return false; + } + + m_img.setPixel(x, y, tqRgb(m_data[k], + m_data[k + 1], + m_data[k + 2])); + k += 3; + m_img.setAlphaBuffer(false); + } + } + } else if (bh.bytes == 4) { + // Has alpha + for (TQ_UINT32 y = 0; y < bh.height; y++) { + for (TQ_UINT32 x = 0; x < bh.width; x++) { + if (static_cast(k + 4) > m_data.size()) { + kdDebug(DBG_AREA_FILE) << "failed in RGBA\n"; + return false; + } + + m_img.setPixel(x, y, tqRgba(m_data[k], + m_data[k + 1], + m_data[k + 2], + m_data[k + 3])); + k += 4; + m_img.setAlphaBuffer(true); + } + } + } else { + return false; + } + + if (m_img.isNull()) { + return false; + } + + setWidth(m_img.width()); + setHeight(m_img.height()); + + setValid(true); + + return true; +} + +KisPaintDeviceSP KisPattern::image(KisColorSpace * colorSpace) { + // Check if there's already a pattern prepared for this colorspace + TQMap::const_iterator it = m_colorspaces.tqfind(colorSpace->id().id()); + if (it != m_colorspaces.end()) + return (*it); + + // If not, create one + KisPaintDeviceSP layer = new KisPaintDevice(colorSpace, "pattern"); + + Q_CHECK_PTR(layer); + + layer->convertFromTQImage(m_img,""); + + m_colorspaces[colorSpace->id().id()] = layer; + return layer; +} + +TQ_INT32 KisPattern::width() const +{ + return m_width; +} + +void KisPattern::setWidth(TQ_INT32 w) +{ + m_width = w; +} + +TQ_INT32 KisPattern::height() const +{ + return m_height; +} + +void KisPattern::setHeight(TQ_INT32 h) +{ + m_height = h; +} + +void KisPattern::setImage(const TQImage& img) +{ + m_hasFile = false; + m_img = img; + m_img.detach(); + + setWidth(img.width()); + setHeight(img.height()); + + setValid(true); +} + +KisPattern* KisPattern::clone() const +{ + KisPattern* pattern = new KisPattern(""); + pattern->setImage(m_img); + pattern->setName(name()); + return pattern; +} + +#include "kis_pattern.moc" diff --git a/chalk/core/kis_pattern.h b/chalk/core/kis_pattern.h new file mode 100644 index 00000000..7d18f1f3 --- /dev/null +++ b/chalk/core/kis_pattern.h @@ -0,0 +1,80 @@ +/* + * kis_pattern.h - part of Krayon + * + * Copyright (c) 2000 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __kis_pattern_h__ +#define __kis_pattern_h__ + +#include + +#include "kis_debug_areas.h" +#include "kis_resource.h" +#include "kis_types.h" + +class TQPoint; +class TQImage; +class KisColorSpace; +class KisPaintDevice; + +class KisPattern : public KisResource { + typedef KisResource super; + Q_OBJECT + TQ_OBJECT + +public: + KisPattern(const TQString& file); + KisPattern(KisPaintDevice* image, int x, int y, int w, int h); + virtual ~KisPattern(); + + virtual bool load(); + virtual bool save(); + virtual TQImage img(); + + /** + * returns a KisPaintDeviceSP made with colorSpace as the ColorSpace strategy + * for use in the fill painter. + **/ + KisPaintDeviceSP image(KisColorSpace * colorSpace); + + TQ_INT32 width() const; + TQ_INT32 height() const; + + void setImage(const TQImage& img); + + KisPattern* clone() const; + +protected: + void setWidth(TQ_INT32 w); + void setHeight(TQ_INT32 h); + +private: + bool init(); + +private: + TQByteArray m_data; + TQImage m_img; + TQMap m_colorspaces; + bool m_hasFile; + + TQ_INT32 m_width; + TQ_INT32 m_height; +}; + +#endif + diff --git a/chalk/core/kis_perspective_grid.cpp b/chalk/core/kis_perspective_grid.cpp new file mode 100644 index 00000000..6eb5fbe8 --- /dev/null +++ b/chalk/core/kis_perspective_grid.cpp @@ -0,0 +1,100 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_perspective_grid.h" + +int KisSubPerspectiveGrid::s_lastIndex = 0; + +KisSubPerspectiveGrid::KisSubPerspectiveGrid(KisPerspectiveGridNodeSP topLeft, KisPerspectiveGridNodeSP topRight, KisPerspectiveGridNodeSP bottomRight, KisPerspectiveGridNodeSP bottomLeft) : m_topLeft(topLeft), m_topRight(topRight), m_bottomRight(bottomRight), m_bottomLeft(bottomLeft), m_subdivisions(5), m_leftGrid(0), m_rightGrid(0), m_topGrid(0), m_bottomGrid(0), m_index(++s_lastIndex) +{ + +} + +bool KisSubPerspectiveGrid::tqcontains(const KisPoint p) const +{ + return true; + KisPerspectiveMath::LineEquation d1 = KisPerspectiveMath::computeLineEquation( topLeft(), topRight() ); + kdDebug() << p.y() << " " << (p.x() * d1.a + d1.b) << endl; + if( p.y() >= p.x() * d1.a + d1.b) + { + d1 = KisPerspectiveMath::computeLineEquation( topRight(), bottomRight() ); + kdDebug() << p.y() << " " << (p.x() * d1.a + d1.b) << endl; + if( p.y() >= p.x() * d1.a + d1.b) + { + d1 = KisPerspectiveMath::computeLineEquation( bottomRight(), bottomLeft() ); + kdDebug() << p.y() << " " << (p.x() * d1.a + d1.b) << endl; + if( p.y() <= p.x() * d1.a + d1.b) + { + d1 = KisPerspectiveMath::computeLineEquation( bottomLeft(), topLeft() ); + kdDebug() << p.y() << " " << (p.x() * d1.a + d1.b) << endl; + if( p.y() <= p.x() * d1.a + d1.b) + { + return true; + } + } + } + } + return false; +} + + +KisPerspectiveGrid::KisPerspectiveGrid() +{ +} + + +KisPerspectiveGrid::~KisPerspectiveGrid() +{ + clearSubGrids( ); +} + +bool KisPerspectiveGrid::addNewSubGrid( KisSubPerspectiveGrid* ng ) +{ + if(hasSubGrids() && !ng->topGrid() && !ng->bottomGrid() && !ng->leftGrid() && !ng->rightGrid() ) + { + kdError() << "sub grids need a neighbourgh if they are not the first grid to be added" << endl; + return false; + } + m_subGrids.push_back(ng); + return true; +} + + +void KisPerspectiveGrid::clearSubGrids( ) +{ + for( TQValueList::const_iterator it = begin(); it != end(); ++it) + { + delete *it; + } + m_subGrids.clear(); +} + +KisSubPerspectiveGrid* KisPerspectiveGrid::gridAt(KisPoint p) +{ + for( TQValueList::const_iterator it = begin(); it != end(); ++it) + { + if( (*it)->tqcontains(p) ) + { + return *it; + } + } + return 0; +} + diff --git a/chalk/core/kis_perspective_grid.h b/chalk/core/kis_perspective_grid.h new file mode 100644 index 00000000..4bd22815 --- /dev/null +++ b/chalk/core/kis_perspective_grid.h @@ -0,0 +1,107 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PERSPECTIVE_GRID_H +#define KIS_PERSPECTIVE_GRID_H + +#include + +#include +#include +#include + +class KisPerspectiveGridNode : public KisPoint, public KShared { + public: + inline KisPerspectiveGridNode(double x, double y) : KisPoint(x,y) { } + inline KisPerspectiveGridNode(KisPoint p) : KisPoint(p) { } +}; +typedef KSharedPtr KisPerspectiveGridNodeSP; + +class KisSubPerspectiveGrid { + public: + KisSubPerspectiveGrid(KisPerspectiveGridNodeSP topLeft, KisPerspectiveGridNodeSP topRight, KisPerspectiveGridNodeSP bottomRight, KisPerspectiveGridNodeSP bottomLeft); + + inline KisPoint topBottomVanishingPoint() { return computeVanishingPoint( topLeft(), topRight(), bottomLeft(), bottomRight() ); }; + inline KisPoint leftRightVanishingPoint() { return computeVanishingPoint( topLeft(), bottomLeft(), topRight(), bottomRight() ); }; + + inline KisSubPerspectiveGrid* leftGrid() { return m_leftGrid; } + inline void setLeftGrid(KisSubPerspectiveGrid* g) { Q_ASSERT(m_leftGrid==0); m_leftGrid = g; } + inline KisSubPerspectiveGrid* rightGrid() { return m_rightGrid; } + inline void setRightGrid(KisSubPerspectiveGrid* g) { Q_ASSERT(m_rightGrid==0); m_rightGrid = g; } + inline KisSubPerspectiveGrid* topGrid() { return m_topGrid; } + inline void setTopGrid(KisSubPerspectiveGrid* g) { Q_ASSERT(m_topGrid==0); m_topGrid = g; } + inline KisSubPerspectiveGrid* bottomGrid() { return m_bottomGrid; } + inline void setBottomGrid(KisSubPerspectiveGrid* g) { Q_ASSERT(m_bottomGrid==0); m_bottomGrid = g; } + inline const KisPerspectiveGridNodeSP topLeft() const { return m_topLeft; } + inline KisPerspectiveGridNodeSP topLeft() { return m_topLeft; } + inline const KisPerspectiveGridNodeSP topRight() const { return m_topRight; } + inline KisPerspectiveGridNodeSP topRight() { return m_topRight; } + inline const KisPerspectiveGridNodeSP bottomLeft() const { return m_bottomLeft; } + inline KisPerspectiveGridNodeSP bottomLeft() { return m_bottomLeft; } + inline const KisPerspectiveGridNodeSP bottomRight() const { return m_bottomRight; } + inline KisPerspectiveGridNodeSP bottomRight() { return m_bottomRight; } + inline int subdivisions() const { return m_subdivisions; } + /** + * Return the index of the subgrid, the value is automaticaly set when the KisSubPerspectiveGrid, it is usefull for + * drawing the perspective grid, to avoid drawing twice the same border, or points + */ + inline int index() const { return m_index; } + + /** + * @return true if the point p is contain by the grid + */ + bool tqcontains(const KisPoint p) const; + private: + inline KisPoint computeVanishingPoint(KisPerspectiveGridNodeSP p11, KisPerspectiveGridNodeSP p12, KisPerspectiveGridNodeSP p21, KisPerspectiveGridNodeSP p22) + { + KisPerspectiveMath::LineEquation d1 = KisPerspectiveMath::computeLineEquation( p11, p12 ); + KisPerspectiveMath::LineEquation d2 = KisPerspectiveMath::computeLineEquation( p21, p22 ); + return KisPerspectiveMath::computeIntersection(d1,d2); + } + private: + KisPerspectiveGridNodeSP m_topLeft, m_topRight, m_bottomLeft, m_bottomRight; + KisSubPerspectiveGrid *m_leftGrid, *m_rightGrid, *m_topGrid, *m_bottomGrid; + int m_subdivisions; + int m_index; + static int s_lastIndex; +}; + +class KisPerspectiveGrid { + public: + KisPerspectiveGrid(); + ~KisPerspectiveGrid(); + /** + * @return false if the grid wasn't added, note that subgrids must be attached to an other grid, except if it's the first grid + */ + bool addNewSubGrid( KisSubPerspectiveGrid* ng ); + inline TQValueList::const_iterator begin() const { return m_subGrids.begin(); } + inline TQValueList::const_iterator end() const { return m_subGrids.end(); } + inline bool hasSubGrids() const { return !m_subGrids.isEmpty(); } + void clearSubGrids(); + inline int countSubGrids() const { return m_subGrids.size(); } + /** + * @return the first grid hit by the point p + */ + KisSubPerspectiveGrid* gridAt(KisPoint p); + private: + TQValueList m_subGrids; +}; + +#endif diff --git a/chalk/core/kis_perspective_math.cpp b/chalk/core/kis_perspective_math.cpp new file mode 100644 index 00000000..a4e2124e --- /dev/null +++ b/chalk/core/kis_perspective_math.cpp @@ -0,0 +1,546 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_perspective_math.h" + +#include + +#if 1 + +#include +#include +#include +//#define NDEBUG // uncomment to remove checking of assert() +#include +#define DEFAULT_ALLOC 2 + +namespace math { // TODO: use eigen + +template class matrix; + +template + class vector +{ + public: + friend class matrix; + ElType * data; + int len; + int length()const; + vector(); + vector(int n); + ~vector(){ delete [] data;} + //Copy operator + vector(const vector& v) ; + //assignment operator + vector& operator =(const vector &original); + ElType& operator[](int i)const ; + void zero(); + vector operator+(const vector& v); + vector operator-(const vector&v); + void rprint()const; //print entries on a single line + void resize(int n); + int operator==(const vector& v)const; + friend vector operator* (ElType c,vector& v ); + friend vector operator*(vector& v,ElType c ); + friend std::ostream& operator<<(std::ostream& s,vector& v); +}; +template + void vector::zero() +{ + for(int i=0;i + int vector::length()const +{ + return len; +} +template + ElType& vector::operator[](int i)const +{ + assert(i>=0 && i < len); + return data[i]; +} + +template + vector::vector() +{ + data=new ElType[ DEFAULT_ALLOC]; + assert(data!=0); + len= DEFAULT_ALLOC; +} +template + vector::vector(int n) +{ + data = new ElType[len=n]; + assert(data!=0); +} +template + vector::vector(const vector& v) +{ + data=new ElType[len=v.len]; + assert(data!=0); + for(int i=0;i + vector& vector::operator =(const vector &original) +{ + if(this != &original) + { + delete [] data; + data= new ElType[len=original.len]; + assert(data!=0); + for(int i=0;i + vector vector::operator+(const vector& v) +{ + vector sum(len); + for(int i=0;i + vector vector::operator-(const vector& v) +{ + vector sum(len); + for(int i=0;i + void vector::rprint()const //print entries on a single line +{ + int i; + std::cout << "VECTOR: "; + std::cout << "("; + for(i=0;i + void vector::resize(int n) +{ + delete[]data; + data = new ElType[len=n]; + assert(data !=0); +} +template + int vector::operator==(const vector& v)const +{ + if(len != v.len) return 0; + for(int i=0;i + vector operator*(ElType c,vector& v ) +{ + vector ans(v.len); + for(int i=0;i + vector operator*(vector& v,ElType c ) +{ + vector ans(v.len); + for(int i=0;i + std::ostream& operator<<(std::ostream& s,vector& v) +{ + s << "("; + for(int i=0;i + class matrix +{ + public: + vector *m; + int rows,cols; + matrix(); + matrix( int r, int c); + matrix(const matrix &s); + ~matrix(); + matrix& operator =(const matrix& s); + vector& operator[](const int i); + vector operator*(const vector&); + friend matrix operator*(const ElType&, const matrix&); + friend matrix operator*(const matrix&, const ElType&); + matrix operator*(const matrix& a); + matrix operator+(const matrix& a); + matrix operator-(const matrix& a); + matrix transpose(); + //matrix inverse(); + friend std::ostream& operator<<(std::ostream& s,matrix& m); + friend void ludcmp(matrix& a,vector& indx,double &d); + friend void lubksb(matrix&a,vector& indx,vector&b); +}; +template + matrix::matrix() +{ + m = new vector[DEFAULT_ALLOC]; + assert(m !=0); + rows=cols=DEFAULT_ALLOC; + for(int i=0;i v; + m[i]= v; + } +} + +template + matrix::matrix(int r, int c) +{ + m= new vector[r]; + assert(m != 0); + rows=r; + cols=c; + for(int i=0;i v(cols); + m[i]=v; + } +} +template + matrix::matrix(const matrix &s) +{ + int i; + rows=s.rows; + m = new vector[rows]; + assert(m!=0); + cols =s.cols; + for(i=0;i + matrix::~matrix() +{ + delete [] m; +} + +template + matrix& matrix::operator =(const matrix &s) +{ + if(this != &s) + { + delete []m; + rows= s.rows; + cols=s.cols; + m = new vector[rows]; + assert(m !=0); + for(int i=0;i + vector& matrix::operator[](const int i) +{ + assert(i>=0 && i < rows); + return m[i]; +} +template + vector matrix::operator*(const vector& v) +{ + int i,j; + assert(cols == v.len); + vector ans(rows); + for(i=0;i + matrix operator*(const ElType& x,const matrix& s) +{ + matrix ans(s.rows,s.cols); + for(int i=0;i + matrix matrix::transpose() +{ + matrix ans(cols,rows); + for(int i=0;i + matrix operator*(const matrix& s,const ElType& x) +{ + matrix ans(s.rows,s.cols); + for(int i=0;i + matrix matrix ::operator*(const matrix& a) +{ + + assert(cols == a.rows); + + matrix ans(rows,a.cols); + for(int i=0;i + matrix matrix ::operator+(const matrix & a) +{ + int i,j; + + assert(rows== a.rows); + assert(cols== a.cols); + + matrix ans(a.rows,a.cols); + for(i=0;i + matrix matrix::operator-(const matrix& a) +{ + int i,j; + assert(rows == a.rows); + assert(cols == a.cols); + matrix ans(rows,cols); + for(i=0;i + std::ostream& operator<<(std::ostream& s,matrix& m) +{ + for(int i=0; i +void ludcmp(matrix& a, vector& indx,double& d) +{ + int i,imax,j,k; + ElType big,dum,sum,temp; + int n=a.rows; + vector vv(n); + assert(a.rows == a.cols); + d=1.0; + for (i=0;i big) big=temp; +/* kdDebug() << temp << " " << fabs(a[i][j]) << " "<< big <= big) + { + big=dum; + imax=i; + } + } + if (j != imax) + { + for (k=0;k +void lubksb(matrix& a,vector& indx,vector& b) +{ + int i,ip,j; + ElType sum; + int n=a.rows; + for (i=0;i=0;i--) + { + sum=b[i]; + for (j=i+1;j a(10,10); + math::vector b(10); + math::vector indx(10); + double d = 0.; + for(int i = 0; i <= 9; i++) + { + for(int j = 0; j <= 9; j++) + { + a[i][j] = 0.; + } + b[i] = 0.; + indx[i] = 0; + } + + // topLeft + a[0][0] = topLeft1.x(); + a[0][1] = topLeft1.y(); + a[0][2] = 1; + a[0][6] = -topLeft2.x() * topLeft1.x(); + a[0][7] = -topLeft2.x() * topLeft1.y(); + a[0][8] = -topLeft2.x(); + a[1][3] = topLeft1.x(); + a[1][4] = topLeft1.y(); + a[1][5] = 1; + a[1][6] = -topLeft2.y() * topLeft1.x(); + a[1][7] = -topLeft2.y() * topLeft1.y(); + a[1][8] = -topLeft2.y(); + // topRight + a[2][0] = topRight1.x(); + a[2][1] = topRight1.y(); + a[2][2] = 1; + a[2][6] = -topRight2.x() * topRight1.x(); + a[2][7] = -topRight2.x() * topRight1.y(); + a[2][8] = -topRight2.x(); + a[3][3] = topRight1.x(); + a[3][4] = topRight1.y(); + a[3][5] = 1; + a[3][6] = -topRight2.y() * topRight1.x(); + a[3][7] = -topRight2.y() * topRight1.y(); + a[3][8] = -topRight2.y(); + // bottomLeft1 + a[4][0] = bottomLeft1.x(); + a[4][1] = bottomLeft1.y(); + a[4][2] = 1; + a[4][6] = -bottomLeft2.x() * bottomLeft1.x(); + a[4][7] = -bottomLeft2.x() * bottomLeft1.y(); + a[4][8] = -bottomLeft2.x(); + a[5][3] = bottomLeft1.x(); + a[5][4] = bottomLeft1.y(); + a[5][5] = 1; + a[5][6] = -bottomLeft2.y() * bottomLeft1.x(); + a[5][7] = -bottomLeft2.y() * bottomLeft1.y(); + a[5][8] = -bottomLeft2.y(); + // bottomRight + a[6][0] = bottomRight1.x(); + a[6][1] = bottomRight1.y(); + a[6][2] = 1; + a[6][6] = -bottomRight2.x() * bottomRight1.x(); + a[6][7] = -bottomRight2.x() * bottomRight1.y(); + a[6][8] = -bottomRight2.x(); + a[7][3] = bottomRight1.x(); + a[7][4] = bottomRight1.y(); + a[7][5] = 1; + a[7][6] = -bottomRight2.y() * bottomRight1.x(); + a[7][7] = -bottomRight2.y() * bottomRight1.y(); + a[7][8] = -bottomRight2.y(); + a[8][8] = 1; + b[8] = 1; +// kdDebug() << " a := { { " << a[0][0] << " , " << a[0][1] << " , " << a[0][2] << " , " << a[0][3] << " , " << a[0][4] << " , " << a[0][5] << " , " << a[0][6] << " , " << a[0][7] << " , " << a[0][8] << " } , { " << a[1][0] << " , " << a[1][1] << " , " << a[1][2] << " , " << a[1][3] << " , " << a[1][4] << " , " << a[1][5] << " , " << a[1][6] << " , " << a[1][7] << " , " << a[1][8] << " } , { " << a[2][0] << " , " << a[2][1] << " , " << a[2][2] << " , " << a[2][3] << " , " << a[2][4] << " , " << a[2][5] << " , " << a[2][6] << " , " << a[2][7] << " , " << a[2][8] << " } , { " << a[3][0] << " , " << a[3][1] << " , " << a[3][2] << " , " << a[3][3] << " , " << a[3][4] << " , " << a[3][5] << " , " << a[3][6] << " , " << a[3][7] << " , " << a[3][8] << " } , { " << a[4][0] << " , " << a[4][1] << " , " << a[4][2] << " , " << a[4][3] << " , " << a[4][4] << " , " << a[4][5] << " , " << a[4][6] << " , " << a[4][7] << " , " << a[4][8] << " } , { " << a[5][0] << " , " << a[5][1] << " , " << a[5][2] << " , " << a[5][3] << " , " << a[5][4] << " , " << a[5][5] << " , " << a[5][6] << " , " << a[5][7] << " , " << a[5][8] << " } , { " << a[6][0] << " , " << a[6][1] << " , " << a[6][2] << " , " << a[6][3] << " , " << a[6][4] << " , " << a[6][5] << " , " << a[6][6] << " , " << a[6][7] << " , " << a[6][8] << " } , { "<< a[7][0] << " , " << a[7][1] << " , " << a[7][2] << " , " << a[7][3] << " , " << a[7][4] << " , " << a[7][5] << " , " << a[7][6] << " , " << a[7][7] << " , " << a[7][8] << " } , { "<< a[8][0] << " , " << a[8][1] << " , " << a[8][2] << " , " << a[8][3] << " , " << a[8][4] << " , " << a[8][5] << " , " << a[8][6] << " , " << a[8][7] << " , " << a[8][8] << " } }; " << endl; + math::ludcmp(a,indx,d); + math::lubksb(a,indx,b); + + for(int i = 0; i < 9; i++) + { + matrix[i] = b[i]; + } + return matrix; +} + +double* KisPerspectiveMath::computeMatrixTransfoToPerspective(const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight, const TQRect& r) +{ + return KisPerspectiveMath::computeMatrixTransfo(topLeft, topRight, bottomLeft, bottomRight, KisPoint(r.topLeft()), KisPoint(r.topRight()), KisPoint(r.bottomLeft()), KisPoint(r.bottomRight())); +} + +double* KisPerspectiveMath::computeMatrixTransfoFromPerspective(const TQRect& r, const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight) +{ + return KisPerspectiveMath::computeMatrixTransfo(KisPoint(r.topLeft()), KisPoint(r.topRight()), KisPoint(r.bottomLeft()), KisPoint(r.bottomRight()), topLeft, topRight, bottomLeft, bottomRight); +} + diff --git a/chalk/core/kis_perspective_math.h b/chalk/core/kis_perspective_math.h new file mode 100644 index 00000000..7cb23770 --- /dev/null +++ b/chalk/core/kis_perspective_math.h @@ -0,0 +1,70 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_PERSPECTVE_MATH_H_ +#define _KIS_PERSPECTVE_MATH_H_ + +#include "kis_point.h" + +class TQRect; + +class KisPerspectiveMath { + private: + KisPerspectiveMath() { } + public: + static double* computeMatrixTransfo( const KisPoint& topLeft1, const KisPoint& topRight1, const KisPoint& bottomLeft1, const KisPoint& bottomRight1 , const KisPoint& topLeft2, const KisPoint& topRight2, const KisPoint& bottomLeft2, const KisPoint& bottomRight2); + static double* computeMatrixTransfoToPerspective(const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight, const TQRect& r); + static double* computeMatrixTransfoFromPerspective(const TQRect& r, const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight); + struct LineEquation { + // y = a*x + b + double a, b; + }; + /// TODO: get ride of this in 2.0 + inline static KisPoint matProd(const double (&m)[3][3], const KisPoint& p) + { + double s = ( p.x() * m[2][0] + p.y() * m[2][1] + 1.0); + s = (s == 0.) ? 1. : 1./s; + return KisPoint( (p.x() * m[0][0] + p.y() * m[0][1] + m[0][2] ) * s, + (p.x() * m[1][0] + p.y() * m[1][1] + m[1][2] ) * s ); + } + static inline LineEquation computeLineEquation(const KisPoint* p1, const KisPoint* p2) + { + LineEquation eq; + double x1 = p1->x(); double x2 = p2->x(); + if( fabs(x1 - x2) < 0.000001 ) + { + x1 += 0.0001; // Introduce a small perturbation + } + eq.a = (p2->y() - p1->y()) / (double)( x2 - x1 ); + eq.b = -eq.a * x1 + p1->y(); + return eq; + } + static inline KisPoint computeIntersection(const LineEquation& d1, const LineEquation& d2) + { + double a1 = d1.a; double a2 = d2.a; + if( fabs(a1 - a2) < 0.000001 ) + { + a1 += 0.0001; // Introduce a small perturbation + } + double x = (d1.b - d2.b) / (a2 - a1); + return KisPoint(x, a2 * x + d2.b); + } +}; + +#endif diff --git a/chalk/core/kis_perspectivetransform_worker.cpp b/chalk/core/kis_perspectivetransform_worker.cpp new file mode 100644 index 00000000..637a61de --- /dev/null +++ b/chalk/core/kis_perspectivetransform_worker.cpp @@ -0,0 +1,121 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_perspectivetransform_worker.h" + +#include "kis_iterators_pixel.h" +#include "kis_paint_device.h" +#include "kis_perspective_math.h" +#include "kis_progress_display_interface.h" +#include "kis_random_sub_accessor.h" +#include "kis_selection.h" + +KisPerspectiveTransformWorker::KisPerspectiveTransformWorker(KisPaintDeviceSP dev, const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight, KisProgressDisplayInterface *progress) + : KisProgressSubject(), m_dev(dev), m_cancelRequested(false), m_progress(progress) + +{ + TQRect m_r; + if(m_dev->hasSelection()) + m_r = m_dev->selection()->selectedExactRect(); + else + m_r = m_dev->exactBounds(); +/* if(m_dev->hasSelection()) + m_dev->selection()->clear();*/ + kdDebug() << "r = " << m_r << endl; + + double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(topLeft, topRight, bottomLeft, bottomRight, m_r); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + kdDebug() << "sol[" << 3*i+j << "]=" << b[3*i+j] << endl; + m_matrix[i][j] = b[3*i+j]; + } + } + delete b; +} + + +KisPerspectiveTransformWorker::~KisPerspectiveTransformWorker() +{ +} + +double norm2(const KisPoint& p) +{ + return sqrt(p.x() * p.x() + p.y() * p.y() ); +} + +void KisPerspectiveTransformWorker::run() +{ + kdDebug() << "r = " << m_r << endl; + + //TODO: understand why my caching of the rect didn't work... + if(m_dev->hasSelection()) + { + m_r = m_dev->selection()->selectedExactRect(); + } + else + { + m_r = m_dev->exactBounds(); + } +// KisColorSpace * cs = m_dev->colorSpace(); + + kdDebug() << "r = " << m_r << endl; + KisRectIteratorPixel dstIt = m_dev->createRectIterator(m_r.x(), m_r.y(), m_r.width(), m_r.height(), true); + KisPaintDeviceSP srcdev = new KisPaintDevice(*m_dev.data()); + { // ensure that the random sub accessor is deleted first + KisRandomSubAccessorPixel srcAcc = srcdev->createRandomSubAccessor(); + // Initialise progress + if(m_progress) + m_progress->setSubject(this, true, true); + m_lastProgressReport = 0; + m_progressStep = 0; + m_progressTotalSteps = m_r.width() * m_r.height(); + //Action + while(!dstIt.isDone()) + { + if(dstIt.isSelected()) + { + KisPoint p; + double sf = ( dstIt.x() * m_matrix[2][0] + dstIt.y() * m_matrix[2][1] + 1.0); + sf = (sf == 0.) ? 1. : 1./sf; + p.setX( ( dstIt.x() * m_matrix[0][0] + dstIt.y() * m_matrix[0][1] + m_matrix[0][2] ) * sf ); + p.setY( ( dstIt.x() * m_matrix[1][0] + dstIt.y() * m_matrix[1][1] + m_matrix[1][2] ) * sf ); + + srcAcc.moveTo( p ); + srcAcc.sampledOldRawData( dstIt.rawData() ); + + // TODO: Should set alpha = alpha*(1-selectedness) +// cs->setAlpha( dstIt.rawData(), 255, 1); + } else { +// cs->setAlpha( dstIt.rawData(), 0, 1); + } + m_progressStep ++; + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + ++dstIt; + } + } +} diff --git a/chalk/core/kis_perspectivetransform_worker.h b/chalk/core/kis_perspectivetransform_worker.h new file mode 100644 index 00000000..f81515cf --- /dev/null +++ b/chalk/core/kis_perspectivetransform_worker.h @@ -0,0 +1,52 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PERSPECTIVETRANSFORM_WORKER_H +#define KIS_PERSPECTIVETRANSFORM_WORKER_H + +#include "kis_types.h" +#include "kis_progress_subject.h" + +class KisPoint; +class KisProgressDisplayInterface; + +class KisPerspectiveTransformWorker : public KisProgressSubject +{ + public: + KisPerspectiveTransformWorker(KisPaintDeviceSP dev, const KisPoint& topLeft, const KisPoint& topRight, const KisPoint& bottomLeft, const KisPoint& bottomRight, KisProgressDisplayInterface *progress); + + ~KisPerspectiveTransformWorker(); + + void run(); + bool isCanceled() { return m_cancelRequested; }; + private: + virtual void cancel() { m_cancelRequested = true; } + private: + TQ_INT32 m_progressTotalSteps; + TQ_INT32 m_lastProgressReport; + TQ_INT32 m_progressStep; + double m_xcenter, m_ycenter, m_p, m_q; + KisPaintDeviceSP m_dev; + bool m_cancelRequested; + KisProgressDisplayInterface *m_progress; + double m_matrix[3][3]; + TQRect m_r; +}; + +#endif diff --git a/chalk/core/kis_point.h b/chalk/core/kis_point.h new file mode 100644 index 00000000..3c576cb5 --- /dev/null +++ b/chalk/core/kis_point.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_POINT_H_ +#define KIS_POINT_H_ + +#include +#include + +/** + * A double-based point class that can return it's coordinates + * approximated to integers. + */ +class KisPoint : public KoPoint { + typedef KoPoint super; +public: + KisPoint() {} + KisPoint(double x, double y) : super(x, y) {} + KisPoint(const TQPoint& pt) : super(pt) {} + KisPoint(const KoPoint& pt) : super(pt) {} + + int floorX() const { return static_cast(x()); } + int floorY() const { return static_cast(y()); } + int roundX() const { return tqRound(x()); } + int roundY() const { return tqRound(y()); } + + TQPoint floorTQPoint() const { return TQPoint(static_cast(x()), static_cast(y())); } + TQPoint roundTQPoint() const { return TQPoint(tqRound(x()), tqRound(y())); } +}; + +typedef TQValueVector vKisPoint; + +#endif // KIS_POINT_H_ + diff --git a/chalk/core/kis_random_accessor.cpp b/chalk/core/kis_random_accessor.cpp new file mode 100644 index 00000000..cfa8ecab --- /dev/null +++ b/chalk/core/kis_random_accessor.cpp @@ -0,0 +1,58 @@ +/* + * This file is part of the Chalk project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_random_accessor.h" + +#include "kis_tiled_random_accessor.h" + +KisRandomAccessor::KisRandomAccessor(KisTiledDataManager *ktm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable) : m_offsetx(offsetx), m_offsety(offsety) +{ + m_accessor = new KisTiledRandomAccessor(ktm, x, y, writable); +} + +KisRandomAccessor::KisRandomAccessor(const KisRandomAccessor& rhs) { + m_accessor = rhs.m_accessor; +} + +KisRandomAccessor::~KisRandomAccessor() +{ + +} + +void KisRandomAccessor::moveTo(TQ_INT32 x, TQ_INT32 y) +{ + m_accessor->moveTo(x - m_offsetx, y - m_offsety); +} + +TQ_UINT8* KisRandomAccessor::rawData() const +{ + return m_accessor->rawData(); +} + +const TQ_UINT8* KisRandomAccessor::oldRawData() const +{ + return m_accessor->oldRawData(); +} + +KisRandomAccessorPixel::KisRandomAccessorPixel(KisTiledDataManager *ktm, KisTiledDataManager *ktmselect, TQ_INT32 x, TQ_INT32 y, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable) : + KisRandomAccessor( ktm, x, y, offsetx, offsety, writable), + KisRandomAccessorPixelTrait( this, (ktmselect) ? new KisRandomAccessor(ktm, x, y, offsetx, offsety, false) : 0 ) +{ + +} diff --git a/chalk/core/kis_random_accessor.h b/chalk/core/kis_random_accessor.h new file mode 100644 index 00000000..6e2e10ad --- /dev/null +++ b/chalk/core/kis_random_accessor.h @@ -0,0 +1,95 @@ +/* + * This file is part of the Chalk project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_RANDOM_ACCESSOR_H +#define KIS_RANDOM_ACCESSOR_H + +#include + +#include + +class KisTiledRandomAccessor; +typedef KSharedPtr KisTiledRandomAccessorSP; + +class KisTiledDataManager; + +class KisRandomAccessor{ + public: + KisRandomAccessor(KisTiledDataManager *ktm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable); + KisRandomAccessor(const KisRandomAccessor& rhs); + ~KisRandomAccessor(); + public: + /// Move to a given x,y position, fetch tiles and data + void moveTo(TQ_INT32 x, TQ_INT32 y); + TQ_UINT8* rawData() const; + const TQ_UINT8* oldRawData() const; + private: + KisTiledRandomAccessorSP m_accessor; + TQ_INT32 m_offsetx, m_offsety; +}; + +class KisRandomAccessorPixelTrait { + public: + inline KisRandomAccessorPixelTrait(KisRandomAccessor* underlyingAccessor, KisRandomAccessor* selectionAccessor) : m_underlyingAccessor(underlyingAccessor), m_selectionAccessor(selectionAccessor) + { + } + ~KisRandomAccessorPixelTrait() { + if(m_selectionAccessor) + delete m_selectionAccessor; + } + inline bool isSelected() const + { + return (m_selectionAccessor) ? *(m_selectionAccessor->rawData()) > SELECTION_THRESHOLD : true; + }; + inline TQ_UINT8 operator[](int index) const + { return m_underlyingAccessor->rawData()[index]; }; + /** + * Returns the degree of selectedness of the pixel. + */ + inline TQ_UINT8 selectedness() const + { + return (m_selectionAccessor) ? *(m_selectionAccessor->rawData()) : MAX_SELECTED; + }; + + /** + * Returns the selectiontqmask from the current point; this is guaranteed + * to have the same number of consecutive pixels that the iterator has + * at a given point. It return a 0 if there is no selection. + */ + inline TQ_UINT8 * selectionMask() const + { + return ( m_selectionAccessor ) ? m_selectionAccessor->rawData() : 0; + } + + inline void moveTo(TQ_INT32 x, TQ_INT32 y) { if(m_selectionAccessor) m_selectionAccessor->moveTo(x,y); } + + private: + KisRandomAccessor* m_underlyingAccessor; + KisRandomAccessor* m_selectionAccessor; +}; + +class KisRandomAccessorPixel : public KisRandomAccessor, public KisRandomAccessorPixelTrait { + public: + KisRandomAccessorPixel(KisTiledDataManager *ktm, KisTiledDataManager *ktmselect, TQ_INT32 x, TQ_INT32 y, TQ_INT32 offsetx, TQ_INT32 offsety, bool writable); + public: + inline void moveTo(TQ_INT32 x, TQ_INT32 y) { KisRandomAccessor::moveTo(x,y); KisRandomAccessorPixelTrait::moveTo(x,y); } +}; + + +#endif diff --git a/chalk/core/kis_random_sub_accessor.cpp b/chalk/core/kis_random_sub_accessor.cpp new file mode 100644 index 00000000..a1ce8aa4 --- /dev/null +++ b/chalk/core/kis_random_sub_accessor.cpp @@ -0,0 +1,84 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kis_random_sub_accessor.h" + +#include "kis_paint_device.h" + +KisRandomSubAccessorPixel::KisRandomSubAccessorPixel(KisPaintDeviceSP device) : + m_device(device), m_currentPoint( 0, 0 ), m_randomAccessor(device->createRandomAccessor(0,0, false)) +{ +} + + +KisRandomSubAccessorPixel::~KisRandomSubAccessorPixel() +{ +} + + +void KisRandomSubAccessorPixel::sampledOldRawData(TQ_UINT8* dst) +{ + const TQ_UINT8* pixels[4]; + TQ_UINT8 weights[4]; + int x = (int)floor(m_currentPoint.x()); + int y = (int)floor(m_currentPoint.y()); + double hsub = m_currentPoint.x() - x; + if(hsub < 0.0 ) hsub = 1.0 + hsub; + double vsub = m_currentPoint.y() - y; + if(vsub < 0.0 ) vsub = 1.0 + vsub; + weights[0] = (int)tqRound( ( 1.0 - hsub) * ( 1.0 - vsub) * 255 ); + m_randomAccessor.moveTo(x, y); + pixels[0] = m_randomAccessor.oldRawData(); + weights[1] = (int)tqRound( ( 1.0 - vsub) * hsub * 255 ); + m_randomAccessor.moveTo(x+1, y); + pixels[1] = m_randomAccessor.oldRawData(); + weights[2] = (int)tqRound( vsub * ( 1.0 - hsub) * 255 ); + m_randomAccessor.moveTo(x, y+1); + pixels[2] = m_randomAccessor.oldRawData(); + weights[3] = (int)tqRound( hsub * vsub * 255 ); + m_randomAccessor.moveTo(x+1, y+1); + pixels[3] = m_randomAccessor.oldRawData(); + m_device->colorSpace()->mixColors(pixels, weights, 4, dst); +} + +void KisRandomSubAccessorPixel::sampledRawData(TQ_UINT8* dst) +{ + const TQ_UINT8* pixels[4]; + TQ_UINT8 weights[4]; + int x = (int)floor(m_currentPoint.x()); + int y = (int)floor(m_currentPoint.y()); + double hsub = m_currentPoint.x() - x; + if(hsub < 0.0 ) hsub = 1.0 + hsub; + double vsub = m_currentPoint.y() - y; + if(vsub < 0.0 ) vsub = 1.0 + vsub; + weights[0] = (int)tqRound( ( 1.0 - hsub) * ( 1.0 - vsub) * 255 ); + m_randomAccessor.moveTo(x, y); + pixels[0] = m_randomAccessor.rawData(); + weights[1] = (int)tqRound( ( 1.0 - vsub) * hsub * 255 ); + m_randomAccessor.moveTo(x+1, y); + pixels[1] = m_randomAccessor.rawData(); + weights[2] = (int)tqRound( vsub * ( 1.0 - hsub) * 255 ); + m_randomAccessor.moveTo(x, y+1); + pixels[2] = m_randomAccessor.rawData(); + weights[3] = (int)tqRound( hsub * vsub * 255 ); + m_randomAccessor.moveTo(x+1, y+1); + pixels[3] = m_randomAccessor.rawData(); + m_device->colorSpace()->mixColors(pixels, weights, 4, dst); +} + diff --git a/chalk/core/kis_random_sub_accessor.h b/chalk/core/kis_random_sub_accessor.h new file mode 100644 index 00000000..6ceb8345 --- /dev/null +++ b/chalk/core/kis_random_sub_accessor.h @@ -0,0 +1,45 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef KIS_CURVE_ITERATOR_H +#define KIS_CURVE_ITERATOR_H + +#include "kis_point.h" +#include "kis_random_accessor.h" +#include "kis_types.h" + +class KisRandomSubAccessorPixel{ + public: + KisRandomSubAccessorPixel(KisPaintDeviceSP device); + ~KisRandomSubAccessorPixel(); + /** + * Copy the sampled old value to destination + */ + void sampledOldRawData(TQ_UINT8* dst); + void sampledRawData(TQ_UINT8* dst); + inline void moveTo(double x, double y) { m_currentPoint.setX(x); m_currentPoint.setY(y); } + inline void moveTo(const KisPoint& p ) { m_currentPoint = p; } + private: + KisPaintDeviceSP m_device; + int m_position, m_end; + KisPoint m_currentPoint; + KisRandomAccessorPixel m_randomAccessor; +}; + +#endif diff --git a/chalk/core/kis_rect.cc b/chalk/core/kis_rect.cc new file mode 100644 index 00000000..175a07a9 --- /dev/null +++ b/chalk/core/kis_rect.cc @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_rect.h" + +TQRect KisRect::qRect() const +{ + return TQRect(static_cast(floor(left())), static_cast(floor(top())), static_cast(ceil(right()) - floor(left())), static_cast(ceil(bottom()) - floor(top()))); +} + diff --git a/chalk/core/kis_rect.h b/chalk/core/kis_rect.h new file mode 100644 index 00000000..30a729c8 --- /dev/null +++ b/chalk/core/kis_rect.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RECT_H_ +#define KIS_RECT_H_ + +#include +#include +#include "kis_point.h" + +/** + * A double-based rect class that can return a TQRect that encloses the KisRect. + */ +class KisRect : public KoRect +{ + typedef KoRect super; +public: + KisRect() {} + KisRect(double x, double y, double w, double h) : super(x, y, w, h) {} + KisRect(const KisPoint& topLeft, const KisPoint& bottomRight) : super(topLeft, bottomRight) {} + KisRect(const TQRect& qr) : super(qr.x(), qr.y(), qr.width(), qr.height()) {} + KisRect(const KoRect& r) : super(r) {} + + /** + * Return the TQRect that encloses this KisRect. + */ + TQRect qRect() const; + +private: + // Use qRect() which uses ceil() and floor() to return a rectangle + // 'enclosing' the rectangle, whereas toTQRect rounds the points. + TQRect toTQRect() const; +}; + +#endif // KIS_RECT_H_ + diff --git a/chalk/core/kis_resource.cc b/chalk/core/kis_resource.cc new file mode 100644 index 00000000..a856cbb1 --- /dev/null +++ b/chalk/core/kis_resource.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_resource.h" +#include "kis_global.h" + +KisResource::KisResource(const TQString& filename) +{ + m_filename = filename; + m_valid = false; +} + +KisResource::~KisResource() +{ +} + +TQString KisResource::filename() const +{ + return m_filename; +} + +void KisResource::setFilename(const TQString& filename) +{ + m_filename = filename; +} + +TQString KisResource::name() const +{ + return m_name; +} + +void KisResource::setName(const TQString& name) +{ + m_name = name; +} + +bool KisResource::valid() const +{ + return m_valid; +} + +void KisResource::setValid(bool valid) +{ + m_valid = valid; +} + +#include "kis_resource.moc" + diff --git a/chalk/core/kis_resource.h b/chalk/core/kis_resource.h new file mode 100644 index 00000000..e07763e3 --- /dev/null +++ b/chalk/core/kis_resource.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RESOURCE_H_ +#define KIS_RESOURCE_H_ + +#include +#include +#include + + +/** + * The KisResource class provides a representation of Chalk image resources. This + * includes, but not limited to, brushes and patterns. + * + * This replaces the KisKrayon facility that used to be present in Krayon. + */ +class KisResource : public TQObject { + typedef TQObject super; + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Creates a new KisResource object using @p filename. No file is opened + * in the constructor, you have to call load. + * + * @param filename the file name to save and load from. + */ + KisResource(const TQString& filename); + virtual ~KisResource(); + +public: + /** + * Load this resource. + */ + virtual bool load() = 0; + + /** + * Save this resource asynchronously. The signal saveComplete is emitted when + * the resource has been saved. + */ + virtual bool save() = 0; + + /** + * Returns a TQImage representing this resource. This image could be null. + */ + virtual TQImage img() = 0; + +public: + TQString filename() const; + void setFilename(const TQString& filename); + TQString name() const; + void setName(const TQString& name); + bool valid() const; + void setValid(bool valid); + +private: + KisResource(const KisResource&); + KisResource& operator=(const KisResource&); + +private: + TQString m_name; + TQString m_filename; + bool m_valid; +}; + +#endif // KIS_RESOURCE_H_ + diff --git a/chalk/core/kis_rotate_visitor.cc b/chalk/core/kis_rotate_visitor.cc new file mode 100644 index 00000000..2a8bfd45 --- /dev/null +++ b/chalk/core/kis_rotate_visitor.cc @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include +#include + +#include "kis_paint_device.h" +#include "kis_rotate_visitor.h" +#include "kis_progress_display_interface.h" +#include "kis_iterators_pixel.h" +#include "kis_selection.h" +#include "kis_painter.h" + +void KisRotateVisitor::rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress) +{ + KisPoint centreOfRotation; + + if (rotateAboutImageCentre) { + centreOfRotation = KisPoint(m_dev->image()->width() / 2.0, m_dev->image()->height() / 2.0); + } else { + TQRect r = m_dev->exactBounds(); + centreOfRotation = KisPoint(r.x() + (r.width() / 2.0), r.y() + (r.height() / 2.0)); + } + + m_progress = progress; + + KisPaintDeviceSP rotated = rotate(m_dev, angle, centreOfRotation); + + if (!m_dev->hasSelection()) { + // Clear everything + m_dev->clear(); + } else { + // Clear selected pixels + m_dev->clearSelection(); + } + + KisPainter p(m_dev); + TQRect r = rotated->extent(); + + // OVER ipv COPY + p.bitBlt(r.x(), r.y(), COMPOSITE_OVER, rotated, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height()); + p.end(); +} + +void KisRotateVisitor::shear(double angleX, double angleY, KisProgressDisplayInterface *progress) +{ + const double pi=3.1415926535897932385; + double thetaX = angleX * pi / 180; + double shearX = tan(thetaX); + double thetaY = angleY * pi / 180; + double shearY = tan(thetaY); + + TQRect r = m_dev->exactBounds(); + + const int xShearSteps = r.height(); + const int yShearSteps = r.width(); + + m_progress = progress; + initProgress(xShearSteps + yShearSteps); + + + KisPaintDeviceSP sheared; + + if (m_dev->hasSelection()) { + sheared = new KisPaintDevice(m_dev->colorSpace(), "sheared"); + KisPainter p1(sheared); + p1.bltSelection(r.x(), r.y(), COMPOSITE_OVER, m_dev, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height()); + p1.end(); + sheared = xShear(sheared, shearX); + } + else { + sheared = xShear(m_dev, shearX); + } + + sheared = yShear(sheared, shearY); + + if (!m_dev->hasSelection()) { + m_dev->clear(); + } else { + // Clear selected pixels + m_dev->clearSelection(); + } + + KisPainter p2(m_dev); + r = sheared->extent(); + + p2.bitBlt(r.x(), r.y(), COMPOSITE_OVER, sheared, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height()); + p2.end(); + + setProgressDone(); +} + +KisPaintDeviceSP KisRotateVisitor::rotateRight90(KisPaintDeviceSP src) +{ + KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateright90"); + dst->setX(src->getX()); + dst->setY(src->getY()); + + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r = src->exactBounds(); + TQ_INT32 x = 0; + + for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) { + KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false); + KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true); + + while (!hit.isDone()) { + if (hit.isSelected()) { + memcpy(vit.rawData(), hit.rawData(), pixelSize); + } + ++hit; + ++vit; + } + ++x; + incrementProgress(); + } + + return dst; +} + +KisPaintDeviceSP KisRotateVisitor::rotateLeft90(KisPaintDeviceSP src) +{ + KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotateleft90"); + + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r = src->exactBounds(); + TQ_INT32 x = 0; + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + // Read the horizontal line from back to front, write onto the vertical column + KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), false); + KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true); + + hit += r.width() - 1; + while (!vit.isDone()) { + if (hit.isSelected()) { + memcpy(vit.rawData(), hit.rawData(), pixelSize); + } + --hit; + ++vit; + } + ++x; + incrementProgress(); + } + + return dst; +} + +KisPaintDeviceSP KisRotateVisitor::rotate180(KisPaintDeviceSP src) +{ + KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "rotate180"); + dst->setX(src->getX()); + dst->setY(src->getY()); + + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r = src->exactBounds(); + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), false); + KisHLineIterator dstIt = dst->createHLineIterator( -r.x() - r.width(), -y, r.width(), true); + + srcIt += r.width() - 1; + while (!dstIt.isDone()) { + if (srcIt.isSelected()) { + memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize); + } + --srcIt; + ++dstIt; + } + incrementProgress(); + } + + return dst; +} + +KisPaintDeviceSP KisRotateVisitor::rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation) +{ + const double pi = 3.1415926535897932385; + + if (angle >= 315 && angle < 360) { + angle = angle - 360; + } else if (angle > -360 && angle < -45) { + angle = angle + 360; + } + + TQRect r = src->exactBounds(); + + const int xShearSteps = r.height(); + const int yShearSteps = r.width(); + const int fixedRotateSteps = r.height(); + + KisPaintDeviceSP dst; + + if (angle == 90) { + initProgress(fixedRotateSteps); + dst = rotateRight90(src); + } else if (angle == 180) { + initProgress(fixedRotateSteps); + dst = rotate180(src); + } else if (angle == 270) { + initProgress(fixedRotateSteps); + dst = rotateLeft90(src); + } else { + double theta; + + if (angle >= -45 && angle < 45) { + + theta = angle * pi / 180; + dst = src; + initProgress(yShearSteps + (2 * xShearSteps)); + } + else if (angle >= 45 && angle < 135) { + + initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps)); + dst = rotateRight90(src); + theta = (angle - 90) * pi / 180; + } + else if (angle >= 135 && angle < 225) { + + initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps)); + dst = rotate180(src); + theta = (angle - 180) * pi / 180; + + } else { + + initProgress(fixedRotateSteps + yShearSteps + (2 * xShearSteps)); + dst = rotateLeft90(src); + theta = (angle - 270) * pi / 180; + } + + double shearX = tan(theta / 2); + double shearY = sin(theta); + + //first perform a shear along the x-axis by tan(theta/2) + dst = xShear(dst, shearX); + //next perform a shear along the y-axis by sin(theta) + dst = yShear(dst, shearY); + //again perform a shear along the x-axis by tan(theta/2) + dst = xShear(dst, shearX); + } + + double sinAngle = sin(angle * pi / 180); + double cosAngle = cos(angle * pi / 180); + + KisPoint rotatedCentreOfRotation( + centreOfRotation.x() * cosAngle - centreOfRotation.y() * sinAngle, + centreOfRotation.x() * sinAngle + centreOfRotation.y() * cosAngle); + + dst->setX((TQ_INT32)(dst->getX() + centreOfRotation.x() - rotatedCentreOfRotation.x())); + dst->setY((TQ_INT32)(dst->getY() + centreOfRotation.y() - rotatedCentreOfRotation.y())); + + setProgressDone(); + + return dst; +} + +KisPaintDeviceSP KisRotateVisitor::xShear(KisPaintDeviceSP src, double shearX) +{ + KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "xShear"); + dst->setX(src->getX()); + dst->setY(src->getY()); + + TQRect r = src->exactBounds(); + + double displacement; + TQ_INT32 displacementInt; + double weight; + + for (TQ_INT32 y = r.top(); y <= r.bottom(); y++) { + + //calculate displacement + displacement = -y * shearX; + + displacementInt = (TQ_INT32)(floor(displacement)); + weight = displacement - displacementInt; + + TQ_UINT8 pixelWeights[2]; + + pixelWeights[0] = static_cast(weight * 255 + 0.5); + pixelWeights[1] = 255 - pixelWeights[0]; + + KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width() + 1, false); + KisHLineIteratorPixel leftSrcIt = src->createHLineIterator(r.x() - 1, y, r.width() + 1, false); + KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x() + displacementInt, y, r.width() + 1, true); + + while (!srcIt.isDone()) { + + const TQ_UINT8 *pixelPtrs[2]; + + pixelPtrs[0] = leftSrcIt.rawData(); + pixelPtrs[1] = srcIt.rawData(); + + src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData()); + + ++srcIt; + ++leftSrcIt; + ++dstIt; + } + incrementProgress(); + } + + return dst; +} + +KisPaintDeviceSP KisRotateVisitor::yShear(KisPaintDeviceSP src, double shearY) +{ + KisPaintDeviceSP dst = new KisPaintDevice(src->colorSpace(), "yShear"); + dst->setX(src->getX()); + dst->setY(src->getY()); + + TQRect r = src->exactBounds(); + + double displacement; + TQ_INT32 displacementInt; + double weight; + + for (TQ_INT32 x = r.left(); x <= r.right(); x++) { + + //calculate displacement + displacement = x * shearY; + + displacementInt = (TQ_INT32)(floor(displacement)); + weight = displacement - displacementInt; + + TQ_UINT8 pixelWeights[2]; + + pixelWeights[0] = static_cast(weight * 255 + 0.5); + pixelWeights[1] = 255 - pixelWeights[0]; + + KisVLineIteratorPixel srcIt = src->createVLineIterator(x, r.y(), r.height() + 1, false); + KisVLineIteratorPixel leftSrcIt = src->createVLineIterator(x, r.y() - 1, r.height() + 1, false); + KisVLineIteratorPixel dstIt = dst->createVLineIterator(x, r.y() + displacementInt, r.height() + 1, true); + + while (!srcIt.isDone()) { + + const TQ_UINT8 *pixelPtrs[2]; + + pixelPtrs[0] = leftSrcIt.rawData(); + pixelPtrs[1] = srcIt.rawData(); + + src->colorSpace()->mixColors(pixelPtrs, pixelWeights, 2, dstIt.rawData()); + + ++srcIt; + ++leftSrcIt; + ++dstIt; + } + incrementProgress(); + } + + return dst; +} + +void KisRotateVisitor::initProgress(TQ_INT32 totalSteps) +{ + if (!m_progress) return; + + m_progressTotalSteps = totalSteps; + m_progressStep = 0; + m_lastProgressPerCent = 0; + + + m_progress->setSubject(this, true, false); + emit notifyProgress(0); + +} + +void KisRotateVisitor::incrementProgress() +{ + if (!m_progress) return; + + m_progressStep++; + TQ_INT32 progressPerCent = (m_progressStep * 100) / m_progressTotalSteps; + + if (progressPerCent != m_lastProgressPerCent) { + m_lastProgressPerCent = progressPerCent; + emit notifyProgress(progressPerCent); + } +} + +void KisRotateVisitor::setProgressDone() +{ + if (!m_progress) return; + + emit notifyProgressDone(); +} + + diff --git a/chalk/core/kis_rotate_visitor.h b/chalk/core/kis_rotate_visitor.h new file mode 100644 index 00000000..ea23f84f --- /dev/null +++ b/chalk/core/kis_rotate_visitor.h @@ -0,0 +1,80 @@ +/* + * copyright (c) 2004 Michael Thaler + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_ROTATE_VISITOR_H_ +#define KIS_ROTATE_VISITOR_H_ + +#include "kis_types.h" +#include "kis_progress_subject.h" + +class TQRect; +class KisPaintDevice; +class KisProgressDisplayInterface; + +class KisRotateVisitor : public KisProgressSubject { + typedef KisProgressSubject super; + + /* Structs for the image rescaling routine */ + +public: + KisRotateVisitor(); + ~KisRotateVisitor(); + + void visitKisPaintDevice(KisPaintDevice* dev); + + void rotate(double angle, bool rotateAboutImageCentre, KisProgressDisplayInterface *progress); + void shear(double angleX, double angleY, KisProgressDisplayInterface *progress); + +private: + KisPaintDeviceSP m_dev; + + // Implement KisProgressSubject + bool m_cancelRequested; + virtual void cancel() { m_cancelRequested = true; } + + void initProgress(TQ_INT32 totalSteps); + void incrementProgress(); + void setProgressDone(); + + KisProgressDisplayInterface *m_progress; + TQ_INT32 m_progressStep; + TQ_INT32 m_progressTotalSteps; + TQ_INT32 m_lastProgressPerCent; + + KisPaintDeviceSP rotateRight90(KisPaintDeviceSP src); + KisPaintDeviceSP rotateLeft90(KisPaintDeviceSP src); + KisPaintDeviceSP rotate180(KisPaintDeviceSP src); + KisPaintDeviceSP rotate(KisPaintDeviceSP src, double angle, KisPoint centreOfRotation); + + KisPaintDeviceSP xShear(KisPaintDeviceSP src, double shearX); + KisPaintDeviceSP yShear(KisPaintDeviceSP src, double shearY); + +}; + +inline KisRotateVisitor::KisRotateVisitor() +{ +} + +inline KisRotateVisitor::~KisRotateVisitor() +{ +} + +inline void KisRotateVisitor::visitKisPaintDevice(KisPaintDevice* dev) +{ + m_dev = dev; +} +#endif // KIS_ROTATE_VISITOR_H_ diff --git a/chalk/core/kis_scale_visitor.cc b/chalk/core/kis_scale_visitor.cc new file mode 100644 index 00000000..25ad47c4 --- /dev/null +++ b/chalk/core/kis_scale_visitor.cc @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2004, 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include + +#include "kis_paint_device.h" +#include "kis_scale_visitor.h" +#include "kis_filter_strategy.h" + + +void KisScaleWorker::run() +{ + double fwidth = m_filterStrategy->support(); + + TQRect rect = m_dev -> exactBounds(); + TQ_INT32 width = rect.width(); + TQ_INT32 height = rect.height(); + m_pixelSize=m_dev -> pixelSize(); + + // compute size of target image + if ( m_sx == 1.0F && m_sy == 1.0F ) { + return; + } + TQ_INT32 targetW = TQABS( tqRound( m_sx * width ) ); + TQ_INT32 targetH = TQABS( tqRound( m_sy * height ) ); + + TQ_UINT8* newData = new TQ_UINT8[targetW * targetH * m_pixelSize ]; + Q_CHECK_PTR(newData); + + double* weight = new double[ m_pixelSize ]; /* filter calculation variables */ + + TQ_UINT8* pel = new TQ_UINT8[ m_pixelSize ]; + Q_CHECK_PTR(pel); + + TQ_UINT8 *pel2 = new TQ_UINT8[ m_pixelSize ]; + Q_CHECK_PTR(pel2); + + bool* bPelDelta = new bool[ m_pixelSize ]; + ContribList *contribX; + ContribList contribY; + const TQ_INT32 BLACK_PIXEL=0; + const TQ_INT32 WHITE_PIXEL=255; + + + // create intermediate row to hold vertical dst row zoom + TQ_UINT8 * tmp = new TQ_UINT8[ width * m_pixelSize ]; + Q_CHECK_PTR(tmp); + + //create array of pointers to intermediate rows + TQ_UINT8 **tmpRows = new TQ_UINT8*[ height ]; + + //create array of pointers to intermediate rows that are actually used simultaneously and allocate memory for the rows + TQ_UINT8 **tmpRowsMem; + if(m_sy < 1.0) + { + tmpRowsMem = new TQ_UINT8*[ (int)(fwidth / m_sy * 2 + 1) ]; + for(int i = 0; i < (int)(fwidth / m_sy * 2 + 1); i++) + { + tmpRowsMem[i] = new TQ_UINT8[ width * m_pixelSize ]; + Q_CHECK_PTR(tmpRowsMem[i]); + } + } + else + { + tmpRowsMem = new TQ_UINT8*[ (int)(fwidth * 2 + 1) ]; + for(int i = 0; i < (int)(fwidth * 2 + 1); i++) + { + tmpRowsMem[i] = new TQ_UINT8[ width * m_pixelSize ]; + Q_CHECK_PTR(tmpRowsMem[i]); + } + } + + // build x weights + contribX = new ContribList[ targetW ]; + for(int x = 0; x < targetW; x++) + { + calcContrib(&contribX[x], m_sx, fwidth, width, m_filterStrategy, x); + } + + TQTime starttime = TQTime::currentTime (); + + for(int y = 0; y < targetH; y++) + { + // build y weights + calcContrib(&contribY, m_sy, fwidth, height, m_filterStrategy, y); + + //copy pixel data to temporary arrays + for(int srcpos = 0; srcpos < contribY.n; srcpos++) + { + if (!(contribY.p[srcpos].m_pixel < 0 || contribY.p[srcpos].m_pixel >= height)) + { + tmpRows[contribY.p[srcpos].m_pixel] = new TQ_UINT8[ width * m_pixelSize ]; + //tmpRows[ contribY.p[srcpos].m_pixel ] = tmpRowsMem[ srcpos ]; + m_dev ->readBytes(tmpRows[contribY.p[srcpos].m_pixel], 0, contribY.p[srcpos].m_pixel, width, 1); + } + } + + /* Apply vert filter to make dst row in tmp. */ + for(int x = 0; x < width; x++) + { + for(int channel = 0; channel < m_pixelSize; channel++){ + weight[channel] = 0.0; + bPelDelta[channel] = FALSE; + pel[channel]=tmpRows[contribY.p[0].m_pixel][ x * m_pixelSize + channel ]; + } + for(int srcpos = 0; srcpos < contribY.n; srcpos++) + { + if (!(contribY.p[srcpos].m_pixel < 0 || contribY.p[srcpos].m_pixel >= height)){ + for(int channel = 0; channel < m_pixelSize; channel++) + { + pel2[channel]=tmpRows[contribY.p[srcpos].m_pixel][ x * m_pixelSize + channel ]; + if(pel2[channel] != pel[channel]) bPelDelta[channel] = TRUE; + weight[channel] += pel2[channel] * contribY.p[srcpos].m_weight; + } + } + } + + for(int channel = 0; channel < m_pixelSize; channel++){ + weight[channel] = bPelDelta[channel] ? static_cast(tqRound(weight[channel])) : pel[channel]; + tmp[ x * m_pixelSize + channel ] = static_cast(CLAMP(weight[channel], BLACK_PIXEL, WHITE_PIXEL)); + } + } /* next row in temp column */ + delete[] contribY.p; + + for(int x = 0; x < targetW; x++) + { + for(int channel = 0; channel < m_pixelSize; channel++){ + weight[channel] = 0.0; + bPelDelta[channel] = FALSE; + pel[channel] = tmp[ contribX[x].p[0].m_pixel * m_pixelSize + channel ]; + } + for(int srcpos = 0; srcpos < contribX[x].n; srcpos++) + { + for(int channel = 0; channel < m_pixelSize; channel++){ + pel2[channel] = tmp[ contribX[x].p[srcpos].m_pixel * m_pixelSize + channel ]; + if(pel2[channel] != pel[channel]) + bPelDelta[channel] = TRUE; + weight[channel] += pel2[channel] * contribX[x].p[srcpos].m_weight; + } + } + for(int channel = 0; channel < m_pixelSize; channel++){ + weight[channel] = bPelDelta[channel] ? static_cast(tqRound(weight[channel])) : pel[channel]; + int currentPos = (y*targetW+x) * m_pixelSize; // try to be at least a little efficient + if (weight[channel]<0) + newData[currentPos + channel] = 0; + else if (weight[channel]>255) + newData[currentPos + channel] = 255; + else + newData[currentPos + channel] = (uchar)weight[channel]; + } + } /* next dst row */ + } /* next dst column */ + + // XXX: I'm thinking that we should be able to cancel earlier, in the look. + if(!isCanceled()){ + m_dev -> writeBytes( newData, 0, 0, targetW, targetH); + m_dev -> crop(0, 0, targetW, targetH); + } + + /* free the memory allocated for horizontal filter weights */ + for(int x = 0; x < targetW; x++) + delete[] contribX[x].p; + delete[] contribX; + + delete[] newData; + delete[] pel; + delete[] pel2; + delete[] tmp; + delete[] weight; + delete[] bPelDelta; + + if(m_sy < 1.0) + { + for(int i = 0; i < (int)(fwidth / m_sy * 2 + 1); i++) + { + delete[] tmpRowsMem[i]; + } + } + else + { + for(int i = 0; i < (int)(fwidth * 2 + 1); i++) + { + delete[] tmpRowsMem[i]; + } + } + + TQTime stoptime = TQTime::currentTime (); + return; +} + +int KisScaleWorker::calcContrib(ContribList *contrib, double scale, double fwidth, int srcwidth, KisFilterStrategy* filterStrategy, TQ_INT32 i) +{ + //ContribList* contribX: receiver of contrib info + //double m_sx: horizontal zooming scale + //double fwidth: Filter sampling width + //int dstwidth: Target bitmap width + //int srcwidth: Source bitmap width + //double (*filterf)(double): Filter proc + //int i: Pixel column in source bitmap being processed + + double width; + double fscale; + double center, begin, end; + double weight; + TQ_INT32 k, n; + + if(scale < 1.0) + { + //Shrinking image + width = fwidth / scale; + fscale = 1.0 / scale; + + contrib->n = 0; + contrib->p = new Contrib[ (int)(width * 2 + 1) ]; + + center = (double) i / scale; + begin = ceil(center - width); + end = floor(center + width); + for(int srcpos = (int)begin; srcpos <= end; ++srcpos) + { + weight = center - (double) srcpos; + weight = filterStrategy->valueAt(weight / fscale) / fscale; + if(srcpos < 0) + n = -srcpos; + else if(srcpos >= srcwidth) + n = (srcwidth - srcpos) + srcwidth - 1; + else + n = srcpos; + + k = contrib->n++; + contrib->p[k].m_pixel = n; + contrib->p[k].m_weight = weight; + } + } + else + { + // Expanding image + contrib->n = 0; + contrib->p = new Contrib[ (int)(fwidth * 2 + 1) ]; + + center = (double) i / scale; + begin = ceil(center - fwidth); + end = floor(center + fwidth); + + for(int srcpos = (int)begin; srcpos <= end; ++srcpos) + { + weight = center - (double) srcpos; + weight = filterStrategy->valueAt(weight); + if(srcpos < 0) { + n = -srcpos; + } else if(srcpos >= srcwidth) { + n = (srcwidth - srcpos) + srcwidth - 1; + } else { + n = srcpos; + } + k = contrib->n++; + contrib->p[k].m_pixel = n; + contrib->p[k].m_weight = weight; + } + } + return 0; +} /* calc_x_contrib */ diff --git a/chalk/core/kis_scale_visitor.h b/chalk/core/kis_scale_visitor.h new file mode 100644 index 00000000..afe358ad --- /dev/null +++ b/chalk/core/kis_scale_visitor.h @@ -0,0 +1,204 @@ +/* + * copyright (c) 2004, 2005 Michael Thaler + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#ifndef KIS_SCALE_VISITOR_H_ +#define KIS_SCALE_VISITOR_H_ + +#include "klocale.h" + +#include "kis_progress_subject.h" +#include "kis_progress_display_interface.h" +#include "kis_thread.h" +#include "kis_layer_visitor.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_transaction.h" +#include "kis_undo_adapter.h" +#include "kis_selection.h" + +class KisProgressDisplayInterface; +class KisFilterStrategy; + +class KisScaleWorker : public KisThread { + + /* Structs for the image rescaling routine */ + class Contrib { + public: + TQ_INT32 m_pixel; + double m_weight; + }; + + class ContribList { + public: + TQ_INT32 n; //number of contributors + Contrib *p; //pointer to list of contributions + }; + +public: + + KisScaleWorker(KisPaintDevice * dev, double sx, double sy, + KisFilterStrategy *filterStrategy) + : KisThread() + , m_dev(dev) + , m_sx(sx) + , m_sy(sy) + , m_filterStrategy(filterStrategy) {}; + + virtual ~KisScaleWorker() {}; + + void run(); + +private: + TQ_INT32 m_pixelSize; + KisPaintDevice * m_dev; + double m_sx, m_sy; + KisFilterStrategy * m_filterStrategy; + + + /** + * calc_x_contrib() + * + * Calculates the filter weights for a single target column. + * contribX->p must be freed afterwards. + * + * Returns -1 if error, 0 otherwise. + */ + int calcContrib(ContribList *contribX, double cale, double fwidth, int srcwidth, KisFilterStrategy *filterStrategy, TQ_INT32 i); + + ContribList * contrib; //array of contribution lists + + +}; + + +class KisScaleVisitor : public KisLayerVisitor, KisProgressSubject { + +public: + + KisScaleVisitor(KisImageSP img, + double sx, + double sy, + KisProgressDisplayInterface *progress, + KisFilterStrategy *filterStrategy) + : KisLayerVisitor() + , m_img(img) + , m_sx(sx) + , m_sy(sy) + , m_progress(progress) + , m_filterStrategy(filterStrategy) + { + if ( progress ) + progress -> setSubject(this, true, true); + emit notifyProgressStage(i18n("Scaling..."),0); + } + + virtual ~KisScaleVisitor() + { + // Wait for all threads to finish + KisThread * t; + int threadcount = m_scalethreads.count(); + int i = 0; + for ( t = m_scalethreads.first(); t; t = m_scalethreads.next()) { + //progress info + if (t) t->wait(); + emit notifyProgress((100 / threadcount) * i); + ++i; + + } + emit notifyProgressDone(); + // Delete all threads + m_scalethreads.setAutoDelete(true); + m_scalethreads.clear(); + } + + bool visit(KisPaintLayer *layer) + { + // XXX: If all is well, then the image's undoadapter will have started a macro for us + // This will break in a more multi-threaded environment + if (m_img->undoAdapter() && m_img->undoAdapter()->undo()) { + KisTransaction * cmd = new KisTransaction("", layer->paintDevice()); + m_img->undoAdapter()->addCommand(cmd); + } + + KisScaleWorker * scaleThread = new KisScaleWorker(layer->paintDevice(), + m_sx, m_sy, m_filterStrategy); + m_scalethreads.append(scaleThread); + scaleThread->start(); + //scaleThread->run(); + layer->setDirty(); + return true; + } + + bool visit(KisGroupLayer *layer) + { + //KisScaleVisitor visitor (m_img, m_sx, m_sy, m_progress, m_filterStrategy); + + // XXX: Maybe faster to scale the projection and do something clever to avoid + // recompositing everything? + layer->resetProjection(); + + + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + + return true; + } + + bool visit(KisPartLayer */*layer*/) + { + return true; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + KisThread * scaleThread = new KisScaleWorker(layer->selection().data(), m_sx, m_sy, m_filterStrategy); + m_scalethreads.append(scaleThread); + scaleThread->start(); + layer->resetCache(); + layer->setDirty(); + return true; + } + + + // Implement KisProgressSubject + virtual void cancel() + { + KisThread * t; + for ( t = m_scalethreads.first(); t; t = m_scalethreads.next()) { + t->cancel(); + } + } + + +private: + + TQPtrList m_scalethreads; + KisImageSP m_img; + double m_sx; + double m_sy; + KisProgressDisplayInterface * m_progress; + KisFilterStrategy * m_filterStrategy; +}; + +#endif // KIS_SCALE_VISITOR_H_ diff --git a/chalk/core/kis_selected_transaction.cc b/chalk/core/kis_selected_transaction.cc new file mode 100644 index 00000000..44eec697 --- /dev/null +++ b/chalk/core/kis_selected_transaction.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_types.h" +#include "kis_global.h" +#include "kis_selected_transaction.h" +#include "kis_selection.h" + +KisSelectedTransaction::KisSelectedTransaction(const TQString& name, KisPaintDeviceSP device) : + KisTransaction(name, device), + m_device(device), + m_hadSelection(device->hasSelection()) +{ + m_selTransaction = new KisTransaction(name, device->selection().data()); + if(! m_hadSelection) { + m_device->deselect(); // let us not be the cause of select + } +} + +KisSelectedTransaction::~KisSelectedTransaction() +{ + delete m_selTransaction; +} + +void KisSelectedTransaction::execute() +{ + super::execute(); + m_selTransaction->execute(); + if(m_redoHasSelection) + m_device->selection(); + else + m_device->deselect(); + m_device->emitSelectionChanged(); +} + +void KisSelectedTransaction::unexecute() +{ + m_redoHasSelection = m_device->hasSelection(); + + super::unexecute(); + m_selTransaction->unexecute(); + if(m_hadSelection) + m_device->selection(); + else + m_device->deselect(); + m_device->emitSelectionChanged(); +} + +void KisSelectedTransaction::unexecuteNoUpdate() +{ + m_redoHasSelection = m_device->hasSelection(); + + super::unexecuteNoUpdate(); + m_selTransaction->unexecuteNoUpdate(); + if(m_hadSelection) + m_device->selection(); + else + m_device->deselect(); +} diff --git a/chalk/core/kis_selected_transaction.h b/chalk/core/kis_selected_transaction.h new file mode 100644 index 00000000..c366f336 --- /dev/null +++ b/chalk/core/kis_selected_transaction.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SELECTED_TRANSACTION_H_ +#define KIS_SELECTED_TRANSACTION_H_ + +#include +#include +#include + +#include "kis_transaction.h" + +#include "koffice_export.h" + +class KRITACORE_EXPORT KisSelectedTransaction : public KisTransaction { + typedef KisTransaction super; +public: + KisSelectedTransaction(const TQString& name, KisPaintDeviceSP device); + virtual ~KisSelectedTransaction(); + +public: + virtual void execute(); + virtual void unexecute(); + virtual void unexecuteNoUpdate(); + +public: + +private: + KisPaintDeviceSP m_device; + KisTransaction *m_selTransaction; + bool m_hadSelection; + bool m_redoHasSelection; +}; + +#endif // KIS_SELECTED_TRANSACTION_H_ diff --git a/chalk/core/kis_selection.cc b/chalk/core/kis_selection.cc new file mode 100644 index 00000000..e988eff0 --- /dev/null +++ b/chalk/core/kis_selection.cc @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#include + +#include +#include +#include + +#include "kis_layer.h" +#include "kis_debug_areas.h" +#include "kis_types.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_fill_painter.h" +#include "kis_iterators_pixel.h" +#include "kis_integer_maths.h" +#include "kis_image.h" +#include "kis_datamanager.h" +#include "kis_fill_painter.h" +#include "kis_selection.h" + +KisSelection::KisSelection(KisPaintDeviceSP dev) + : super(dev->tqparentLayer() + , KisMetaRegistry::instance()->csRegistry()->getAlpha8() + , (TQString("selection for ") + dev->name()).latin1()) + , m_parentPaintDevice(dev) + , m_doCacheExactRect(false) + , m_dirty(false) +{ + Q_ASSERT(dev); +} + +KisSelection::KisSelection() + : super(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), "anonymous selection") + , m_parentPaintDevice(0), m_dirty(false) +{ +} + +KisSelection::KisSelection(const KisSelection& rhs) + : super(rhs), m_parentPaintDevice(rhs.m_parentPaintDevice), m_doCacheExactRect(rhs.m_doCacheExactRect), + m_cachedExactRect(rhs.m_cachedExactRect), m_dirty(rhs.m_dirty) +{ +} + +KisSelection::~KisSelection() +{ +} + +TQ_UINT8 KisSelection::selected(TQ_INT32 x, TQ_INT32 y) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, false); + + TQ_UINT8 *pix = iter.rawData(); + + return *pix; +} + +void KisSelection::setSelected(TQ_INT32 x, TQ_INT32 y, TQ_UINT8 s) +{ + KisHLineIteratorPixel iter = createHLineIterator(x, y, 1, true); + + TQ_UINT8 *pix = iter.rawData(); + + *pix = s; +} + +TQImage KisSelection::tqmaskImage() +{ + // If part of a KisAdjustmentLayer, there may be no tqparent device. + TQImage img; + TQRect bounds; + if (m_parentPaintDevice) { + + bounds = m_parentPaintDevice->exactBounds(); + bounds = bounds.intersect( m_parentPaintDevice->image()->bounds() ); + img = TQImage(bounds.width(), bounds.height(), 32); + } + else { + bounds = TQRect( 0, 0, image()->width(), image()->height()); + img = TQImage(bounds.width(), bounds.height(), 32); + } + + KisHLineIteratorPixel it = createHLineIterator(bounds.x(), bounds.y(), bounds.width(), false); + for (int y2 = bounds.y(); y2 < bounds.height() - bounds.y(); ++y2) { + int x2 = 0; + while (!it.isDone()) { + TQ_UINT8 s = MAX_SELECTED - *(it.rawData()); + TQ_INT32 c = tqRgb(s, s, s); + img.setPixel(x2, y2, c); + ++x2; + ++it; + } + it.nextRow(); + } + return img; +} +void KisSelection::select(TQRect r) +{ + KisFillPainter painter(this); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + painter.fillRect(r, KisColor(TQt::white, cs), MAX_SELECTED); + TQ_INT32 x, y, w, h; + extent(x, y, w, h); +} + +void KisSelection::clear(TQRect r) +{ + KisFillPainter painter(this); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + painter.fillRect(r, KisColor(TQt::white, cs), MIN_SELECTED); +} + +void KisSelection::clear() +{ + TQ_UINT8 defPixel = MIN_SELECTED; + m_datamanager->setDefaultPixel(&defPixel); + m_datamanager->clear(); +} + +void KisSelection::invert() +{ + TQ_INT32 x,y,w,h; + + extent(x, y, w, h); + KisRectIterator it = createRectIterator(x, y, w, h, true); + while ( ! it.isDone() ) + { + // CBR this is wrong only first byte is inverted + // BSAR: But we have always only one byte in this color model :-). + *(it.rawData()) = MAX_SELECTED - *(it.rawData()); + ++it; + } + TQ_UINT8 defPixel = MAX_SELECTED - *(m_datamanager->defaultPixel()); + m_datamanager->setDefaultPixel(&defPixel); +} + +bool KisSelection::isTotallyUnselected(TQRect r) +{ + if(*(m_datamanager->defaultPixel()) != MIN_SELECTED) + return false; + TQRect sr = selectedExactRect(); + return ! r.intersects(sr); +} + +bool KisSelection::isProbablyTotallyUnselected(TQRect r) +{ + if(*(m_datamanager->defaultPixel()) != MIN_SELECTED) + return false; + TQRect sr = selectedRect(); + return ! r.intersects(sr); +} + + +TQRect KisSelection::selectedRect() const +{ + if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice) + return extent(); + else + return extent().unite(m_parentPaintDevice->extent()); +} + +TQRect KisSelection::selectedExactRect() const +{ + if(m_doCacheExactRect) + return m_cachedExactRect; + else if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice) + return exactBounds(); + else + return exactBounds().unite(m_parentPaintDevice->exactBounds()); +} + +void KisSelection::stopCachingExactRect() +{ + kdDebug() << "stop caching the exact rect" << endl; + m_doCacheExactRect = false; +} + + +void KisSelection::startCachingExactRect() +{ + kdDebug() << "start caching the exact rect" << endl; + if(*(m_datamanager->defaultPixel()) == MIN_SELECTED || !m_parentPaintDevice) + m_cachedExactRect = exactBounds(); + else + m_cachedExactRect = exactBounds().unite(m_parentPaintDevice->exactBounds()); + m_doCacheExactRect = true; +} + +void KisSelection::paintUniformSelectionRegion(TQImage img, const TQRect& imageRect, const TQRegion& uniformRegion) +{ + Q_ASSERT(img.size() == imageRect.size()); + Q_ASSERT(imageRect.tqcontains(uniformRegion.boundingRect())); + + if (img.isNull() || img.size() != imageRect.size() || !imageRect.tqcontains(uniformRegion.boundingRect())) { + return; + } + + if (*m_datamanager->defaultPixel() == MIN_SELECTED) { + + TQRegion region = uniformRegion & TQRegion(imageRect); + + if (!region.isEmpty()) { + TQMemArray rects = region.tqrects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + TQRect r = rects[i]; + + for (TQ_INT32 y = 0; y < r.height(); ++y) { + + TQRgb *imagePixel = reinterpret_cast(img.scanLine(r.y() - imageRect.y() + y)); + imagePixel += r.x() - imageRect.x(); + + TQ_INT32 numPixels = r.width(); + + while (numPixels > 0) { + + TQRgb srcPixel = *imagePixel; + TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9; + TQ_UINT8 srcAlpha = tqAlpha(srcPixel); + + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192); + + TQRgb dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + *imagePixel = dstPixel; + + ++imagePixel; + --numPixels; + } + } + } + } + } +} + +void KisSelection::paintSelection(TQImage img, TQ_INT32 imageRectX, TQ_INT32 imageRectY, TQ_INT32 imageRectWidth, TQ_INT32 imageRectHeight) +{ + Q_ASSERT(img.size() == TQSize(imageRectWidth, imageRectHeight)); + + if (img.isNull() || img.size() != TQSize(imageRectWidth, imageRectHeight)) { + return; + } + + TQRect imageRect(imageRectX, imageRectY, imageRectWidth, imageRectHeight); + TQRect selectionExtent = extent(); + + selectionExtent.setLeft(selectionExtent.left() - 1); + selectionExtent.setTop(selectionExtent.top() - 1); + selectionExtent.setWidth(selectionExtent.width() + 2); + selectionExtent.setHeight(selectionExtent.height() + 2); + + TQRegion uniformRegion = TQRegion(imageRect); + uniformRegion -= TQRegion(selectionExtent); + + if (!uniformRegion.isEmpty()) { + paintUniformSelectionRegion(img, imageRect, uniformRegion); + } + + TQRect nonuniformRect = imageRect & selectionExtent; + + if (!nonuniformRect.isEmpty()) { + + const TQ_INT32 imageRectOffsetX = nonuniformRect.x() - imageRectX; + const TQ_INT32 imageRectOffsetY = nonuniformRect.y() - imageRectY; + + imageRectX = nonuniformRect.x(); + imageRectY = nonuniformRect.y(); + imageRectWidth = nonuniformRect.width(); + imageRectHeight = nonuniformRect.height(); + + const TQ_INT32 NUM_SELECTION_ROWS = 3; + + TQ_UINT8 *selectionRow[NUM_SELECTION_ROWS]; + + TQ_INT32 aboveRowIndex = 0; + TQ_INT32 centreRowIndex = 1; + TQ_INT32 belowRowIndex = 2; + + selectionRow[aboveRowIndex] = new TQ_UINT8[imageRectWidth + 2]; + selectionRow[centreRowIndex] = new TQ_UINT8[imageRectWidth + 2]; + selectionRow[belowRowIndex] = new TQ_UINT8[imageRectWidth + 2]; + + readBytes(selectionRow[centreRowIndex], imageRectX - 1, imageRectY - 1, imageRectWidth + 2, 1); + readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY, imageRectWidth + 2, 1); + + for (TQ_INT32 y = 0; y < imageRectHeight; ++y) { + + TQ_INT32 oldAboveRowIndex = aboveRowIndex; + aboveRowIndex = centreRowIndex; + centreRowIndex = belowRowIndex; + belowRowIndex = oldAboveRowIndex; + + readBytes(selectionRow[belowRowIndex], imageRectX - 1, imageRectY + y + 1, imageRectWidth + 2, 1); + + const TQ_UINT8 *aboveRow = selectionRow[aboveRowIndex] + 1; + const TQ_UINT8 *centreRow = selectionRow[centreRowIndex] + 1; + const TQ_UINT8 *belowRow = selectionRow[belowRowIndex] + 1; + + TQRgb *imagePixel = reinterpret_cast(img.scanLine(imageRectOffsetY + y)); + imagePixel += imageRectOffsetX; + + for (TQ_INT32 x = 0; x < imageRectWidth; ++x) { + + TQ_UINT8 centre = *centreRow; + + if (centre != MAX_SELECTED) { + + // this is where we come if the pixels should be blue or bluish + + TQRgb srcPixel = *imagePixel; + TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9; + TQ_UINT8 srcAlpha = tqAlpha(srcPixel); + + // Colour influence is proportional to alphaPixel. + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + + TQRgb dstPixel; + + if (centre == MIN_SELECTED) { + //this is where we come if the pixels should be blue (or red outline) + + TQ_UINT8 left = *(centreRow - 1); + TQ_UINT8 right = *(centreRow + 1); + TQ_UINT8 above = *aboveRow; + TQ_UINT8 below = *belowRow; + + // Stop unselected transparent areas from appearing the same + // as selected transparent areas. + TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192); + + // now for a simple outline based on 4-connectivity + if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) { + dstPixel = tqRgba(255, 0, 0, dstAlpha); + } else { + dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + } + } else { + dstPixel = tqRgba(UINT8_BLEND(tqRed(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(tqGreen(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(tqBlue(srcPixel), srcGrey + 165, centre), + srcAlpha); + } + + *imagePixel = dstPixel; + } + + aboveRow++; + centreRow++; + belowRow++; + imagePixel++; + } + } + + delete [] selectionRow[aboveRowIndex]; + delete [] selectionRow[centreRowIndex]; + delete [] selectionRow[belowRowIndex]; + } +} + +void KisSelection::paintSelection(TQImage img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize) +{ + if (img.isNull() || scaledImageRect.isEmpty() || scaledImageSize.isEmpty() || imageSize.isEmpty()) { + return; + } + + Q_ASSERT(img.size() == scaledImageRect.size()); + + if (img.size() != scaledImageRect.size()) { + return; + } + + TQ_INT32 imageWidth = imageSize.width(); + TQ_INT32 imageHeight = imageSize.height(); + + TQRect selectionExtent = extent(); + + selectionExtent.setLeft(selectionExtent.left() - 1); + selectionExtent.setTop(selectionExtent.top() - 1); + selectionExtent.setWidth(selectionExtent.width() + 2); + selectionExtent.setHeight(selectionExtent.height() + 2); + + double xScale = static_cast(scaledImageSize.width()) / imageWidth; + double yScale = static_cast(scaledImageSize.height()) / imageHeight; + + TQRect scaledSelectionExtent; + + scaledSelectionExtent.setLeft(static_cast(selectionExtent.left() * xScale)); + scaledSelectionExtent.setRight(static_cast(ceil((selectionExtent.right() + 1) * xScale)) - 1); + scaledSelectionExtent.setTop(static_cast(selectionExtent.top() * yScale)); + scaledSelectionExtent.setBottom(static_cast(ceil((selectionExtent.bottom() + 1) * yScale)) - 1); + + TQRegion uniformRegion = TQRegion(scaledImageRect); + uniformRegion -= TQRegion(scaledSelectionExtent); + + if (!uniformRegion.isEmpty()) { + paintUniformSelectionRegion(img, scaledImageRect, uniformRegion); + } + + TQRect nonuniformRect = scaledImageRect & scaledSelectionExtent; + + if (!nonuniformRect.isEmpty()) { + + const TQ_INT32 scaledImageRectXOffset = nonuniformRect.x() - scaledImageRect.x(); + const TQ_INT32 scaledImageRectYOffset = nonuniformRect.y() - scaledImageRect.y(); + + const TQ_INT32 scaledImageRectX = nonuniformRect.x(); + const TQ_INT32 scaledImageRectY = nonuniformRect.y(); + const TQ_INT32 scaledImageRectWidth = nonuniformRect.width(); + const TQ_INT32 scaledImageRectHeight = nonuniformRect.height(); + + const TQ_INT32 imageRowLeft = static_cast(scaledImageRectX / xScale); + const TQ_INT32 imageRowRight = static_cast((ceil((scaledImageRectX + scaledImageRectWidth - 1 + 1) / xScale)) - 1); + + const TQ_INT32 imageRowWidth = imageRowRight - imageRowLeft + 1; + const TQ_INT32 imageRowStride = imageRowWidth + 2; + + const TQ_INT32 NUM_SELECTION_ROWS = 3; + + TQ_INT32 aboveRowIndex = 0; + TQ_INT32 centreRowIndex = 1; + TQ_INT32 belowRowIndex = 2; + + TQ_INT32 aboveRowSrcY = -3; + TQ_INT32 centreRowSrcY = -3; + TQ_INT32 belowRowSrcY = -3; + + TQ_UINT8 *selectionRows = new TQ_UINT8[imageRowStride * NUM_SELECTION_ROWS]; + TQ_UINT8 *selectionRow[NUM_SELECTION_ROWS]; + + selectionRow[0] = selectionRows + 1; + selectionRow[1] = selectionRow[0] + imageRowStride; + selectionRow[2] = selectionRow[0] + (2 * imageRowStride); + + for (TQ_INT32 y = 0; y < scaledImageRectHeight; ++y) { + + TQ_INT32 scaledY = scaledImageRectY + y; + TQ_INT32 srcY = (scaledY * imageHeight) / scaledImageSize.height(); + + TQ_UINT8 *aboveRow; + TQ_UINT8 *centreRow; + TQ_UINT8 *belowRow; + + if (srcY - 1 == aboveRowSrcY) { + aboveRow = selectionRow[aboveRowIndex]; + centreRow = selectionRow[centreRowIndex]; + belowRow = selectionRow[belowRowIndex]; + } else if (srcY - 1 == centreRowSrcY) { + + TQ_INT32 oldAboveRowIndex = aboveRowIndex; + + aboveRowIndex = centreRowIndex; + centreRowIndex = belowRowIndex; + belowRowIndex = oldAboveRowIndex; + + aboveRow = selectionRow[aboveRowIndex]; + centreRow = selectionRow[centreRowIndex]; + belowRow = selectionRow[belowRowIndex]; + + readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1); + + } else if (srcY - 1 == belowRowSrcY) { + + TQ_INT32 oldAboveRowIndex = aboveRowIndex; + TQ_INT32 oldCentreRowIndex = centreRowIndex; + + aboveRowIndex = belowRowIndex; + centreRowIndex = oldAboveRowIndex; + belowRowIndex = oldCentreRowIndex; + + aboveRow = selectionRow[aboveRowIndex]; + centreRow = selectionRow[centreRowIndex]; + belowRow = selectionRow[belowRowIndex]; + + if (belowRowIndex == centreRowIndex + 1) { + readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 2); + } else { + readBytes(centreRow - 1, imageRowLeft - 1, srcY, imageRowStride, 1); + readBytes(belowRow - 1, imageRowLeft - 1, srcY + 1, imageRowStride, 1); + } + + } else { + + aboveRowIndex = 0; + centreRowIndex = 1; + belowRowIndex = 2; + + aboveRow = selectionRow[aboveRowIndex]; + centreRow = selectionRow[centreRowIndex]; + belowRow = selectionRow[belowRowIndex]; + + readBytes(selectionRows, imageRowLeft - 1, srcY - 1, imageRowStride, NUM_SELECTION_ROWS); + } + + aboveRowSrcY = srcY - 1; + centreRowSrcY = aboveRowSrcY + 1; + belowRowSrcY = centreRowSrcY + 1; + + TQRgb *imagePixel = reinterpret_cast(img.scanLine(scaledImageRectYOffset + y)); + imagePixel += scaledImageRectXOffset; + + for (TQ_INT32 x = 0; x < scaledImageRectWidth; ++x) { + + TQ_INT32 scaledX = scaledImageRectX + x; + TQ_INT32 srcX = (scaledX * imageWidth) / scaledImageSize.width(); + + TQ_UINT8 centre = *(centreRow + srcX - imageRowLeft); + + if (centre != MAX_SELECTED) { + + // this is where we come if the pixels should be blue or bluish + + TQRgb srcPixel = *imagePixel; + TQ_UINT8 srcGrey = (tqRed(srcPixel) + tqGreen(srcPixel) + tqBlue(srcPixel)) / 9; + TQ_UINT8 srcAlpha = tqAlpha(srcPixel); + + // Colour influence is proportional to alphaPixel. + srcGrey = UINT8_MULT(srcGrey, srcAlpha); + + TQRgb dstPixel; + + if (centre == MIN_SELECTED) { + //this is where we come if the pixels should be blue (or red outline) + + TQ_UINT8 left = *(centreRow + (srcX - imageRowLeft) - 1); + TQ_UINT8 right = *(centreRow + (srcX - imageRowLeft) + 1); + TQ_UINT8 above = *(aboveRow + (srcX - imageRowLeft)); + TQ_UINT8 below = *(belowRow + (srcX - imageRowLeft)); + + // Stop unselected transparent areas from appearing the same + // as selected transparent areas. + TQ_UINT8 dstAlpha = TQMAX(srcAlpha, 192); + + // now for a simple outline based on 4-connectivity + if (left != MIN_SELECTED || right != MIN_SELECTED || above != MIN_SELECTED || below != MIN_SELECTED) { + dstPixel = tqRgba(255, 0, 0, dstAlpha); + } else { + dstPixel = tqRgba(128 + srcGrey, 128 + srcGrey, 165 + srcGrey, dstAlpha); + } + } else { + dstPixel = tqRgba(UINT8_BLEND(tqRed(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(tqGreen(srcPixel), srcGrey + 128, centre), + UINT8_BLEND(tqBlue(srcPixel), srcGrey + 165, centre), + srcAlpha); + } + + *imagePixel = dstPixel; + } + + imagePixel++; + } + } + + delete [] selectionRows; + } +} + +void KisSelection::setDirty(const TQRect& rc) +{ + if (m_dirty) + super::setDirty(rc); +} + +void KisSelection::setDirty() +{ + if (m_dirty) + super::setDirty(); +} diff --git a/chalk/core/kis_selection.h b/chalk/core/kis_selection.h new file mode 100644 index 00000000..f41915da --- /dev/null +++ b/chalk/core/kis_selection.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_SELECTION_H_ +#define KIS_SELECTION_H_ + +#include + +#include "kis_types.h" +#include "kis_paint_device.h" + +#include + + +enum enumSelectionMode { + SELECTION_ADD, + SELECTION_SUBTRACT +}; + +/** + * KisSelection contains a byte-map representation of a layer, where + * the value of a byte signifies whether a corresponding pixel is selected, or not. + * + * NOTE: If you need to manually call emitSelectionChanged on the owner paint device + * of a selection. KisSelection does not emit any signals by itself because + * often you want to combine several actions in to perfom one operation and you + * do not want recomposition to happen all the time. + */ +class KRITACORE_EXPORT KisSelection : public KisPaintDevice { + + typedef KisPaintDevice super; + +public: + /** + * Create a new KisSelection + * @param dev the tqparent paint device. The selection will never be bigger than the tqparent + * paint device. + */ + KisSelection(KisPaintDeviceSP dev); + + /** + * Create a new KisSelection. This selection will not have a tqparent paint device. + */ + KisSelection(); + + /** + * Copy the selection + */ + KisSelection(const KisSelection& rhs); + + virtual ~KisSelection(); + + // Returns selectedness, or 0 if invalid coordinates + TQ_UINT8 selected(TQ_INT32 x, TQ_INT32 y); + + void setSelected(TQ_INT32 x, TQ_INT32 y, TQ_UINT8 s); + + TQImage tqmaskImage(); + + void select(TQRect r); + + void invert(); + + void clear(TQRect r); + + void clear(); + + /// Tests if the the rect is totally outside the selection + bool isTotallyUnselected(TQRect r); + + /** + * Tests if the the rect is totally outside the selection, but uses selectedRect + * instead of selectedRect, and this is faster (but might deliver false positives!) + * + * XXX: This comment makes no sense anymore! (BSAR) + */ + bool isProbablyTotallyUnselected(TQRect r); + + /** + * Rough, but fastish way of determining the area + * of the tiles used by the selection. + */ + TQRect selectedRect() const; + + /** + * Slow, but exact way of determining the rectangle + * that encloses the selection + */ + TQRect selectedExactRect() const; + + void paintSelection(TQImage img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + void paintSelection(TQImage img, const TQRect& scaledImageRect, const TQSize& scaledImageSize, const TQSize& imageSize); + + void startCachingExactRect(); + void stopCachingExactRect(); + + // if the tqparent layer is interested in keeping up to date with the dirtyness + // of this layer, set to true + void setInterestedInDirtyness(bool b) { m_dirty = b; } + bool interestedInDirtyness() const { return m_dirty; } + + virtual void setDirty(const TQRect & rc); + virtual void setDirty(); + inline KisPaintDeviceSP tqparentPaintDevice() { return m_parentPaintDevice; } +private: + void paintUniformSelectionRegion(TQImage img, const TQRect& imageRect, const TQRegion& uniformRegion); + +private: + + // We don't want these methods to be used on selections: + void extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const + { + KisPaintDevice::extent(x,y,w,h); + } + + TQRect extent() const { return KisPaintDevice::extent(); } + + void exactBounds(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const + { + return KisPaintDevice::exactBounds(x,y,w,h); + } + + TQRect exactBounds() const + { + return KisPaintDevice::exactBounds(); + } + + TQRect exactBoundsOldMethod() const + { + return KisPaintDevice::exactBoundsOldMethod(); + } + + TQRect exactBoundsImprovedOldMethod() const + { + return KisPaintDevice::exactBoundsImprovedOldMethod(); + } + + +private: + KisPaintDeviceSP m_parentPaintDevice; + bool m_doCacheExactRect; + TQRect m_cachedExactRect; + bool m_dirty; +}; + +#endif // KIS_SELECTION_H_ diff --git a/chalk/core/kis_shear_visitor.h b/chalk/core/kis_shear_visitor.h new file mode 100644 index 00000000..9a48181e --- /dev/null +++ b/chalk/core/kis_shear_visitor.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SHEAR_VISITOR_H_ +#define KIS_SHEAR_VISITOR_H_ + +#include "kis_types.h" +#include "kis_progress_subject.h" +#include "kis_layer_visitor.h" +#include "kis_transform_worker.h" +#include "kis_filter_strategy.h" +#include "kis_undo_adapter.h" +#include "kis_transaction.h" +#include "kis_rotate_visitor.h" + +class KisShearVisitor : public KisLayerVisitor { +public: + KisShearVisitor(double xshear, double yshear, KisProgressDisplayInterface *progress) + : m_xshear(xshear), m_yshear(yshear), m_progress(progress), m_strategy(0), m_undo(0) {}; + + void setStrategy(KisFilterStrategy* strategy) { m_strategy = strategy; } + void setUndoAdapter(KisUndoAdapter* undo) { m_undo = undo; } +public: + virtual bool visit(KisPaintLayer* layer) { + KisPaintDeviceSP dev = layer->paintDevice(); + if(!dev) + return true; + + KisFilterStrategy* strategy = 0; + if (m_strategy) + strategy = m_strategy; + else + strategy = new KisMitchellFilterStrategy; + + KisTransaction* t = 0; + + if (m_undo && m_undo->undo()) + t = new KisTransaction("", dev.data()); + + //Doesn't do anything, internally transforms x and y shear to 0 each :-/// + //KisTransformWorker w(dev, 1.0, 1.0, m_xshear, m_yshear, 0, 0, 0, m_progress, strategy); + //w.run(); + + KisRotateVisitor v; + v.visitKisPaintDevice(dev); + v.shear(m_xshear, m_yshear, m_progress); + + if (m_undo && m_undo->undo()) + m_undo->addCommand(t); + + if (!m_strategy) + delete strategy; + + layer->setDirty(); + + return true; + } + + virtual bool visit(KisGroupLayer* layer) { + KisLayerSP child = layer->firstChild(); + + while(child) + { + child->accept(*this); + child = child->nextSibling(); + } + return true; + } + + virtual bool visit(KisPartLayer*) { return true; } + virtual bool visit(KisAdjustmentLayer *) { return true; } +private: + double m_xshear; + double m_yshear; + KisProgressDisplayInterface* m_progress; + KisFilterStrategy* m_strategy; + KisUndoAdapter* m_undo; +}; + +#endif // KIS_SHEAR_VISITOR_H_ diff --git a/chalk/core/kis_strategy_move.cc b/chalk/core/kis_strategy_move.cc new file mode 100644 index 00000000..7391777c --- /dev/null +++ b/chalk/core/kis_strategy_move.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_strategy_move.h" +#include "kis_undo_adapter.h" + +KisStrategyMove::KisStrategyMove() +{ + reset(0); +} + +KisStrategyMove::KisStrategyMove(KisCanvasSubject *subject) +{ + reset(subject); +} + +KisStrategyMove::~KisStrategyMove() +{ +} + +void KisStrategyMove::reset(KisCanvasSubject *subject) +{ + m_subject = subject; + m_dragging = false; + + if (m_subject) { + m_controller = subject->canvasController(); + } else { + m_controller = 0; + } +} + +void KisStrategyMove::startDrag(const TQPoint& pos) +{ + // pos is the user chosen handle point + + if (m_subject) { + KisImageSP img; + KisLayerSP dev; + + if (!(img = m_subject->currentImg())) + return; + + dev = img->activeLayer(); + + if (!dev || !dev->visible()) + return; + + m_dragging = true; + m_dragStart.setX(pos.x()); + m_dragStart.setY(pos.y()); + m_layerStart.setX(dev->x()); + m_layerStart.setY(dev->y()); + m_layerPosition = m_layerStart; + } +} + +void KisStrategyMove::drag(const TQPoint& original) +{ + // original is the position of the user chosen handle point + + if (m_subject && m_dragging) { + KisImageSP img = m_subject->currentImg(); + KisLayerSP dev; + + if (img && (dev = img->activeLayer())) { + TQPoint pos = original; + TQRect rc; + + pos -= m_dragStart; // convert to delta + rc = dev->extent(); + dev->setX(dev->x() + pos.x()); + dev->setY(dev->y() + pos.y()); + rc = rc.unite(dev->extent()); + + m_layerPosition = TQPoint(dev->x(), dev->y()); + m_dragStart = original; + + dev->setDirty(rc); + } + } +} + +void KisStrategyMove::endDrag(const TQPoint& pos, bool undo) +{ + if (m_subject && m_dragging) { + KisImageSP img = m_subject->currentImg(); + KisLayerSP dev; + + if (img && (dev = img->activeLayer())) { + drag(pos); + m_dragging = false; + + if (undo && img->undo()) { + KCommand *cmd = dev->moveCommand(m_layerStart, m_layerPosition); + Q_CHECK_PTR(cmd); + + KisUndoAdapter *adapter = img->undoAdapter(); + if (adapter) { + adapter->addCommand(cmd); + } else { + delete cmd; + } + } + img->setModified(); + } + } +} + +void KisStrategyMove::simpleMove(const TQPoint& pt1, const TQPoint& pt2) +{ + startDrag(pt1); + endDrag(pt2); +} + +void KisStrategyMove::simpleMove(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2) +{ + startDrag(TQPoint(x1, y1)); + endDrag(TQPoint(x2, y2)); +} + diff --git a/chalk/core/kis_strategy_move.h b/chalk/core/kis_strategy_move.h new file mode 100644 index 00000000..c3535be9 --- /dev/null +++ b/chalk/core/kis_strategy_move.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_STRATEGY_MOVE_H_ +#define KIS_STRATEGY_MOVE_H_ + +#include +#include + +#include + +class KisCanvasController; +class KisCanvasSubject; + +class KRITAUI_EXPORT KisStrategyMove { +public: + KisStrategyMove(); + explicit KisStrategyMove(KisCanvasSubject *subject); + virtual ~KisStrategyMove(); + +public: + void reset(KisCanvasSubject *subject); + void startDrag(const TQPoint& pos); + void drag(const TQPoint& pos); + void endDrag(const TQPoint& pos, bool undo = true); + void simpleMove(const TQPoint& pt1, const TQPoint& pt2); + void simpleMove(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2); + +private: + KisStrategyMove(const KisStrategyMove&); + KisStrategyMove& operator=(const KisStrategyMove&); + +private: + KisCanvasController *m_controller; + KisCanvasSubject *m_subject; + TQRect m_deviceBounds; + TQPoint m_dragStart; + TQPoint m_layerStart; + TQPoint m_layerPosition; + bool m_dragging; +}; + +#endif // KIS_STRATEGY_MOVE_H_ + diff --git a/chalk/core/kis_substrate.h b/chalk/core/kis_substrate.h new file mode 100644 index 00000000..274f2680 --- /dev/null +++ b/chalk/core/kis_substrate.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_SUBSTRATE_H +#define KIS_SUBSTRATE_H + +#include +#include + +class KisImage; + +/// All values are normalized to a range between 0 and 1. +/// XXX: Do we need more? +struct KisSubstratePixel { + float height; // absolute height of the current position + float smoothness; // determines how easily the painting tool "slips" over the surface + float absorbency; // determines how much wetness the substrate can absorb. XXX: How about speed of absorbing? + float density; // XXX? + TQ_UINT8 r; //.Red component of reflectivity + TQ_UINT8 g; // Green component of reflectivity + TQ_UINT8 b; // Blue component of reflectivity + TQ_UINT8 alpha; // For composition with the background +}; + +/** + * This abstract class defines the properties of a substrate -- that is, the simulation + * of the paper or canvas for natural media. + * + * Subclass this interface to define a specific type of substrate: repeating, + * or full-size, with specific and cool ways of generating the surface, or + * maybe based on scans of real substrates. + */ +class KisSubstrate : public KShared { + +public: + + KisSubstrate(KisImage * /*img*/) : KShared() {}; + virtual ~KisSubstrate() {}; + + + /** + * Copy the pixel values in the specified rect into an array of Substrate. + * Make sure the array is big enough! + */ + virtual void getPixels(KisSubstratePixel * substrate, const TQRect & rc) const = 0; + + /** + * Copy the specified rect of substrate pixels onto the substrate. Make sure + * the array is big enough. + */ + virtual void writePixels(const KisSubstratePixel * substrate, const TQRect & rc) = 0; + /** + * Read the value at the specified position into the given substrate pixel. + */ + virtual void getPixel(KisSubstratePixel * ksp, int x, int y) const = 0; + + /** + * Copy the value of the given substrate pixel to the specified location. + */ + virtual void writePixel(const KisSubstratePixel & ksp, int x, int y) = 0; + +}; + +#endif diff --git a/chalk/core/kis_thread.h b/chalk/core/kis_thread.h new file mode 100644 index 00000000..61feda24 --- /dev/null +++ b/chalk/core/kis_thread.h @@ -0,0 +1,57 @@ +/* + * copyright (c) 2005 Boudewijn Rempt + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ + +#ifndef KIS_THREAD_ +#define KIS_THREAD_ + +#include +#include + +/** + * A KisThread is a TQThread that can be set in the canceled state. + * Lengthy operations initiated in run() should regularly read the + * canceled state and stop when it's set to true + */ +class KisThread : public TQThread { + +public: + + /** + * Create a new KisThread with the canceled state set to false + */ + KisThread() : TQThread(), m_canceled(false) {}; + + /** + * Request the thread to cancel at the first opportunity. Note + * that the owner of the thread is responsible for restoring the + * previous state of paint devices etc, the thread itself just stops + * as soon as possible. + */ + virtual void cancel() { m_canceled = true; } + virtual bool isCanceled() { return m_canceled; } + + void runDirectly() { run(); } + +protected: + + bool m_canceled; + +}; + + +#endif diff --git a/chalk/core/kis_thread_pool.cc b/chalk/core/kis_thread_pool.cc new file mode 100644 index 00000000..e617c8cb --- /dev/null +++ b/chalk/core/kis_thread_pool.cc @@ -0,0 +1,192 @@ +/* + * copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_thread_pool.h" +#include +#include +#include + +KisThreadPool * KisThreadPool::m_singleton = 0; + +KisThreadPool::KisThreadPool() +{ + Q_ASSERT(KisThreadPool::m_singleton == 0); + + KisThreadPool::m_singleton = this; + + KConfig * cfg = KGlobal::config(); + cfg->setGroup(""); + m_maxThreads = cfg->readNumEntry("maxthreads", 10); + m_numberOfRunningThreads = 0; + m_numberOfQueuedThreads = 0; + m_wait = 200; + + start(); +} + + +KisThreadPool::~KisThreadPool() +{ + m_poolMutex.lock(); + + m_canceled = true; + + m_runningThreads.setAutoDelete(true); + m_threads.setAutoDelete(true); + m_oldThreads.setAutoDelete(true); + + KisThread * t; + + for ( t = m_threads.first(); t; t = m_threads.next()) { + if (t) { + t->cancel(); + t->wait(); + m_threads.remove(t); + } + } + + for ( t = m_runningThreads.first(); t; t = m_runningThreads.next()) { + if (t) { + t->cancel(); + t->wait(); + m_runningThreads.remove(t); + } + } + + for ( t = m_oldThreads.first(); t; t = m_oldThreads.next()) { + if (t) { + t->cancel(); + t->wait(); + m_runningThreads.remove(t); + } + } + KisThreadPool::m_singleton = 0; + m_poolMutex.unlock(); + +} + + +KisThreadPool * KisThreadPool::instance() +{ + if(KisThreadPool::m_singleton == 0) + { + KisThreadPool::m_singleton = new KisThreadPool(); + } + else { + + if (KisThreadPool::m_singleton->finished()) { + delete KisThreadPool::m_singleton; + KisThreadPool::m_singleton = 0; + KisThreadPool::m_singleton = new KisThreadPool(); + } + } + + return KisThreadPool::m_singleton; +} + +void KisThreadPool::enqueue(KisThread * thread) +{ + m_poolMutex.lock(); + m_threads.append(thread); + m_numberOfQueuedThreads++; + m_poolMutex.unlock(); + m_wait = 200; +} + + +void KisThreadPool::dequeue(KisThread * thread) +{ + KisThread * t = 0; + + m_poolMutex.lock(); + + int i = m_threads.tqfindRef(thread); + if (i >= 0) { + t = m_threads.take(i); + m_numberOfQueuedThreads--; + } else { + i = m_runningThreads.tqfindRef(thread); + if (i >= 0) { + t = m_runningThreads.take(i); + m_numberOfRunningThreads--; + } + else { + i = m_oldThreads.tqfindRef(thread); + if (i >= 0) { + t = m_oldThreads.take(i); + } + } + } + + m_poolMutex.unlock(); + + if (t) { + t->cancel(); + t->wait(); + delete t; + } + +} + +void KisThreadPool::run() +{ + int sleeps = 10; + + while(!m_canceled) { + if (m_numberOfQueuedThreads > 0 && m_numberOfRunningThreads < m_maxThreads) { + KisThread * thread = 0; + m_poolMutex.lock(); + if (m_threads.count() > 0) { + thread = m_threads.take(); + m_numberOfQueuedThreads--; + } + if (thread) { + thread->start(); + m_runningThreads.append(thread); + m_numberOfRunningThreads++; + } + m_poolMutex.unlock(); + } + else { + msleep(m_wait); + m_poolMutex.lock(); + for ( KisThread * t = m_runningThreads.first(); t; t = m_runningThreads.next()) { + if (t) { + if (t->finished()) { + m_runningThreads.remove(t); + m_numberOfRunningThreads--; + m_oldThreads.append(t); + } + } + } + m_poolMutex.unlock(); + m_poolMutex.lock(); + if (m_numberOfQueuedThreads == 0 && m_numberOfRunningThreads == 0) { + sleeps--; + if (sleeps == 0) { + m_poolMutex.unlock(); + return; + } + m_poolMutex.unlock(); + + } + m_poolMutex.unlock(); + + } + } +} diff --git a/chalk/core/kis_thread_pool.h b/chalk/core/kis_thread_pool.h new file mode 100644 index 00000000..904606bf --- /dev/null +++ b/chalk/core/kis_thread_pool.h @@ -0,0 +1,70 @@ +/* + * copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can distribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_THREAD_POOL_ +#define KIS_THREAD_POOL_ + +#include +#include +#include + +#include "kis_thread.h" + +/** + * A thread pool starts executing threads some time after they are added, + * running a maximum number of threads at one time. + * + * The pool takes ownership of the threads and _deletes_ them once they + * have run. This means that you cannot add getters for important data to + * threads you feed the threadpool. Instead, post the data using a customevent. + */ +class KisThreadPool : public KisThread { + +public: + + virtual ~KisThreadPool(); + + static KisThreadPool * instance(); + + void enqueue(KisThread * thread); + void dequeue(KisThread * thread); + + void run(); + + + KisThreadPool(); + +private: + + KisThreadPool(const KisThreadPool&); + KisThreadPool operator=(const KisThreadPool&); + + TQMutex m_poolMutex; + int m_numberOfRunningThreads; + int m_numberOfQueuedThreads; + int m_maxThreads; + int m_wait; + TQPtrList m_threads; + TQPtrList m_runningThreads; + TQPtrList m_oldThreads; + + static KisThreadPool * m_singleton; +}; + + +#endif diff --git a/chalk/core/kis_transaction.cc b/chalk/core/kis_transaction.cc new file mode 100644 index 00000000..b755c597 --- /dev/null +++ b/chalk/core/kis_transaction.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_types.h" +#include "kis_global.h" +#include "kis_tile.h" +#include "kis_tileddatamanager.h" +#include "kis_image.h" +#include "kis_transaction.h" +#include "kis_memento.h" +#include "kis_paint_device.h" +#include "kis_layer.h" + +class KisTransactionPrivate { +public: + TQString m_name; + KisPaintDeviceSP m_device; + KisMementoSP m_memento; + +}; + +KisTransaction::KisTransaction(const TQString& name, KisPaintDeviceSP device) +{ + m_private = new KisTransactionPrivate; + + m_private->m_name = name; + m_private->m_device = device; + m_private->m_memento = device->getMemento(); +} + +KisTransaction::~KisTransaction() +{ + if (m_private->m_memento) { + // For debugging purposes + m_private->m_memento->setInvalid(); + } + delete m_private; +} + +void KisTransaction::execute() +{ + Q_ASSERT(m_private->m_memento != 0); + + m_private->m_device->rollforward(m_private->m_memento); + + TQRect rc; + TQ_INT32 x, y, width, height; + m_private->m_memento->extent(x,y,width,height); + rc.setRect(x + m_private->m_device->getX(), y + m_private->m_device->getY(), width, height); + + KisLayerSP l = m_private->m_device->tqparentLayer(); + if (l) l->setDirty(rc); +} + +void KisTransaction::unexecute() +{ + Q_ASSERT(m_private->m_memento != 0); + m_private->m_device->rollback(m_private->m_memento); + + TQRect rc; + TQ_INT32 x, y, width, height; + m_private->m_memento->extent(x,y,width,height); + rc.setRect(x + m_private->m_device->getX(), y + m_private->m_device->getY(), width, height); + + KisLayerSP l = m_private->m_device->tqparentLayer(); + if (l) l->setDirty(rc); + +} + +void KisTransaction::unexecuteNoUpdate() +{ + Q_ASSERT(m_private->m_memento != 0); + + m_private->m_device->rollback(m_private->m_memento); +} + +TQString KisTransaction::name() const +{ + return m_private->m_name; +} diff --git a/chalk/core/kis_transaction.h b/chalk/core/kis_transaction.h new file mode 100644 index 00000000..521b0204 --- /dev/null +++ b/chalk/core/kis_transaction.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TILE_COMMAND_H_ +#define KIS_TILE_COMMAND_H_ + +#include + +#include + +#include "kis_types.h" + +class TQRect; +class KisTransactionPrivate; + +class KisTransaction : public KCommand { +public: + KisTransaction(const TQString& name, KisPaintDeviceSP device); + virtual ~KisTransaction(); + +public: + virtual void execute(); + virtual void unexecute(); + virtual void unexecuteNoUpdate(); + virtual TQString name() const; +private: + KisTransactionPrivate * m_private; +}; + +#endif // KIS_TILE_COMMAND_H_ + diff --git a/chalk/core/kis_transform_visitor.h b/chalk/core/kis_transform_visitor.h new file mode 100644 index 00000000..9e6f51c0 --- /dev/null +++ b/chalk/core/kis_transform_visitor.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2006 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TRANSFORM_VISITOR_H_ +#define KIS_TRANSFORM_VISITOR_H_ + +#include "tqrect.h" + +#include "klocale.h" + +#include "kis_layer_visitor.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_transaction.h" +#include "kis_transform_worker.h" +#include + +class KisProgressDisplayInterface; +class KisFilterStrategy; + +class KisTransformVisitor : public KisLayerVisitor { + +public: + + KisTransformVisitor(KisImageSP img, double xscale, double yscale, + double /*xshear*/, double /*yshear*/, double angle, + TQ_INT32 tx, TQ_INT32 ty, KisProgressDisplayInterface *progress, KisFilterStrategy *filter) + : KisLayerVisitor() + , m_sx(xscale) + , m_sy(yscale) + , m_tx(tx) + , m_ty(ty) + , m_filter(filter) + , m_angle(angle) + , m_progress(progress) + , m_img(img) + { + } + + virtual ~KisTransformVisitor() + { + } + + /** + * Crops the specified layer and adds the undo information to the undo adapter of the + * layer's image. + */ + bool visit(KisPaintLayer *layer) + { + KisPaintDeviceSP dev = layer->paintDevice(); + + KisTransaction * t = 0; + if (m_img->undo()) { + t = new KisTransaction(i18n("Rotate Layer"), dev); + Q_CHECK_PTR(t); + } + + KisTransformWorker tw(dev, m_sx, m_sy, 0.0, 0.0, m_angle, m_tx, m_ty, m_progress, m_filter, true); + tw.run(); + + if (m_img->undo()) { + m_img->undoAdapter()->addCommand(t); + } + layer->setDirty(); + return true; + }; + + bool visit(KisGroupLayer *layer) + { + layer->resetProjection(); + + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + layer->setDirty(); + return true; + }; + + bool visit(KisPartLayer */*layer*/) + { + return true; + }; + + virtual bool visit(KisAdjustmentLayer* layer) + { + KisPaintDeviceSP dev = layer->selection().data(); + + KisTransaction * t = 0; + + if (m_img->undo()) { + t = new KisTransaction(i18n("Rotate Layer"), dev); + Q_CHECK_PTR(t); + } + + KisTransformWorker tw(dev, m_sx, m_sy, 0.0, 0.0, m_angle, m_tx, m_ty, m_progress, m_filter, true); + tw.run(); + + if (m_img->undo()) { + m_img->undoAdapter()->addCommand(t); + } + layer->setDirty(); + + layer->resetCache(); + return true; + } + + +private: + double m_sx, m_sy; + TQ_INT32 m_tx, m_ty; + KisFilterStrategy *m_filter; + double m_angle; + KisProgressDisplayInterface *m_progress; + KisImageSP m_img; +}; + + +#endif diff --git a/chalk/core/kis_transform_worker.cc b/chalk/core/kis_transform_worker.cc new file mode 100644 index 00000000..fbc952ea --- /dev/null +++ b/chalk/core/kis_transform_worker.cc @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2004 Michael Thaler filters + * Copyright (c) 2005 Casper Boemann + * Copyright (c) 2005 Boudewijn Rempt right angle rotators + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "kis_debug_areas.h" +#include "kis_paint_device.h" +#include "kis_selection.h" +#include "kis_transform_worker.h" +#include "kis_progress_display_interface.h" +#include "kis_iterators_pixel.h" +#include "kis_filter_strategy.h" +#include "kis_layer.h" +#include "kis_painter.h" + +KisTransformWorker::KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale, + double xshear, double yshear, double rotation, + TQ_INT32 xtranslate, TQ_INT32 ytranslate, + KisProgressDisplayInterface *progress, KisFilterStrategy *filter, bool fixBorderAlpha) +{ + m_dev= dev; + m_xscale = xscale; + m_yscale = yscale; + m_xshear = xshear; + m_yshear = yshear; + m_rotation = rotation, + m_xtranslate = xtranslate; + m_ytranslate = ytranslate; + m_progress = progress; + m_filter = filter; + m_fixBorderAlpha = fixBorderAlpha; +} + +void KisTransformWorker::rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst) +{ + KisSelectionSP dstSelection; + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r; + KisColorSpace *cs = src->colorSpace(); + + if(src->hasSelection()) + { + r = src->selection()->selectedExactRect(); + dstSelection = dst->selection(); + } + else + { + r = src->exactBounds(); + dstSelection = new KisSelection(dst); // essentially a dummy to be deleted + } + + KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), r.top(), r.width(), true); + KisHLineIterator vit = dst->createHLineIterator(r.x(), r.top(), r.width(), true); + KisHLineIterator dstSelIt = dstSelection->createHLineIterator(r.x(), r.top(), r.width(), true); + for (TQ_INT32 i = 0; i < r.height(); ++i) { + while (!hit.isDone()) { + if (hit.isSelected()) { + memcpy(vit.rawData(), hit.rawData(), pixelSize); + + // XXX: Should set alpha = alpha*(1-selectedness) + cs->setAlpha(hit.rawData(), 0, 1); + } + *(dstSelIt.rawData()) = hit.selectedness(); + ++hit; + ++vit; + ++dstSelIt; + } + hit.nextRow(); + vit.nextRow(); + dstSelIt.nextRow(); + + //progress info + m_progressStep += r.width(); + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + } +} + +void KisTransformWorker::rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst) +{ + KisSelectionSP dstSelection; + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r; + KisColorSpace *cs = src->colorSpace(); + + if(src->hasSelection()) + { + r = src->selection()->selectedExactRect(); + dstSelection = dst->selection(); + } + else + { + r = src->exactBounds(); + dstSelection = new KisSelection(dst); // essentially a dummy to be deleted + } + + for (TQ_INT32 y = r.bottom(); y >= r.top(); --y) { + KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true); + KisVLineIterator vit = dst->createVLineIterator(-y, r.x(), r.width(), true); + KisVLineIterator dstSelIt = dstSelection->createVLineIterator(-y, r.x(), r.width(), true); + + while (!hit.isDone()) { + if (hit.isSelected()) { + memcpy(vit.rawData(), hit.rawData(), pixelSize); + + // XXX: Should set alpha = alpha*(1-selectedness) + cs->setAlpha(hit.rawData(), 0, 1); + } + *(dstSelIt.rawData()) = hit.selectedness(); + ++hit; + ++vit; + ++dstSelIt; + } + + //progress info + m_progressStep += r.width(); + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + } +} + +void KisTransformWorker::rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst) +{ + kdDebug() << "rotateLeft90 called\n"; + KisSelectionSP dstSelection; + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r; + KisColorSpace *cs = src->colorSpace(); + + if(src->hasSelection()) + { + r = src->selection()->selectedExactRect(); + dstSelection = dst->selection(); + } + else + { + r = src->exactBounds(); + dstSelection = new KisSelection(dst); // essentially a dummy to be deleted + } + TQ_INT32 x = 0; + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + // Read the horizontal line from back to front, write onto the vertical column + KisHLineIteratorPixel hit = src->createHLineIterator(r.x(), y, r.width(), true); + KisVLineIterator vit = dst->createVLineIterator(y, -r.x() - r.width(), r.width(), true); + KisVLineIterator dstSelIt = dstSelection->createVLineIterator(y, -r.x() - r.width(), r.width(), true); + + hit += r.width() - 1; + while (!vit.isDone()) { + if (hit.isSelected()) { + memcpy(vit.rawData(), hit.rawData(), pixelSize); + + // XXX: Should set alpha = alpha*(1-selectedness) + cs->setAlpha(hit.rawData(), 0, 1); + } + *(dstSelIt.rawData()) = hit.selectedness(); + --hit; + ++vit; + ++dstSelIt; + } + ++x; + + //progress info + m_progressStep += r.width(); + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + } +} + +void KisTransformWorker::rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst) +{ + kdDebug() << "Rotating 180\n"; + KisSelectionSP dstSelection; + TQ_INT32 pixelSize = src->pixelSize(); + TQRect r; + KisColorSpace *cs = src->colorSpace(); + + if(src->hasSelection()) + { + r = src->selection()->selectedExactRect(); + dstSelection = dst->selection(); + } + else + { + r = src->exactBounds(); + dstSelection = new KisSelection(dst); // essentially a dummy to be deleted + } + + for (TQ_INT32 y = r.top(); y <= r.bottom(); ++y) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), y, r.width(), true); + KisHLineIterator dstIt = dst->createHLineIterator(-r.x() - r.width(), -y, r.width(), true); + KisHLineIterator dstSelIt = dstSelection->createHLineIterator(-r.x() - r.width(), -y, r.width(), true); + + srcIt += r.width() - 1; + while (!dstIt.isDone()) { + if (srcIt.isSelected()) { + memcpy(dstIt.rawData(), srcIt.rawData(), pixelSize); + + // XXX: Should set alpha = alpha*(1-selectedness) + cs->setAlpha(srcIt.rawData(), 0, 1); + } + *(dstSelIt.rawData()) = srcIt.selectedness(); + --srcIt; + ++dstIt; + ++dstSelIt; + } + + //progress info + m_progressStep += r.width(); + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + } +} + +template iter createIterator(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len); + +template <> KisHLineIteratorPixel createIterator +(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len) +{ + return dev->createHLineIterator(start, lineNum, len, true); +} + +template <> KisVLineIteratorPixel createIterator +(KisPaintDevice *dev, TQ_INT32 start, TQ_INT32 lineNum, TQ_INT32 len) +{ + return dev->createVLineIterator(lineNum, start, len, true); +} + +template void calcDimensions (KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines); + +template <> void calcDimensions +(KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines) +{ + if(dev->hasSelection()) + { + TQRect r = dev->selection()->selectedExactRect(); + r.rect(&srcStart, &firstLine, &srcLen, &numLines); + } + else + dev->exactBounds(srcStart, firstLine, srcLen, numLines); +} + +template <> void calcDimensions +(KisPaintDevice *dev, TQ_INT32 &srcStart, TQ_INT32 &srcLen, TQ_INT32 &firstLine, TQ_INT32 &numLines) +{ + if(dev->hasSelection()) + { + TQRect r = dev->selection()->selectedExactRect(); + r.rect(&firstLine, &srcStart, &numLines, &srcLen); + } + else + dev->exactBounds(firstLine, srcStart, numLines, srcLen); +} + +struct FilterValues +{ + TQ_UINT8 numWeights; + TQ_UINT8 *weight; + ~FilterValues() {delete [] weight;} +}; + +template void KisTransformWorker::transformPass(KisPaintDevice *src, KisPaintDevice *dst, double floatscale, double shear, TQ_INT32 dx, KisFilterStrategy *filterStrategy, bool fixBorderAlpha) +{ + TQ_INT32 lineNum,srcStart,firstLine,srcLen,numLines; + TQ_INT32 center, begin, end; /* filter calculation variables */ + TQ_UINT8 *data; + TQ_UINT8 pixelSize = src->pixelSize(); + KisSelectionSP dstSelection; + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 scale; + TQ_INT32 scaleDenom; + TQ_INT32 shearFracOffset; + + if(src->hasSelection()) + dstSelection = dst->selection(); + else + dstSelection = new KisSelection(dst); // essentially a dummy to be deleted + + calcDimensions (src, srcStart, srcLen, firstLine, numLines); + + scale = int(floatscale*srcLen); + scaleDenom = srcLen; + + if(scaleDenom == 0) + return; + + TQ_INT32 support = filterStrategy->intSupport(); + TQ_INT32 dstLen, dstStart; + TQ_INT32 invfscale = 256; + + // handle magnification/minification + if(abs(scale) < scaleDenom) + { + support *= scaleDenom; + support /= scale; + + invfscale *= scale; + invfscale /= scaleDenom; + if(scale < 0) // handle mirroring + { + support = -support; + invfscale = -invfscale; + } + } + + // handle mirroring + if(scale < 0) + dstLen = - scale; + else + dstLen = scale; + + // Calculate extra length (in each side) needed due to shear + TQ_INT32 extraLen = (support+256)>>8 + 1; + + TQ_UINT8 *tmpLine = new TQ_UINT8[(srcLen +2*extraLen)* pixelSize]; + Q_CHECK_PTR(tmpLine); + + TQ_UINT8 *tmpSel = new TQ_UINT8[srcLen+2*extraLen]; + Q_CHECK_PTR(tmpSel); + + //allocate space for colors + const TQ_UINT8 **colors = new const TQ_UINT8 *[2*support+1]; + + // Precalculate weights + FilterValues *filterWeights = new FilterValues[256]; + + for(int center = 0; center<256; ++center) + { + TQ_INT32 begin = (255 + center - support)>>8; // takes ceiling by adding 255 + TQ_INT32 span = ((center + support)>>8) - begin + 1; // takes floor to get end. Subtracts begin to get span + TQ_INT32 t = (((begin<<8) - center) * invfscale)>>8; + TQ_INT32 dt = invfscale; + filterWeights[center].weight = new TQ_UINT8[span]; +//printf("%d (",center); + TQ_UINT32 sum=0; + for(int num = 0; numintValueAt(t) * invfscale; + + tmpw >>=8; + filterWeights[center].weight[num] = tmpw; +//printf(" %d=%d,%d",t,filterWeights[center].weight[num],tmpw); + t += dt; + sum+=tmpw; + } +//printf(" )%d sum =%d",span,sum); + if(sum!=255) + { + double fixfactor= 255.0/sum; + sum=0; + for(int num = 0; num(src, srcStart - extraLen, lineNum, srcLen+2*extraLen); + TQ_INT32 i = 0; + while(!srcIt.isDone()) + { + TQ_UINT8 *data; + + data = srcIt.rawData(); + memcpy(&tmpLine[i*pixelSize], data, pixelSize); + + if(srcIt.isSelected()) + { + // XXX: Should set alpha = alpha*(1-selectedness) + cs->setAlpha(data, 0, 1); + tmpSel[i] = 255; + } + else { + tmpSel[i] = 0; + } + ++srcIt; + i++; + } + + T dstIt = createIterator (dst, dstStart, lineNum, dstLen); + T dstSelIt = createIterator (dstSelection, dstStart, lineNum, dstLen); + + i=0; + while(!dstIt.isDone()) + { + if(scaleDenom<2500) + center = ((i<<8) * scaleDenom) / scale; + else + { + if(scaleDenom<46000) // real limit is actually 46340 pixels + center = ((i * scaleDenom) / scale)<<8; + else + center = ((i<<8)/scale * scaleDenom) / scale; // XXX fails for sizes over 2^23 pixels src width + } + + if(scale < 0) + center += srcLen<<8; + + center += 128*scaleDenom/scale;//xxx doesn't work for scale<0; + center += (extraLen<<8) + shearFracOffset; + + // find contributing pixels + begin = (255 + center - support)>>8; // takes ceiling by adding 255 + end = (center + support)>>8; // takes floor + +////printf("sup=%d begin=%d end=%d",support,begin,end); + TQ_UINT8 selectedness = tmpSel[center>>8]; + if(selectedness) + { + int num=0; + for(int srcpos = begin; srcpos <= end; ++srcpos) + { + colors[num] = &tmpLine[srcpos*pixelSize]; + num++; + } + data = dstIt.rawData(); + cs->mixColors(colors, filterWeights[center&255].weight, filterWeights[center&255].numWeights, data); + + //possibly fix the alpha of the border if user wants it + if(fixBorderAlpha && (i==0 || i==dstLen-1)) + cs->setAlpha(data, cs->getAlpha(&tmpLine[(center>>8)*pixelSize]), 1); + + data = dstSelIt.rawData(); + *data = selectedness; + } + + ++dstSelIt; + ++dstIt; + i++; + } + + //progress info + m_progressStep += dstLen; + if(m_lastProgressReport != (m_progressStep * 100) / m_progressTotalSteps) + { + m_lastProgressReport = (m_progressStep * 100) / m_progressTotalSteps; + emit notifyProgress(m_lastProgressReport); + } + if (m_cancelRequested) { + break; + } + } + delete [] colors; + delete [] tmpLine; + delete [] tmpSel; + delete [] filterWeights; +} + +bool KisTransformWorker::run() +{ + //progress info + m_cancelRequested = false; + if(m_progress) + m_progress->setSubject(this, true, true); + m_progressTotalSteps = 0; + m_progressStep = 0; + TQRect r; + if(m_dev->hasSelection()) + r = m_dev->selection()->selectedExactRect(); + else + r = m_dev->exactBounds(); + + KisPaintDeviceSP tmpdev1 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev1");; + KisPaintDeviceSP tmpdev2 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");; + KisPaintDeviceSP tmpdev3 = new KisPaintDevice(m_dev->colorSpace(),"transform_tmpdev2");; + KisPaintDeviceSP srcdev = m_dev; + + double xscale = m_xscale; + double yscale = m_yscale; + double xshear = m_xshear; + double yshear = m_yshear; + double rotation = m_rotation; + TQ_INT32 xtranslate = m_xtranslate; + TQ_INT32 ytranslate = m_ytranslate; + + if(rotation < 0.0) + rotation = -fmod(-rotation, 2*M_PI) + 2*M_PI; + else + rotation = fmod(rotation, 2*M_PI); + int rotQuadrant = int(rotation /(M_PI/2) + 0.5) & 3; + + // Figure out how we will do the initial right angle rotations + double tmp; + switch(rotQuadrant) + { + default: // just to shut up the compiler + case 0: + m_progressTotalSteps = 0; + break; + case 1: + rotation -= M_PI/2; + tmp = xscale; + xscale=yscale; + yscale=tmp; + m_progressTotalSteps = r.width() * r.height(); + break; + case 2: + rotation -= M_PI; + m_progressTotalSteps = r.width() * r.height(); + break; + case 3: + rotation -= -M_PI/2 + 2*M_PI; + tmp = xscale; + xscale = yscale; + yscale = tmp; + m_progressTotalSteps = r.width() * r.height(); + break; + } + + // Calculate some auxillary values + yshear = sin(rotation); + xshear = -tan(rotation/2); + xtranslate -= int(xshear*ytranslate); + + // Calculate progress steps + m_progressTotalSteps += int(yscale * r.width() * r.height()); + m_progressTotalSteps += int(xscale * r.width() * (r.height() * yscale + r.width()*yshear)); + + m_lastProgressReport=0; + + // Now that we have everything in place it's time to do the actual right angle rotations + switch(rotQuadrant) + { + default: // just to shut up the compiler + case 0: + break; + case 1: + rotateRight90(srcdev, tmpdev1); + srcdev = tmpdev1; + break; + case 2: + rotate180(srcdev, tmpdev1); + srcdev = tmpdev1; + break; + case 3: + rotateLeft90(srcdev, tmpdev1); + srcdev = tmpdev1; + break; + } + + // Handle simple move case possibly with rotation of 90,180,270 + if(rotation == 0.0 && xscale == 1.0 && yscale == 1.0) + { + if(rotQuadrant==0) + { + // Though not nessesay in the general case because we make several passes + // We need to move (not just copy) the data to a temp dev so we can move them back + rotateNone(srcdev, tmpdev1); + srcdev = tmpdev1; + } + if(m_dev->hasSelection()) + m_dev->selection()->clear(); + + srcdev->move(srcdev->getX() + xtranslate, srcdev->getY() + ytranslate); + rotateNone(srcdev, m_dev); + + //progress info + emit notifyProgressDone(); + m_dev->emitSelectionChanged(); + + return m_cancelRequested; + } + + if ( m_cancelRequested) { + emit notifyProgressDone(); + return false; + } + + transformPass (srcdev, tmpdev2, xscale, yscale*xshear, 0, m_filter, m_fixBorderAlpha); + if(m_dev->hasSelection()) + m_dev->selection()->clear(); + + if ( m_cancelRequested) { + emit notifyProgressDone(); + return false; + } + + // Now do the second pass + transformPass (tmpdev2.data(), tmpdev3.data(), yscale, yshear, ytranslate, m_filter, m_fixBorderAlpha); + + if(m_dev->hasSelection()) + m_dev->selection()->clear(); + + if ( m_cancelRequested) { + emit notifyProgressDone(); + return false; + } + + if (xshear != 0.0) + transformPass (tmpdev3, m_dev, 1.0, xshear, xtranslate, m_filter, m_fixBorderAlpha); + else + { + // No need to filter again when we are only scaling + tmpdev3->move(tmpdev3->getX() + xtranslate, tmpdev3->getY()); + rotateNone(tmpdev3, m_dev); + } + + if (m_dev->tqparentLayer()) { + m_dev->tqparentLayer()->setDirty(); + } + //progress info + emit notifyProgressDone(); + m_dev->emitSelectionChanged(); + + return m_cancelRequested; +} diff --git a/chalk/core/kis_transform_worker.h b/chalk/core/kis_transform_worker.h new file mode 100644 index 00000000..a48b8589 --- /dev/null +++ b/chalk/core/kis_transform_worker.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2004 Michael Thaler + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TRANSFORM_WORKER_H_ +#define KIS_TRANSFORM_WORKER_H_ + +#include "kis_types.h" +#include "kis_progress_subject.h" + +class KisPaintDevice; +class KisProgressDisplayInterface; +class KisHLineIteratorPixel; +class KisVLineIteratorPixel; +class KisFilterStrategy; + +class KisTransformWorker : public KisProgressSubject { + typedef KisProgressSubject super; + +public: + KisTransformWorker(KisPaintDeviceSP dev, double xscale, double yscale, + double xshear, double yshear, double rotation, + TQ_INT32 xtranslate, TQ_INT32 ytranslate, + KisProgressDisplayInterface *progress, KisFilterStrategy *filter, bool fixBorderAlpha=false); + ~KisTransformWorker(); + +public: + bool isCanceled() { return m_cancelRequested;}; + + bool run(); + +private: + // XXX (BSAR): Why didn't we use the shared-pointer versions of the paint device classes? + template void transformPass(KisPaintDevice *src, KisPaintDevice *dst, double xscale, double shear, TQ_INT32 dx, KisFilterStrategy *filterStrategy, bool fixBorderAlpha); + +public: + void rotateNone(KisPaintDeviceSP src, KisPaintDeviceSP dst); + void rotateRight90(KisPaintDeviceSP src, KisPaintDeviceSP dst); + void rotateLeft90(KisPaintDeviceSP src, KisPaintDeviceSP dst); + void rotate180(KisPaintDeviceSP src, KisPaintDeviceSP dst); + +private: + KisPaintDeviceSP m_dev; + double m_xscale, m_yscale; + double m_xshear, m_yshear, m_rotation; + TQ_INT32 m_xtranslate, m_ytranslate; + KisProgressDisplayInterface *m_progress; + KisFilterStrategy *m_filter; + // Implement KisProgressSubject + bool m_cancelRequested; + virtual void cancel() { m_cancelRequested = true; } + TQ_INT32 m_progressTotalSteps; + TQ_INT32 m_progressStep; + TQ_INT32 m_progressScaler; + TQ_INT32 m_lastProgressReport; + bool m_fixBorderAlpha; +}; + + +inline KisTransformWorker::~KisTransformWorker() +{ +} + +#endif // KIS_TRANSFORM_VISITOR_H_ diff --git a/chalk/core/kis_types.h b/chalk/core/kis_types.h new file mode 100644 index 00000000..b789fdd4 --- /dev/null +++ b/chalk/core/kis_types.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KISTYPES_H_ +#define KISTYPES_H_ + +#include +#include +#include + +#include + +#include "kis_shared_ptr_vector.h" + +/** + * Define lots of shared pointer versions of Chalk classes. + * Shared pointer classes have the advantage of near automatic + * memory management (but take care of circular references) + * and the disadvantage that inheritiance relations are no longer + * recognizable + */ + +class KisImage; +typedef KSharedPtr KisImageSP; + +class KisPaintDevice; +typedef KSharedPtr KisPaintDeviceSP; +typedef KisSharedPtrVector vKisPaintDeviceSP; +typedef vKisPaintDeviceSP::iterator vKisPaintDeviceSP_it; +typedef vKisPaintDeviceSP::const_iterator vKisPaintDeviceSP_cit; + +class KisLayer; +typedef KSharedPtr KisLayerSP; +typedef KisSharedPtrVector vKisLayerSP; +typedef vKisLayerSP::iterator vKisLayerSP_it; +typedef vKisLayerSP::const_iterator vKisLayerSP_cit; + +class KisPartLayer; +typedef KSharedPtr KisPartLayerSP; + +class KisPaintLayer; +typedef KSharedPtr KisPaintLayerSP; + +class KisAdjustmentLayer; +typedef KSharedPtr KisAdjustmentLayerSP; + +class KisGroupLayer; +typedef KSharedPtr KisGroupLayerSP; + +class KisSelection; +typedef KSharedPtr KisSelectionSP; + +class KisBackground; +typedef KSharedPtr KisBackgroundSP; + +class KisSubstrate; +typedef KSharedPtr KisSubstrateSP; + +class KisHistogram; +typedef KSharedPtr KisHistogramSP; + +class KisPaintOpFactory; +typedef KSharedPtr KisPaintOpFactorySP; + +typedef TQValueVector vKisSegments; + +//class KisGuide; +//typedef KSharedPtr KisGuideSP; + +class KisAlphaMask; +typedef KSharedPtr KisAlphaMaskSP; + +class KisFilter; +typedef KSharedPtr KisFilterSP; + +#endif // KISTYPES_H_ diff --git a/chalk/core/kis_vec.cc b/chalk/core/kis_vec.cc new file mode 100644 index 00000000..fa54e1f9 --- /dev/null +++ b/chalk/core/kis_vec.cc @@ -0,0 +1,67 @@ +/* + * kis_vec.cc - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_vec.h" + +KisVector2D& KisVector2D::normalize() +{ + double length, ilength; + + length = m_x*m_x + m_y*m_y; + length = sqrt (length); + + if (length > epsilon) + { + ilength = 1/length; + m_x *= ilength; + m_y *= ilength; + } + return *this; +} + +KisVector3D& KisVector3D::normalize() +{ + double length, ilength; + + length = m_x*m_x + m_y*m_y + m_z*m_z; + length = sqrt (length); + + if (length > epsilon) + { + ilength = 1/length; + m_x *= ilength; + m_y *= ilength; + m_z *= ilength; + } + return *this; +} + +KisVector3D& KisVector3D::crossProduct(const KisVector3D &v) +{ + double x,y,z; + + x = m_y*v.m_z - m_z*v.m_y; + y = m_z*v.m_x - m_x*v.m_z; + z = m_x*v.m_y - m_y*v.m_x; + m_x=x; m_y=y; m_z=z; + + return *this; +} + diff --git a/chalk/core/kis_vec.h b/chalk/core/kis_vec.h new file mode 100644 index 00000000..08b9c541 --- /dev/null +++ b/chalk/core/kis_vec.h @@ -0,0 +1,405 @@ +/* + * kis_vec.h - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __kis_vec_h__ +#define __kis_vec_h__ + +#include +#include +#include +#include "kis_point.h" + +/* + * vector classes + */ +const double epsilon = DBL_EPSILON; + +class KisVector2D +{ +public: + KisVector2D(); + KisVector2D(double x, double y); + KisVector2D(const TQPoint& p); + KisVector2D(const KisPoint& p); + + bool isNull() const; + + double length() const; + + double x() const; + double y() const; + void setX(double); + void setY(double); + + KisVector2D &normalize(); + double dotProduct(const KisVector2D &) const; + + KisVector2D &operator+=(const KisVector2D &); + KisVector2D &operator-=(const KisVector2D &); + KisVector2D &operator*=(int); + KisVector2D &operator*=(long); + KisVector2D &operator*=(double); + KisVector2D &operator/=(int); + KisVector2D &operator/=(long); + KisVector2D &operator/=(double); + + friend inline bool operator==(const KisVector2D &, const KisVector2D &); + friend inline bool operator!=(const KisVector2D &, const KisVector2D &); + friend inline KisVector2D operator+(const KisVector2D &, const KisVector2D &); + friend inline KisVector2D operator-(const KisVector2D &, const KisVector2D &); + friend inline KisVector2D operator*(const KisVector2D &, int); + friend inline KisVector2D operator*(int, const KisVector2D &); + friend inline KisVector2D operator*(const KisVector2D &, long); + friend inline KisVector2D operator*(long, const KisVector2D &); + friend inline KisVector2D operator*(const KisVector2D &, double); + friend inline KisVector2D operator*(double, const KisVector2D &); + friend inline KisVector2D operator-(const KisVector2D &); + friend inline KisVector2D operator/(const KisVector2D &, int); + friend inline KisVector2D operator/(const KisVector2D &, long); + friend inline KisVector2D operator/(const KisVector2D &, double); + + KisPoint toKisPoint() const; + +private: + double m_x; + double m_y; +}; + +inline KisVector2D::KisVector2D() +{ m_x=0; m_y=0; } + +inline KisVector2D::KisVector2D(double x, double y) +{ m_x=x; m_y=y; } + +inline KisVector2D::KisVector2D(const TQPoint& p) +{ + m_x=p.x(); m_y=p.y(); +} + +inline KisVector2D::KisVector2D(const KisPoint& p) +{ + m_x=p.x(); m_y=p.y(); +} + +inline bool KisVector2D::isNull() const +{ return fabs(m_x) < epsilon && fabs(m_y) < epsilon; } + +inline double KisVector2D::length() const +{ return (sqrt(m_x*m_x + m_y*m_y)); } + +inline double KisVector2D::dotProduct(const KisVector2D &v) const +{ return m_x*v.m_x + m_y*v.m_y; } + +inline double KisVector2D::x() const +{ return m_x; } + +inline double KisVector2D::y() const +{ return m_y; } + +inline void KisVector2D::setX(double x) +{ m_x=x; } + +inline void KisVector2D::setY(double y) +{ m_y=y; } + +inline KisVector2D &KisVector2D::operator+=(const KisVector2D &v) +{ m_x+=v.m_x; m_y+=v.m_y; return *this; } + +inline KisVector2D &KisVector2D::operator-=(const KisVector2D &v) +{ m_x-=v.m_x; m_y-=v.m_y; return *this; } + +inline KisVector2D &KisVector2D::operator*=(int c) +{ m_x*=c; m_y*=c; return *this; } + +inline KisVector2D &KisVector2D::operator*=(long c) +{ m_x*=c; m_y*=c; return *this; } + +inline KisVector2D &KisVector2D::operator*=(double c) +{ m_x*=c; m_y*=c; return *this; } + +inline bool operator==(const KisVector2D &v1, const KisVector2D &v2) +{ return fabs(v1.m_x - v2.m_x) < epsilon && fabs(v1.m_y - v2.m_y) < epsilon; } + +inline bool operator!=(const KisVector2D &v1, const KisVector2D &v2) +{ return !(v1 == v2); } + +inline KisVector2D operator+(const KisVector2D &v1, const KisVector2D &v2) +{ return KisVector2D(v1.m_x+v2.m_x, v1.m_y+v2.m_y); } + +inline KisVector2D operator-(const KisVector2D &v1, const KisVector2D &v2) +{ return KisVector2D(v1.m_x-v2.m_x, v1.m_y-v2.m_y); } + +inline KisVector2D operator*(const KisVector2D &v, int c) +{ return KisVector2D((v.m_x*c), (v.m_y*c)); } + +inline KisVector2D operator*(int c, const KisVector2D &v) +{ return KisVector2D((v.m_x*c), (v.m_y*c)); } + +inline KisVector2D operator*(const KisVector2D &v, long c) +{ return KisVector2D((v.m_x*c), (v.m_y*c)); } + +inline KisVector2D operator*(long c, const KisVector2D &v) +{ return KisVector2D((v.m_x*c), (v.m_y*c)); } + +inline KisVector2D operator*(const KisVector2D &v, double c) +{ return KisVector2D(v.m_x*c, v.m_y*c); } + +inline KisVector2D operator*(double c, const KisVector2D &v) +{ return KisVector2D(v.m_x*c, v.m_y*c); } + +inline KisVector2D operator-(const KisVector2D &v) +{ return KisVector2D(-v.m_x, -v.m_y); } + +inline KisVector2D operator/(const KisVector2D &v, int c) +{ + if (c != 0) { + return KisVector2D(v.x() / c, v.y() / c); + } else { + return v; + } +} + +inline KisVector2D operator/(const KisVector2D &v, long c) +{ + if (c != 0) { + return KisVector2D(v.x() / c, v.y() / c); + } else { + return v; + } +} + +inline KisVector2D operator/(const KisVector2D &v, double c) +{ + if (c > DBL_EPSILON || c < -DBL_EPSILON) { + return KisVector2D(v.x() / c, v.y() / c); + } else { + return v; + } +} + +inline KisVector2D &KisVector2D::operator/=(int c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + } + return *this; +} + +inline KisVector2D &KisVector2D::operator/=(long c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + } + return *this; +} + +inline KisVector2D &KisVector2D::operator/=(double c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + } + return *this; +} + +inline KisPoint KisVector2D::toKisPoint() const +{ + return KisPoint(m_x, m_y); +} + +class KisVector3D +{ +public: + KisVector3D(); + KisVector3D(double x, double y, double z = 0); + KisVector3D(int x, int y, int z = 0); + KisVector3D(long x, long y, long z = 0); + + bool isNull() const; + + double length() const; + + double x() const; + double y() const; + double z() const; + void setX(double); + void setY(double); + void setZ(double); + + KisVector3D &normalize(); + KisVector3D &crossProduct(const KisVector3D &); + double dotProduct(const KisVector3D &) const; + + KisVector3D &operator+=(const KisVector3D &); + KisVector3D &operator-=(const KisVector3D &); + KisVector3D &operator*=(int); + KisVector3D &operator*=(long); + KisVector3D &operator*=(double); + KisVector3D &operator/=(int); + KisVector3D &operator/=(long); + KisVector3D &operator/=(double); + + friend inline bool operator==(const KisVector3D &, const KisVector3D &); + friend inline bool operator!=(const KisVector3D &, const KisVector3D &); + friend inline KisVector3D operator+(const KisVector3D &, const KisVector3D &); + friend inline KisVector3D operator-(const KisVector3D &, const KisVector3D &); + friend inline KisVector3D operator*(const KisVector3D &, int); + friend inline KisVector3D operator*(int, const KisVector3D &); + friend inline KisVector3D operator*(const KisVector3D &, long); + friend inline KisVector3D operator*(long, const KisVector3D &); + friend inline KisVector3D operator*(const KisVector3D &, double); + friend inline KisVector3D operator*(double, const KisVector3D &); + friend inline KisVector3D operator-(const KisVector3D &); + friend inline KisVector3D operator/(const KisVector3D &, int); + friend inline KisVector3D operator/(const KisVector3D &, long); + friend inline KisVector3D operator/(const KisVector3D &, double); + +private: + double m_x; + double m_y; + double m_z; +}; + +inline KisVector3D::KisVector3D() +{ m_x=0; m_y=0; m_z=0; } + +inline KisVector3D::KisVector3D(double x, double y, double z) +{ m_x=x; m_y=y; m_z=z; } + +inline KisVector3D::KisVector3D(int x, int y, int z) +{ m_x=static_cast(x); m_y=static_cast(y); m_z=static_cast(z); } + +inline KisVector3D::KisVector3D(long x, long y, long z) +{ m_x=static_cast(x); m_y=static_cast(y); m_z=static_cast(z); } + +inline bool KisVector3D::isNull() const +{ return fabs(m_x) < epsilon && fabs(m_y) < epsilon && fabs(m_z) < epsilon; } + +inline double KisVector3D::length() const +{ return (sqrt(m_x*m_x + m_y*m_y + m_z*m_z)); } + +inline double KisVector3D::dotProduct(const KisVector3D &v) const +{ return m_x*v.m_x + m_y*v.m_y + m_z*v.m_z; } + +inline double KisVector3D::x() const +{ return m_x; } + +inline double KisVector3D::y() const +{ return m_y; } + +inline double KisVector3D::z() const +{ return m_z; } + +inline void KisVector3D::setX(double x) +{ m_x=x; } + +inline void KisVector3D::setY(double y) +{ m_y=y; } + +inline void KisVector3D::setZ(double z) +{ m_z=z; } + +inline KisVector3D &KisVector3D::operator+=(const KisVector3D &v) +{ m_x+=v.m_x; m_y+=v.m_y; m_z+=v.m_z; return *this; } + +inline KisVector3D &KisVector3D::operator-=(const KisVector3D &v) +{ m_x-=v.m_x; m_y-=v.m_y; m_z-=v.m_z; return *this; } + +inline KisVector3D &KisVector3D::operator*=(int c) +{ m_x*=c; m_y*=c; m_z*=c; return *this; } + +inline KisVector3D &KisVector3D::operator*=(long c) +{ m_x*=c; m_y*=c; m_z*=c; return *this; } + +inline KisVector3D &KisVector3D::operator*=(double c) +{ m_x*=c; m_y*=c; m_z*=c; return *this; } + +inline bool operator==(const KisVector3D &v1, const KisVector3D &v2) +{ return fabs(v1.m_x - v2.m_x) < epsilon && fabs(v1.m_y - v2.m_y) < epsilon && fabs(v1.m_z - v2.m_z) < epsilon; } + +inline bool operator!=(const KisVector3D &v1, const KisVector3D &v2) +{ return !(v1 == v2); } + +inline KisVector3D operator+(const KisVector3D &v1, const KisVector3D &v2) +{ return KisVector3D(v1.m_x+v2.m_x, v1.m_y+v2.m_y, v1.m_z+v2.m_z); } + +inline KisVector3D operator-(const KisVector3D &v1, const KisVector3D &v2) +{ return KisVector3D(v1.m_x-v2.m_x, v1.m_y-v2.m_y, v1.m_z-v2.m_z); } + +inline KisVector3D operator*(const KisVector3D &v, int c) +{ return KisVector3D((v.m_x*c), (v.m_y*c), (v.m_z*c)); } + +inline KisVector3D operator*(int c, const KisVector3D &v) +{ return KisVector3D((v.m_x*c), (v.m_y*c), (v.m_z*c)); } + +inline KisVector3D operator*(const KisVector3D &v, long c) +{ return KisVector3D((v.m_x*c), (v.m_y*c), (v.m_z*c)); } + +inline KisVector3D operator*(long c, const KisVector3D &v) +{ return KisVector3D((v.m_x*c), (v.m_y*c), (v.m_z*c)); } + +inline KisVector3D operator*(const KisVector3D &v, double c) +{ return KisVector3D(v.m_x*c, v.m_y*c, v.m_z*c); } + +inline KisVector3D operator*(double c, const KisVector3D &v) +{ return KisVector3D(v.m_x*c, v.m_y*c, v.m_z*c); } + +inline KisVector3D operator-(const KisVector3D &v) +{ return KisVector3D(-v.m_x, -v.m_y, -v.m_z); } + +inline KisVector3D &KisVector3D::operator/=(int c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + m_z/=c; + } + return *this; +} + +inline KisVector3D &KisVector3D::operator/=(long c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + m_z/=c; + } + return *this; +} + +inline KisVector3D &KisVector3D::operator/=(double c) +{ + if (!c == 0) + { + m_x/=c; + m_y/=c; + m_z/=c; + } + return *this; +} + +#endif diff --git a/chalk/core/tests/Makefile.am b/chalk/core/tests/Makefile.am new file mode 100644 index 00000000..239c1ba6 --- /dev/null +++ b/chalk/core/tests/Makefile.am @@ -0,0 +1,30 @@ +AM_CPPFLAGS = \ + -I$(srcdir)/../ \ + -I$(srcdir)/../tiles \ + -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../chalkcolor \ + -I$(srcdir)/../../colorspaces/rgb_u8 \ + $(KOFFICE_INCLUDES) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_integer_maths_tester.la kunittest_kis_image_tester.la kunittest_kis_filter_configuration_tester.la + +kunittest_kis_integer_maths_tester_la_SOURCES = kis_integer_maths_tester.cpp +kunittest_kis_integer_maths_tester_la_LIBADD = -lkunittest ../../libchalkcommon.la +kunittest_kis_integer_maths_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +kunittest_kis_image_tester_la_SOURCES = kis_image_tester.cpp +kunittest_kis_image_tester_la_LIBADD = -lkunittest ../../libchalkcommon.la +kunittest_kis_image_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + + +kunittest_kis_filter_configuration_tester_la_SOURCES = kis_filter_configuration_tester.cc +kunittest_kis_filter_configuration_tester_la_LIBADD = -lkunittest ../../libchalkcommon.la +kunittest_kis_filter_configuration_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + + +check-local: kunittest_kis_integer_maths_tester.la kunittest_kis_image_tester.la kunittest_kis_filter_configuration_tester.la + kunittestmodrunner diff --git a/chalk/core/tests/kis_filter_configuration_tester.cc b/chalk/core/tests/kis_filter_configuration_tester.cc new file mode 100644 index 00000000..6a4a2631 --- /dev/null +++ b/chalk/core/tests/kis_filter_configuration_tester.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include "kis_filter_configuration_tester.h" +#include "../kis_filter_configuration.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE(kunittest_kis_filter_configuration_tester, "KisFilterConfiguration Tester"); +KUNITTEST_MODULE_REGISTER_TESTER(KisFilterConfigurationTester); + +void KisFilterConfigurationTester::allTests() +{ + testCreation(); + testSetGetProperty(); + testRoundTrip(); +} + +void KisFilterConfigurationTester::testCreation() +{ + KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + if ( kfc == 0 ) failure("Could not create test filter configuration"); + CHECK(kfc->version(), 1); + CHECK(kfc->name(), TQString("test")); + + delete kfc; + success("testCreation success"); +} + +void KisFilterConfigurationTester::testRoundTrip() +{ + KisFilterConfiguration * kfc = new KisFilterConfiguration("test", 1); + CHECK(kfc->version(), 1); + CHECK(kfc->name(), TQString("test")); + TQString s = kfc->toString(); + delete kfc; + kfc = new KisFilterConfiguration(s); + CHECK(kfc->version(), 1); + CHECK(kfc->name(), TQString("test")); + delete kfc; + success("testDeserializaton success"); +} + +void KisFilterConfigurationTester::testSetGetProperty() +{ +} diff --git a/chalk/core/tests/kis_filter_configuration_tester.h b/chalk/core/tests/kis_filter_configuration_tester.h new file mode 100644 index 00000000..6e1ca2e5 --- /dev/null +++ b/chalk/core/tests/kis_filter_configuration_tester.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_FILTER_CONFIGURATION_TESTER_H +#define KIS_FILTER_CONFIGURATION_TESTER_H + +#include + +class KisFilterConfigurationTester : public KUnitTest::Tester +{ +public: + void allTests(); + void testCreation(); + void testRoundTrip(); + void testSetGetProperty(); +}; + +#endif + diff --git a/chalk/core/tests/kis_image_tester.cpp b/chalk/core/tests/kis_image_tester.cpp new file mode 100644 index 00000000..f660f394 --- /dev/null +++ b/chalk/core/tests/kis_image_tester.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include "kis_image_tester.h" +#include "kis_image.h" +#include "kis_meta_registry.h" +#include "kis_rgb_colorspace.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_color.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE(kunittest_kis_image_tester, "KisImage Tester"); +KUNITTEST_MODULE_REGISTER_TESTER(KisImageTester); + +void KisImageTester::allTests() +{ + mergeTests(); +} + +#define IMAGE_WIDTH 1 +#define IMAGE_HEIGHT 1 + +void KisImageTester::mergeTests() +{ + KisColorSpace * colorSpace = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""), ""); + + KisImageSP image = new KisImage(0, IMAGE_WIDTH, IMAGE_HEIGHT, colorSpace, "merge test"); + + KisColor mergedPixel = image->mergedPixel(0, 0); + + TQColor colour; + TQ_UINT8 opacity; + + mergedPixel.toTQColor(&colour, &opacity); + + CHECK(opacity, OPACITY_TRANSPARENT); + + KisPaintLayer * layer = new KisPaintLayer(image, "layer 1", OPACITY_OPAQUE); + image->addLayer(layer, image->rootLayer(), 0); + + layer->paintDevice()->setPixel(0, 0, TQColor(255, 128, 64), OPACITY_OPAQUE); + + mergedPixel = image->mergedPixel(0, 0); + mergedPixel.toTQColor(&colour, &opacity); + + CHECK(opacity, OPACITY_OPAQUE); + CHECK(colour.red(), 255); + CHECK(colour.green(), 128); + CHECK(colour.blue(), 64); + + KisPaintLayer * layer2 = new KisPaintLayer(image, "layer 2", OPACITY_OPAQUE / 2); + image->addLayer(layer2, image->rootLayer(), layer); + + layer2->paintDevice()->setPixel(0, 0, TQColor(255, 255, 255), OPACITY_OPAQUE); + + mergedPixel = image->mergedPixel(0, 0); + mergedPixel.toTQColor(&colour, &opacity); + + CHECK(opacity, OPACITY_OPAQUE); + CHECK(colour.red(), 255); + CHECK(colour.green(), 128 + ((255 - 128) / 2)); + CHECK(colour.blue(), 64 + ((255 - 64) / 2)); +} + + diff --git a/chalk/core/tests/kis_image_tester.h b/chalk/core/tests/kis_image_tester.h new file mode 100644 index 00000000..4e676838 --- /dev/null +++ b/chalk/core/tests/kis_image_tester.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_IMAGE_TESTER_H +#define KIS_IMAGE_TESTER_H + +#include + +class KisImageTester : public KUnitTest::Tester +{ +public: + void allTests(); + void mergeTests(); +}; + +#endif + diff --git a/chalk/core/tests/kis_integer_maths_tester.cpp b/chalk/core/tests/kis_integer_maths_tester.cpp new file mode 100644 index 00000000..1878731b --- /dev/null +++ b/chalk/core/tests/kis_integer_maths_tester.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_integer_maths_tester.h" +#include "kis_integer_maths.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE(kunittest_kis_integer_maths_tester, "Integer Maths Tester"); +KUNITTEST_MODULE_REGISTER_TESTER(KisIntegerMathsTester); + +void KisIntegerMathsTester::allTests() +{ + UINT8Tests(); + UINT16Tests(); + conversionTests(); +} + +void KisIntegerMathsTester::UINT8Tests() +{ + CHECK((int)UINT8_MULT(0, 255), 0); + CHECK((int)UINT8_MULT(255, 255), 255); + + CHECK((int)UINT8_MULT(128, 255), 128); + CHECK((int)UINT8_MULT(255, 128), 128); + + CHECK((int)UINT8_MULT(1, 255), 1); + CHECK((int)UINT8_MULT(1, 127), 0); + CHECK((int)UINT8_MULT(64, 128), 32); + + CHECK((int)UINT8_DIVIDE(255, 255), 255); + CHECK((int)UINT8_DIVIDE(64, 128), 128); + CHECK((int)UINT8_DIVIDE(1, 64), 4); + CHECK((int)UINT8_DIVIDE(0, 1), 0); + + CHECK((int)UINT8_BLEND(255, 0, 0), 0); + CHECK((int)UINT8_BLEND(255, 0, 128), 128); + CHECK((int)UINT8_BLEND(255, 128, 128), 192); + CHECK((int)UINT8_BLEND(128, 64, 255), 128); +} + +void KisIntegerMathsTester::UINT16Tests() +{ + CHECK((int)UINT16_MULT(0, 65535), 0); + CHECK((int)UINT16_MULT(65535, 65535), 65535); + + CHECK((int)UINT16_MULT(32768, 65535), 32768); + CHECK((int)UINT16_MULT(65535, 32768), 32768); + + CHECK((int)UINT16_MULT(1, 65535), 1); + CHECK((int)UINT16_MULT(1, 32767), 0); + CHECK((int)UINT16_MULT(16384, 32768), 8192); + + CHECK((int)UINT16_DIVIDE(65535, 65535), 65535); + CHECK((int)UINT16_DIVIDE(16384, 32768), 32768); + CHECK((int)UINT16_DIVIDE(1, 16384), 4); + CHECK((int)UINT16_DIVIDE(0, 1), 0); + + CHECK((int)UINT16_BLEND(65535, 0, 0), 0); + CHECK((int)UINT16_BLEND(65535, 0, 32768), 32768); + CHECK((int)UINT16_BLEND(65535, 32768, 32768), 49152); + CHECK((int)UINT16_BLEND(32768, 16384, 65535), 32768); +} + +void KisIntegerMathsTester::conversionTests() +{ + CHECK((int)UINT8_TO_UINT16(255), 65535); + CHECK((int)UINT8_TO_UINT16(0), 0); + CHECK((int)UINT8_TO_UINT16(128), 128 * 257); + + CHECK((int)UINT16_TO_UINT8(65535), 255); + CHECK((int)UINT16_TO_UINT8(0), 0); + CHECK((int)UINT16_TO_UINT8(128 * 257), 128); +} + diff --git a/chalk/core/tests/kis_integer_maths_tester.h b/chalk/core/tests/kis_integer_maths_tester.h new file mode 100644 index 00000000..2a9a9a20 --- /dev/null +++ b/chalk/core/tests/kis_integer_maths_tester.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_INTEGER_MATHS_TESTER_H +#define KIS_INTEGER_MATHS_TESTER_H + +#include + +class KisIntegerMathsTester : public KUnitTest::Tester +{ +public: + void allTests(); + void UINT8Tests(); + void UINT16Tests(); + void conversionTests(); +}; + +#endif + diff --git a/chalk/core/tiles/Makefile.am b/chalk/core/tiles/Makefile.am new file mode 100644 index 00000000..1e334ab4 --- /dev/null +++ b/chalk/core/tiles/Makefile.am @@ -0,0 +1,23 @@ +if include_kunittest_tests +TESTSDIR = tests +endif + +SUBDIRS = . $(TESTSDIR) + +INCLUDES = -I$(srcdir)/../ \ + -I$(srcdir)/../../sdk \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(all_includes) + +noinst_LTLIBRARIES = libchalktile.la + +libchalktile_la_SOURCES = kis_tiledvlineiterator.cc kis_tiledhlineiterator.cc \ + kis_tileddatamanager.cc kis_tile.cc kis_tilediterator.cc kis_tiledrectiterator.cc \ + kis_memento.cc kis_tilemanager.cc kis_tiled_random_accessor.cc + +libchalktile_la_METASOURCES = AUTO + +include_HEADERS = \ + kis_tileddatamanager.h +noinst_HEADERS = kis_tiled_random_accessor.h diff --git a/chalk/core/tiles/kis_memento.cc b/chalk/core/tiles/kis_memento.cc new file mode 100644 index 00000000..aaec3724 --- /dev/null +++ b/chalk/core/tiles/kis_memento.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_global.h" +#include "kis_memento.h" +#include "kis_tile.h" +#include "kis_tile_global.h" + +KisMemento::KisMemento(TQ_UINT32 pixelSize) : KShared() +{ + m_hashTable = new KisTile * [1024]; + Q_CHECK_PTR(m_hashTable); + + m_redoHashTable = new KisTile * [1024]; + Q_CHECK_PTR(m_redoHashTable); + + for(int i = 0; i < 1024; i++) + { + m_hashTable [i] = 0; + m_redoHashTable [i] = 0; + } + m_numTiles = 0; + m_defPixel = new TQ_UINT8[pixelSize]; + m_redoDefPixel = new TQ_UINT8[pixelSize]; + m_valid = true; +} + +KisMemento::~KisMemento() +{ + // Deep delete every tile + for(int i = 0; i < 1024; i++) + { + deleteAll(m_hashTable[i]); + deleteAll(m_redoHashTable[i]); + } + delete [] m_hashTable; + delete [] m_redoHashTable; + + // Delete defPixel arrays; + delete [] m_defPixel; + delete [] m_redoDefPixel; +} + +KisMemento::DeletedTileList::~DeletedTileList() +{ + clear(); +} + +void KisMemento::DeletedTileList::clear() +{ + // They are not tiles just references. The actual tiles have already been deleted, + // so just delete the references. + + const DeletedTile *deletedTile = m_firstDeletedTile; + + while (deletedTile) + { + const DeletedTile *d = deletedTile; + deletedTile = deletedTile->next(); + delete d; + } + + m_firstDeletedTile = 0; +} + +void KisMemento::deleteAll(KisTile *tile) +{ + while(tile) + { + KisTile *deltile = tile; + tile = tile->getNext(); + delete deltile; + } +} + +void KisMemento::extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const +{ + TQ_INT32 maxX = TQ_INT32_MIN; + TQ_INT32 maxY = TQ_INT32_MIN; + x = TQ_INT32_MAX; + y = TQ_INT32_MAX; + + for(int i = 0; i < 1024; i++) + { + KisTile *tile = m_hashTable[i]; + + while(tile) + { + if(x > tile->getCol() * KisTile::WIDTH) + x = tile->getCol() * KisTile::WIDTH; + if(maxX < (tile->getCol() + 1) * KisTile::WIDTH - 1) + maxX = (tile->getCol() + 1) * KisTile::WIDTH - 1; + if(y > tile->getRow() * KisTile::HEIGHT) + y = tile->getRow() * KisTile::HEIGHT; + if(maxY < (tile->getRow() +1) * KisTile::HEIGHT - 1) + maxY = (tile->getRow() +1) * KisTile::HEIGHT - 1; + + tile = tile->getNext(); + } + } + + if(maxX < x) + w = 0; + else + w = maxX - x +1; + + if(maxY < y) + h = 0; + else + h = maxY - y +1; +} + +TQRect KisMemento::extent() const +{ + TQ_INT32 x; + TQ_INT32 y; + TQ_INT32 w; + TQ_INT32 h; + + extent(x, y, w, h); + + return TQRect(x, y, w, h); +} + +bool KisMemento::containsTile(TQ_INT32 col, TQ_INT32 row, TQ_UINT32 tileHash) const +{ + const KisTile *tile = m_hashTable[tileHash]; + + while (tile != 0) + { + if (tile->getRow() == row && tile->getCol() == col) { + return true; + } + + tile = tile->getNext(); + } + + return false; +} + diff --git a/chalk/core/tiles/kis_memento.h b/chalk/core/tiles/kis_memento.h new file mode 100644 index 00000000..5942dc44 --- /dev/null +++ b/chalk/core/tiles/kis_memento.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_MEMENTO_H_ +#define KIS_MEMENTO_H_ + +#include +#include + +#include + +class KisTile; +class KisTiledDataManager; + +class KisMemento; +typedef KSharedPtr KisMementoSP; + +class KisMemento : public KShared +{ +public: + KisMemento(TQ_UINT32 pixelSize); + ~KisMemento(); +/* + // For consolidating transactions + virtual KisTransaction &operator+=(const KisTransaction &) = 0; + // For consolidating transactions + virtual KisTransaction &operator+(const KisTransaction &, + const KisTransaction &) = 0; +*/ + void extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const; + TQRect extent() const; + + bool containsTile(TQ_INT32 col, TQ_INT32 row, TQ_UINT32 tileHash) const; + + // For debugging use + bool valid() const { return m_valid; } + void setInvalid() { m_valid = false; } + +private: + + class DeletedTile { + public: + DeletedTile(TQ_INT32 col, TQ_INT32 row, const DeletedTile *next) + : m_col(col), + m_row(row), + m_next(next) + { + } + + TQ_INT32 col() const { return m_col; } + TQ_INT32 row() const { return m_row; } + const DeletedTile *next() const { return m_next; } + + private: + TQ_INT32 m_col; + TQ_INT32 m_row; + const DeletedTile *m_next; + }; + + class DeletedTileList { + public: + DeletedTileList() + : m_firstDeletedTile(0) + { + } + + ~DeletedTileList(); + + void addTile(TQ_INT32 col, TQ_INT32 row) + { + DeletedTile *d = new DeletedTile(col, row, m_firstDeletedTile); + Q_CHECK_PTR(d); + + m_firstDeletedTile = d; + } + + DeletedTile *firstTile() const + { + return m_firstDeletedTile; + } + + void clear(); + + private: + DeletedTile *m_firstDeletedTile; + }; + + void addTileToDeleteOnRedo(TQ_INT32 col, TQ_INT32 row) + { + m_redoDelTilesList.addTile(col, row); + } + + DeletedTile *tileListToDeleteOnRedo() + { + return m_redoDelTilesList.firstTile(); + } + + void clearTilesToDeleteOnRedo() + { + m_redoDelTilesList.clear(); + } + + void addTileToDeleteOnUndo(TQ_INT32 col, TQ_INT32 row) + { + m_undoDelTilesList.addTile(col, row); + } + + DeletedTile *tileListToDeleteOnUndo() + { + return m_undoDelTilesList.firstTile(); + } + + void clearTilesToDeleteOnUndo() + { + m_undoDelTilesList.clear(); + } + + friend class KisTiledDataManager; + KisTiledDataManager *originator; + KisTile **m_hashTable; + TQ_UINT32 m_numTiles; + KisTile **m_redoHashTable; + DeletedTileList m_redoDelTilesList; + DeletedTileList m_undoDelTilesList; + TQ_UINT8 *m_defPixel; + TQ_UINT8 *m_redoDefPixel; + void deleteAll(KisTile *tile); + + bool m_valid; +}; + +#endif // KIS_MEMENTO_H_ diff --git a/chalk/core/tiles/kis_tile.cc b/chalk/core/tiles/kis_tile.cc new file mode 100644 index 00000000..86d55128 --- /dev/null +++ b/chalk/core/tiles/kis_tile.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "kis_tile_global.h" +#include "kis_tile.h" +#include "kis_tileddatamanager.h" +#include "kis_tilemanager.h" + +const TQ_INT32 KisTile::WIDTH = 64; +const TQ_INT32 KisTile::HEIGHT = 64; + + +KisTile::KisTile(TQ_INT32 pixelSize, TQ_INT32 col, TQ_INT32 row, const TQ_UINT8 *defPixel) +{ + m_pixelSize = pixelSize; + m_data = 0; + m_nextTile = 0; + m_col = col; + m_row = row; + m_nReadlock = 0; + + allocate(); + + KisTileManager::instance()->registerTile(this); + + setData(defPixel); +} + +KisTile::KisTile(const KisTile& rhs, TQ_INT32 col, TQ_INT32 row) +{ + if (this != &rhs) { + m_pixelSize = rhs.m_pixelSize; + m_data = 0; + m_nextTile = 0; + m_nReadlock = 0; + + allocate(); + + // Assure we have data to copy + rhs.addReader(); + memcpy(m_data, rhs.m_data, WIDTH * HEIGHT * m_pixelSize * sizeof(TQ_UINT8)); + rhs.removeReader(); + + m_col = col; + m_row = row; + + KisTileManager::instance()->registerTile(this); + } +} + +KisTile::KisTile(const KisTile& rhs) +{ + if (this != &rhs) { + m_pixelSize = rhs.m_pixelSize; + m_col = rhs.m_col; + m_row = rhs.m_row; + m_data = 0; + m_nextTile = 0; + m_nReadlock = 0; + + allocate(); + + rhs.addReader(); + memcpy(m_data, rhs.m_data, WIDTH * HEIGHT * m_pixelSize * sizeof(TQ_UINT8)); + rhs.removeReader(); + + KisTileManager::instance()->registerTile(this); + } +} + +KisTile::~KisTile() +{ + KisTileManager::instance()->deregisterTile(this); // goes before the deleting of m_data! + + if (m_data) { +// delete[] m_data; + KisTileManager::instance()->dontNeedTileData(m_data, m_pixelSize); + m_data = 0; + } + assert( !readers() ); +} + +void KisTile::allocate() +{ + if (m_data == 0) { + assert (!readers()); + m_data = KisTileManager::instance()->requestTileData(m_pixelSize); + Q_CHECK_PTR(m_data); + } +} + +void KisTile::setNext(KisTile *n) +{ + m_nextTile = n; +} + +TQ_UINT8 *KisTile::data(TQ_INT32 x, TQ_INT32 y ) const +{ + addReader(); + removeReader(); + + Q_ASSERT(m_data != 0); + if (m_data == 0) return 0; + + return m_data + m_pixelSize * ( y * WIDTH + x ); +} + +void KisTile::setData(const TQ_UINT8 *pixel) +{ + addReader(); + TQ_UINT8 *dst = m_data; + for(int i=0; i ensureTileLoaded(this); + else if (m_nReadlock < 0) { + kdDebug(41000) << m_nReadlock << endl; + assert(0); + } + assert(m_data); +} + +void KisTile::removeReader() const +{ + if (--m_nReadlock == 0) + KisTileManager::instance()->maySwapTile(this); +} diff --git a/chalk/core/tiles/kis_tile.h b/chalk/core/tiles/kis_tile.h new file mode 100644 index 00000000..f2d6f1e9 --- /dev/null +++ b/chalk/core/tiles/kis_tile.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TILE_H_ +#define KIS_TILE_H_ + +#include +#include + +class KisTiledDataManager; +class KisTiledIterator; + +/** + * Provides abstraction to a tile. A tile tqcontains + * a part of a PaintDevice, but only the individual pixels + * are accesable and that only via iterators. + */ +class KisTile { +public: + KisTile(TQ_INT32 pixelSize, TQ_INT32 col, TQ_INT32 row, const TQ_UINT8 *defPixel); + KisTile(const KisTile& rhs, TQ_INT32 col, TQ_INT32 row); + KisTile(const KisTile& rhs); + ~KisTile(); + +public: + void release(); + void allocate(); + + TQ_UINT8 *data(TQ_INT32 xoff, TQ_INT32 yoff) const; + TQ_UINT8 *data() const { return m_data; } + + void setData(const TQ_UINT8 *pixel); + + TQ_INT32 refCount() const; + void ref(); + + TQ_INT32 getRow() const { return m_row; } + TQ_INT32 getCol() const { return m_col; } + + TQRect extent() const { return TQRect(m_col * WIDTH, m_row * HEIGHT, WIDTH, HEIGHT); } + + void setNext(KisTile *); + KisTile *getNext() const { return m_nextTile; } + + // These are const because they don't change the external data the tile represents, + // although they do change internal representations. We need to be able to request + // access to a tile in a const enviroment (like copyconstructor and so)! + void addReader() const; + void removeReader() const; + TQ_INT32 readers() { return m_nReadlock; } + + friend class KisTiledIterator; + friend class KisTiledDataManager; + friend class KisMemento; + friend class KisTileManager; +private: + KisTile& operator=(const KisTile&); + +private: + TQ_UINT8 *m_data; + mutable TQ_INT32 m_nReadlock; + TQ_INT32 m_row; + TQ_INT32 m_col; + TQ_INT32 m_pixelSize; + KisTile *m_nextTile; + +public: + static const TQ_INT32 WIDTH; + static const TQ_INT32 HEIGHT; +}; + +#endif // KIS_TILE_H_ + diff --git a/chalk/core/tiles/kis_tile_global.h b/chalk/core/tiles/kis_tile_global.h new file mode 100644 index 00000000..93052a4f --- /dev/null +++ b/chalk/core/tiles/kis_tile_global.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TILE_GLOBAL_H_ +#define KIS_TILE_GLOBAL_H_ + +#define DBG_AREA_TILES 41000 + +#endif diff --git a/chalk/core/tiles/kis_tiled_random_accessor.cc b/chalk/core/tiles/kis_tiled_random_accessor.cc new file mode 100644 index 00000000..159faf18 --- /dev/null +++ b/chalk/core/tiles/kis_tiled_random_accessor.cc @@ -0,0 +1,115 @@ +/* + * copyright (c) 2006 Cyrille Berger + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#include "kis_tiled_random_accessor.h" + + +const TQ_UINT32 KisTiledRandomAccessor::CACHESIZE = 4; // Define the number of tiles we keep in cache + +KisTiledRandomAccessor::KisTiledRandomAccessor(KisTiledDataManager *ktm, TQ_INT32 x, TQ_INT32 y, bool writable) : m_ktm(ktm), m_tilesCache(new KisTileInfo*[4]), m_tilesCacheSize(0), m_pixelSize (m_ktm->pixelSize()), m_writable(writable) +{ + Q_ASSERT(ktm != 0); + moveTo(x, y); +} + +KisTiledRandomAccessor::~KisTiledRandomAccessor() +{ + for( uint i = 0; i < m_tilesCacheSize; i++) + { + m_tilesCache[i]->tile->removeReader(); + m_tilesCache[i]->oldtile->removeReader(); + delete m_tilesCache[i]; + } + delete m_tilesCache; +} + +void KisTiledRandomAccessor::moveTo(TQ_INT32 x, TQ_INT32 y) +{ + // Look in the cache if the tile if the data is available + for( uint i = 0; i < m_tilesCacheSize; i++) + { + if( x >= m_tilesCache[i]->area_x1 && x <= m_tilesCache[i]->area_x2 && + y >= m_tilesCache[i]->area_y1 && y <= m_tilesCache[i]->area_y2 ) + { + KisTileInfo* kti = m_tilesCache[i]; + TQ_UINT32 offset = x - kti->area_x1 + (y -kti->area_y1) * KisTile::WIDTH; + offset *= m_pixelSize; + m_data = kti->data + offset; + m_oldData = kti->oldData + offset; + if(i > 0) + { + memmove(m_tilesCache+1,m_tilesCache, i * sizeof(KisTileInfo*)); + m_tilesCache[0] = kti; + } + return; + } + } + // The tile wasn't in cache + if(m_tilesCacheSize == KisTiledRandomAccessor::CACHESIZE ) + { // Remove last element of cache + m_tilesCache[CACHESIZE-1]->tile->removeReader(); + m_tilesCache[CACHESIZE-1]->oldtile->removeReader(); + delete m_tilesCache[CACHESIZE-1]; + } else { + m_tilesCacheSize++; + } + TQ_UINT32 col = xToCol( x ); + TQ_UINT32 row = yToRow( y ); + KisTileInfo* kti = fetchTileData(col, row); + TQ_UINT32 offset = x - kti->area_x1 + (y - kti->area_y1) * KisTile::WIDTH; + offset *= m_pixelSize; + m_data = kti->data + offset; + m_oldData = kti->oldData + offset; + memmove(m_tilesCache+1,m_tilesCache, (KisTiledRandomAccessor::CACHESIZE-1) * sizeof(KisTileInfo*)); + m_tilesCache[0] = kti; +} + + +TQ_UINT8 * KisTiledRandomAccessor::rawData() const +{ + return m_data; +} + + +const TQ_UINT8 * KisTiledRandomAccessor::oldRawData() const +{ +#ifdef DEBUG + kdWarning(!m_ktm->hasCurrentMemento(), DBG_AREA_TILES) << "Accessing oldRawData() when no transaction is in progress.\n"; +#endif + return m_oldData; +} + +KisTiledRandomAccessor::KisTileInfo* KisTiledRandomAccessor::fetchTileData(TQ_INT32 col, TQ_INT32 row) +{ + KisTileInfo* kti = new KisTileInfo; + kti->tile = m_ktm->getTile(col, row, m_writable); + + kti->tile->addReader(); + + kti->data = kti->tile->data(); + + kti->area_x1 = col * KisTile::HEIGHT; + kti->area_y1 = row * KisTile::WIDTH; + kti->area_x2 = kti->area_x1 + KisTile::HEIGHT - 2; + kti->area_y2 = kti->area_y1 + KisTile::WIDTH - 2; + + // set old data + kti->oldtile = m_ktm->getOldTile(col, row, kti->tile); + kti->oldtile->addReader(); + kti->oldData = kti->oldtile->data(); + return kti; +} diff --git a/chalk/core/tiles/kis_tiled_random_accessor.h b/chalk/core/tiles/kis_tiled_random_accessor.h new file mode 100644 index 00000000..23768ee6 --- /dev/null +++ b/chalk/core/tiles/kis_tiled_random_accessor.h @@ -0,0 +1,66 @@ +/* + * copyright (c) 2006 Cyrille Berger + * + * this program is free software; you can redistribute it and/or modify + * it under the terms of the gnu general public license as published by + * the free software foundation; either version 2 of the license, or + * (at your option) any later version. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * gnu general public license for more details. + * + * you should have received a copy of the gnu general public license + * along with this program; if not, write to the free software + * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. + */ +#ifndef KIS_TILED_RANDOM_ACCESSOR_H +#define KIS_TILED_RANDOM_ACCESSOR_H + +#include +#include + +#include + +#include + +class KisTile; + +class KisTiledRandomAccessor : public KShared { + struct KisTileInfo { + KisTile* tile; + KisTile* oldtile; + TQ_UINT8* data; + const TQ_UINT8* oldData; + TQ_INT32 area_x1, area_y1, area_x2, area_y2; + }; + public: + KisTiledRandomAccessor(KisTiledDataManager *ktm, TQ_INT32 x, TQ_INT32 y, bool writable); + ~KisTiledRandomAccessor(); + + + private: + inline TQ_UINT32 xToCol(TQ_UINT32 x) const { if (m_ktm) return m_ktm->xToCol(x); else return 0; }; + inline TQ_UINT32 yToRow(TQ_UINT32 y) const { if (m_ktm) return m_ktm->yToRow(y); else return 0; }; + KisTileInfo* fetchTileData(TQ_INT32 col, TQ_INT32 row); + + public: + /// Move to a given x,y position, fetch tiles and data + void moveTo(TQ_INT32 x, TQ_INT32 y); + TQ_UINT8* rawData() const; + const TQ_UINT8* oldRawData() const; + + private: + KisTiledDataManager *m_ktm; + KisTileInfo** m_tilesCache; + TQ_UINT32 m_tilesCacheSize; + TQ_INT32 m_pixelSize; + TQ_UINT8* m_data; + const TQ_UINT8* m_oldData; + bool m_writable; + static const TQ_UINT32 CACHESIZE; // Define the number of tiles we keep in cache + +}; + +#endif diff --git a/chalk/core/tiles/kis_tileddatamanager.cc b/chalk/core/tiles/kis_tileddatamanager.cc new file mode 100644 index 00000000..629b1b38 --- /dev/null +++ b/chalk/core/tiles/kis_tileddatamanager.cc @@ -0,0 +1,1044 @@ +/* + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +#include "kis_global.h" +#include "kis_debug_areas.h" +#include "kis_tileddatamanager.h" +#include "kis_tilediterator.h" +#include "kis_tile.h" +#include "kis_memento.h" +#include "kis_tilemanager.h" + +/* The data area is divided into tiles each say 64x64 pixels (defined at compiletime) + * The tiles are laid out in a matrix that can have negative indexes. + * The matrix grows automatically if needed (a call for writeacces to a tile outside the current extent) + * Even though the matrix has grown it may still not contain tiles at specific positions. They are created on demand + */ + +KisTiledDataManager::KisTiledDataManager(TQ_UINT32 pixelSize, const TQ_UINT8 *defPixel) +{ + m_pixelSize = pixelSize; + + m_defPixel = new TQ_UINT8[m_pixelSize]; + Q_CHECK_PTR(m_defPixel); + memcpy(m_defPixel, defPixel, m_pixelSize); + + m_defaultTile = new KisTile(pixelSize,0,0, m_defPixel); + Q_CHECK_PTR(m_defaultTile); + + m_hashTable = new KisTile * [1024]; + Q_CHECK_PTR(m_hashTable); + + for(int i = 0; i < 1024; i++) + m_hashTable [i] = 0; + m_numTiles = 0; + m_currentMemento = 0; + m_extentMinX = TQ_INT32_MAX; + m_extentMinY = TQ_INT32_MAX; + m_extentMaxX = TQ_INT32_MIN; + m_extentMaxY = TQ_INT32_MIN; +} + +KisTiledDataManager::KisTiledDataManager(const KisTiledDataManager & dm) + : KShared() +{ + m_pixelSize = dm.m_pixelSize; + + m_defPixel = new TQ_UINT8[m_pixelSize]; + Q_CHECK_PTR(m_defPixel); + memcpy(m_defPixel, dm.m_defPixel, m_pixelSize); + + m_defaultTile = new KisTile(*dm.m_defaultTile, dm.m_defaultTile->getCol(), dm.m_defaultTile->getRow()); + Q_CHECK_PTR(m_defaultTile); + + m_hashTable = new KisTile * [1024]; + Q_CHECK_PTR(m_hashTable); + + m_numTiles = 0; + m_currentMemento = 0; + m_extentMinX = dm.m_extentMinX; + m_extentMinY = dm.m_extentMinY; + m_extentMaxX = dm.m_extentMaxX; + m_extentMaxY = dm.m_extentMaxY; + + // Deep copy every tile. XXX: Make this copy-on-write! + for(int i = 0; i < 1024; i++) + { + const KisTile *tile = dm.m_hashTable[i]; + + m_hashTable[i] = 0; + + while(tile) + { + KisTile *newtile = new KisTile(*tile, tile->getCol(), tile->getRow()); + Q_CHECK_PTR(newtile); + + newtile->setNext(m_hashTable[i]); + m_hashTable[i] = newtile; + tile = tile->getNext(); + + m_numTiles++; + } + } + +} + +KisTiledDataManager::~KisTiledDataManager() +{ + // Deep delete every tile + for(int i = 0; i < 1024; i++) + { + const KisTile *tile = m_hashTable[i]; + + while(tile) + { + const KisTile *deltile = tile; + tile = tile->getNext(); + delete deltile; + } + } + delete [] m_hashTable; + delete m_defaultTile; + delete [] m_defPixel; +} + +void KisTiledDataManager::setDefaultPixel(const TQ_UINT8 *defPixel) +{ + if (defPixel == 0) return; + + memcpy(m_defPixel, defPixel, m_pixelSize); + + m_defaultTile->setData(m_defPixel); +} + +bool KisTiledDataManager::write(KoStore *store) +{ + + if (store == 0) return false; + //Q_ASSERT(store != 0); + + char str[80]; + + sprintf(str, "%d\n", m_numTiles); + store->write(str,strlen(str)); + + for(int i = 0; i < 1024; i++) + { + const KisTile *tile = m_hashTable[i]; + + while(tile) + { + sprintf(str, "%d,%d,%d,%d\n", tile->getCol() * KisTile::WIDTH, + tile->getRow() * KisTile::HEIGHT, + KisTile::WIDTH, KisTile::HEIGHT); + store->write(str,strlen(str)); + + tile->addReader(); + store->write((char *)tile->m_data, KisTile::HEIGHT * KisTile::WIDTH * m_pixelSize); + tile->removeReader(); + + tile = tile->getNext(); + } + } + + return true; +} +bool KisTiledDataManager::read(KoStore *store) +{ + if (store == 0) return false; + //Q_ASSERT(store != 0); + + char str[80]; + TQ_INT32 x,y,w,h; + + TQIODevice *stream = store->device(); + if (stream == 0) return false; + //Q_ASSERT(stream != 0); + + stream->readLine(str, 79); + + sscanf(str,"%u",&m_numTiles); + + for(TQ_UINT32 i = 0; i < m_numTiles; i++) + { + stream->readLine(str, 79); + sscanf(str,"%d,%d,%d,%d",&x,&y,&w,&h); + + // the following is only correct as long as tile size is not changed + // The first time we change tilesize the dimensions just read needs to be respected + // but for now we just assume that tiles are the same size as ever. + TQ_INT32 row = yToRow(y); + TQ_INT32 col = xToCol(x); + TQ_UINT32 tileHash = calcTileHash(col, row); + + KisTile *tile = new KisTile(m_pixelSize, col, row, m_defPixel); + Q_CHECK_PTR(tile); + + updateExtent(col,row); + + tile->addReader(); + store->read((char *)tile->m_data, KisTile::HEIGHT * KisTile::WIDTH * m_pixelSize); + tile->removeReader(); + + tile->setNext(m_hashTable[tileHash]); + m_hashTable[tileHash] = tile; + } + return true; +} + +void KisTiledDataManager::extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const +{ + x = m_extentMinX; + y = m_extentMinY; + + if (m_extentMaxX >= m_extentMinX) { + w = m_extentMaxX - m_extentMinX + 1; + } else { + w = 0; + } + + if (m_extentMaxY >= m_extentMinY) { + h = m_extentMaxY - m_extentMinY + 1; + } else { + h = 0; + } +} + +TQRect KisTiledDataManager::extent() const +{ + TQ_INT32 x; + TQ_INT32 y; + TQ_INT32 w; + TQ_INT32 h; + + extent(x, y, w, h); + + return TQRect(x, y, w, h); +} + +void KisTiledDataManager::setExtent(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + TQRect newRect = TQRect(x, y, w, h).normalize(); + //printRect("newRect", newRect); + TQRect oldRect = TQRect(m_extentMinX, m_extentMinY, m_extentMaxX - m_extentMinX + 1, m_extentMaxY - m_extentMinY + 1).normalize(); + //printRect("oldRect", oldRect); + + // Do nothing if the desired size is bigger than we currently are: that is handled by the autoextending automatically + if (newRect.tqcontains(oldRect)) return; + + // Loop through all tiles, if a tile is wholly outside the extent, add to the memento, then delete it, + // if the tile is partially outside the extent, clear the outside pixels to the default pixel. + for(int tileHash = 0; tileHash < 1024; tileHash++) + { + KisTile *tile = m_hashTable[tileHash]; + KisTile *previousTile = 0; + + while(tile) + { + TQRect tileRect = TQRect(tile->getCol() * KisTile::WIDTH, tile->getRow() * KisTile::HEIGHT, KisTile::WIDTH, KisTile::HEIGHT); + //printRect("tileRect", tileRect); + + if (newRect.tqcontains(tileRect)) { + // Completely inside, do nothing + previousTile = tile; + tile = tile->getNext(); + } + else { + ensureTileMementoed(tile->getCol(), tile->getRow(), tileHash, tile); + + if (newRect.intersects(tileRect)) { + + // Create the intersection of the tile and new rect + TQRect intersection = newRect.intersect(tileRect); + //printRect("intersection", intersection); + intersection.setRect(intersection.x() - tileRect.x(), intersection.y() - tileRect.y(), intersection.width(), intersection.height()); + + // This can be done a lot more efficiently, no doubt, by clearing runs of pixels to the left and the right of + // the intersecting line. + tile->addReader(); + for (int y = 0; y < KisTile::HEIGHT; ++y) { + for (int x = 0; x < KisTile::WIDTH; ++x) { + if (!intersection.tqcontains(x,y)) { + TQ_UINT8 * ptr = tile->data(x, y); + memcpy(ptr, m_defPixel, m_pixelSize); + } + } + } + tile->removeReader(); + previousTile = tile; + tile = tile->getNext(); + } + else { + KisTile *deltile = tile; + tile = tile->getNext(); + + m_numTiles--; + + if (previousTile) + previousTile->setNext(tile); + else + m_hashTable[tileHash] = tile; + delete deltile; + } + } + } + } + + // Set the extent correctly + m_extentMinX = x; + m_extentMinY = y; + m_extentMaxX = x + w - 1; + m_extentMaxY = y + h - 1; +} + +void KisTiledDataManager::recalculateExtent() +{ + m_extentMinX = TQ_INT32_MAX; + m_extentMinY = TQ_INT32_MAX; + m_extentMaxX = TQ_INT32_MIN; + m_extentMaxY = TQ_INT32_MIN; + + // Loop through all tiles. + for (int tileHash = 0; tileHash < 1024; tileHash++) + { + const KisTile *tile = m_hashTable[tileHash]; + + while (tile) + { + updateExtent(tile->getCol(), tile->getRow()); + tile = tile->getNext(); + } + } +} + +void KisTiledDataManager::clear(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, TQ_UINT8 clearValue) +{ + if (w < 1 || h < 1) { + return; + } + + TQ_INT32 firstColumn = xToCol(x); + TQ_INT32 lastColumn = xToCol(x + w - 1); + + TQ_INT32 firstRow = yToRow(y); + TQ_INT32 lastRow = yToRow(y + h - 1); + + TQRect clearRect(x, y, w, h); + + const TQ_UINT32 rowStride = KisTile::WIDTH * m_pixelSize; + + for (TQ_INT32 row = firstRow; row <= lastRow; ++row) { + for (TQ_INT32 column = firstColumn; column <= lastColumn; ++column) { + + KisTile *tile = getTile(column, row, true); + TQRect tileRect = tile->extent(); + + TQRect clearTileRect = clearRect & tileRect; + + tile->addReader(); + if (clearTileRect == tileRect) { + // Clear whole tile + memset(tile->data(), clearValue, KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize); + } else { + + TQ_UINT32 rowsRemaining = clearTileRect.height(); + TQ_UINT8 *dst = tile->data(clearTileRect.x() - tileRect.x(), clearTileRect.y() - tileRect.y()); + + while (rowsRemaining > 0) { + memset(dst, clearValue, clearTileRect.width() * m_pixelSize); + dst += rowStride; + --rowsRemaining; + } + } + tile->removeReader(); + } + } +} + +void KisTiledDataManager::clear(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const TQ_UINT8 *clearPixel) +{ + Q_ASSERT(clearPixel != 0); + + if (clearPixel == 0 || w < 1 || h < 1) { + return; + } + + bool pixelBytesAreTheSame = true; + + for (TQ_UINT32 i = 0; i < m_pixelSize; ++i) { + if (clearPixel[i] != clearPixel[0]) { + pixelBytesAreTheSame = false; + break; + } + } + + if (pixelBytesAreTheSame) { + clear(x, y, w, h, clearPixel[0]); + } else { + + TQ_INT32 firstColumn = xToCol(x); + TQ_INT32 lastColumn = xToCol(x + w - 1); + + TQ_INT32 firstRow = yToRow(y); + TQ_INT32 lastRow = yToRow(y + h - 1); + + TQRect clearRect(x, y, w, h); + + const TQ_UINT32 rowStride = KisTile::WIDTH * m_pixelSize; + + TQ_UINT8 *clearPixelData = 0; + + if (w >= KisTile::WIDTH && h >= KisTile::HEIGHT) { + + // There might be a whole tile to be cleared so generate a cleared tile. + clearPixelData = new TQ_UINT8[KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize]; + + TQ_UINT8 *dst = clearPixelData; + TQ_UINT32 pixelsRemaining = KisTile::WIDTH; + + // Generate one row + while (pixelsRemaining > 0) { + memcpy(dst, clearPixel, m_pixelSize); + dst += m_pixelSize; + --pixelsRemaining; + } + + TQ_UINT32 rowsRemaining = KisTile::HEIGHT - 1; + + // Copy to the rest of the rows. + while (rowsRemaining > 0) { + memcpy(dst, clearPixelData, rowStride); + dst += rowStride; + --rowsRemaining; + } + + } else { + + // Generate one row + TQ_UINT32 maxRunLength = TQMIN(w, KisTile::WIDTH); + + clearPixelData = new TQ_UINT8[maxRunLength * m_pixelSize]; + + TQ_UINT8 *dst = clearPixelData; + TQ_UINT32 pixelsRemaining = maxRunLength; + + while (pixelsRemaining > 0) { + memcpy(dst, clearPixel, m_pixelSize); + dst += m_pixelSize; + --pixelsRemaining; + } + } + + for (TQ_INT32 row = firstRow; row <= lastRow; ++row) { + for (TQ_INT32 column = firstColumn; column <= lastColumn; ++column) { + + KisTile *tile = getTile(column, row, true); + TQRect tileRect = tile->extent(); + + TQRect clearTileRect = clearRect & tileRect; + + if (clearTileRect == tileRect) { + + // Clear whole tile + tile->addReader(); + memcpy(tile->data(), clearPixelData, KisTile::WIDTH * KisTile::HEIGHT * m_pixelSize); + tile->removeReader(); + } else { + + TQ_UINT32 rowsRemaining = clearTileRect.height(); + tile->addReader(); + TQ_UINT8 *dst = tile->data(clearTileRect.x() - tileRect.x(), clearTileRect.y() - tileRect.y()); + + while (rowsRemaining > 0) { + memcpy(dst, clearPixelData, clearTileRect.width() * m_pixelSize); + dst += rowStride; + --rowsRemaining; + } + tile->removeReader(); + } + } + } + + delete [] clearPixelData; + } +} + +void KisTiledDataManager::clear() +{ + // Loop through all tiles, add to the memento, then delete it, + for(int tileHash = 0; tileHash < 1024; tileHash++) + { + const KisTile *tile = m_hashTable[tileHash]; + + while(tile) + { + ensureTileMementoed(tile->getCol(), tile->getRow(), tileHash, tile); + + const KisTile *deltile = tile; + tile = tile->getNext(); + + delete deltile; + } + m_hashTable[tileHash] = 0; + } + + m_numTiles = 0; + + // Set the extent correctly + m_extentMinX = TQ_INT32_MAX; + m_extentMinY = TQ_INT32_MAX; + m_extentMaxX = TQ_INT32_MIN; + m_extentMaxY = TQ_INT32_MIN; +} + +void KisTiledDataManager::paste(KisDataManagerSP data, TQ_INT32 sx, TQ_INT32 sy, TQ_INT32 dx, TQ_INT32 dy, + TQ_INT32 w, TQ_INT32 h) +{ + //CBR_MISSING + sx=sy=dx=dy=w=h;data=0; +} + + +TQ_UINT32 KisTiledDataManager::calcTileHash(TQ_INT32 col, TQ_INT32 row) +{ + return ((row << 5) + (col & 0x1F)) & 0x3FF; +} + +KisMementoSP KisTiledDataManager::getMemento() +{ + m_currentMemento = new KisMemento(m_pixelSize); + Q_CHECK_PTR(m_currentMemento); + + memcpy(m_currentMemento->m_defPixel, m_defPixel, m_pixelSize); + + return m_currentMemento; +} + +void KisTiledDataManager::rollback(KisMementoSP memento) +{ + if (memento == 0) return; + //Q_ASSERT(memento != 0); + + if (m_currentMemento != 0) { + // Undo means our current memento is no longer valid so remove it. + m_currentMemento = 0; + } + + // Rollback means restoring all of the tiles in the memento to our hashtable. + + // But first clear the memento redo hashtable. + // This is nessesary as new changes might have been done since last rollback (automatic filters) + for(int i = 0; i < 1024; i++) + { + memento->deleteAll(memento->m_redoHashTable[i]); + memento->m_redoHashTable[i]=0; + } + + // Also clear the table of deleted tiles + memento->clearTilesToDeleteOnRedo(); + + // Now on to the real rollback + + memcpy(memento->m_redoDefPixel, m_defPixel, m_pixelSize); + setDefaultPixel(memento->m_defPixel); + + for(int i = 0; i < 1024; i++) + { + KisTile *tile = memento->m_hashTable[i]; + + while(tile) + { + // The memento has a tile stored that we need to roll back + // Now find the corresponding one in our hashtable + KisTile *curTile = m_hashTable[i]; + KisTile *preTile = 0; + while(curTile) + { + if(curTile->getRow() == tile->getRow() && curTile->getCol() == tile->getCol()) + { + break; + } + preTile = curTile; + curTile = curTile->getNext(); + } + + if(curTile) + { + // Remove it from our hashtable + if(preTile) + preTile->setNext(curTile->getNext()); + else + m_hashTable[i]= curTile->getNext(); + + m_numTiles--; + + // And put it in the redo hashtable of the memento + curTile->setNext(memento->m_redoHashTable[i]); + memento->m_redoHashTable[i] = curTile; + } + else + { + memento->addTileToDeleteOnRedo(tile->getCol(), tile->getRow()); + // As we are pratically adding a new tile we need to update the extent + updateExtent(tile->getCol(), tile->getRow()); + } + + // Put a copy of the memento tile into our hashtable + curTile = new KisTile(*tile); + Q_CHECK_PTR(curTile); + m_numTiles++; + + curTile->setNext(m_hashTable[i]); + m_hashTable[i] = curTile; + + tile = tile->getNext(); + } + } + + if (memento->tileListToDeleteOnUndo() != 0) { + // XXX: We currently add these tiles above, only to delete them again here. + deleteTiles(memento->tileListToDeleteOnUndo()); + } +} + +void KisTiledDataManager::rollforward(KisMementoSP memento) +{ + if (memento == 0) return; + //Q_ASSERT(memento != 0); + + if (m_currentMemento != 0) { + // Redo means our current memento is no longer valid so remove it. + m_currentMemento = 0; + } + + // Rollforward means restoring all of the tiles in the memento's redo to our hashtable. + + setDefaultPixel(memento->m_redoDefPixel); + + for(int i = 0; i < 1024; i++) + { + KisTile *tile = memento->m_redoHashTable[i]; + + while(tile) + { + // The memento has a tile stored that we need to roll forward + // Now find the corresponding one in our hashtable + KisTile *curTile = m_hashTable[i]; + KisTile *preTile = 0; + while(curTile) + { + if(curTile->getRow() == tile->getRow() && curTile->getCol() == tile->getCol()) + { + break; + } + preTile = curTile; + curTile = curTile->getNext(); + } + + if (curTile) + { + // Remove it from our hashtable + if(preTile) + preTile->setNext(curTile->getNext()); + else + m_hashTable[i]= curTile->getNext(); + + // And delete it (it's equal to the one stored in the memento's undo) + m_numTiles--; + delete curTile; + } + + // Put a copy of the memento tile into our hashtable + curTile = new KisTile(*tile); + Q_CHECK_PTR(curTile); + + curTile->setNext(m_hashTable[i]); + m_hashTable[i] = curTile; + m_numTiles++; + updateExtent(curTile->getCol(), curTile->getRow()); + + tile = tile->getNext(); + } + } + + // Roll forward also means re-deleting the tiles that was deleted but restored by the undo + if (memento->tileListToDeleteOnRedo() != 0) { + deleteTiles(memento->tileListToDeleteOnRedo()); + } +} + +void KisTiledDataManager::deleteTiles(const KisMemento::DeletedTile *d) +{ + while (d) + { + TQ_UINT32 tileHash = calcTileHash(d->col(), d->row()); + KisTile *curTile = m_hashTable[tileHash]; + KisTile *preTile = 0; + while(curTile) + { + if(curTile->getRow() == d->row() && curTile->getCol() == d->col()) + { + break; + } + preTile = curTile; + curTile = curTile->getNext(); + } + if (curTile) { + // Remove it from our hashtable + if(preTile) + preTile->setNext(curTile->getNext()); + else + m_hashTable[tileHash] = curTile->getNext(); + + // And delete it (it's equal to the one stored in the memento's undo) + m_numTiles--; + delete curTile; + } + d = d->next(); + } + + recalculateExtent(); +} + +void KisTiledDataManager::ensureTileMementoed(TQ_INT32 col, TQ_INT32 row, TQ_UINT32 tileHash, const KisTile *refTile) +{ + if (refTile == 0) return; + //Q_ASSERT(refTile != 0); + + // Basically we search for the tile in the current memento, and if it's already there we do nothing, otherwise + // we make a copy of the tile and put it in the current memento + + if(!m_currentMemento) + return; + + KisTile *tile = m_currentMemento->m_hashTable[tileHash]; + while(tile != 0) + { + if(tile->getRow() == row && tile->getCol() == col) + break; + + tile = tile->getNext(); + } + if(tile) + return; // it has allready been stored + + tile = new KisTile(*refTile); + Q_CHECK_PTR(tile); + + tile->setNext(m_currentMemento->m_hashTable[tileHash]); + m_currentMemento->m_hashTable[tileHash] = tile; + m_currentMemento->m_numTiles++; +} + +void KisTiledDataManager::updateExtent(TQ_INT32 col, TQ_INT32 row) +{ + if(m_extentMinX > col * KisTile::WIDTH) + m_extentMinX = col * KisTile::WIDTH; + if(m_extentMaxX < (col+1) * KisTile::WIDTH - 1) + m_extentMaxX = (col+1) * KisTile::WIDTH - 1; + if(m_extentMinY > row * KisTile::HEIGHT) + m_extentMinY = row * KisTile::HEIGHT; + if(m_extentMaxY < (row+1) * KisTile::HEIGHT - 1) + m_extentMaxY = (row+1) * KisTile::HEIGHT - 1; +} + +KisTile *KisTiledDataManager::getTile(TQ_INT32 col, TQ_INT32 row, bool writeAccess) +{ + TQ_UINT32 tileHash = calcTileHash(col, row); + + // Lookup tile in hash table + KisTile *tile = m_hashTable[tileHash]; + while(tile != 0) + { + if(tile->getRow() == row && tile->getCol() == col) + break; + + tile = tile->getNext(); + } + + // Might not have been created yet + if(!tile) + { + if(writeAccess) + { + // Create a new tile + tile = new KisTile(*m_defaultTile, col, row); + Q_CHECK_PTR(tile); + + tile->setNext(m_hashTable[tileHash]); + m_hashTable[tileHash] = tile; + m_numTiles++; + updateExtent(col, row); + + if (m_currentMemento && !m_currentMemento->containsTile(col, row, tileHash)) { + m_currentMemento->addTileToDeleteOnUndo(col, row); + } + } + else + // If only read access then it's enough to share a default tile + tile = m_defaultTile; + } + + if(writeAccess) + ensureTileMementoed(col, row, tileHash, tile); + + return tile; +} + +KisTile *KisTiledDataManager::getOldTile(TQ_INT32 col, TQ_INT32 row, KisTile *def) +{ + KisTile *tile = 0; + + // Lookup tile in hash table of current memento + if (m_currentMemento) + { + if (!m_currentMemento->valid()) return def; + //Q_ASSERT(m_currentMemento->valid()); + + TQ_UINT32 tileHash = calcTileHash(col, row); + tile = m_currentMemento->m_hashTable[tileHash]; + while (tile != 0) + { + if (tile->getRow() == row && tile->getCol() == col) + break; + + tile = tile->getNext(); + } + } + + if (!tile) + tile = def; + + return tile; +} + +TQ_UINT8* KisTiledDataManager::pixelPtr(TQ_INT32 x, TQ_INT32 y, bool writable) +{ + // Ahem, this is a bit not as good. The point is, this function needs the tile data, + // but it might be swapped out. This code swaps it in, but at function exit it might + // be swapped out again! THIS MAKES THE RETURNED POINTER TQUITE VOLATILE + return pixelPtrSafe(x, y, writable) -> data(); +} + +KisTileDataWrapperSP KisTiledDataManager::pixelPtrSafe(TQ_INT32 x, TQ_INT32 y, bool writable) { + TQ_INT32 row = yToRow(y); + TQ_INT32 col = xToCol(x); + + // calc limits within the tile + TQ_INT32 yInTile = y - row * KisTile::HEIGHT; + TQ_INT32 xInTile = x - col * KisTile::WIDTH; + TQ_INT32 offset = m_pixelSize * (yInTile * KisTile::WIDTH + xInTile); + + KisTile *tile = getTile(col, row, writable); + + return new KisTileDataWrapper(tile, offset); +} + +const TQ_UINT8* KisTiledDataManager::pixel(TQ_INT32 x, TQ_INT32 y) +{ + return pixelPtr(x, y, false); +} + +TQ_UINT8* KisTiledDataManager::writablePixel(TQ_INT32 x, TQ_INT32 y) +{ + return pixelPtr(x, y, true); +} + +void KisTiledDataManager::setPixel(TQ_INT32 x, TQ_INT32 y, const TQ_UINT8 * data) +{ + TQ_UINT8 *pixel = pixelPtr(x, y, true); + memcpy(pixel, data, m_pixelSize); +} + + +void KisTiledDataManager::readBytes(TQ_UINT8 * data, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h) +{ + if (data == 0) return; + //Q_ASSERT(data != 0); + if (w < 0) + w = 0; + + if (h < 0) + h = 0; + + TQ_INT32 dstY = 0; + TQ_INT32 srcY = y; + TQ_INT32 rowsRemaining = h; + + while (rowsRemaining > 0) { + + TQ_INT32 dstX = 0; + TQ_INT32 srcX = x; + TQ_INT32 columnsRemaining = w; + TQ_INT32 numContiguousSrcRows = numContiguousRows(srcY, srcX, srcX + w - 1); + + TQ_INT32 rows = TQMIN(numContiguousSrcRows, rowsRemaining); + + while (columnsRemaining > 0) { + + TQ_INT32 numContiguousSrcColumns = numContiguousColumns(srcX, srcY, srcY + rows - 1); + + TQ_INT32 columns = TQMIN(numContiguousSrcColumns, columnsRemaining); + + KisTileDataWrapperSP tileData = pixelPtrSafe(srcX, srcY, false); + const TQ_UINT8 *srcData = tileData -> data(); + TQ_INT32 srcRowStride = rowStride(srcX, srcY); + + TQ_UINT8 *dstData = data + ((dstX + (dstY * w)) * m_pixelSize); + TQ_INT32 dstRowStride = w * m_pixelSize; + + for (TQ_INT32 row = 0; row < rows; row++) { + memcpy(dstData, srcData, columns * m_pixelSize); + dstData += dstRowStride; + srcData += srcRowStride; + } + + srcX += columns; + dstX += columns; + columnsRemaining -= columns; + } + + srcY += rows; + dstY += rows; + rowsRemaining -= rows; + } + +} + + +void KisTiledDataManager::writeBytes(const TQ_UINT8 * bytes, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h) +{ + if (bytes == 0) return; + //Q_ASSERT(bytes != 0); + + // XXX: Is this correct? + if (w < 0) + w = 0; + + if (h < 0) + h = 0; + + TQ_INT32 srcY = 0; + TQ_INT32 dstY = y; + TQ_INT32 rowsRemaining = h; + + while (rowsRemaining > 0) { + + TQ_INT32 srcX = 0; + TQ_INT32 dstX = x; + TQ_INT32 columnsRemaining = w; + TQ_INT32 numContiguousdstRows = numContiguousRows(dstY, dstX, dstX + w - 1); + + TQ_INT32 rows = TQMIN(numContiguousdstRows, rowsRemaining); + + while (columnsRemaining > 0) { + + TQ_INT32 numContiguousdstColumns = numContiguousColumns(dstX, dstY, dstY + rows - 1); + + TQ_INT32 columns = TQMIN(numContiguousdstColumns, columnsRemaining); + + //TQ_UINT8 *dstData = writablePixel(dstX, dstY); + KisTileDataWrapperSP tileData = pixelPtrSafe(dstX, dstY, true); + TQ_UINT8 *dstData = tileData->data(); + TQ_INT32 dstRowStride = rowStride(dstX, dstY); + + const TQ_UINT8 *srcData = bytes + ((srcX + (srcY * w)) * m_pixelSize); + TQ_INT32 srcRowStride = w * m_pixelSize; + + for (TQ_INT32 row = 0; row < rows; row++) { + memcpy(dstData, srcData, columns * m_pixelSize); + srcData += srcRowStride; + dstData += dstRowStride; + } + + dstX += columns; + srcX += columns; + columnsRemaining -= columns; + } + + dstY += rows; + srcY += rows; + rowsRemaining -= rows; + } +} + +TQ_INT32 KisTiledDataManager::numContiguousColumns(TQ_INT32 x, TQ_INT32 minY, TQ_INT32 maxY) +{ + TQ_INT32 numColumns; + + Q_UNUSED(minY); + Q_UNUSED(maxY); + + if (x >= 0) { + numColumns = KisTile::WIDTH - (x % KisTile::WIDTH); + } else { + numColumns = ((-x - 1) % KisTile::WIDTH) + 1; + } + + return numColumns; +} + +TQ_INT32 KisTiledDataManager::numContiguousRows(TQ_INT32 y, TQ_INT32 minX, TQ_INT32 maxX) +{ + TQ_INT32 numRows; + + Q_UNUSED(minX); + Q_UNUSED(maxX); + + if (y >= 0) { + numRows = KisTile::HEIGHT - (y % KisTile::HEIGHT); + } else { + numRows = ((-y - 1) % KisTile::HEIGHT) + 1; + } + + return numRows; +} + +TQ_INT32 KisTiledDataManager::rowStride(TQ_INT32 x, TQ_INT32 y) +{ + Q_UNUSED(x); + Q_UNUSED(y); + + return KisTile::WIDTH * m_pixelSize; +} + +TQ_INT32 KisTiledDataManager::numTiles(void) const +{ + return m_numTiles; +} + +KisTileDataWrapper::KisTileDataWrapper(KisTile* tile, TQ_INT32 offset) + : m_tile(tile), m_offset(offset) +{ + m_tile->addReader(); +} + +KisTileDataWrapper::~KisTileDataWrapper() +{ + m_tile->removeReader(); +} diff --git a/chalk/core/tiles/kis_tileddatamanager.h b/chalk/core/tiles/kis_tileddatamanager.h new file mode 100644 index 00000000..20d78085 --- /dev/null +++ b/chalk/core/tiles/kis_tileddatamanager.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TILEDDATAMANAGER_H_ +#define KIS_TILEDDATAMANAGER_H_ + +#include +#include + +#include + +#include "kis_tile_global.h" +#include "kis_tile.h" +#include "kis_memento.h" + +class KisTiledDataManager; +typedef KSharedPtr KisTiledDataManagerSP; + +class KisDataManager; +typedef KSharedPtr KisDataManagerSP; + +class KisTiledIterator; +class KisTiledRandomAccessor; +class KoStore; + +class KisTileDataWrapper : public KShared { + KisTile* m_tile; + TQ_INT32 m_offset; +public: + KisTileDataWrapper(KisTile* tile, TQ_INT32 offset); + virtual ~KisTileDataWrapper(); + TQ_UINT8* data() const { return m_tile->data() + m_offset; } +}; + +typedef KSharedPtr KisTileDataWrapperSP; + +/** + * KisTiledDataManager implements the interface that KisDataManager defines + * + * The interface definition is enforced by KisDataManager calling all the methods + * which must also be defined in KisTiledDataManager. It is not allowed to change the interface + * as other datamangers may also rely on the same interface. + * + * * Storing undo/redo data + * * Offering ordered and unordered iterators over rects of pixels + * * (eventually) efficiently loading and saving data in a format + * that may allow deferred loading. + * + * A datamanager knows nothing about the type of pixel data except + * how many TQ_UINT8's a single pixel takes. + */ + +class KisTiledDataManager : public KShared { + +protected: + KisTiledDataManager(TQ_UINT32 pixelSize, const TQ_UINT8 *defPixel); + ~KisTiledDataManager(); + KisTiledDataManager(const KisTiledDataManager &dm); + KisTiledDataManager & operator=(const KisTiledDataManager &dm); + + +protected: + // Allow the baseclass of iterators acces to the interior + // derived iterator classes must go through KisTiledIterator + friend class KisTiledIterator; + friend class KisTiledRandomAccessor; + +protected: + + void setDefaultPixel(const TQ_UINT8 *defPixel); + const TQ_UINT8 * defaultPixel() const { return m_defPixel;}; + + KisMementoSP getMemento(); + void rollback(KisMementoSP memento); + void rollforward(KisMementoSP memento); + + // For debugging use. + bool hasCurrentMemento() const { return m_currentMemento != 0; } + +protected: + /** + * Reads and writes the tiles from/onto a KoStore (which is simply a file within a zip file) + * + */ + bool write(KoStore *store); + bool read(KoStore *store); + +protected: + + TQ_UINT32 pixelSize(); + + void extent(TQ_INT32 &x, TQ_INT32 &y, TQ_INT32 &w, TQ_INT32 &h) const; + TQRect extent() const; + + void setExtent(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + +protected: + + void clear(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, TQ_UINT8 clearValue); + void clear(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, const TQ_UINT8 *clearPixel); + void clear(); + + +protected: + + void paste(KisDataManagerSP data, TQ_INT32 sx, TQ_INT32 sy, TQ_INT32 dx, TQ_INT32 dy, + TQ_INT32 w, TQ_INT32 h); + + +protected: + + + /** + * Get a read-only pointer to pixel (x, y). + */ + const TQ_UINT8* pixel(TQ_INT32 x, TQ_INT32 y); + + /** + * Get a read-write pointer to pixel (x, y). + */ + TQ_UINT8* writablePixel(TQ_INT32 x, TQ_INT32 y); + + /** + * write the specified data to x, y. There is no checking on pixelSize! + */ + void setPixel(TQ_INT32 x, TQ_INT32 y, const TQ_UINT8 * data); + + + /** + * Copy the bytes in the specified rect to a vector. The caller is responsible + * for managing the vector. + */ + void readBytes(TQ_UINT8 * bytes, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h); + /** + * Copy the bytes in the vector to the specified rect. If there are bytes left + * in the vector after filling the rect, they will be ignored. If there are + * not enough bytes, the rest of the rect will be filled with the default value + * given (by default, 0); + */ + void writeBytes(const TQ_UINT8 * bytes, + TQ_INT32 x, TQ_INT32 y, + TQ_INT32 w, TQ_INT32 h); + + /// Get the number of contiguous columns starting at x, valid for all values + /// of y between minY and maxY. + TQ_INT32 numContiguousColumns(TQ_INT32 x, TQ_INT32 minY, TQ_INT32 maxY); + + /// Get the number of contiguous rows starting at y, valid for all values + /// of x between minX and maxX. + TQ_INT32 numContiguousRows(TQ_INT32 y, TQ_INT32 minX, TQ_INT32 maxX); + + /// Get the row stride at pixel (x, y). This is the number of bytes to add to a + /// pointer to pixel (x, y) to access (x, y + 1). + TQ_INT32 rowStride(TQ_INT32 x, TQ_INT32 y); + + // For debugging use + TQ_INT32 numTiles() const; + +private: + + TQ_UINT32 m_pixelSize; + TQ_UINT32 m_numTiles; + KisTile *m_defaultTile; + KisTile **m_hashTable; + KisMementoSP m_currentMemento; + TQ_INT32 m_extentMinX; + TQ_INT32 m_extentMinY; + TQ_INT32 m_extentMaxX; + TQ_INT32 m_extentMaxY; + TQ_UINT8 *m_defPixel; + +private: + + void ensureTileMementoed(TQ_INT32 col, TQ_INT32 row, TQ_UINT32 tileHash, const KisTile *refTile); + KisTile *getOldTile(TQ_INT32 col, TQ_INT32 row, KisTile *def); + KisTile *getTile(TQ_INT32 col, TQ_INT32 row, bool writeAccess); + TQ_UINT32 calcTileHash(TQ_INT32 col, TQ_INT32 row); + void updateExtent(TQ_INT32 col, TQ_INT32 row); + void recalculateExtent(); + void deleteTiles(const KisMemento::DeletedTile *deletedTileList); + TQ_INT32 xToCol(TQ_INT32 x) const; + TQ_INT32 yToRow(TQ_INT32 y) const; + void getContiguousColumnsAndRows(TQ_INT32 x, TQ_INT32 y, TQ_INT32 *columns, TQ_INT32 *rows); + TQ_UINT8* pixelPtr(TQ_INT32 x, TQ_INT32 y, bool writable); + KisTileDataWrapperSP pixelPtrSafe(TQ_INT32 x, TQ_INT32 y, bool writable); +}; + + +inline TQ_UINT32 KisTiledDataManager::pixelSize() +{ + return m_pixelSize; +} + +inline TQ_INT32 KisTiledDataManager::xToCol(TQ_INT32 x) const +{ + if (x >= 0) { + return x / KisTile::WIDTH; + } else { + return -(((-x - 1) / KisTile::WIDTH) + 1); + } +} + +inline TQ_INT32 KisTiledDataManager::yToRow(TQ_INT32 y) const +{ + if (y >= 0) { + return y / KisTile::HEIGHT; + } else { + return -(((-y - 1) / KisTile::HEIGHT) + 1); + } +} + +// during development the following line helps to check the interface is correct +// it should be safe to keep it here even during normal compilation +#include "kis_datamanager.h" + +#endif // KIS_TILEDDATAMANAGER_H_ + diff --git a/chalk/core/tiles/kis_tiledhlineiterator.cc b/chalk/core/tiles/kis_tiledhlineiterator.cc new file mode 100644 index 00000000..cf023c1e --- /dev/null +++ b/chalk/core/tiles/kis_tiledhlineiterator.cc @@ -0,0 +1,213 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_tile_global.h" +#include "kis_tilediterator.h" + +KisTiledHLineIterator::KisTiledHLineIterator( KisTiledDataManager *ndevice, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable) : + KisTiledIterator(ndevice), + m_right(x+w-1), m_left(x) +{ + Q_ASSERT(ndevice != 0); + + m_writable = writable; + m_x = x; + m_y = y; + + // Find tile row,col matching x,y + m_row = yToRow(m_y); + m_leftCol = xToCol(m_x); + m_rightCol = xToCol(m_right); + m_col = m_leftCol; + + // calc limits within the tile + m_yInTile = m_y - m_row * KisTile::HEIGHT; + m_leftInTile = m_x - m_leftCol * KisTile::WIDTH; + + if(m_col == m_rightCol) + m_rightInTile = m_right - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; + + m_xInTile = m_leftInTile; + + fetchTileData(m_col, m_row); + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); +} + +KisTiledHLineIterator::KisTiledHLineIterator(const KisTiledHLineIterator& rhs) + : KisTiledIterator(rhs) +{ + if (this != &rhs) { + m_right = rhs.m_right; + m_left = rhs.m_left; + m_leftCol = rhs.m_leftCol; + m_rightCol = rhs.m_rightCol; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_leftInTile = rhs.m_leftInTile; + m_rightInTile = rhs.m_rightInTile; + } +} + +KisTiledHLineIterator& KisTiledHLineIterator::operator=(const KisTiledHLineIterator& rhs) +{ + if (this != &rhs) { + KisTiledIterator::operator=(rhs); + m_right = rhs.m_right; + m_left = rhs.m_left; + m_leftCol = rhs.m_leftCol; + m_rightCol = rhs.m_rightCol; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_leftInTile = rhs.m_leftInTile; + m_rightInTile = rhs.m_rightInTile; + } + return *this; +} + +KisTiledHLineIterator::~KisTiledHLineIterator( ) +{ +} + +KisTiledHLineIterator & KisTiledHLineIterator::operator ++ () +{ + if(m_xInTile >= m_rightInTile) + { + nextTile(); + fetchTileData(m_col, m_row); + m_xInTile =m_leftInTile; + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + } + else + { + m_xInTile++; + m_offset += m_pixelSize; + } + m_x++; + + return *this; +} + +void KisTiledHLineIterator::nextTile() +{ + if(m_col < m_rightCol) + { + m_col++; + m_leftInTile = 0; + + if(m_col == m_rightCol) + m_rightInTile = m_right - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; + } +} + +void KisTiledHLineIterator::prevTile() +{ + if(m_col > m_leftCol) + { + m_col--; + + if(m_col == m_leftCol) { + m_leftInTile = m_left - m_leftCol * KisTile::WIDTH; + } else { + m_leftInTile = 0; + } + // the only place this doesn't apply, is if we're in rightCol, and we can't go there + m_rightInTile = KisTile::WIDTH - 1; + } +} + +TQ_INT32 KisTiledHLineIterator::nConseqHPixels() const +{ + return m_rightInTile - m_xInTile + 1; +} + +KisTiledHLineIterator & KisTiledHLineIterator::operator+=(int n) +{ + // XXX what if outside the valid range of this iterator? + if(m_xInTile + n > m_rightInTile) + { + m_x += n; + m_col = xToCol(m_x); + m_xInTile = m_x - m_col * KisTile::WIDTH; + m_leftInTile = 0; + + if(m_col == m_rightCol) + m_rightInTile = m_right - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; + + fetchTileData(m_col, m_row); + } + else + { + m_xInTile += n; + m_x += n; + } + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + + return *this; +} + +KisTiledHLineIterator & KisTiledHLineIterator::operator -- () +{ + if(m_xInTile <= 0) + { + prevTile(); + fetchTileData(m_col, m_row); + m_xInTile = KisTile::WIDTH - 1; + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + } + else + { + m_xInTile--; + m_offset -= m_pixelSize; + } + m_x--; + + return *this; +} + +void KisTiledHLineIterator::nextRow() +{ + m_y++; + m_yInTile++; + m_x = m_left; + m_leftInTile = m_x - m_leftCol * KisTile::WIDTH; + m_xInTile = m_leftInTile; + if( m_yInTile >= KisTile::HEIGHT ) + { // Need a new row + m_yInTile = 0; + m_row++; + m_col = m_leftCol; + fetchTileData(m_col, m_row); + } else if( m_leftCol != m_col ) { + m_col = m_leftCol; + fetchTileData(m_col, m_row); + } + if(m_col == m_rightCol) + m_rightInTile = m_right - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); +} diff --git a/chalk/core/tiles/kis_tilediterator.cc b/chalk/core/tiles/kis_tilediterator.cc new file mode 100644 index 00000000..d6205f5a --- /dev/null +++ b/chalk/core/tiles/kis_tilediterator.cc @@ -0,0 +1,131 @@ +/* + * This file is part of the Chalk + * + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_tile_global.h" +#include "kis_tilediterator.h" + +KisTiledIterator::KisTiledIterator( KisTiledDataManager *ndevice) +{ + Q_ASSERT(ndevice != 0); + m_ktm = ndevice; + m_x = 0; + m_y = 0; + m_row = 0; + m_col = 0; + m_pixelSize = m_ktm->pixelSize(); + m_tile = 0; + m_oldTile = 0; +} + +KisTiledIterator::~KisTiledIterator( ) +{ + if (m_tile) + m_tile->removeReader(); + if (m_oldTile) + m_oldTile->removeReader(); +} + +KisTiledIterator::KisTiledIterator(const KisTiledIterator& rhs) + : KShared() +{ + if (this != &rhs) { + m_ktm = rhs.m_ktm; + m_pixelSize = rhs.m_pixelSize; + m_x = rhs.m_x; + m_y = rhs.m_y; + m_row = rhs.m_row; + m_col = rhs.m_col; + m_data = rhs.m_data; + m_oldData = rhs.m_oldData; + m_offset = rhs.m_offset; + m_tile = rhs.m_tile; + m_oldTile = rhs.m_oldTile; + m_writable = rhs.m_writable; + if (m_tile) + m_tile->addReader(); + } +} + +KisTiledIterator& KisTiledIterator::operator=(const KisTiledIterator& rhs) +{ + if (this != &rhs) { + if (m_tile) + m_tile->removeReader(); + if (m_oldTile) + m_oldTile->removeReader(); + m_ktm = rhs.m_ktm; + m_pixelSize = rhs.m_pixelSize; + m_x = rhs.m_x; + m_y = rhs.m_y; + m_row = rhs.m_row; + m_col = rhs.m_col; + m_data = rhs.m_data; + m_oldData = rhs.m_oldData; + m_offset = rhs.m_offset; + m_tile = rhs.m_tile; + m_oldTile = rhs.m_oldTile; + m_writable = rhs.m_writable; + if (m_tile) + m_tile->addReader(); + } + return *this; +} + +TQ_UINT8 * KisTiledIterator::rawData() const +{ + return m_data + m_offset; +} + + +const TQ_UINT8 * KisTiledIterator::oldRawData() const +{ +#ifdef DEBUG + // Warn if we're misusing oldRawData(). If there's no memento, oldRawData is the same + // as rawData(). + kdWarning(!m_ktm->hasCurrentMemento(), DBG_AREA_TILES) << "Accessing oldRawData() when no transaction is in progress.\n"; +#endif + return m_oldData + m_offset; +} + +void KisTiledIterator::fetchTileData(TQ_INT32 col, TQ_INT32 row) +{ + if (m_tile) + m_tile->removeReader(); + if (m_oldTile) + m_oldTile->removeReader(); + m_oldTile = 0; + + m_tile = m_ktm->getTile(col, row, m_writable); + + if (m_tile == 0) return; + //Q_ASSERT(m_tile != 0); + m_tile->addReader(); + + m_data = m_tile->data(); + if (m_data == 0) return; + + //Q_ASSERT(m_data != 0); + + // set old data but default to current value + m_oldTile = m_ktm->getOldTile(col, row, m_tile); + m_oldTile->addReader(); // Double locking in case m_oldTile==m_tile is no problem + m_oldData = m_oldTile->data(); +} diff --git a/chalk/core/tiles/kis_tilediterator.h b/chalk/core/tiles/kis_tilediterator.h new file mode 100644 index 00000000..958876cd --- /dev/null +++ b/chalk/core/tiles/kis_tilediterator.h @@ -0,0 +1,213 @@ +/* This file is part of the KDE project + * Copyright (c) 2004 Casper Boemann + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TILED_ITERATOR_H_ +#define KIS_TILED_ITERATOR_H_ + +#include + +#include + +#include +#include +#include +/** + * The KisIterator class iterates through the pixels of a KisPaintDevice hiding the tile structure + */ +class KRITACORE_EXPORT KisTiledIterator : public KShared { + +protected: + KisTiledDataManager *m_ktm; + TQ_INT32 m_pixelSize; // bytes per pixel + TQ_INT32 m_x; // current x position + TQ_INT32 m_y; // cirrent y position + TQ_INT32 m_row; // row in tilemgr + TQ_INT32 m_col; // col in tilemgr + TQ_UINT8 *m_data; + TQ_UINT8 *m_oldData; + TQ_INT32 m_offset; + KisTile *m_tile; + KisTile* m_oldTile; + bool m_writable; + +protected: + inline TQ_UINT32 xToCol(TQ_UINT32 x) const { if (m_ktm) return m_ktm->xToCol(x); else return 0; }; + inline TQ_UINT32 yToRow(TQ_UINT32 y) const { if (m_ktm) return m_ktm->yToRow(y); else return 0; }; + void fetchTileData(TQ_INT32 col, TQ_INT32 row); + +public: + KisTiledIterator( KisTiledDataManager *ktm); + KisTiledIterator(const KisTiledIterator&); + KisTiledIterator& operator=(const KisTiledIterator&); + ~KisTiledIterator(); + +public: + // current x position + TQ_INT32 x() const { return m_x; }; + + // cirrent y position + TQ_INT32 y() const { return m_y; }; + + /// Returns a pointer to the pixel data. Do NOT interpret the data - leave that to a colorstrategy + TQ_UINT8 *rawData() const; + + /// Returns a pointer to the pixel data as it was at the moment tof he last memento creation. + const TQ_UINT8 * oldRawData() const; +}; + +/** + * The KisRectIterator class iterates through the pixels of a rect in a KisPaintDevice hiding the + * tile structure + */ +class KRITACORE_EXPORT KisTiledRectIterator : public KisTiledIterator +{ + +public: + /// do not call constructor directly use factory method in KisDataManager instead. + KisTiledRectIterator( KisTiledDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h, bool writable); + KisTiledRectIterator(const KisTiledRectIterator&); + KisTiledRectIterator& operator=(const KisTiledRectIterator&); + ~KisTiledRectIterator(); + +public: + TQ_INT32 nConseqPixels() const; + + /// Advances a number of pixels until it reaches the end of the rect + KisTiledRectIterator & operator+=(int n); + + /// Advances one pixel. Going to the beginning of the next line when it reaches the end of a line + KisTiledRectIterator & operator++(); + + /// Goes back one pixel. Going to the end of the line above when it reaches the beginning of a line + //KisTiledRectIterator & operator--(); + + /// returns true when the iterator has reached the end + inline bool isDone() const { return m_beyondEnd; } + + +protected: + TQ_INT32 m_left; + TQ_INT32 m_top; + TQ_INT32 m_w; + TQ_INT32 m_h; + TQ_INT32 m_topRow; + TQ_INT32 m_bottomRow; + TQ_INT32 m_leftCol; + TQ_INT32 m_rightCol; + TQ_INT32 m_xInTile; + TQ_INT32 m_yInTile; + TQ_INT32 m_leftInTile; + TQ_INT32 m_rightInTile; + TQ_INT32 m_topInTile; + TQ_INT32 m_bottomInTile; + bool m_beyondEnd; + +private: + void nextTile(); +}; + +/** + * The KisHLineIterator class iterates through the pixels of a horizontal line in a KisPaintDevice hiding the + * tile structure + */ +class KRITACORE_EXPORT KisTiledHLineIterator : public KisTiledIterator +{ + +public: + /// do not call constructor directly use factory method in KisDataManager instead. + KisTiledHLineIterator( KisTiledDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, bool writable); + KisTiledHLineIterator(const KisTiledHLineIterator&); + KisTiledHLineIterator& operator=(const KisTiledHLineIterator&); + ~KisTiledHLineIterator(); + +public: + /// Advances one pixel. Going to the beginning of the next line when it reaches the end of a line + KisTiledHLineIterator & operator++(); + + /// Returns the number of consequtive horizontal pixels that we point at + /// This is useful for optimizing + TQ_INT32 nConseqHPixels() const; + + /// Advances a number of pixels until it reaches the end of the line + KisTiledHLineIterator & operator+=(int); + + /// Goes back one pixel. Going to the end of the line above when it reaches the beginning of a line + KisTiledHLineIterator & operator--(); + + /// returns true when the iterator has reached the end + bool isDone() const { return m_x > m_right; } + + /// increment to the next row and rewind to the begining + void nextRow(); + +protected: + TQ_INT32 m_right; + TQ_INT32 m_left; + TQ_INT32 m_leftCol; + TQ_INT32 m_rightCol; + TQ_INT32 m_xInTile; + TQ_INT32 m_yInTile; + TQ_INT32 m_leftInTile; + TQ_INT32 m_rightInTile; + +private: + void nextTile(); + void prevTile(); +}; + +/** + * The KisVLineIterator class iterates through the pixels of a vertical line in a KisPaintDevice hiding the + * tile structure + */ +class KRITACORE_EXPORT KisTiledVLineIterator : public KisTiledIterator +{ + +public: + /// do not call constructor directly use factory method in KisDataManager instead. + KisTiledVLineIterator( KisTiledDataManager *dm, TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable); + KisTiledVLineIterator(const KisTiledVLineIterator&); + KisTiledVLineIterator& operator=(const KisTiledVLineIterator&); + ~KisTiledVLineIterator(); + +public: + /// Advances one pixel. Going to the beginning of the next line when it reaches the end of a line + KisTiledVLineIterator & operator++(); + + /// Goes back one pixel. Going to the end of the line above when it reaches the beginning of a line + //KisTiledVLineIterator & operator--(); + + /// returns true when the iterator has reached the end + bool isDone() const { return m_y > m_bottom; } + + /// increment to the next column and rewind to the begining + void nextCol(); + +protected: + TQ_INT32 m_top; + TQ_INT32 m_bottom; + TQ_INT32 m_topRow; + TQ_INT32 m_bottomRow; + TQ_INT32 m_xInTile; + TQ_INT32 m_yInTile; + TQ_INT32 m_topInTile; + TQ_INT32 m_bottomInTile; + +private: + void nextTile(); +}; + +#endif // KIS_TILED_ITERATOR_H_ diff --git a/chalk/core/tiles/kis_tiledrectiterator.cc b/chalk/core/tiles/kis_tiledrectiterator.cc new file mode 100644 index 00000000..8f0f7ed1 --- /dev/null +++ b/chalk/core/tiles/kis_tiledrectiterator.cc @@ -0,0 +1,242 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_tile_global.h" +#include "kis_tilediterator.h" + +KisTiledRectIterator::KisTiledRectIterator( KisTiledDataManager *ndevice, TQ_INT32 nleft, + TQ_INT32 ntop, TQ_INT32 nw, TQ_INT32 nh, bool writable) : + KisTiledIterator(ndevice), + m_left(nleft), + m_top(ntop), + m_w(nw), + m_h(nh) +{ + + Q_ASSERT(ndevice != 0); + + m_writable = writable; + m_x = nleft; + m_y = ntop; + m_beyondEnd = (m_w == 0) || (m_h == 0); + + // Find tile row,col matching x,y + m_topRow = yToRow(m_y); + m_bottomRow = yToRow(m_y + m_h - 1); + m_leftCol = xToCol(m_x); + m_rightCol = xToCol(m_x + m_w - 1); + m_row = m_topRow; + m_col = m_leftCol; + + // calc limits within the tile + m_topInTile = m_top - m_topRow * KisTile::HEIGHT; + + if(m_row == m_bottomRow) + m_bottomInTile = m_top + m_h - 1 - m_bottomRow * KisTile::HEIGHT; + else + m_bottomInTile = KisTile::HEIGHT - 1; + + m_leftInTile = m_left - m_leftCol * KisTile::WIDTH; + + if(m_col == m_rightCol) + m_rightInTile = m_left + m_w - 1 - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; + + m_xInTile = m_leftInTile; + m_yInTile = m_topInTile; + + if( ! m_beyondEnd) + fetchTileData(m_col, m_row); + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); +} + +KisTiledRectIterator::KisTiledRectIterator(const KisTiledRectIterator& rhs) + : KisTiledIterator(rhs) +{ + if (this != &rhs) { + m_left = rhs.m_left; + m_top = rhs.m_top; + m_w = rhs.m_w; + m_h = rhs.m_h; + m_topRow = rhs.m_topRow; + m_bottomRow = rhs.m_bottomRow; + m_leftCol = rhs.m_leftCol; + m_rightCol = rhs.m_rightCol; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_leftInTile = rhs.m_leftInTile; + m_rightInTile = rhs.m_rightInTile; + m_topInTile = rhs.m_topInTile; + m_bottomInTile = rhs.m_bottomInTile; + m_beyondEnd = rhs.m_beyondEnd; + } +} + +KisTiledRectIterator& KisTiledRectIterator::operator=(const KisTiledRectIterator& rhs) +{ + if (this != &rhs) { + KisTiledIterator::operator=(rhs); + m_left = rhs.m_left; + m_top = rhs.m_top; + m_w = rhs.m_w; + m_h = rhs.m_h; + m_topRow = rhs.m_topRow; + m_bottomRow = rhs.m_bottomRow; + m_leftCol = rhs.m_leftCol; + m_rightCol = rhs.m_rightCol; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_leftInTile = rhs.m_leftInTile; + m_rightInTile = rhs.m_rightInTile; + m_topInTile = rhs.m_topInTile; + m_bottomInTile = rhs.m_bottomInTile; + m_beyondEnd = rhs.m_beyondEnd; + } + return *this; +} + +KisTiledRectIterator::~KisTiledRectIterator( ) +{ +} + +TQ_INT32 KisTiledRectIterator::nConseqPixels() const +{ + if(m_leftInTile || (m_rightInTile != KisTile::WIDTH - 1)) + return m_rightInTile - m_xInTile + 1; + else + return KisTile::WIDTH * (m_bottomInTile - m_yInTile + 1) - m_xInTile; +} + +KisTiledRectIterator & KisTiledRectIterator::operator+=(int n) +{ + int remainInTile; + + remainInTile= (m_bottomInTile - m_yInTile) * (m_rightInTile - m_leftInTile + 1); + remainInTile += m_rightInTile - m_xInTile + 1; + + // This while loop may not bet the fastest, but usually it's not entered more than once. + while(n >= remainInTile) + { + n -= remainInTile; + nextTile(); + if(m_beyondEnd) + return *this; + m_yInTile = m_topInTile; + m_xInTile = m_leftInTile; + remainInTile= (m_bottomInTile - m_yInTile) * (m_rightInTile - m_leftInTile + 1); + remainInTile += m_rightInTile - m_xInTile + 1; + } + + int lWidth = m_rightInTile - m_leftInTile + 1; + while(n >= lWidth) + { + n -= lWidth; + m_yInTile++; + } + m_xInTile += n; + m_x = m_col * KisTile::WIDTH + m_xInTile; + m_y = m_row * KisTile::HEIGHT + m_yInTile; + fetchTileData(m_col, m_row); + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + + return *this; +} + + +KisTiledRectIterator & KisTiledRectIterator::operator ++ () +{ + // advance through rect completing each tile before moving on + // as per excellent suggestion by Cyrille, avoiding excessive tile switching + if(m_xInTile >= m_rightInTile) + { + if (m_yInTile >= m_bottomInTile) + { + nextTile(); + if(m_beyondEnd) + return *this; + m_yInTile = m_topInTile; + m_x = m_col * KisTile::WIDTH + m_leftInTile; + m_y = m_row * KisTile::HEIGHT + m_topInTile; + fetchTileData(m_col, m_row); + } + else + { + m_x -= m_rightInTile - m_leftInTile; + m_y++; + m_yInTile++; + } + m_xInTile =m_leftInTile; + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + } + else + { + m_x++; + m_xInTile++; + m_offset += m_pixelSize; + } + return *this; +} + +void KisTiledRectIterator::nextTile() +{ + if(m_col >= m_rightCol) + { + // needs to switch row + if(m_row >= m_bottomRow) + m_beyondEnd = true; + else + { + m_col = m_leftCol; + m_row++; + // The row has now changed, so recalc vertical limits + if(m_row == m_topRow) + m_topInTile = m_top - m_topRow * KisTile::HEIGHT; + else + m_topInTile = 0; + + if(m_row == m_bottomRow) + m_bottomInTile = m_top + m_h - 1 - m_bottomRow * KisTile::HEIGHT; + else + m_bottomInTile = KisTile::HEIGHT - 1; + } + } + else + m_col++; + + // No matter what the column has now changed, so recalc horizontal limits + if(m_col == m_leftCol) + m_leftInTile = m_left - m_leftCol * KisTile::WIDTH; + else + m_leftInTile = 0; + + if(m_col == m_rightCol) + m_rightInTile = m_left + m_w - 1 - m_rightCol * KisTile::WIDTH; + else + m_rightInTile = KisTile::WIDTH - 1; +} + +/* +KisTiledRectIterator & KisTiledRectIterator::operator -- () +{ + return *this; +} +*/ diff --git a/chalk/core/tiles/kis_tiledvlineiterator.cc b/chalk/core/tiles/kis_tiledvlineiterator.cc new file mode 100644 index 00000000..0fe8514f --- /dev/null +++ b/chalk/core/tiles/kis_tiledvlineiterator.cc @@ -0,0 +1,154 @@ +/* + * This file is part of the Chalk + * + * Copyright (c) 2004 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include + +#include "kis_tile_global.h" +#include "kis_tilediterator.h" + +KisTiledVLineIterator::KisTiledVLineIterator( KisTiledDataManager *ndevice, TQ_INT32 x, TQ_INT32 y, TQ_INT32 h, bool writable) : + KisTiledIterator(ndevice), + m_bottom(y + h - 1) +{ + m_writable = writable; + m_top = y; + m_x = x; + m_y = y; + + // Find tile row,col matching x,y + m_col = xToCol(m_x); + m_topRow = yToRow(m_y); + m_bottomRow = yToRow(m_bottom); + m_row = m_topRow; + + // calc limits within the tile + m_xInTile = m_x - m_col * KisTile::WIDTH; + m_topInTile = m_y - m_topRow * KisTile::HEIGHT; + + if(m_row == m_bottomRow) + m_bottomInTile = m_bottom - m_bottomRow * KisTile::HEIGHT; + else + m_bottomInTile = KisTile::HEIGHT - 1; + + m_yInTile = m_topInTile; + + fetchTileData(m_col, m_row); + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); +} + +KisTiledVLineIterator::KisTiledVLineIterator(const KisTiledVLineIterator& rhs) + : KisTiledIterator(rhs) +{ + if (this != &rhs) { + m_top = rhs.m_top; + m_bottom = rhs.m_bottom; + m_topRow = rhs.m_topRow; + m_bottomRow = rhs.m_bottomRow; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_topInTile = rhs.m_topInTile; + m_bottomInTile = rhs.m_bottomInTile; + } +} + +KisTiledVLineIterator& KisTiledVLineIterator::operator=(const KisTiledVLineIterator& rhs) +{ + if (this != &rhs) { + KisTiledIterator::operator=(rhs); + + m_top = rhs.m_top; + m_bottom = rhs.m_bottom; + m_topRow = rhs.m_topRow; + m_bottomRow = rhs.m_bottomRow; + m_xInTile = rhs.m_xInTile; + m_yInTile = rhs.m_yInTile; + m_topInTile = rhs.m_topInTile; + m_bottomInTile = rhs.m_bottomInTile; + } + return *this; +} + +KisTiledVLineIterator::~KisTiledVLineIterator( ) +{ +} + +KisTiledVLineIterator & KisTiledVLineIterator::operator ++ () +{ + if(m_yInTile >= m_bottomInTile) + { + nextTile(); + fetchTileData(m_col, m_row); + m_yInTile =m_topInTile; + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); + } + else + { + m_yInTile++; + m_offset += m_pixelSize * KisTile::WIDTH; + } + m_y++; + + return *this; +} + +void KisTiledVLineIterator::nextTile() +{ + if(m_row < m_bottomRow) + { + m_row++; + m_topInTile = 0; + + if(m_row == m_bottomRow) + m_bottomInTile = m_bottom - m_bottomRow * KisTile::HEIGHT; + else + m_bottomInTile = KisTile::HEIGHT - 1; + } +} + +void KisTiledVLineIterator::nextCol() +{ + m_x++; + m_xInTile++; + m_y = m_top; + m_topInTile = m_y - m_topRow * KisTile::HEIGHT; + m_yInTile = m_topInTile; + if( m_xInTile >= KisTile::WIDTH ) + { // Need a new row + m_xInTile = 0; + m_col++; + m_row = m_topRow; + fetchTileData(m_col, m_row); + } else if( m_topRow != m_row ) { + m_row = m_topRow; + fetchTileData(m_col, m_row); + } + if(m_row == m_bottomRow) + m_bottomInTile = m_bottom - m_bottomRow * KisTile::HEIGHT; + else + m_bottomInTile = KisTile::HEIGHT - 1; + + m_offset = m_pixelSize * (m_yInTile * KisTile::WIDTH + m_xInTile); +} + +/* +KisTiledVLineIterator & KisTiledVLineIterator::operator -- () +{ + return *this; +} +*/ diff --git a/chalk/core/tiles/kis_tilemanager.cc b/chalk/core/tiles/kis_tilemanager.cc new file mode 100644 index 00000000..dc9811e9 --- /dev/null +++ b/chalk/core/tiles/kis_tilemanager.cc @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2005-2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "kis_tileddatamanager.h" +#include "kis_tile.h" +#include "kis_tilemanager.h" + +// Note: the cache file doesn't get deleted when we crash and so :( + +KisTileManager* KisTileManager::m_singleton = 0; + +static KStaticDeleter staticDeleter; + +KisTileManager::KisTileManager() { + + Q_ASSERT(KisTileManager::m_singleton == 0); + KisTileManager::m_singleton = this; + m_bytesInMem = 0; + m_bytesTotal = 0; + m_swapForbidden = false; + + // Hardcoded (at the moment only?): 4 pools of 1000 tiles each + m_tilesPerPool = 1000; + + m_pools = new TQ_UINT8*[4]; + m_poolPixelSizes = new TQ_INT32[4]; + m_poolFreeList = new PoolFreeList[4]; + for (int i = 0; i < 4; i++) { + m_pools[i] = 0; + m_poolPixelSizes[i] = 0; + m_poolFreeList[i] = PoolFreeList(); + } + m_currentInMem = 0; + + KConfig * cfg = KGlobal::config(); + cfg->setGroup(""); + m_maxInMem = cfg->readNumEntry("maxtilesinmem", 4000); + m_swappiness = cfg->readNumEntry("swappiness", 100); + + m_tileSize = KisTile::WIDTH * KisTile::HEIGHT; + m_freeLists.resize(8); + + counter = 0; + + m_poolMutex = new TQMutex(true); + m_swapMutex = new TQMutex(true); +} + +KisTileManager::~KisTileManager() { + if (!m_freeLists.empty()) { // See if there are any nonempty freelists + FreeListList::iterator listsIt = m_freeLists.begin(); + FreeListList::iterator listsEnd = m_freeLists.end(); + + while(listsIt != listsEnd) { + if ( ! (*listsIt).empty() ) { + FreeList::iterator it = (*listsIt).begin(); + FreeList::iterator end = (*listsIt).end(); + + while (it != end) { + delete *it; + ++it; + } + (*listsIt).clear(); + } + ++listsIt; + } + m_freeLists.clear(); + } + + for (FileList::iterator it = m_files.begin(); it != m_files.end(); ++it) { + (*it).tempFile->close(); + (*it).tempFile->unlink(); + delete (*it).tempFile; + } + + delete [] m_poolPixelSizes; + delete [] m_pools; + + delete m_poolMutex; + delete m_swapMutex; +} + +KisTileManager* KisTileManager::instance() +{ + if(KisTileManager::m_singleton == 0) { + staticDeleter.setObject(KisTileManager::m_singleton, new KisTileManager()); + Q_CHECK_PTR(KisTileManager::m_singleton); + } + return KisTileManager::m_singleton; +} + +void KisTileManager::registerTile(KisTile* tile) +{ + + m_swapMutex->lock(); + + TileInfo* info = new TileInfo(); + info->tile = tile; + info->inMem = true; + info->mmapped = false; + info->onFile = false; + info->file = 0; + info->filePos = 0; + info->size = tile->WIDTH * tile->HEIGHT * tile->m_pixelSize; + info->fsize = 0; // the size in the file + info->validNode = true; + + m_tileMap[tile] = info; + m_swappableList.push_back(info); + info->node = -- m_swappableList.end(); + + m_currentInMem++; + m_bytesTotal += info->size; + m_bytesInMem += info->size; + + doSwapping(); + + if (++counter % 50 == 0) + printInfo(); + + m_swapMutex->unlock(); +} + +void KisTileManager::deregisterTile(KisTile* tile) { + + m_swapMutex->lock(); + + if (!m_tileMap.tqcontains(tile)) { + m_swapMutex->unlock(); + return; + } + // Q_ASSERT(m_tileMap.tqcontains(tile)); + + TileInfo* info = m_tileMap[tile]; + + if (info->onFile) { // It was once mmapped + // To freelist + FreeInfo* freeInfo = new FreeInfo(); + freeInfo->file = info->file; + freeInfo->filePos = info->filePos; + freeInfo->size = info->fsize; + uint pixelSize = (info->size / m_tileSize); + + // It is still mmapped? + if (info->mmapped) { + // munmap it + munmap(info->tile->m_data, info->size); + m_bytesInMem -= info->size; + m_currentInMem--; + } + + if (m_freeLists.capacity() <= pixelSize) + m_freeLists.resize(pixelSize + 1); + m_freeLists[pixelSize].push_back(freeInfo); + + // the KisTile will attempt to delete its data. This is of course silly when + // it was mmapped. So change the m_data to NULL, which is safe to delete + tile->m_data = 0; + } else { + m_bytesInMem -= info->size; + m_currentInMem--; + } + + if (info->validNode) { + m_swappableList.erase(info->node); + info->validNode = false; + } + + m_bytesTotal -= info->size; + + delete info; + m_tileMap.erase(tile); + + doSwapping(); + + m_swapMutex->unlock(); +} + +void KisTileManager::ensureTileLoaded(const KisTile* tile) +{ + + m_swapMutex->lock(); + + TileInfo* info = m_tileMap[tile]; + if (info->validNode) { + m_swappableList.erase(info->node); + info->validNode = false; + } + + if (!info->inMem) { + fromSwap(info); + } + + m_swapMutex->unlock(); +} + +void KisTileManager::maySwapTile(const KisTile* tile) +{ + + m_swapMutex->lock(); + + TileInfo* info = m_tileMap[tile]; + m_swappableList.push_back(info); + info->validNode = true; + info->node = -- m_swappableList.end(); + + doSwapping(); + + m_swapMutex->unlock(); +} + +void KisTileManager::fromSwap(TileInfo* info) +{ + m_swapMutex->lock(); + + if (info->inMem) { + m_swapMutex->unlock(); + return; + } + + doSwapping(); + + Q_ASSERT(info->onFile); + Q_ASSERT(info->file); + Q_ASSERT(!info->mmapped); + + if (!chalkMmap(info->tile->m_data, 0, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, + info->file->handle(), info->filePos)) { + kdWarning() << "fromSwap failed!" << endl; + m_swapMutex->unlock(); + return; + } + + info->inMem = true; + info->mmapped = true; + + m_currentInMem++; + m_bytesInMem += info->size; + + m_swapMutex->unlock(); +} + +void KisTileManager::toSwap(TileInfo* info) { + m_swapMutex->lock(); + + //Q_ASSERT(info->inMem); + if (!info || !info->inMem) { + m_swapMutex->unlock(); + return; + } + + KisTile *tile = info->tile; + + if (!info->onFile) { + // This tile is not yet in the file. Save it there + uint pixelSize = (info->size / m_tileSize); + bool foundFree = false; + + if (m_freeLists.capacity() > pixelSize) { + if (!m_freeLists[pixelSize].empty()) { + // found one + FreeList::iterator it = m_freeLists[pixelSize].begin(); + + info->file = (*it)->file; + info->filePos = (*it)->filePos; + info->fsize = (*it)->size; + + delete *it; + m_freeLists[pixelSize].erase(it); + + foundFree = true; + } + } + + if (!foundFree) { // No position found or free, create a new + long pagesize = sysconf(_SC_PAGESIZE); + TempFile* tfile = 0; + if (m_files.empty() || m_files.back().fileSize >= MaxSwapFileSize) { + m_files.push_back(TempFile()); + tfile = &(m_files.back()); + tfile->tempFile = new KTempFile(); + tfile->fileSize = 0; + } else { + tfile = &(m_files.back()); + } + off_t newsize = tfile->fileSize + info->size; + newsize = newsize + newsize % pagesize; + + if (ftruncate(tfile->tempFile->handle(), newsize)) { + // XXX make these maybe i18n()able and in an error box, but then through + // some kind of proxy such that we don't pollute this with GUI code + kdWarning(DBG_AREA_TILES) << "Resizing the temporary swapfile failed!" << endl; + // Be somewhat pollite and try to figure out why it failed + switch (errno) { + case EIO: kdWarning(DBG_AREA_TILES) << "Error was E IO, " + << "possible reason is a disk error!" << endl; break; + case EINVAL: kdWarning(DBG_AREA_TILES) << "Error was E INVAL, " + << "possible reason is that you are using more memory than " + << "the filesystem or disk can handle" << endl; break; + default: kdWarning(DBG_AREA_TILES) << "Errno was: " << errno << endl; + } + kdWarning(DBG_AREA_TILES) << "The swapfile is: " << tfile->tempFile->name() << endl; + kdWarning(DBG_AREA_TILES) << "Will try to avoid using the swap any further" << endl; + + kdDebug(DBG_AREA_TILES) << "Failed ftruncate info: " + << "tried adding " << info->size << " bytes " + << "(rounded to pagesize: " << newsize << ") " + << "from a " << tfile->fileSize << " bytes file" << endl; + printInfo(); + + m_swapForbidden = true; + m_swapMutex->unlock(); + return; + } + + info->file = tfile->tempFile; + info->fsize = info->size; + info->filePos = tfile->fileSize; + tfile->fileSize = newsize; + } + + //memcpy(data, tile->m_data, info->size); + TQFile* file = info->file->file(); + if(!file) { + kdWarning() << "Opening the file as TQFile failed" << endl; + m_swapForbidden = true; + m_swapMutex->unlock(); + return; + } + + int fd = file->handle(); + TQ_UINT8* data = 0; + if (!chalkMmap(data, 0, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, info->filePos)) { + kdWarning() << "Initial mmap failed" << endl; + m_swapForbidden = true; + m_swapMutex->unlock(); + return; + } + + memcpy(data, info->tile->m_data, info->size); + munmap(data, info->size); + + m_poolMutex->lock(); + if (isPoolTile(tile->m_data, tile->m_pixelSize)) + reclaimTileToPool(tile->m_data, tile->m_pixelSize); + else + delete[] tile->m_data; + m_poolMutex->unlock(); + + tile->m_data = 0; + } else { + //madvise(info->tile->m_data, info->fsize, MADV_DONTNEED); + Q_ASSERT(info->mmapped); + + // munmap it + munmap(tile->m_data, info->size); + tile->m_data = 0; + } + + info->inMem = false; + info->mmapped = false; + info->onFile = true; + + m_currentInMem--; + m_bytesInMem -= info->size; + + m_swapMutex->unlock(); +} + +void KisTileManager::doSwapping() +{ + m_swapMutex->lock(); + + if (m_swapForbidden || m_currentInMem <= m_maxInMem) { + m_swapMutex->unlock(); + return; + } + +#if 1 // enable this to enable swapping + + TQ_UINT32 count = TQMIN(m_swappableList.size(), m_swappiness); + + for (TQ_UINT32 i = 0; i < count && !m_swapForbidden; i++) { + toSwap(m_swappableList.front()); + m_swappableList.front()->validNode = false; + m_swappableList.pop_front(); + } + +#endif + + m_swapMutex->unlock(); +} + +void KisTileManager::printInfo() +{ + kdDebug(DBG_AREA_TILES) << m_bytesInMem << " out of " << m_bytesTotal << " bytes in memory\n"; + kdDebug(DBG_AREA_TILES) << m_currentInMem << " out of " << m_tileMap.size() << " tiles in memory\n"; + kdDebug(DBG_AREA_TILES) << m_files.size() << " swap files in use" << endl; + kdDebug(DBG_AREA_TILES) << m_swappableList.size() << " elements in the swapable list\n"; + kdDebug(DBG_AREA_TILES) << "Freelists information\n"; + for (uint i = 0; i < m_freeLists.capacity(); i++) { + if ( ! m_freeLists[i].empty() ) { + kdDebug(DBG_AREA_TILES) << m_freeLists[i].size() + << " elements in the freelist for pixelsize " << i << "\n"; + } + } + kdDebug(DBG_AREA_TILES) << "Pool stats (" << m_tilesPerPool << " tiles per pool)" << endl; + for (int i = 0; i < 4; i++) { + if (m_pools[i]) { + kdDebug(DBG_AREA_TILES) << "Pool " << i << ": Freelist count: " << m_poolFreeList[i].count() + << ", pixelSize: " << m_poolPixelSizes[i] << endl; + } + } + if (m_swapForbidden) + kdDebug(DBG_AREA_TILES) << "Something was wrong with the swap, see above for details" << endl; + kdDebug(DBG_AREA_TILES) << endl; +} + +TQ_UINT8* KisTileManager::requestTileData(TQ_INT32 pixelSize) +{ + m_swapMutex->lock(); + + TQ_UINT8* data = findTileFor(pixelSize); + if ( data ) { + m_swapMutex->unlock(); + return data; + } + m_swapMutex->unlock(); + return new TQ_UINT8[m_tileSize * pixelSize]; +} + +void KisTileManager::dontNeedTileData(TQ_UINT8* data, TQ_INT32 pixelSize) +{ + m_poolMutex->lock(); + if (isPoolTile(data, pixelSize)) { + reclaimTileToPool(data, pixelSize); + } else + delete[] data; + m_poolMutex->unlock(); +} + +TQ_UINT8* KisTileManager::findTileFor(TQ_INT32 pixelSize) +{ + m_poolMutex->lock(); + + for (int i = 0; i < 4; i++) { + if (m_poolPixelSizes[i] == pixelSize) { + if (!m_poolFreeList[i].isEmpty()) { + TQ_UINT8* data = m_poolFreeList[i].front(); + m_poolFreeList[i].pop_front(); + m_poolMutex->unlock(); + return data; + } + } + if (m_pools[i] == 0) { + // allocate new pool + m_poolPixelSizes[i] = pixelSize; + m_pools[i] = new TQ_UINT8[pixelSize * m_tileSize * m_tilesPerPool]; + // j = 1 because we return the first element, so no need to add it to the freelist + for (int j = 1; j < m_tilesPerPool; j++) + m_poolFreeList[i].append(&m_pools[i][j * pixelSize * m_tileSize]); + m_poolMutex->unlock(); + return m_pools[i]; + } + } + + m_poolMutex->unlock(); + return 0; +} + +bool KisTileManager::isPoolTile(TQ_UINT8* data, TQ_INT32 pixelSize) { + + if (data == 0) + return false; + + m_poolMutex->lock(); + for (int i = 0; i < 4; i++) { + if (m_poolPixelSizes[i] == pixelSize) { + bool b = data >= m_pools[i] + && data < m_pools[i] + pixelSize * m_tileSize * m_tilesPerPool; + if (b) { + m_poolMutex->unlock(); + return true; + } + } + } + m_poolMutex->unlock(); + return false; +} + +void KisTileManager::reclaimTileToPool(TQ_UINT8* data, TQ_INT32 pixelSize) { + m_poolMutex->lock(); + for (int i = 0; i < 4; i++) { + if (m_poolPixelSizes[i] == pixelSize) + if (data >= m_pools[i] && data < m_pools[i] + pixelSize * m_tileSize * m_tilesPerPool) { + m_poolFreeList[i].append(data); + } + } + m_poolMutex->unlock(); +} + +void KisTileManager::configChanged() { + KConfig * cfg = KGlobal::config(); + cfg->setGroup(""); + m_maxInMem = cfg->readNumEntry("maxtilesinmem", 4000); + m_swappiness = cfg->readNumEntry("swappiness", 100); + + m_swapMutex->lock(); + doSwapping(); + m_swapMutex->unlock(); +} + +bool KisTileManager::chalkMmap(TQ_UINT8*& result, void *start, size_t length, + int prot, int flags, int fd, off_t offset) { + result = (TQ_UINT8*) mmap(start, length, prot, flags, fd, offset); + + // Same here for warning and GUI + if (result == (TQ_UINT8*)-1) { + kdWarning(DBG_AREA_TILES) << "mmap failed: errno is " << errno << "; we're probably going to crash very soon now...\n"; + + // Try to ignore what happened and carry on, but unlikely that we'll get + // much further, since the file resizing went OK and this is memory-related... + if (errno == ENOMEM) { + kdWarning(DBG_AREA_TILES) << "mmap failed with E NOMEM! This means that " + << "either there are no more memory mappings available for Chalk, " + << "or that there is no more memory available!" << endl; + } + + kdWarning(DBG_AREA_TILES) << "Trying to continue anyway (no guarantees)" << endl; + kdWarning(DBG_AREA_TILES) << "Will try to avoid using the swap any further" << endl; + kdDebug(DBG_AREA_TILES) << "Failed mmap info: " + << "tried mapping " << length << " bytes" << endl; + if (!m_files.empty()) { + kdDebug(DBG_AREA_TILES) << "Probably to a " << m_files.back().fileSize << " bytes file" << endl; + } + printInfo(); + + // Be nice + result = 0; + + return false; + } + + return true; +} diff --git a/chalk/core/tiles/kis_tilemanager.h b/chalk/core/tiles/kis_tilemanager.h new file mode 100644 index 00000000..d6886abe --- /dev/null +++ b/chalk/core/tiles/kis_tilemanager.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TILEMANAGER_H_ +#define KIS_TILEMANAGER_H_ + +#include + +#include +#include +#include +#include + +#include + +class KisTile; +class KisTiledDataManager; + +/** + * This class keeps has the intention to make certain tile-related operations faster or more + * efficient. It does this by keeping lots of info on KisTiles, and manages the way they are + * created, used, etc. + * It mainly does the following more visible things + * * provide a way to store tiles on disk to a swap file, to reduce memory usage + * * keep a list of previously swapped (but now unused) tiles, to reuse these when we want + * to swap new tiles. + * * tries to preallocate and recycle some tiles to make future allocations faster + * (not done yet) + */ +class KisTileManager { +public: + ~KisTileManager(); + static KisTileManager* instance(); + +public: // Tile management + void registerTile(KisTile* tile); + void deregisterTile(KisTile* tile); + // these can change the tile indirectly, though, through the actual swapping! + void ensureTileLoaded(const KisTile* tile); + void maySwapTile(const KisTile* tile); + +public: // Pool management + TQ_UINT8* requestTileData(TQ_INT32 pixelSize); + void dontNeedTileData(TQ_UINT8* data, TQ_INT32 pixelSize); + +public: // Configuration + void configChanged(); + +private: + KisTileManager(); + KisTileManager(KisTileManager&) {} + KisTileManager operator=(const KisTileManager&); + +private: + static KisTileManager *m_singleton; + + // For use when any swap-allocating function failed; the risk of swap allocating failing + // again is too big, and we'd clutter the logs with kdWarnings otherwise + bool m_swapForbidden; + + // This keeps track of open swap files, and their associated filesizes + struct TempFile { + KTempFile* tempFile; + off_t fileSize; + }; + // validNode says if you can swap it (true) or not (false) mmapped, if this tile + // currently is memory mapped. If it is false, but onFile, it is on disk, + // but not mmapped, and should be mapped! + // filePos is the position inside the file; size is the actual size, fsize is the size + // being used in the swap for this tile (may be larger!) + // The file points to 0 if it is not swapped, and to the relevant TempFile otherwise + struct TileInfo { KisTile *tile; KTempFile* file; off_t filePos; int size; int fsize; + TQValueList::iterator node; + bool inMem; bool onFile; bool mmapped; bool validNode; }; + typedef struct { KTempFile* file; off_t filePos; int size; } FreeInfo; + typedef TQMap TileMap; + typedef TQValueList TileList; + typedef TQValueList FreeList; + typedef TQValueVector FreeListList; + typedef TQValueList PoolFreeList; + typedef TQValueList FileList; + + + TileMap m_tileMap; + TileList m_swappableList; + FreeListList m_freeLists; + FileList m_files; + TQ_INT32 m_maxInMem; + TQ_INT32 m_currentInMem; + TQ_UINT32 m_swappiness; + TQ_INT32 m_tileSize; // size of a tile if it used 1 byte per pixel + unsigned long m_bytesInMem; + unsigned long m_bytesTotal; + + TQ_UINT8 **m_pools; + TQ_INT32 *m_poolPixelSizes; + TQ_INT32 m_tilesPerPool; + PoolFreeList *m_poolFreeList; + TQMutex * m_poolMutex; + TQMutex * m_swapMutex; + + // This is the constant that we will use to see if we want to add a new tempfile + // We use 1<<30 (one gigabyte) because aptqparently 32bit systems don't really like very + // large files. + static const long MaxSwapFileSize = 1<<30; // For debugging purposes: 1<<20 is a megabyte + + // debug + int counter; + +private: + void fromSwap(TileInfo* info); + void toSwap(TileInfo* info); + void doSwapping(); + void printInfo(); + TQ_UINT8* findTileFor(TQ_INT32 pixelSize); + bool isPoolTile(TQ_UINT8* data, TQ_INT32 pixelSize); + void reclaimTileToPool(TQ_UINT8* data, TQ_INT32 pixelSize); + + // Mmap wrapper that prints warnings on error. The result is stored in the *& result + // the return value is true on succes, false on failure. Other args as in man mmap + bool chalkMmap(TQ_UINT8*& result, void *start, size_t length, + int prot, int flags, int fd, off_t offset); +}; + +#endif // KIS_TILEMANAGER_H_ diff --git a/chalk/core/tiles/tests/Makefile.am b/chalk/core/tiles/tests/Makefile.am new file mode 100644 index 00000000..c546d7f5 --- /dev/null +++ b/chalk/core/tiles/tests/Makefile.am @@ -0,0 +1,15 @@ +AM_CPPFLAGS = -I$(srcdir)/../ \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../../../sdk \ + $(all_includes) + +# The check_ target makes sure we don't install the modules, +# $(KDE_CHECK_PLUGIN) assures a shared library is created. +check_LTLIBRARIES = kunittest_kis_tiled_data_tester.la +kunittest_kis_tiled_data_tester_la_SOURCES = kis_tiled_data_tester.cpp +kunittest_kis_tiled_data_tester_la_LIBADD = -lkunittest ../../../libchalkcommon.la +kunittest_kis_tiled_data_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries) + +check-local: kunittest_kis_tiled_data_tester.la + kunittestmodrunner + diff --git a/chalk/core/tiles/tests/kis_tiled_data_tester.cpp b/chalk/core/tiles/tests/kis_tiled_data_tester.cpp new file mode 100644 index 00000000..15d3e50b --- /dev/null +++ b/chalk/core/tiles/tests/kis_tiled_data_tester.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_tiled_data_tester.h" +#include "kis_datamanager.h" +#include "kis_global.h" + +using namespace KUnitTest; + +KUNITTEST_MODULE( kunittest_kis_tiled_data_tester, "Tiled Data Tester" ); +KUNITTEST_MODULE_REGISTER_TESTER( KisTiledDataTester ); + +#define TEST_PIXEL_SIZE 4 + +static TQ_UINT8 defaultPixel[TEST_PIXEL_SIZE] = {0, 0, 0, OPACITY_TRANSPARENT}; + +void KisTiledDataTester::allTests() +{ + KisDataManager *dm = new KisDataManager(TEST_PIXEL_SIZE, defaultPixel); + + TQ_INT32 extentX; + TQ_INT32 extentY; + TQ_INT32 extentWidth; + TQ_INT32 extentHeight; + + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentWidth, 0); + CHECK(extentHeight, 0); + + const TQ_UINT8 *readOnlyPixel = dm->pixel(KisTile::WIDTH/2, KisTile::HEIGHT/2); + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentWidth, 0); + CHECK(extentHeight, 0); + + TQ_UINT8 *writablePixel = dm->writablePixel(KisTile::WIDTH/2, KisTile::HEIGHT/2); + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentX, 0); + CHECK(extentY, 0); + CHECK(extentWidth, KisTile::WIDTH); + CHECK(extentHeight, KisTile::HEIGHT); + + writablePixel = dm->writablePixel(-KisTile::WIDTH, -KisTile::HEIGHT); + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentX, -KisTile::WIDTH); + CHECK(extentY, -KisTile::HEIGHT); + CHECK(extentWidth, 2*KisTile::WIDTH); + CHECK(extentHeight, 2*KisTile::HEIGHT); + + dm->clear(); + dm->extent(extentX, extentY, extentWidth, extentHeight); + CHECK(extentWidth, 0); + CHECK(extentHeight, 0); + + delete dm; +} + diff --git a/chalk/core/tiles/tests/kis_tiled_data_tester.h b/chalk/core/tiles/tests/kis_tiled_data_tester.h new file mode 100644 index 00000000..8a569d23 --- /dev/null +++ b/chalk/core/tiles/tests/kis_tiled_data_tester.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef KIS_TILED_DATA_TESTER_H +#define KIS_TILED_DATA_TESTER_H + +#include + +class KisTiledDataTester : public KUnitTest::Tester +{ +public: + void allTests(); +}; + +#endif + diff --git a/chalk/data/Makefile.am b/chalk/data/Makefile.am new file mode 100644 index 00000000..3c3e4d20 --- /dev/null +++ b/chalk/data/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = . brushes patterns gradients profiles palettes images +kde_servicetypes_DATA = \ + chalk_filter.desktop \ + chalk_paintop.desktop \ + chalk_plugin.desktop \ + chalk_tool.desktop + diff --git a/chalk/data/README b/chalk/data/README new file mode 100644 index 00000000..572ae1c5 --- /dev/null +++ b/chalk/data/README @@ -0,0 +1,13 @@ +Chalk is moving towards compatibility with the Gimp in the area of data +like patterns, brushes and gradients. All brushes, patterns etc. here +are taken from the Gimp CVS. + +This is the contents of the original authors file: + +This distribution of gimp-data is based on Frederico Mena's +gimp-data-0.99.11, which was based on Matt Hawkins +gimp-data-0.99.pre11-3.5, which was based on gimp-data-0.99.9 by Spencer +Kimball and Peter Mattis. + +Adrian Likins + diff --git a/chalk/data/brushes/10x10square.gbr b/chalk/data/brushes/10x10square.gbr new file mode 100644 index 00000000..d680172a Binary files /dev/null and b/chalk/data/brushes/10x10square.gbr differ diff --git a/chalk/data/brushes/10x10squareBlur.gbr b/chalk/data/brushes/10x10squareBlur.gbr new file mode 100644 index 00000000..9c8efe4e Binary files /dev/null and b/chalk/data/brushes/10x10squareBlur.gbr differ diff --git a/chalk/data/brushes/11circle.gbr b/chalk/data/brushes/11circle.gbr new file mode 100644 index 00000000..d843b1b1 Binary files /dev/null and b/chalk/data/brushes/11circle.gbr differ diff --git a/chalk/data/brushes/11fcircle.gbr b/chalk/data/brushes/11fcircle.gbr new file mode 100644 index 00000000..86bd9853 Binary files /dev/null and b/chalk/data/brushes/11fcircle.gbr differ diff --git a/chalk/data/brushes/13circle.gbr b/chalk/data/brushes/13circle.gbr new file mode 100644 index 00000000..ae4269fa Binary files /dev/null and b/chalk/data/brushes/13circle.gbr differ diff --git a/chalk/data/brushes/13fcircle.gbr b/chalk/data/brushes/13fcircle.gbr new file mode 100644 index 00000000..456d1056 Binary files /dev/null and b/chalk/data/brushes/13fcircle.gbr differ diff --git a/chalk/data/brushes/15circle.gbr b/chalk/data/brushes/15circle.gbr new file mode 100644 index 00000000..ce99d36e Binary files /dev/null and b/chalk/data/brushes/15circle.gbr differ diff --git a/chalk/data/brushes/15fcircle.gbr b/chalk/data/brushes/15fcircle.gbr new file mode 100644 index 00000000..c198ef4e Binary files /dev/null and b/chalk/data/brushes/15fcircle.gbr differ diff --git a/chalk/data/brushes/17circle.gbr b/chalk/data/brushes/17circle.gbr new file mode 100644 index 00000000..b063f54c Binary files /dev/null and b/chalk/data/brushes/17circle.gbr differ diff --git a/chalk/data/brushes/17fcircle.gbr b/chalk/data/brushes/17fcircle.gbr new file mode 100644 index 00000000..1a170560 Binary files /dev/null and b/chalk/data/brushes/17fcircle.gbr differ diff --git a/chalk/data/brushes/19circle.gbr b/chalk/data/brushes/19circle.gbr new file mode 100644 index 00000000..a0a581b2 Binary files /dev/null and b/chalk/data/brushes/19circle.gbr differ diff --git a/chalk/data/brushes/19fcircle.gbr b/chalk/data/brushes/19fcircle.gbr new file mode 100644 index 00000000..6418446d Binary files /dev/null and b/chalk/data/brushes/19fcircle.gbr differ diff --git a/chalk/data/brushes/1circle.gbr b/chalk/data/brushes/1circle.gbr new file mode 100644 index 00000000..8c81f6bf Binary files /dev/null and b/chalk/data/brushes/1circle.gbr differ diff --git a/chalk/data/brushes/20x20square.gbr b/chalk/data/brushes/20x20square.gbr new file mode 100644 index 00000000..011259f0 Binary files /dev/null and b/chalk/data/brushes/20x20square.gbr differ diff --git a/chalk/data/brushes/20x20squareBlur.gbr b/chalk/data/brushes/20x20squareBlur.gbr new file mode 100644 index 00000000..fd3df8ed Binary files /dev/null and b/chalk/data/brushes/20x20squareBlur.gbr differ diff --git a/chalk/data/brushes/3circle.gbr b/chalk/data/brushes/3circle.gbr new file mode 100644 index 00000000..ddddec9f Binary files /dev/null and b/chalk/data/brushes/3circle.gbr differ diff --git a/chalk/data/brushes/3fcircle.gbr b/chalk/data/brushes/3fcircle.gbr new file mode 100644 index 00000000..7a07a1af Binary files /dev/null and b/chalk/data/brushes/3fcircle.gbr differ diff --git a/chalk/data/brushes/5circle.gbr b/chalk/data/brushes/5circle.gbr new file mode 100644 index 00000000..c910e294 Binary files /dev/null and b/chalk/data/brushes/5circle.gbr differ diff --git a/chalk/data/brushes/5fcircle.gbr b/chalk/data/brushes/5fcircle.gbr new file mode 100644 index 00000000..83d50423 Binary files /dev/null and b/chalk/data/brushes/5fcircle.gbr differ diff --git a/chalk/data/brushes/5x5square.gbr b/chalk/data/brushes/5x5square.gbr new file mode 100644 index 00000000..921b4531 Binary files /dev/null and b/chalk/data/brushes/5x5square.gbr differ diff --git a/chalk/data/brushes/5x5squareBlur.gbr b/chalk/data/brushes/5x5squareBlur.gbr new file mode 100644 index 00000000..97ae6a03 Binary files /dev/null and b/chalk/data/brushes/5x5squareBlur.gbr differ diff --git a/chalk/data/brushes/7circle.gbr b/chalk/data/brushes/7circle.gbr new file mode 100644 index 00000000..45ea2103 Binary files /dev/null and b/chalk/data/brushes/7circle.gbr differ diff --git a/chalk/data/brushes/7fcircle.gbr b/chalk/data/brushes/7fcircle.gbr new file mode 100644 index 00000000..b069c6f8 Binary files /dev/null and b/chalk/data/brushes/7fcircle.gbr differ diff --git a/chalk/data/brushes/9circle.gbr b/chalk/data/brushes/9circle.gbr new file mode 100644 index 00000000..369d85cc Binary files /dev/null and b/chalk/data/brushes/9circle.gbr differ diff --git a/chalk/data/brushes/9fcircle.gbr b/chalk/data/brushes/9fcircle.gbr new file mode 100644 index 00000000..6e1c414c Binary files /dev/null and b/chalk/data/brushes/9fcircle.gbr differ diff --git a/chalk/data/brushes/BRUSHES.README b/chalk/data/brushes/BRUSHES.README new file mode 100644 index 00000000..c7193aac --- /dev/null +++ b/chalk/data/brushes/BRUSHES.README @@ -0,0 +1,19 @@ + CURSOR BRUSHES + -------------- + + These brushes are for use with The GIMP. + + Copy them to your ~/.gimp-version/brushes directory to + make them available to The GIMP. + Click the Refresh button in the Brushes Dialog to make + them available without restarting The GIMP. + + The brushes are licensed under the GNU General Public License + as published by the Free Software Foundation; either + version 2 of the License, or any later version. + + For more details see the file COPYING. + + --------------------------------------------------------- + + Natalie nat@switch.demon.nl diff --git a/chalk/data/brushes/COPYING b/chalk/data/brushes/COPYING new file mode 100644 index 00000000..c13faf0d --- /dev/null +++ b/chalk/data/brushes/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/chalk/data/brushes/DStar11.gbr b/chalk/data/brushes/DStar11.gbr new file mode 100644 index 00000000..cab5714a Binary files /dev/null and b/chalk/data/brushes/DStar11.gbr differ diff --git a/chalk/data/brushes/DStar17.gbr b/chalk/data/brushes/DStar17.gbr new file mode 100644 index 00000000..496919cb Binary files /dev/null and b/chalk/data/brushes/DStar17.gbr differ diff --git a/chalk/data/brushes/DStar25.gbr b/chalk/data/brushes/DStar25.gbr new file mode 100644 index 00000000..29f8fb25 Binary files /dev/null and b/chalk/data/brushes/DStar25.gbr differ diff --git a/chalk/data/brushes/Makefile.am b/chalk/data/brushes/Makefile.am new file mode 100644 index 00000000..d65b044e --- /dev/null +++ b/chalk/data/brushes/Makefile.am @@ -0,0 +1,69 @@ +chalkbrushesdir = $(prefix)/share/apps/chalk/brushes + +chalkbrushes_DATA = \ + 10x10squareBlur.gbr \ + 10x10square.gbr \ + 11circle.gbr \ + 11fcircle.gbr \ + 13circle.gbr \ + 13fcircle.gbr \ + 15circle.gbr \ + 15fcircle.gbr \ + 17circle.gbr \ + 17fcircle.gbr \ + 19circle.gbr \ + 19fcircle.gbr \ + 1circle.gbr \ + 20x20squareBlur.gbr \ + 20x20square.gbr \ + 3circle.gbr \ + 3fcircle.gbr \ + 5circle.gbr \ + 5fcircle.gbr \ + 5x5squareBlur.gbr \ + 5x5square.gbr \ + 7circle.gbr \ + 7fcircle.gbr \ + 9circle.gbr \ + 9fcircle.gbr \ + callig1.gbr \ + callig2.gbr \ + callig3.gbr \ + callig4.gbr \ + confetti.gbr \ + confetti.gih \ + cursor_big_lb.gbr \ + cursor_big_lw.gbr \ + cursor_big_rb.gbr \ + cursor_big_rw.gbr \ + cursor.gbr \ + cursor_lw.gbr \ + cursor_resize_diag_1.gbr \ + cursor_resize_diag_2.gbr \ + cursor_resize_hor.gbr \ + cursor_resize_vert.gbr \ + cursor_rw.gbr \ + cursor_small_lb.gbr \ + cursor_small_lw.gbr \ + cursor_small_rb.gbr \ + cursor_small_rw.gbr \ + cursor_tiny_lw.gbr \ + cursor_tiny_rw.gbr \ + cursor_up.gbr \ + DStar11.gbr \ + DStar17.gbr \ + DStar25.gbr \ + dunes.gbr \ + feltpen.gih \ + galaxy_big.gbr \ + galaxy.gbr \ + galaxy_small.gbr \ + hsparks.gih \ + Makefile.am \ + Makefile.in \ + pepper.gbr \ + pixel.gbr \ + SketchBrush-16.gih \ + SketchBrush-32.gih \ + SketchBrush-64.gih \ + vine.gih diff --git a/chalk/data/brushes/SketchBrush-16.gih b/chalk/data/brushes/SketchBrush-16.gih new file mode 100644 index 00000000..32c76dec Binary files /dev/null and b/chalk/data/brushes/SketchBrush-16.gih differ diff --git a/chalk/data/brushes/SketchBrush-32.gih b/chalk/data/brushes/SketchBrush-32.gih new file mode 100644 index 00000000..6fae028d Binary files /dev/null and b/chalk/data/brushes/SketchBrush-32.gih differ diff --git a/chalk/data/brushes/SketchBrush-64.gih b/chalk/data/brushes/SketchBrush-64.gih new file mode 100644 index 00000000..8dbff8fd Binary files /dev/null and b/chalk/data/brushes/SketchBrush-64.gih differ diff --git a/chalk/data/brushes/callig1.gbr b/chalk/data/brushes/callig1.gbr new file mode 100644 index 00000000..ef3bfa2b Binary files /dev/null and b/chalk/data/brushes/callig1.gbr differ diff --git a/chalk/data/brushes/callig2.gbr b/chalk/data/brushes/callig2.gbr new file mode 100644 index 00000000..d607dd57 Binary files /dev/null and b/chalk/data/brushes/callig2.gbr differ diff --git a/chalk/data/brushes/callig3.gbr b/chalk/data/brushes/callig3.gbr new file mode 100644 index 00000000..d84c256c Binary files /dev/null and b/chalk/data/brushes/callig3.gbr differ diff --git a/chalk/data/brushes/callig4.gbr b/chalk/data/brushes/callig4.gbr new file mode 100644 index 00000000..8be1bc1d Binary files /dev/null and b/chalk/data/brushes/callig4.gbr differ diff --git a/chalk/data/brushes/confetti.gbr b/chalk/data/brushes/confetti.gbr new file mode 100644 index 00000000..d7ba158e Binary files /dev/null and b/chalk/data/brushes/confetti.gbr differ diff --git a/chalk/data/brushes/confetti.gih b/chalk/data/brushes/confetti.gih new file mode 100644 index 00000000..dfa9cc88 Binary files /dev/null and b/chalk/data/brushes/confetti.gih differ diff --git a/chalk/data/brushes/cursor.gbr b/chalk/data/brushes/cursor.gbr new file mode 100644 index 00000000..80be888e Binary files /dev/null and b/chalk/data/brushes/cursor.gbr differ diff --git a/chalk/data/brushes/cursor_big_lb.gbr b/chalk/data/brushes/cursor_big_lb.gbr new file mode 100644 index 00000000..be0dab11 Binary files /dev/null and b/chalk/data/brushes/cursor_big_lb.gbr differ diff --git a/chalk/data/brushes/cursor_big_lw.gbr b/chalk/data/brushes/cursor_big_lw.gbr new file mode 100644 index 00000000..f9253911 Binary files /dev/null and b/chalk/data/brushes/cursor_big_lw.gbr differ diff --git a/chalk/data/brushes/cursor_big_rb.gbr b/chalk/data/brushes/cursor_big_rb.gbr new file mode 100644 index 00000000..09c356ae Binary files /dev/null and b/chalk/data/brushes/cursor_big_rb.gbr differ diff --git a/chalk/data/brushes/cursor_big_rw.gbr b/chalk/data/brushes/cursor_big_rw.gbr new file mode 100644 index 00000000..53e64f93 Binary files /dev/null and b/chalk/data/brushes/cursor_big_rw.gbr differ diff --git a/chalk/data/brushes/cursor_lw.gbr b/chalk/data/brushes/cursor_lw.gbr new file mode 100644 index 00000000..be41e431 Binary files /dev/null and b/chalk/data/brushes/cursor_lw.gbr differ diff --git a/chalk/data/brushes/cursor_resize_diag_1.gbr b/chalk/data/brushes/cursor_resize_diag_1.gbr new file mode 100644 index 00000000..d3110164 Binary files /dev/null and b/chalk/data/brushes/cursor_resize_diag_1.gbr differ diff --git a/chalk/data/brushes/cursor_resize_diag_2.gbr b/chalk/data/brushes/cursor_resize_diag_2.gbr new file mode 100644 index 00000000..e4be9425 Binary files /dev/null and b/chalk/data/brushes/cursor_resize_diag_2.gbr differ diff --git a/chalk/data/brushes/cursor_resize_hor.gbr b/chalk/data/brushes/cursor_resize_hor.gbr new file mode 100644 index 00000000..fbbbfed8 Binary files /dev/null and b/chalk/data/brushes/cursor_resize_hor.gbr differ diff --git a/chalk/data/brushes/cursor_resize_vert.gbr b/chalk/data/brushes/cursor_resize_vert.gbr new file mode 100644 index 00000000..941eb615 Binary files /dev/null and b/chalk/data/brushes/cursor_resize_vert.gbr differ diff --git a/chalk/data/brushes/cursor_rw.gbr b/chalk/data/brushes/cursor_rw.gbr new file mode 100644 index 00000000..50f2bd1a Binary files /dev/null and b/chalk/data/brushes/cursor_rw.gbr differ diff --git a/chalk/data/brushes/cursor_small_lb.gbr b/chalk/data/brushes/cursor_small_lb.gbr new file mode 100644 index 00000000..b64e1371 Binary files /dev/null and b/chalk/data/brushes/cursor_small_lb.gbr differ diff --git a/chalk/data/brushes/cursor_small_lw.gbr b/chalk/data/brushes/cursor_small_lw.gbr new file mode 100644 index 00000000..abdcaacd Binary files /dev/null and b/chalk/data/brushes/cursor_small_lw.gbr differ diff --git a/chalk/data/brushes/cursor_small_rb.gbr b/chalk/data/brushes/cursor_small_rb.gbr new file mode 100644 index 00000000..90058590 Binary files /dev/null and b/chalk/data/brushes/cursor_small_rb.gbr differ diff --git a/chalk/data/brushes/cursor_small_rw.gbr b/chalk/data/brushes/cursor_small_rw.gbr new file mode 100644 index 00000000..5b928fbe Binary files /dev/null and b/chalk/data/brushes/cursor_small_rw.gbr differ diff --git a/chalk/data/brushes/cursor_tiny_lw.gbr b/chalk/data/brushes/cursor_tiny_lw.gbr new file mode 100644 index 00000000..d2b67eb9 Binary files /dev/null and b/chalk/data/brushes/cursor_tiny_lw.gbr differ diff --git a/chalk/data/brushes/cursor_tiny_rw.gbr b/chalk/data/brushes/cursor_tiny_rw.gbr new file mode 100644 index 00000000..a8293bf8 Binary files /dev/null and b/chalk/data/brushes/cursor_tiny_rw.gbr differ diff --git a/chalk/data/brushes/cursor_up.gbr b/chalk/data/brushes/cursor_up.gbr new file mode 100644 index 00000000..edb8ebec Binary files /dev/null and b/chalk/data/brushes/cursor_up.gbr differ diff --git a/chalk/data/brushes/dunes.gbr b/chalk/data/brushes/dunes.gbr new file mode 100644 index 00000000..fc7eed23 Binary files /dev/null and b/chalk/data/brushes/dunes.gbr differ diff --git a/chalk/data/brushes/feltpen.gih b/chalk/data/brushes/feltpen.gih new file mode 100644 index 00000000..37d9c771 Binary files /dev/null and b/chalk/data/brushes/feltpen.gih differ diff --git a/chalk/data/brushes/galaxy.gbr b/chalk/data/brushes/galaxy.gbr new file mode 100644 index 00000000..20a13c26 Binary files /dev/null and b/chalk/data/brushes/galaxy.gbr differ diff --git a/chalk/data/brushes/galaxy_big.gbr b/chalk/data/brushes/galaxy_big.gbr new file mode 100644 index 00000000..dbcc5689 Binary files /dev/null and b/chalk/data/brushes/galaxy_big.gbr differ diff --git a/chalk/data/brushes/galaxy_small.gbr b/chalk/data/brushes/galaxy_small.gbr new file mode 100644 index 00000000..d7f3da57 Binary files /dev/null and b/chalk/data/brushes/galaxy_small.gbr differ diff --git a/chalk/data/brushes/hsparks.gih b/chalk/data/brushes/hsparks.gih new file mode 100644 index 00000000..99f75cd9 Binary files /dev/null and b/chalk/data/brushes/hsparks.gih differ diff --git a/chalk/data/brushes/pepper.gbr b/chalk/data/brushes/pepper.gbr new file mode 100644 index 00000000..34861d14 Binary files /dev/null and b/chalk/data/brushes/pepper.gbr differ diff --git a/chalk/data/brushes/pixel.gbr b/chalk/data/brushes/pixel.gbr new file mode 100644 index 00000000..9de22c12 Binary files /dev/null and b/chalk/data/brushes/pixel.gbr differ diff --git a/chalk/data/brushes/vine.gih b/chalk/data/brushes/vine.gih new file mode 100644 index 00000000..65acae04 Binary files /dev/null and b/chalk/data/brushes/vine.gih differ diff --git a/chalk/data/chalk_filter.desktop b/chalk/data/chalk_filter.desktop new file mode 100644 index 00000000..c865db10 --- /dev/null +++ b/chalk/data/chalk_filter.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Chalk/Filter +Comment=Filter plugin for Chalk +Comment[bg]=Приставка за филтриране за Chalk +Comment[ca]=Connector de filtre per a Chalk +Comment[da]=Plugin med filter for Chalk +Comment[de]=Filter-Modul für Chalk +Comment[el]=Πρόσθετο φίλτρου για το Chalk +Comment[eo]=Filtrilkromaĵo por Chalk +Comment[es]=Complemento de filtrado para Chalk +Comment[et]=Chalk filtriplugin +Comment[eu]=Chalk-ren iragazkia +Comment[fa]=وصلۀ پالایه برای Chalk +Comment[fi]=Suodinliitännäinen Chalklle +Comment[fr]=Module de filtres de Chalk +Comment[fy]=Filterplugin foar Chalk +Comment[gl]=Plugin de filtro para Chalk +Comment[he]=תוסף סינון של Chalk +Comment[hu]=Szűrőmodul a Kritához +Comment[is]=Síu íforrit fyrir Chalk +Comment[it]=Plugin di filtro per Chalk +Comment[ja]=Chalk フィルタプラグイン +Comment[km]=កម្មវិធី​ជំនួយ​តម្រង​សម្រាប់ Chalk +Comment[lv]=Chalk filtra spraudnis +Comment[ms]=Plugin penapis Chalk +Comment[nb]=Filter-programtillegg for Chalk +Comment[nds]=Filtermoduul för Chalk +Comment[ne]=क्रिताका लागि फिल्टर प्लगइन +Comment[nl]=Filterplugin voor Chalk +Comment[nn]=Chalk-programtillegg for filter +Comment[pl]=Wtyczka filtrów dla Chalk +Comment[pt]='Plugin' de filtragem do Chalk +Comment[pt_BR]=Plugin de filtro para o Chalk +Comment[ru]=Фильтр Chalk +Comment[sk]=Filter modul pre Chalk +Comment[sl]=Vstavek za filtriranje za Krito +Comment[sr]=Филтерски прикључак за Chalk-у +Comment[sr@Latn]=Filterski priključak za Chalk-u +Comment[sv]=Insticksprogram med filter för Chalk +Comment[uk]=Втулок фільтра для Chalk +Comment[uz]=Chalk uchun filter plagini +Comment[uz@cyrillic]=Chalk учун филтер плагини +Comment[zh_CN]=Chalk 过滤器插件 +Comment[zh_TW]=Chalk 的過濾器外掛程式 +[PropertyDef::X-Chalk-Version] +Type=int diff --git a/chalk/data/chalk_paintop.desktop b/chalk/data/chalk_paintop.desktop new file mode 100644 index 00000000..1dd6f0bd --- /dev/null +++ b/chalk/data/chalk_paintop.desktop @@ -0,0 +1,41 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Chalk/Paintop +Comment=Paint operation plugin for Chalk +Comment[bg]=Приставка за рисуване за Chalk +Comment[ca]=Connector d'operació de pintura per a Chalk +Comment[da]=Plugin med malehandlinger for Chalk +Comment[de]=Maloperation-Modul für Chalk +Comment[el]=Πρόσθετο λειτουργίας ζωγραφικής για το Chalk +Comment[eo]=Pentrooperacia kromaĵo por Chalk +Comment[es]=Complemento de operación de pintura para Chalk +Comment[et]=Chalk joonistamistoimingute plugin +Comment[fa]=وصلۀ عمل رنگ‌آمیزی برای Chalk +Comment[fi]=Chalkn maalaustoimintoliitännäinen +Comment[fr]=Module d'opération pour Chalk +Comment[fy]=Ferfhannelingsplugin foar Chalk +Comment[gl]=Plugin de pintar para Chalk +Comment[he]=תוסף פעולת צביעה של Chalk +Comment[hu]=Festőmodul a Kritához +Comment[is]=Málunar íforrit fyrir Chalk +Comment[it]=Plugin per l'operazione di disegno per Chalk +Comment[ja]=Chalk 描画操作プラグイン +Comment[km]=កម្មវិធី​ជំនួយ​ក្នុង​ការ​គូរ សម្រាប់ Chalk +Comment[nb]=Chalk-programtillegg for male-handlinger +Comment[nds]=Maalmoduul för Chalk +Comment[ne]=क्रिताका लागि पेन्ट अपरेसन प्लगइन +Comment[nl]=Verfverrichtingplugin voor Chalk +Comment[pl]=Wtyczka operacji malowania dla Chalk +Comment[pt]='Plugin' de operações de pintura do Chalk +Comment[pt_BR]=Plugin de operações de pintura do Chalk +Comment[ru]=Инструмент рисования Chalk +Comment[sk]=Kresliaci modul pre Chalk +Comment[sl]=Vstavek s slikarskim postopkom za Krito +Comment[sr]=Прикључак за сликарске операције за Chalk-у +Comment[sr@Latn]=Priključak za slikarske operacije za Chalk-u +Comment[sv]=Insticksprogram med målningsåtgärder för Chalk +Comment[uk]=Втулок малювання для Chalk +Comment[zh_CN]=Chalk 的绘画操作插件 +Comment[zh_TW]=Chalk 的繪畫操作外掛程式 +[PropertyDef::X-Chalk-Version] +Type=int diff --git a/chalk/data/chalk_plugin.desktop b/chalk/data/chalk_plugin.desktop new file mode 100644 index 00000000..def61cbf --- /dev/null +++ b/chalk/data/chalk_plugin.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Chalk/ViewPlugin +Comment=GUI functionality for Chalk +Comment[bg]=ГПИ функционалност за Chalk +Comment[ca]=Funcionalitat d'interfície d'usuari per a Chalk +Comment[cy]=Swyddogaeth GUI ar gyfer Chalk +Comment[da]=GUI-funktionalitet for Chalk +Comment[de]=GUI-Funktionalität für Chalk +Comment[el]=Άρθρωμα λειτουργικότητας περιβάλλοντος για το Chalk +Comment[es]=Funcionalidad de GUI para Chalk +Comment[et]=Chalk GUI funktsioonid +Comment[fa]=کارآمدی ونک برای Chalk +Comment[fr]=Interface graphique pour Chalk +Comment[fy]=Ynterfacefunksjonaliteit foar Chalk +Comment[gl]=Funcionalidade da GUI de Chalk +Comment[he]=מודול פונקציונליות בסיסית של Chalk +Comment[hu]=Grafikus felület a Kritához +Comment[is]=Gluggavirkni fyrir Chalk +Comment[it]=Funzionalità d'interfaccia per Chalk +Comment[ja]=Chalk の GUI 機能 +Comment[km]=មុខងារ​ចំណុចប្រទាក់​អ្នក​ប្រើ សម្រាប់ Chalk +Comment[nb]=Chalk-modul for GUI-funksjonalitet +Comment[nds]=Böversietfunkschonen för Chalk +Comment[ne]=क्रिताका लागि GUI कार्यात्मक +Comment[nl]=Interfacefunctionaliteit voor Chalk +Comment[pl]=Graficzny interfejs użytkownika programu Chalk +Comment[pt]=Funcionalidade gráfica para o Chalk +Comment[pt_BR]=Funcionalidade de interface gráfica para o Chalk +Comment[ru]=Интерфейс Chalk +Comment[sk]=GUI functionalita pre Chalk +Comment[sl]=Funkcionalnost grafičnega vmesnika za Krito +Comment[sr]=Функционалност GUI-ја за Chalk-у +Comment[sr@Latn]=Funkcionalnost GUI-ja za Chalk-u +Comment[sv]=Grafisk gränssnittsfunktion för Chalk +Comment[uk]=Функціональність графічного інтерфейсу для Chalk +Comment[uz]=Chalk grafik interfeysi +Comment[uz@cyrillic]=Chalk график интерфейси +Comment[zh_CN]=Chalk 的图形界面模块 +Comment[zh_TW]=Chalk 的 GUI 功能 +[PropertyDef::X-Chalk-Version] +Type=int diff --git a/chalk/data/chalk_tool.desktop b/chalk/data/chalk_tool.desktop new file mode 100644 index 00000000..5508cae3 --- /dev/null +++ b/chalk/data/chalk_tool.desktop @@ -0,0 +1,46 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=Chalk/Tool +Comment=Tool plugin for Chalk +Comment[bg]=Приставка за инструмент за Chalk +Comment[ca]=Connector d'eines per a Chalk +Comment[da]=Værktøjsplugin for Chalk +Comment[de]=Werkzeug-Modul für Chalk +Comment[el]=Πρόσθετο εργαλείων για το Chalk +Comment[eo]=Ilkromaĵo por Chalk +Comment[es]=Complemento de herramienta para Chalk +Comment[et]=Chalk tööriistade plugin +Comment[eu]=Chalk-ren Tresna plugina +Comment[fa]=وصله ابزار برای Chalk +Comment[fi]=Chalkn työkaluliitännäinen +Comment[fr]=Module d'outils pour Chalk +Comment[fy]=Arkplugin foar Chalk +Comment[gl]=Ferramenta de plugin para Chalk +Comment[he]=תוסף כלים של Chalk +Comment[hu]=Eszközmodul a Kritához +Comment[is]=Tóla íforrit fyrir Chalk +Comment[it]=Plugin per gli strumenti per Chalk +Comment[ja]=Chalk ツールプラグイン +Comment[km]=កម្មវិធី​ជំនួយ​ឧបករណ៍ សម្រាប់ Chalk +Comment[ms]=Plugin alat Chalk +Comment[nb]=Chalk-programtillegg for verktøy +Comment[nds]=Warktüüchmoduul för Chalk +Comment[ne]=क्रिताका लागि उपकरण प्लगइन +Comment[nl]=Gereedschapsplugin voor Chalk +Comment[nn]=Chalk-programtillegg for verktøy +Comment[pl]=Wtyczka narzędzi dla Chalk +Comment[pt]='Plugin' de ferramentas do Chalk +Comment[pt_BR]=Plugin de ferramenta para o Chalk +Comment[ru]=Инструменты Chalk +Comment[sk]=Modul nástrojov pre Chalk +Comment[sl]=Vstavek z orodjem za Krito +Comment[sr]=Алатни прикључак за Chalk-у +Comment[sr@Latn]=Alatni priključak za Chalk-u +Comment[sv]=Verktygsinsticksprogram för Chalk +Comment[uk]=Втулок інструментів для Chalk +Comment[uz]=Chalk uchun vosita plagini +Comment[uz@cyrillic]=Chalk учун восита плагини +Comment[zh_CN]=Chalk 工具插件 +Comment[zh_TW]=Chalk 的工具外掛程式 +[PropertyDef::X-Chalk-Version] +Type=int diff --git a/chalk/data/gradients/Abstract_1.ggr b/chalk/data/gradients/Abstract_1.ggr new file mode 100644 index 00000000..5e681d22 --- /dev/null +++ b/chalk/data/gradients/Abstract_1.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Abstract 1 +6 +0.000000 0.286311 0.572621 0.269543 0.259267 1.000000 1.000000 0.215635 0.407414 0.984953 1.000000 0 0 +0.572621 0.657763 0.716194 0.215635 0.407414 0.984953 1.000000 0.040368 0.833333 0.619375 1.000000 0 0 +0.716194 0.734558 0.749583 0.040368 0.833333 0.619375 1.000000 0.680490 0.355264 0.977430 1.000000 0 0 +0.749583 0.784641 0.824708 0.680490 0.355264 0.977430 1.000000 0.553909 0.351853 0.977430 1.000000 0 0 +0.824708 0.853088 0.876461 0.553909 0.351853 0.977430 1.000000 1.000000 0.000000 1.000000 1.000000 0 0 +0.876461 0.943172 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Abstract_2.ggr b/chalk/data/gradients/Abstract_2.ggr new file mode 100644 index 00000000..913ae019 --- /dev/null +++ b/chalk/data/gradients/Abstract_2.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Abstract 2 +6 +0.000000 0.333532 0.570952 1.000000 0.000000 0.055296 1.000000 0.922731 0.452483 0.984953 1.000000 0 0 +0.570952 0.616469 0.664441 0.922731 0.452483 0.984953 1.000000 0.122236 0.319840 0.583333 1.000000 0 0 +0.664441 0.727880 0.756260 0.122236 0.319840 0.583333 1.000000 0.059646 1.000000 0.558369 1.000000 0 0 +0.756260 0.799666 0.843072 0.059646 1.000000 0.558369 1.000000 0.969697 0.948568 0.533333 1.000000 0 0 +0.843072 0.905766 0.949917 0.969697 0.948568 0.533333 1.000000 1.000000 0.490000 1.000000 1.000000 0 0 +0.949917 0.988314 1.000000 1.000000 0.490000 1.000000 1.000000 0.238108 0.191841 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Abstract_3.ggr b/chalk/data/gradients/Abstract_3.ggr new file mode 100644 index 00000000..5052750a --- /dev/null +++ b/chalk/data/gradients/Abstract_3.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Abstract 3 +6 +0.000000 0.050083 0.435726 0.000000 0.424242 0.070751 1.000000 1.000000 0.725647 0.428066 1.000000 0 0 +0.435726 0.490818 0.590985 1.000000 0.725647 0.428066 1.000000 0.115248 0.249315 0.651515 1.000000 0 0 +0.590985 0.660267 0.799666 0.115248 0.249315 0.651515 1.000000 0.552948 0.624658 0.550758 1.000000 0 0 +0.799666 0.879800 0.943239 0.552948 0.624658 0.550758 1.000000 0.990647 1.000000 0.450000 1.000000 0 0 +0.943239 0.961603 0.979967 0.990647 1.000000 0.450000 1.000000 0.317635 0.843781 1.000000 1.000000 0 0 +0.979967 0.989983 1.000000 0.317635 0.843781 1.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Aneurism.ggr b/chalk/data/gradients/Aneurism.ggr new file mode 100644 index 00000000..092b2292 --- /dev/null +++ b/chalk/data/gradients/Aneurism.ggr @@ -0,0 +1,11 @@ +GIMP Gradient +Name: Aneurism +8 +0.000000 0.119571 0.235803 0.000000 0.000000 0.000000 0.000000 0.202999 0.003788 0.265152 1.000000 0 0 +0.235803 0.306652 0.377501 0.202999 0.003788 0.265152 1.000000 0.300711 0.001894 0.393939 1.000000 0 0 +0.377501 0.409118 0.437396 0.300711 0.001894 0.393939 1.000000 0.388992 0.000947 0.206459 1.000000 0 0 +0.437396 0.455760 0.474124 0.388992 0.000947 0.206459 1.000000 0.689394 0.000000 0.027414 1.000000 0 0 +0.474124 0.504174 0.534224 0.689394 0.000000 0.027414 1.000000 0.388992 0.000947 0.206459 1.000000 0 0 +0.534224 0.571786 0.609349 0.388992 0.000947 0.206459 1.000000 0.300711 0.001894 0.393939 1.000000 0 0 +0.609349 0.708556 0.770562 0.300711 0.001894 0.393939 1.000000 0.202999 0.003788 0.265152 1.000000 0 0 +0.770562 0.885281 1.000000 0.202999 0.003788 0.265152 1.000000 0.000000 0.000000 0.000000 0.000000 0 0 diff --git a/chalk/data/gradients/Blinds.ggr b/chalk/data/gradients/Blinds.ggr new file mode 100644 index 00000000..a6bca825 --- /dev/null +++ b/chalk/data/gradients/Blinds.ggr @@ -0,0 +1,12 @@ +GIMP Gradient +Name: Blinds +9 +0.000000 0.041667 0.166667 0.000000 0.000000 0.000000 1.000000 0.500000 0.500000 0.500000 1.000000 2 0 +0.166667 0.186978 0.250000 0.500000 0.500000 0.500000 1.000000 1.000000 1.000000 1.000000 1.000000 2 0 +0.250000 0.250000 0.346689 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 +0.346689 0.425710 0.425710 0.000000 0.000000 0.000000 1.000000 0.500000 0.500000 0.500000 1.000000 2 0 +0.425710 0.541667 0.583333 0.500000 0.500000 0.500000 1.000000 1.000000 1.000000 1.000000 1.000000 2 0 +0.583333 0.583333 0.671119 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 +0.671119 0.761269 0.835003 0.000000 0.000000 0.000000 1.000000 0.416667 0.416667 0.416667 1.000000 2 0 +0.835003 0.875000 0.916667 0.416667 0.416667 0.416667 1.000000 0.833333 0.833333 0.833333 1.000000 2 0 +0.916667 0.916667 1.000000 0.833333 0.833333 0.833333 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 diff --git a/chalk/data/gradients/Blue_Green.ggr b/chalk/data/gradients/Blue_Green.ggr new file mode 100644 index 00000000..4b504576 --- /dev/null +++ b/chalk/data/gradients/Blue_Green.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Blue Green +2 +0.000000 0.135225 0.565943 0.000000 0.481711 1.000000 1.000000 0.283820 0.887055 1.000000 1.000000 0 0 +0.565943 0.918197 1.000000 0.283820 0.887055 1.000000 1.000000 0.000000 1.000000 0.631509 1.000000 0 0 diff --git a/chalk/data/gradients/Browns.ggr b/chalk/data/gradients/Browns.ggr new file mode 100644 index 00000000..7b826a39 --- /dev/null +++ b/chalk/data/gradients/Browns.ggr @@ -0,0 +1,14 @@ +GIMP Gradient +Name: Browns +11 +0.000000 0.055092 0.116861 0.550000 0.353971 0.192500 1.000000 0.734848 0.461927 0.168587 1.000000 0 0 +0.116861 0.176962 0.253756 0.734848 0.461927 0.168587 1.000000 0.550000 0.328592 0.022000 1.000000 0 0 +0.253756 0.347245 0.404006 0.550000 0.328592 0.022000 1.000000 0.780303 0.457033 0.022095 1.000000 0 0 +0.404006 0.439065 0.507513 0.780303 0.457033 0.022095 1.000000 0.696970 0.330262 0.221382 1.000000 0 0 +0.507513 0.562604 0.592654 0.696970 0.330262 0.221382 1.000000 0.681667 0.487159 0.348063 1.000000 0 0 +0.592654 0.614357 0.644407 0.681667 0.487159 0.348063 1.000000 0.722109 0.527005 0.406758 1.000000 0 0 +0.644407 0.676127 0.706177 0.722109 0.527005 0.406758 1.000000 0.765919 0.570170 0.470341 1.000000 0 0 +0.706177 0.742905 0.782972 0.765919 0.570170 0.470341 1.000000 0.590909 0.402374 0.336818 1.000000 0 0 +0.782972 0.850862 0.883695 0.590909 0.402374 0.336818 1.000000 0.759037 0.555096 0.387109 1.000000 0 0 +0.883695 0.914858 0.934335 0.759037 0.555096 0.387109 1.000000 0.679587 0.523656 0.364325 1.000000 0 0 +0.934335 0.967167 1.000000 0.679587 0.523656 0.364325 1.000000 0.550000 0.353971 0.192500 1.000000 0 0 diff --git a/chalk/data/gradients/Brushed_Aluminium.ggr b/chalk/data/gradients/Brushed_Aluminium.ggr new file mode 100644 index 00000000..3b246258 --- /dev/null +++ b/chalk/data/gradients/Brushed_Aluminium.ggr @@ -0,0 +1,27 @@ +GIMP Gradient +Name: Brushed Aluminium +24 +0.000000 0.031250 0.041736 0.435294 0.447059 0.411765 1.000000 0.498070 0.508364 0.477482 1.000000 0 0 +0.041736 0.066308 0.072621 0.498070 0.508364 0.477482 1.000000 0.529458 0.539017 0.510340 1.000000 0 0 +0.072621 0.081803 0.125000 0.549020 0.556863 0.529412 1.000000 0.560845 0.569669 0.543199 1.000000 0 0 +0.125000 0.130217 0.154946 0.560845 0.569669 0.543199 1.000000 0.623621 0.630974 0.608916 1.000000 0 0 +0.154946 0.186196 0.203255 0.623621 0.630974 0.608916 1.000000 0.686397 0.692279 0.674632 1.000000 0 0 +0.203255 0.278798 0.285476 0.686397 0.692279 0.674632 1.000000 0.749173 0.753585 0.740349 1.000000 0 0 +0.285476 0.320534 0.333890 0.749173 0.753585 0.740349 1.000000 0.811948 0.814890 0.806066 1.000000 4 0 +0.333890 0.333890 0.365609 0.756863 0.756863 0.756863 1.000000 0.843336 0.845542 0.838925 1.000000 0 0 +0.365609 0.393990 0.399833 0.843336 0.845542 0.838925 1.000000 0.800000 0.796078 0.756863 1.000000 0 0 +0.399833 0.485392 0.517529 0.800000 0.796078 0.756863 1.000000 0.937500 0.937500 0.937500 1.000000 3 0 +0.517529 0.531250 0.552483 0.937500 0.937500 0.937500 1.000000 0.772549 0.772549 0.772549 1.000000 4 0 +0.552483 0.563439 0.569282 0.658824 0.658824 0.658824 1.000000 0.784314 0.784314 0.800000 1.000000 3 0 +0.569282 0.577629 0.586394 0.784314 0.784314 0.800000 1.000000 0.823529 0.811765 0.811765 1.000000 0 0 +0.586394 0.618322 0.626043 0.823529 0.811765 0.811765 1.000000 0.726583 0.728537 0.731807 1.000000 0 0 +0.626043 0.641068 0.663606 0.726583 0.728537 0.731807 1.000000 0.737255 0.760784 0.721569 1.000000 0 0 +0.663606 0.675292 0.682805 0.737255 0.760784 0.721569 1.000000 0.621109 0.628462 0.613266 1.000000 0 0 +0.682805 0.703673 0.722473 0.621109 0.628462 0.613266 1.000000 0.529412 0.529412 0.529412 1.000000 4 0 +0.722473 0.746680 0.758765 0.529412 0.529412 0.529412 1.000000 0.498039 0.492157 0.472549 1.000000 4 0 +0.758765 0.763773 0.770451 0.447059 0.443137 0.427451 1.000000 0.560784 0.537255 0.549020 1.000000 0 0 +0.770451 0.799145 0.827838 0.513725 0.517647 0.501961 1.000000 0.486417 0.479213 0.477687 1.000000 4 0 +0.827838 0.833890 0.851419 0.486417 0.479213 0.477687 1.000000 0.477872 0.467187 0.470092 1.000000 3 0 +0.851419 0.876461 0.892321 0.477872 0.467187 0.470092 1.000000 0.469328 0.455162 0.462497 1.000000 0 0 +0.892321 0.934474 0.941569 0.469328 0.455162 0.462497 1.000000 0.478431 0.462745 0.470588 1.000000 4 0 +0.941569 0.965776 1.000000 0.465056 0.449150 0.458699 1.000000 0.556863 0.537255 0.552941 1.000000 0 0 diff --git a/chalk/data/gradients/Burning_Paper.ggr b/chalk/data/gradients/Burning_Paper.ggr new file mode 100644 index 00000000..df064eb0 --- /dev/null +++ b/chalk/data/gradients/Burning_Paper.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Burning Paper +6 +0.000000 0.264608 0.502504 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.502504 0.601002 0.637730 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1 0 +0.637730 0.700343 0.744574 0.000000 0.000000 0.000000 1.000000 0.890000 0.329199 0.177758 1.000000 0 0 +0.744574 0.767761 0.786311 0.890000 0.329199 0.177758 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 +0.786311 0.829920 0.891486 1.000000 1.000000 0.000000 1.000000 0.910000 0.574437 0.000000 1.000000 0 0 +0.891486 0.944908 1.000000 0.910000 0.574437 0.000000 1.000000 0.727273 0.127938 0.148370 1.000000 0 0 diff --git a/chalk/data/gradients/Burning_Transparency.ggr b/chalk/data/gradients/Burning_Transparency.ggr new file mode 100644 index 00000000..fccbc4a9 --- /dev/null +++ b/chalk/data/gradients/Burning_Transparency.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Burning Transparency +6 +0.000000 0.264608 0.502504 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0 0 +0.502504 0.601002 0.637730 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1 0 +0.637730 0.700343 0.744574 0.000000 0.000000 0.000000 1.000000 0.890000 0.329199 0.177758 1.000000 0 0 +0.744574 0.767761 0.786311 0.890000 0.329199 0.177758 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 +0.786311 0.829920 0.891486 1.000000 1.000000 0.000000 1.000000 0.910000 0.574437 0.000000 1.000000 0 0 +0.891486 0.944908 1.000000 0.910000 0.574437 0.000000 1.000000 0.727273 0.127938 0.148370 0.000000 0 0 diff --git a/chalk/data/gradients/CD.ggr b/chalk/data/gradients/CD.ggr new file mode 100644 index 00000000..824df960 --- /dev/null +++ b/chalk/data/gradients/CD.ggr @@ -0,0 +1,21 @@ +GIMP Gradient +Name: CD +18 +0.000000 0.010566 0.023372 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 +0.023372 0.045682 0.063439 0.879999 0.880000 0.880000 1.000000 0.999999 1.000000 1.000000 1.000000 0 0 +0.063439 0.082638 0.176962 0.999999 1.000000 1.000000 1.000000 0.909999 0.910000 0.910000 1.000000 0 0 +0.176962 0.205342 0.236227 0.909999 0.910000 0.910000 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.236227 0.267623 0.281302 0.819999 0.820000 0.820000 1.000000 0.903167 1.000000 0.000000 1.000000 0 0 +0.281302 0.296327 0.310518 0.903167 1.000000 0.000000 1.000000 0.000000 0.877893 1.000000 1.000000 0 0 +0.310518 0.321369 0.340568 0.000000 0.877893 1.000000 1.000000 0.384390 1.000000 0.900682 1.000000 0 0 +0.340568 0.357129 0.373957 0.384390 1.000000 0.900682 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.373957 0.434190 0.500000 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 +0.500000 0.510566 0.523372 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 +0.523372 0.545682 0.563439 0.879999 0.880000 0.880000 1.000000 0.999999 1.000000 1.000000 1.000000 0 0 +0.563439 0.582638 0.676962 0.999999 1.000000 1.000000 1.000000 0.909999 0.910000 0.910000 1.000000 0 0 +0.676962 0.705342 0.736227 0.909999 0.910000 0.910000 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.736227 0.767623 0.781302 0.819999 0.820000 0.820000 1.000000 0.903167 1.000000 0.000000 1.000000 0 0 +0.781302 0.796327 0.810518 0.903167 1.000000 0.000000 1.000000 0.000000 0.877893 1.000000 1.000000 0 0 +0.810518 0.821369 0.840568 0.000000 0.877893 1.000000 1.000000 0.384390 1.000000 0.900682 1.000000 0 0 +0.840568 0.857129 0.873957 0.384390 1.000000 0.900682 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.873957 0.934190 1.000000 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 diff --git a/chalk/data/gradients/CD_Half.ggr b/chalk/data/gradients/CD_Half.ggr new file mode 100644 index 00000000..fdc5dd38 --- /dev/null +++ b/chalk/data/gradients/CD_Half.ggr @@ -0,0 +1,12 @@ +GIMP Gradient +Name: CD Half +9 +0.000000 0.021131 0.046745 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 +0.046745 0.091364 0.126878 0.879999 0.880000 0.880000 1.000000 0.999999 1.000000 1.000000 1.000000 0 0 +0.126878 0.165275 0.353923 0.999999 1.000000 1.000000 1.000000 0.909999 0.910000 0.910000 1.000000 0 0 +0.353923 0.410684 0.472454 0.909999 0.910000 0.910000 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.472454 0.535246 0.562604 0.819999 0.820000 0.820000 1.000000 0.903167 1.000000 0.000000 1.000000 0 0 +0.562604 0.592654 0.621035 0.903167 1.000000 0.000000 1.000000 0.000000 0.877893 1.000000 1.000000 0 0 +0.621035 0.642738 0.681135 0.000000 0.877893 1.000000 1.000000 0.384390 1.000000 0.900682 1.000000 0 0 +0.681135 0.714259 0.747913 0.384390 1.000000 0.900682 1.000000 0.819999 0.820000 0.820000 1.000000 0 0 +0.747913 0.868381 1.000000 0.819999 0.820000 0.820000 1.000000 0.879999 0.880000 0.880000 1.000000 0 0 diff --git a/chalk/data/gradients/Caribbean_Blues.ggr b/chalk/data/gradients/Caribbean_Blues.ggr new file mode 100644 index 00000000..232b7b8b --- /dev/null +++ b/chalk/data/gradients/Caribbean_Blues.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Caribbean Blues +3 +0.000000 0.403766 0.567613 0.000000 0.130219 0.583333 1.000000 0.200000 0.833333 0.726927 1.000000 0 0 +0.567613 0.642738 0.681135 0.200000 0.833333 0.726927 1.000000 1.000000 0.988352 0.860000 1.000000 0 0 +0.681135 0.790397 1.000000 1.000000 0.988352 0.860000 1.000000 0.000000 0.431818 0.000000 1.000000 1 0 diff --git a/chalk/data/gradients/Coffee.ggr b/chalk/data/gradients/Coffee.ggr new file mode 100644 index 00000000..24baee0e --- /dev/null +++ b/chalk/data/gradients/Coffee.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Coffee +1 +0.000000 0.949917 1.000000 0.560606 0.435893 0.311332 0.000000 0.300000 0.233262 0.166605 1.000000 4 0 diff --git a/chalk/data/gradients/Cold_Steel.ggr b/chalk/data/gradients/Cold_Steel.ggr new file mode 100644 index 00000000..f6b27a02 --- /dev/null +++ b/chalk/data/gradients/Cold_Steel.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Cold Steel +2 +0.000000 0.208681 0.647746 1.000000 1.000000 1.000000 1.000000 0.047059 0.023529 0.137255 1.000000 0 0 +0.647746 0.669449 1.000000 0.047059 0.023529 0.137255 1.000000 0.364706 0.733333 0.756863 1.000000 0 0 diff --git a/chalk/data/gradients/Cold_Steel_2.ggr b/chalk/data/gradients/Cold_Steel_2.ggr new file mode 100644 index 00000000..f09dcf89 --- /dev/null +++ b/chalk/data/gradients/Cold_Steel_2.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Cold Steel 2 +3 +0.000000 0.068447 0.101836 0.143939 0.013928 0.100000 1.000000 1.000000 1.000000 1.000000 1.000000 1 0 +0.101836 0.501669 0.901503 1.000000 1.000000 1.000000 1.000000 0.088684 0.075143 0.174242 1.000000 1 0 +0.901503 0.929902 1.000000 0.200503 0.169888 0.393939 1.000000 0.047059 0.023529 0.137255 1.000000 1 0 diff --git a/chalk/data/gradients/Crown_molding.ggr b/chalk/data/gradients/Crown_molding.ggr new file mode 100644 index 00000000..56ffb013 --- /dev/null +++ b/chalk/data/gradients/Crown_molding.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Crown molding +6 +0.000000 0.155120 0.238453 0.000000 0.000000 0.000000 1.000000 0.840000 0.840000 0.840000 1.000000 0 0 +0.238453 0.287145 0.288815 0.840000 0.840000 0.840000 1.000000 0.333333 0.333333 0.333333 1.000000 4 0 +0.288815 0.317195 0.388982 0.333333 0.333333 0.333333 1.000000 0.900000 0.900000 0.900000 1.000000 2 0 +0.388982 0.583333 0.713411 0.900000 0.900000 0.900000 1.000000 0.333333 0.333333 0.333333 1.000000 2 0 +0.713411 0.796745 0.878408 0.333333 0.333333 0.333333 1.000000 1.000000 1.000000 1.000000 1.000000 2 0 +0.878408 0.949917 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Dark_1.ggr b/chalk/data/gradients/Dark_1.ggr new file mode 100644 index 00000000..52a0f804 --- /dev/null +++ b/chalk/data/gradients/Dark_1.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Dark 1 +3 +0.000000 0.315713 0.560935 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.560935 0.677796 0.774624 0.000000 0.000000 0.000000 1.000000 0.636364 0.280000 0.280000 1.000000 0 0 +0.774624 0.923326 1.000000 0.636364 0.280000 0.280000 1.000000 1.000000 0.895652 0.840000 1.000000 0 0 diff --git a/chalk/data/gradients/Deep_Sea.ggr b/chalk/data/gradients/Deep_Sea.ggr new file mode 100644 index 00000000..c6cfc5fe --- /dev/null +++ b/chalk/data/gradients/Deep_Sea.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Deep Sea +2 +0.000000 0.580968 0.764608 0.000000 0.009040 0.166667 1.000000 0.179032 0.390004 0.621212 1.000000 0 0 +0.764608 0.888147 1.000000 0.179032 0.390004 0.621212 1.000000 0.000000 0.969697 0.969697 1.000000 0 0 diff --git a/chalk/data/gradients/Default.ggr b/chalk/data/gradients/Default.ggr new file mode 100644 index 00000000..82511f35 --- /dev/null +++ b/chalk/data/gradients/Default.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Default +1 +0.000000 0.500000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Flare_Glow_Angular_1.ggr b/chalk/data/gradients/Flare_Glow_Angular_1.ggr new file mode 100644 index 00000000..b0e2dc9c --- /dev/null +++ b/chalk/data/gradients/Flare_Glow_Angular_1.ggr @@ -0,0 +1,49 @@ +GIMP Gradient +Name: Flare Glow Angular 1 +46 +0.000000 0.006944 0.013889 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.120000 0 0 +0.013889 0.025598 0.038954 1.000000 1.000000 1.000000 0.120000 1.000000 1.000000 1.000000 0.860000 0 0 +0.038954 0.045214 0.057874 1.000000 1.000000 1.000000 0.860000 1.000000 1.000000 1.000000 0.730000 0 0 +0.057874 0.075748 0.087368 1.000000 1.000000 1.000000 0.730000 1.000000 1.000000 1.000000 1.000000 0 0 +0.087368 0.097941 0.108514 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0 0 +0.108514 0.117085 0.135678 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.770000 0 0 +0.135678 0.150815 0.172510 1.000000 1.000000 1.000000 0.770000 1.000000 1.000000 1.000000 1.000000 0 0 +0.172510 0.179517 0.187500 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.100000 0 0 +0.187500 0.196995 0.209446 1.000000 1.000000 1.000000 0.100000 1.000000 1.000000 1.000000 0.760000 0 0 +0.209446 0.224645 0.239844 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 0.420000 0 0 +0.239844 0.244922 0.250000 1.000000 1.000000 1.000000 0.420000 1.000000 1.000000 1.000000 1.000000 0 0 +0.250000 0.264853 0.278154 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0 0 +0.278154 0.299261 0.312500 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.760000 0 0 +0.312500 0.322917 0.333333 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 1.000000 0 0 +0.333333 0.340278 0.347222 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.240000 0 0 +0.347222 0.358932 0.372287 1.000000 1.000000 1.000000 0.240000 1.000000 1.000000 1.000000 0.860000 0 0 +0.372287 0.380078 0.395833 1.000000 1.000000 1.000000 0.860000 1.000000 1.000000 1.000000 0.730000 0 0 +0.395833 0.408459 0.416667 1.000000 1.000000 1.000000 0.730000 1.000000 1.000000 1.000000 1.000000 0 0 +0.416667 0.429257 0.441848 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.160000 0 0 +0.441848 0.449230 0.465246 1.000000 1.000000 1.000000 0.160000 1.000000 1.000000 1.000000 0.610000 0 0 +0.465246 0.470949 0.491374 1.000000 1.000000 1.000000 0.610000 1.000000 1.000000 1.000000 0.770000 0 0 +0.491374 0.499722 0.511686 1.000000 1.000000 1.000000 0.770000 1.000000 1.000000 1.000000 1.000000 0 0 +0.511686 0.515962 0.526459 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0 0 +0.526459 0.536698 0.542780 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.760000 0 0 +0.542780 0.547606 0.563613 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 0.420000 0 0 +0.563613 0.577090 0.590568 1.000000 1.000000 1.000000 0.420000 1.000000 1.000000 1.000000 1.000000 0 0 +0.590568 0.600984 0.611401 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.490000 0 0 +0.611401 0.616671 0.624957 1.000000 1.000000 1.000000 0.490000 1.000000 1.000000 1.000000 0.000000 0 0 +0.624957 0.635417 0.645833 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.760000 0 0 +0.645833 0.656250 0.661937 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 1.000000 0 0 +0.661937 0.673611 0.680556 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.240000 0 0 +0.680556 0.698664 0.705620 1.000000 1.000000 1.000000 0.240000 1.000000 1.000000 1.000000 0.860000 0 0 +0.705620 0.709794 0.729167 1.000000 1.000000 1.000000 0.860000 1.000000 1.000000 1.000000 0.100000 0 0 +0.729167 0.741792 0.750000 1.000000 1.000000 1.000000 0.100000 1.000000 1.000000 1.000000 1.000000 0 0 +0.750000 0.762590 0.775181 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.510000 0 0 +0.775181 0.793795 0.806692 1.000000 1.000000 1.000000 0.510000 1.000000 1.000000 1.000000 0.610000 0 0 +0.806692 0.811352 0.822204 1.000000 1.000000 1.000000 0.610000 1.000000 1.000000 1.000000 0.770000 0 0 +0.822204 0.830219 0.835559 1.000000 1.000000 1.000000 0.770000 1.000000 1.000000 1.000000 1.000000 0 0 +0.835559 0.843072 0.854167 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.110000 0 0 +0.854167 0.870031 0.876113 1.000000 1.000000 1.000000 0.110000 1.000000 1.000000 1.000000 0.760000 0 0 +0.876113 0.886530 0.894164 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 0.420000 0 0 +0.894164 0.904024 0.913884 1.000000 1.000000 1.000000 0.420000 1.000000 1.000000 1.000000 1.000000 0 0 +0.913884 0.927083 0.932303 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.490000 0 0 +0.932303 0.947917 0.959015 1.000000 1.000000 1.000000 0.490000 1.000000 1.000000 1.000000 0.000000 0 0 +0.959015 0.968750 0.979167 1.000000 1.000000 1.000000 0.200000 1.000000 1.000000 1.000000 0.760000 0 0 +0.979167 0.989583 1.000000 1.000000 1.000000 1.000000 0.760000 1.000000 1.000000 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Flare_Glow_Radial_1.ggr b/chalk/data/gradients/Flare_Glow_Radial_1.ggr new file mode 100644 index 00000000..318f43fe --- /dev/null +++ b/chalk/data/gradients/Flare_Glow_Radial_1.ggr @@ -0,0 +1,7 @@ +GIMP Gradient +Name: Flare Glow Radial 1 +4 +0.000000 0.353923 0.535893 1.000000 1.000000 1.000000 0.940000 0.780303 0.560606 1.000000 0.480000 1 0 +0.535893 0.595400 0.616550 0.780303 0.560606 1.000000 0.480000 0.900000 0.800000 1.000000 0.860000 1 0 +0.616550 0.636956 0.717863 0.900000 0.800000 1.000000 0.860000 0.780303 0.560606 1.000000 0.480000 1 0 +0.717863 0.854758 1.000000 0.780303 0.560606 1.000000 0.480000 0.900000 0.800000 1.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Flare_Glow_Radial_2.ggr b/chalk/data/gradients/Flare_Glow_Radial_2.ggr new file mode 100644 index 00000000..97282599 --- /dev/null +++ b/chalk/data/gradients/Flare_Glow_Radial_2.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Flare Glow Radial 2 +5 +0.000000 0.260896 0.530885 0.500000 1.000000 1.000000 0.000000 0.653680 0.728264 0.846320 0.000000 1 2 +0.530885 0.567758 0.646077 0.653680 0.728264 0.846320 0.000000 0.622773 0.921464 0.578536 0.250000 1 2 +0.646077 0.726210 0.766467 0.622773 0.921464 0.578536 0.250000 1.000000 0.500000 0.500000 0.800000 1 2 +0.766467 0.804674 0.888110 1.000000 0.500000 0.500000 0.800000 0.750000 0.500000 1.000000 0.250000 1 2 +0.888110 0.966611 1.000000 0.750000 0.500000 1.000000 0.250000 0.500000 1.000000 1.000000 0.000000 1 2 diff --git a/chalk/data/gradients/Flare_Glow_Radial_3.ggr b/chalk/data/gradients/Flare_Glow_Radial_3.ggr new file mode 100644 index 00000000..42c24e1a --- /dev/null +++ b/chalk/data/gradients/Flare_Glow_Radial_3.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Flare Glow Radial 3 +5 +0.000000 0.173623 0.350584 1.000000 0.920000 0.920000 0.809524 1.000000 0.737255 0.737255 0.306122 2 0 +0.350584 0.375626 0.400668 1.000000 0.737255 0.737255 0.306122 1.000000 0.636060 0.636060 0.306122 0 0 +0.400668 0.411797 0.421223 1.000000 0.636060 0.636060 0.306122 1.000000 0.517647 0.517647 0.605442 1 0 +0.421223 0.430718 0.440735 1.000000 0.517647 0.517647 0.605442 0.988235 0.501961 0.501961 0.306122 1 0 +0.440735 0.720367 1.000000 0.988235 0.501961 0.501961 0.306122 1.000000 0.000000 0.000000 0.000000 0 0 diff --git a/chalk/data/gradients/Flare_Glow_Radial_4.ggr b/chalk/data/gradients/Flare_Glow_Radial_4.ggr new file mode 100644 index 00000000..966f8538 --- /dev/null +++ b/chalk/data/gradients/Flare_Glow_Radial_4.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Flare Glow Radial 4 +3 +0.000000 0.737896 0.878130 1.000000 0.999999 0.999999 0.100000 1.000000 0.755000 0.755000 0.550000 1 0 +0.878130 0.920520 0.943039 1.000000 0.755000 0.755000 0.550000 1.000000 0.510000 0.510000 1.000000 1 0 +0.943039 0.974958 1.000000 1.000000 0.510000 0.510000 1.000000 1.000000 0.632500 0.632500 0.000000 1 0 diff --git a/chalk/data/gradients/Flare_Radial_101.ggr b/chalk/data/gradients/Flare_Radial_101.ggr new file mode 100644 index 00000000..eff7920f --- /dev/null +++ b/chalk/data/gradients/Flare_Radial_101.ggr @@ -0,0 +1,10 @@ +GIMP Gradient +Name: Flare Radial 101 +7 +0.000000 0.050918 0.101836 1.000000 0.999999 0.999999 1.000000 1.000000 0.999999 0.999999 1.000000 0 0 +0.101836 0.151085 0.200334 1.000000 0.999999 0.999999 1.000000 1.000000 0.691315 0.691315 0.650000 0 0 +0.200334 0.250417 0.300501 1.000000 0.691315 0.691315 0.650000 1.000000 0.590658 0.590658 0.357895 0 0 +0.300501 0.350584 0.400668 1.000000 0.590658 0.590658 0.357895 1.000000 0.490000 0.490000 0.200000 0 0 +0.400668 0.455760 0.500000 1.000000 0.490000 0.490000 0.200000 1.000000 0.300000 0.300000 0.800000 4 0 +0.500000 0.511269 0.515860 1.000000 0.300000 0.300000 0.800000 1.000000 0.300000 0.300000 0.800000 3 0 +0.515860 0.601002 1.000000 1.000000 0.300000 0.300000 0.800000 1.000000 1.000000 1.000000 0.000000 3 0 diff --git a/chalk/data/gradients/Flare_Radial_102.ggr b/chalk/data/gradients/Flare_Radial_102.ggr new file mode 100644 index 00000000..ac50a3c9 --- /dev/null +++ b/chalk/data/gradients/Flare_Radial_102.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Flare Radial 102 +6 +0.000000 0.024937 0.058431 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.900000 0 0 +0.058431 0.083751 0.105175 1.000000 1.000000 1.000000 0.900000 1.000000 0.490000 0.490000 0.820000 0 0 +0.105175 0.157763 0.208681 1.000000 0.490000 0.490000 0.820000 1.000000 0.250000 0.250000 0.650000 0 0 +0.208681 0.278798 0.405676 1.000000 0.250000 0.250000 0.650000 1.000000 0.250000 0.250000 0.250000 0 0 +0.405676 0.534224 0.799666 1.000000 0.250000 0.250000 0.250000 1.000000 0.250000 0.250000 0.000000 0 0 +0.799666 0.899833 1.000000 1.000000 0.250000 0.250000 0.000000 1.000000 0.250000 0.250000 0.000000 0 0 diff --git a/chalk/data/gradients/Flare_Radial_103.ggr b/chalk/data/gradients/Flare_Radial_103.ggr new file mode 100644 index 00000000..a73fbe9e --- /dev/null +++ b/chalk/data/gradients/Flare_Radial_103.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Flare Radial 103 +1 +0.000000 0.517529 1.000000 1.000000 1.000000 1.000000 0.490000 1.000000 0.510000 0.510000 1.000000 0 0 diff --git a/chalk/data/gradients/Flare_Rays_Radial_1.ggr b/chalk/data/gradients/Flare_Rays_Radial_1.ggr new file mode 100644 index 00000000..66a848d5 --- /dev/null +++ b/chalk/data/gradients/Flare_Rays_Radial_1.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Flare Rays Radial 1 +2 +0.000000 0.514267 0.657763 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.500000 1 0 +0.657763 0.938230 1.000000 1.000000 1.000000 1.000000 0.500000 1.000000 1.000000 1.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Flare_Rays_Radial_2.ggr b/chalk/data/gradients/Flare_Rays_Radial_2.ggr new file mode 100644 index 00000000..c38e061c --- /dev/null +++ b/chalk/data/gradients/Flare_Rays_Radial_2.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Flare Rays Radial 2 +2 +0.000000 0.181970 0.434057 1.000000 1.000000 1.000000 0.000000 1.000000 0.600000 0.600000 0.600000 1 0 +0.434057 0.582638 1.000000 1.000000 0.600000 0.600000 0.600000 1.000000 1.000000 1.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Flare_Rays_Size_1.ggr b/chalk/data/gradients/Flare_Rays_Size_1.ggr new file mode 100644 index 00000000..f5d85e7f --- /dev/null +++ b/chalk/data/gradients/Flare_Rays_Size_1.ggr @@ -0,0 +1,19 @@ +GIMP Gradient +Name: Flare Rays Size 1 +16 +0.000000 0.031250 0.062500 1.000000 1.000000 1.000000 1.000000 0.240000 0.240000 0.240000 1.000000 0 0 +0.062500 0.117659 0.153589 0.240000 0.240000 0.240000 1.000000 0.860000 0.860000 0.860000 1.000000 0 0 +0.153589 0.161496 0.187500 0.860000 0.860000 0.860000 1.000000 0.730000 0.730000 0.730000 1.000000 0 0 +0.187500 0.225376 0.250000 0.730000 0.730000 0.730000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.250000 0.287771 0.325543 1.000000 1.000000 1.000000 1.000000 0.510000 0.510000 0.510000 1.000000 0 0 +0.325543 0.341148 0.375000 0.510000 0.510000 0.510000 1.000000 0.610000 0.610000 0.610000 1.000000 0 0 +0.375000 0.388982 0.439065 0.610000 0.610000 0.610000 1.000000 0.770000 0.770000 0.770000 1.000000 0 0 +0.439065 0.464107 0.500000 0.770000 0.770000 0.770000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.500000 0.529215 0.562500 1.000000 1.000000 1.000000 1.000000 0.280000 0.280000 0.280000 1.000000 0 0 +0.562500 0.610093 0.628339 0.280000 0.280000 0.280000 1.000000 0.760000 0.760000 0.760000 1.000000 0 0 +0.628339 0.659589 0.690839 0.760000 0.760000 0.760000 1.000000 0.420000 0.420000 0.420000 1.000000 0 0 +0.690839 0.720419 0.750000 0.420000 0.420000 0.420000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.750000 0.781250 0.812500 1.000000 1.000000 1.000000 1.000000 0.490000 0.490000 0.490000 1.000000 0 0 +0.812500 0.843750 0.856427 0.490000 0.490000 0.490000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.856427 0.906250 0.937500 0.000000 0.000000 0.000000 1.000000 0.760000 0.760000 0.760000 1.000000 0 0 +0.937500 0.968750 1.000000 0.760000 0.760000 0.760000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Flare_Sizefac_101.ggr b/chalk/data/gradients/Flare_Sizefac_101.ggr new file mode 100644 index 00000000..e654a9ee --- /dev/null +++ b/chalk/data/gradients/Flare_Sizefac_101.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Flare Sizefac 101 +1 +0.000000 0.500000 1.000000 0.370000 0.370000 0.370000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Four_bars.ggr b/chalk/data/gradients/Four_bars.ggr new file mode 100644 index 00000000..7a0a3e24 --- /dev/null +++ b/chalk/data/gradients/Four_bars.ggr @@ -0,0 +1,11 @@ +GIMP Gradient +Name: Four bars +8 +0.000000 0.062500 0.125000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.125000 0.187500 0.250000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.250000 0.312500 0.375000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.375000 0.437500 0.500000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.500000 0.562500 0.625000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.625000 0.687500 0.750000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.750000 0.812500 0.875000 0.000000 0.000000 0.000000 1.000000 0.875000 0.875000 0.875000 1.000000 0 0 +0.875000 0.937500 1.000000 0.875000 0.875000 0.875000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/French_flag.ggr b/chalk/data/gradients/French_flag.ggr new file mode 100644 index 00000000..a6167970 --- /dev/null +++ b/chalk/data/gradients/French_flag.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: French flag +3 +0.000000 0.166667 0.333333 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0 0 +0.333333 0.500000 0.666667 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.666667 0.833333 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/French_flag_smooth.ggr b/chalk/data/gradients/French_flag_smooth.ggr new file mode 100644 index 00000000..61b179df --- /dev/null +++ b/chalk/data/gradients/French_flag_smooth.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: French flag smooth +2 +0.000000 0.250000 0.500000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.500000 0.750000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Full_saturation_spectrum_CCW.ggr b/chalk/data/gradients/Full_saturation_spectrum_CCW.ggr new file mode 100644 index 00000000..9bd2ea3b --- /dev/null +++ b/chalk/data/gradients/Full_saturation_spectrum_CCW.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Full saturation spectrum CCW +1 +0.000000 0.500000 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 1 diff --git a/chalk/data/gradients/Full_saturation_spectrum_CW.ggr b/chalk/data/gradients/Full_saturation_spectrum_CW.ggr new file mode 100644 index 00000000..d70ba643 --- /dev/null +++ b/chalk/data/gradients/Full_saturation_spectrum_CW.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Full saturation spectrum CW +1 +0.000000 0.500000 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 2 diff --git a/chalk/data/gradients/German_flag.ggr b/chalk/data/gradients/German_flag.ggr new file mode 100644 index 00000000..8d76ac20 --- /dev/null +++ b/chalk/data/gradients/German_flag.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: German flag +3 +0.000000 0.166667 0.333333 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.333333 0.500000 0.666667 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 +0.666667 0.833333 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/German_flag_smooth.ggr b/chalk/data/gradients/German_flag_smooth.ggr new file mode 100644 index 00000000..efadfdbc --- /dev/null +++ b/chalk/data/gradients/German_flag_smooth.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: German flag smooth +2 +0.000000 0.250000 0.500000 0.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 +0.500000 0.750000 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Golden.ggr b/chalk/data/gradients/Golden.ggr new file mode 100644 index 00000000..4f1a65e2 --- /dev/null +++ b/chalk/data/gradients/Golden.ggr @@ -0,0 +1,17 @@ +GIMP Gradient +Name: Golden +14 +0.000000 0.080316 0.163606 0.137255 0.156863 0.011760 1.000000 0.533330 0.415600 0.086270 1.000000 0 0 +0.163606 0.193879 0.224151 0.533330 0.415600 0.086270 1.000000 0.650000 0.550000 0.161000 1.000000 0 0 +0.224151 0.254424 0.284697 0.650000 0.550000 0.161000 1.000000 0.800000 0.710000 0.290000 1.000000 0 0 +0.284697 0.314969 0.345242 0.800000 0.710000 0.290000 1.000000 0.920000 0.859000 0.400000 1.000000 0 0 +0.345242 0.382304 0.414023 0.920000 0.859000 0.400000 1.000000 0.960000 0.925000 0.440000 1.000000 0 0 +0.414023 0.467446 0.516416 0.960000 0.925000 0.440000 1.000000 0.820000 0.745000 0.298000 1.000000 0 0 +0.516416 0.541681 0.571953 0.820000 0.745000 0.298000 1.000000 0.733300 0.612000 0.200000 1.000000 0 0 +0.571953 0.602226 0.632499 0.733300 0.612000 0.200000 1.000000 0.658800 0.556900 0.165000 1.000000 0 0 +0.632499 0.662771 0.698052 0.658800 0.556900 0.165000 1.000000 0.792160 0.682300 0.266667 1.000000 0 0 +0.698052 0.728325 0.757930 0.792160 0.682300 0.266667 1.000000 0.855000 0.792000 0.337000 1.000000 0 0 +0.757930 0.787201 0.817474 0.855000 0.792000 0.337000 1.000000 0.816000 0.733300 0.286300 1.000000 0 0 +0.817474 0.847746 0.878019 0.816000 0.733300 0.286300 1.000000 0.733300 0.612000 0.200000 1.000000 0 0 +0.878019 0.906511 0.934891 0.733300 0.612000 0.200000 1.000000 0.537000 0.423500 0.101000 1.000000 0 0 +0.934891 0.973289 1.000000 0.537000 0.423500 0.101000 1.000000 0.137255 0.156863 0.011760 1.000000 0 0 diff --git a/chalk/data/gradients/Greens.ggr b/chalk/data/gradients/Greens.ggr new file mode 100644 index 00000000..0f307a01 --- /dev/null +++ b/chalk/data/gradients/Greens.ggr @@ -0,0 +1,12 @@ +GIMP Gradient +Name: Greens +9 +0.000000 0.062500 0.086811 0.146341 0.393939 0.133992 1.000000 0.198883 0.300000 0.135000 1.000000 0 0 +0.086811 0.200334 0.250000 0.198883 0.300000 0.135000 1.000000 0.406805 0.613636 0.276136 1.000000 0 0 +0.250000 0.312500 0.375000 0.406805 0.613636 0.276136 1.000000 0.324169 0.454545 0.114714 1.000000 0 0 +0.375000 0.437500 0.500835 0.324169 0.454545 0.114714 1.000000 0.098346 0.136364 0.085909 1.000000 0 0 +0.500835 0.535893 0.577629 0.098346 0.136364 0.085909 1.000000 0.196692 0.272727 0.171818 1.000000 0 0 +0.577629 0.621035 0.657763 0.234710 0.243859 0.187625 1.000000 0.272727 0.214990 0.203431 1.000000 0 0 +0.657763 0.709516 0.757930 0.272727 0.214990 0.203431 1.000000 0.430776 0.666667 0.326636 1.000000 1 0 +0.757930 0.811352 0.839733 0.430776 0.666667 0.326636 1.000000 0.369390 0.420000 0.344400 1.000000 1 0 +0.839733 0.968280 1.000000 0.369390 0.420000 0.344400 1.000000 0.091517 0.260000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Horizon_1.ggr b/chalk/data/gradients/Horizon_1.ggr new file mode 100644 index 00000000..25db002b --- /dev/null +++ b/chalk/data/gradients/Horizon_1.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Horizon 1 +5 +0.000000 0.348915 0.532554 0.047059 0.360784 0.572549 1.000000 1.000000 0.984314 0.984314 1.000000 0 0 +0.532554 0.542571 0.555927 1.000000 0.984314 0.984314 1.000000 0.258824 0.121569 0.035294 1.000000 3 0 +0.555927 0.582638 0.612688 0.258824 0.121569 0.035294 1.000000 1.000000 0.811765 0.549020 1.000000 3 0 +0.612688 0.778798 0.948247 1.000000 0.811765 0.549020 1.000000 0.349020 0.160784 0.058824 1.000000 0 0 +0.948247 0.974124 1.000000 0.349020 0.160784 0.058824 1.000000 1.000000 0.556863 0.219608 1.000000 0 0 diff --git a/chalk/data/gradients/Horizon_2.ggr b/chalk/data/gradients/Horizon_2.ggr new file mode 100644 index 00000000..e2d07424 --- /dev/null +++ b/chalk/data/gradients/Horizon_2.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Horizon 2 +5 +0.000000 0.290484 0.348915 0.047059 0.360784 0.572549 1.000000 0.370303 0.628966 0.787879 1.000000 0 0 +0.348915 0.470785 0.532554 0.370303 0.628966 0.787879 1.000000 1.000000 0.984314 0.984314 1.000000 0 0 +0.532554 0.542571 0.555927 1.000000 0.984314 0.984314 1.000000 0.039048 0.132980 0.265152 1.000000 3 0 +0.555927 0.582638 0.612688 0.039048 0.132980 0.265152 1.000000 0.522500 0.823569 0.950000 1.000000 3 0 +0.612688 0.754591 1.000000 0.522500 0.823569 0.950000 1.000000 0.087500 0.131053 0.250000 1.000000 0 0 diff --git a/chalk/data/gradients/Incandescent.ggr b/chalk/data/gradients/Incandescent.ggr new file mode 100644 index 00000000..64a3438b --- /dev/null +++ b/chalk/data/gradients/Incandescent.ggr @@ -0,0 +1,7 @@ +GIMP Gradient +Name: Incandescent +4 +0.000000 0.459098 0.594324 0.000000 0.000000 0.000000 1.000000 0.729412 0.000000 0.000000 1.000000 0 0 +0.594324 0.677796 0.809683 0.729412 0.000000 0.000000 1.000000 1.000000 0.545098 0.196078 1.000000 0 0 +0.809683 0.853088 0.899833 1.000000 0.545098 0.196078 1.000000 0.972549 0.937255 0.074510 1.000000 0 0 +0.899833 0.948247 1.000000 0.972549 0.937255 0.074510 1.000000 0.976471 0.968627 0.831373 1.000000 0 0 diff --git a/chalk/data/gradients/Land_1.ggr b/chalk/data/gradients/Land_1.ggr new file mode 100644 index 00000000..a2180779 --- /dev/null +++ b/chalk/data/gradients/Land_1.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Land 1 +5 +0.000000 0.348915 0.532554 0.047059 0.360784 0.572549 1.000000 1.000000 0.984314 0.984314 1.000000 0 0 +0.532554 0.542571 0.555927 1.000000 0.984314 0.984314 1.000000 0.258824 0.121569 0.035294 1.000000 3 0 +0.555927 0.582638 0.612688 0.258824 0.121569 0.035294 1.000000 0.378491 0.689394 0.398544 1.000000 3 0 +0.612688 0.702838 0.948247 0.378491 0.689394 0.398544 1.000000 0.058824 0.349020 0.114977 1.000000 0 0 +0.948247 0.974124 1.000000 0.058824 0.349020 0.114977 1.000000 0.111468 0.507576 0.162566 1.000000 0 0 diff --git a/chalk/data/gradients/Land_and_Sea.ggr b/chalk/data/gradients/Land_and_Sea.ggr new file mode 100644 index 00000000..a932b188 --- /dev/null +++ b/chalk/data/gradients/Land_and_Sea.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Land and Sea +5 +0.000000 0.081803 0.166945 1.000000 1.000000 1.000000 1.000000 0.560606 0.560606 0.560606 1.000000 0 0 +0.166945 0.212020 0.265442 0.560606 0.560606 0.560606 1.000000 0.083243 0.462121 0.112054 1.000000 0 0 +0.265442 0.378965 0.390651 0.083243 0.462121 0.112054 1.000000 1.000000 0.988739 0.298904 1.000000 0 0 +0.390651 0.400668 0.459098 1.000000 0.988739 0.298904 1.000000 0.529502 0.586235 1.000000 1.000000 0 0 +0.459098 0.507513 1.000000 0.529502 0.586235 1.000000 1.000000 0.019021 0.108157 0.590909 1.000000 0 0 diff --git a/chalk/data/gradients/Makefile.am b/chalk/data/gradients/Makefile.am new file mode 100644 index 00000000..da445ce8 --- /dev/null +++ b/chalk/data/gradients/Makefile.am @@ -0,0 +1,4 @@ + +chalkgradientsdir = $(prefix)/share/apps/chalk/gradients + +chalkgradients_DATA = Abstract_1.ggr Abstract_2.ggr Abstract_3.ggr Aneurism.ggr Blinds.ggr Blue_Green.ggr Browns.ggr Brushed_Aluminium.ggr Burning_Paper.ggr Burning_Transparency.ggr Caribbean_Blues.ggr CD.ggr CD_Half.ggr Coffee.ggr Cold_Steel_2.ggr Cold_Steel.ggr Crown_molding.ggr Dark_1.ggr Deep_Sea.ggr Default.ggr Flare_Glow_Angular_1.ggr Flare_Glow_Radial_1.ggr Flare_Glow_Radial_2.ggr Flare_Glow_Radial_3.ggr Flare_Glow_Radial_4.ggr Flare_Radial_101.ggr Flare_Radial_102.ggr Flare_Radial_103.ggr Flare_Rays_Radial_1.ggr Flare_Rays_Radial_2.ggr Flare_Rays_Size_1.ggr Flare_Sizefac_101.ggr Four_bars.ggr French_flag.ggr French_flag_smooth.ggr Full_saturation_spectrum_CCW.ggr Full_saturation_spectrum_CW.ggr German_flag.ggr German_flag_smooth.ggr Golden.ggr Greens.ggr Horizon_1.ggr Horizon_2.ggr Incandescent.ggr Land_1.ggr Land_and_Sea.ggr Metallic_Something.ggr Mexican_flag.ggr Mexican_flag_smooth.ggr Nauseating_Headache.ggr Neon_Cyan.ggr Neon_Green.ggr Neon_Yellow.ggr Pastel_Rainbow.ggr Pastels.ggr Purples.ggr Radial_Eyeball_Blue.ggr Radial_Eyeball_Brown.ggr Radial_Eyeball_Green.ggr Radial_Glow_1.ggr Radial_Rainbow_Hoop.ggr Romanian_flag.ggr Romanian_flag_smooth.ggr Rounded_edge.ggr Shadows_1.ggr Shadows_2.ggr Shadows_3.ggr Skyline.ggr Skyline_polluted.ggr Square_Wood_Frame.ggr Sunrise.ggr Three_bars_sin.ggr Tropical_Colors.ggr Tube_Red.ggr Wood_1.ggr Wood_2.ggr Yellow_Contrast.ggr Yellow_Orange.ggr diff --git a/chalk/data/gradients/Metallic_Something.ggr b/chalk/data/gradients/Metallic_Something.ggr new file mode 100644 index 00000000..19e675b7 --- /dev/null +++ b/chalk/data/gradients/Metallic_Something.ggr @@ -0,0 +1,11 @@ +GIMP Gradient +Name: Metallic Something +8 +0.000000 0.036728 0.096828 0.020000 0.050000 0.080000 1.000000 0.142500 0.168750 0.195000 1.000000 2 0 +0.096828 0.163606 0.220367 0.142500 0.168750 0.195000 1.000000 0.317326 0.344269 0.371212 1.000000 2 0 +0.220367 0.287237 0.333890 0.317326 0.344269 0.371212 1.000000 0.425000 0.357284 0.327250 1.000000 2 0 +0.333890 0.368835 0.423205 0.425000 0.357284 0.327250 1.000000 0.271322 0.389264 0.500000 1.000000 2 0 +0.423205 0.517744 0.574290 0.271322 0.389264 0.500000 1.000000 0.592000 0.632258 0.800000 1.000000 2 0 +0.574290 0.657691 0.742905 0.592000 0.632258 0.800000 1.000000 0.931818 0.906382 0.782727 1.000000 2 0 +0.742905 0.808013 0.859766 0.931818 0.906382 0.782727 1.000000 0.841294 0.844890 0.848485 1.000000 2 0 +0.859766 0.914858 1.000000 0.841294 0.844890 0.848485 1.000000 0.581685 0.611610 0.674242 1.000000 2 0 diff --git a/chalk/data/gradients/Mexican_flag.ggr b/chalk/data/gradients/Mexican_flag.ggr new file mode 100644 index 00000000..bcb7686d --- /dev/null +++ b/chalk/data/gradients/Mexican_flag.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Mexican flag +3 +0.000000 0.166667 0.333333 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0.000000 1.000000 0 0 +0.333333 0.500000 0.666667 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.666667 0.833333 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Mexican_flag_smooth.ggr b/chalk/data/gradients/Mexican_flag_smooth.ggr new file mode 100644 index 00000000..ee363116 --- /dev/null +++ b/chalk/data/gradients/Mexican_flag_smooth.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Mexican flag smooth +2 +0.000000 0.250000 0.500000 0.000000 1.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.500000 0.750000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Nauseating_Headache.ggr b/chalk/data/gradients/Nauseating_Headache.ggr new file mode 100644 index 00000000..347453ac --- /dev/null +++ b/chalk/data/gradients/Nauseating_Headache.ggr @@ -0,0 +1,28 @@ +GIMP Gradient +Name: Nauseating Headache +25 +0.000000 0.058431 0.098497 0.391197 0.651515 0.409796 1.000000 0.495110 0.916667 0.865009 1.000000 0 1 +0.098497 0.100167 0.101836 0.495110 0.916667 0.865009 1.000000 0.451393 0.807720 0.778663 1.000000 0 0 +0.101836 0.103506 0.105175 0.451393 0.807720 0.778663 1.000000 0.407676 0.698774 0.692318 1.000000 0 0 +0.105175 0.106845 0.108514 0.407676 0.698774 0.692318 1.000000 0.363958 0.589828 0.605972 1.000000 0 0 +0.108514 0.110184 0.111853 0.363958 0.589828 0.605972 1.000000 0.320241 0.480881 0.519626 1.000000 0 0 +0.111853 0.122705 0.133556 0.320241 0.480881 0.519626 1.000000 0.276524 0.371935 0.433280 1.000000 0 0 +0.133556 0.144407 0.157763 0.276524 0.371935 0.433280 1.000000 0.232807 0.262989 0.346934 1.000000 0 0 +0.157763 0.161937 0.166110 0.232807 0.262989 0.346934 1.000000 0.390299 0.317958 0.537879 1.000000 0 0 +0.166110 0.256469 0.313022 0.390299 0.317958 0.537879 1.000000 0.145373 0.045096 0.174242 1.000000 0 0 +0.313022 0.333890 0.355175 0.145373 0.045096 0.174242 1.000000 0.424242 0.065931 0.036105 1.000000 0 0 +0.355175 0.494470 0.626043 0.424242 0.065931 0.036105 1.000000 0.145373 0.045096 0.174242 1.000000 2 0 +0.626043 0.635363 0.645614 0.232807 0.262989 0.346934 1.000000 0.390299 0.317958 0.537879 1.000000 0 0 +0.645614 0.679871 0.724958 0.390299 0.317958 0.537879 1.000000 0.145373 0.045096 0.174242 1.000000 0 0 +0.724958 0.729132 0.729132 0.232807 0.262989 0.346934 1.000000 0.390299 0.317958 0.537879 1.000000 0 0 +0.729132 0.740427 0.751722 0.390299 0.317958 0.537879 1.000000 0.359683 0.283851 0.492424 1.000000 0 0 +0.751722 0.763016 0.774311 0.359683 0.283851 0.492424 1.000000 0.329067 0.249743 0.446970 1.000000 0 0 +0.774311 0.785606 0.796901 0.329067 0.249743 0.446970 1.000000 0.298452 0.215635 0.401515 1.000000 0 0 +0.796901 0.808196 0.819491 0.298452 0.215635 0.401515 1.000000 0.267836 0.181527 0.356061 1.000000 0 0 +0.819491 0.830786 0.842081 0.267836 0.181527 0.356061 1.000000 0.237220 0.147420 0.310606 1.000000 0 0 +0.842081 0.853375 0.864670 0.310606 0.000000 0.003409 1.000000 0.424242 0.137255 0.137255 1.000000 2 0 +0.864670 0.867435 0.874067 0.206604 0.113312 0.265152 1.000000 0.951331 1.000000 0.487291 1.000000 0 0 +0.874067 0.878939 0.884060 0.951331 1.000000 0.487291 1.000000 0.951331 1.000000 0.487291 1.000000 0 0 +0.884060 0.893477 0.902894 0.951331 1.000000 0.487291 1.000000 0.951331 1.000000 0.487291 1.000000 0 0 +0.902894 0.908389 0.910267 0.951331 1.000000 0.487291 1.000000 0.145373 0.045096 0.174242 1.000000 0 0 +0.910267 1.000000 1.000000 0.145373 0.045096 0.174242 1.000000 0.495110 0.916667 0.865009 1.000000 0 0 diff --git a/chalk/data/gradients/Neon_Cyan.ggr b/chalk/data/gradients/Neon_Cyan.ggr new file mode 100644 index 00000000..4ae27583 --- /dev/null +++ b/chalk/data/gradients/Neon_Cyan.ggr @@ -0,0 +1,7 @@ +GIMP Gradient +Name: Neon Cyan +4 +0.000000 0.672788 0.699499 0.000000 1.000000 0.949020 0.000000 0.000000 1.000000 0.933333 0.901961 1 0 +0.699499 0.737062 0.774624 0.000000 1.000000 0.913725 0.901961 0.827451 1.000000 0.988235 1.000000 1 0 +0.774624 0.812187 0.849750 0.827451 1.000000 0.984314 1.000000 0.000000 1.000000 0.913725 0.901961 1 0 +0.849750 0.874791 1.000000 0.000000 1.000000 0.913725 0.901961 0.000000 1.000000 0.933333 0.000000 1 0 diff --git a/chalk/data/gradients/Neon_Green.ggr b/chalk/data/gradients/Neon_Green.ggr new file mode 100644 index 00000000..1f7402f8 --- /dev/null +++ b/chalk/data/gradients/Neon_Green.ggr @@ -0,0 +1,7 @@ +GIMP Gradient +Name: Neon Green +4 +0.000000 0.672788 0.699499 0.000000 1.000000 0.000000 0.000000 0.129412 1.000000 0.000000 0.901961 1 0 +0.699499 0.737062 0.774624 0.129412 1.000000 0.000000 0.901961 0.823529 1.000000 0.807843 1.000000 1 0 +0.774624 0.812187 0.849750 0.823529 1.000000 0.807843 1.000000 0.196078 1.000000 0.000000 0.901961 1 0 +0.849750 0.874791 1.000000 0.196078 1.000000 0.000000 0.901961 0.031373 1.000000 0.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Neon_Yellow.ggr b/chalk/data/gradients/Neon_Yellow.ggr new file mode 100644 index 00000000..31648b04 --- /dev/null +++ b/chalk/data/gradients/Neon_Yellow.ggr @@ -0,0 +1,7 @@ +GIMP Gradient +Name: Neon Yellow +4 +0.000000 0.672788 0.699499 1.000000 0.949020 0.000000 0.000000 1.000000 0.933333 0.000000 0.901961 1 0 +0.699499 0.737062 0.774624 1.000000 0.933333 0.000000 0.901961 0.996078 1.000000 0.819608 1.000000 1 0 +0.774624 0.812187 0.849750 1.000000 0.996078 0.819608 1.000000 1.000000 0.949020 0.000000 0.901961 1 0 +0.849750 0.874791 1.000000 1.000000 0.949020 0.000000 0.901961 1.000000 0.949020 0.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Pastel_Rainbow.ggr b/chalk/data/gradients/Pastel_Rainbow.ggr new file mode 100644 index 00000000..28a71847 --- /dev/null +++ b/chalk/data/gradients/Pastel_Rainbow.ggr @@ -0,0 +1,4 @@ +GIMP Gradient +Name: Pastel Rainbow +1 +0.000000 0.500000 1.000000 1.000000 0.749020 0.749020 1.000000 1.000000 0.749020 0.749020 1.000000 0 1 diff --git a/chalk/data/gradients/Pastels.ggr b/chalk/data/gradients/Pastels.ggr new file mode 100644 index 00000000..f57fa5af --- /dev/null +++ b/chalk/data/gradients/Pastels.ggr @@ -0,0 +1,17 @@ +GIMP Gradient +Name: Pastels +14 +0.000000 0.035714 0.091462 0.960000 0.880000 0.690000 1.000000 0.962857 0.741400 0.930894 1.000000 0 0 +0.091462 0.127176 0.137849 0.962857 0.741400 0.930894 1.000000 0.761897 0.812851 0.965714 1.000000 0 0 +0.137849 0.171953 0.189244 0.761897 0.812851 0.965714 1.000000 0.719697 0.628944 0.660036 1.000000 0 0 +0.189244 0.223706 0.252087 0.719697 0.628944 0.660036 1.000000 0.670286 0.728675 0.971429 1.000000 0 0 +0.252087 0.300501 0.323754 0.670286 0.728675 0.971429 1.000000 0.951464 0.974286 0.876857 1.000000 0 0 +0.323754 0.365609 0.386835 0.951464 0.974286 0.876857 1.000000 0.977143 0.634945 0.718332 1.000000 0 0 +0.386835 0.430897 0.470785 0.977143 0.634945 0.718332 1.000000 0.391757 0.449753 0.484848 1.000000 0 0 +0.470785 0.549249 0.581445 0.391757 0.449753 0.484848 1.000000 0.982857 0.804789 0.790632 1.000000 0 0 +0.581445 0.598796 0.646077 0.982857 0.804789 0.790632 1.000000 0.666941 0.500514 0.727273 1.000000 0 0 +0.646077 0.720308 0.742905 0.666941 0.500514 0.727273 1.000000 0.988571 0.870321 0.798764 1.000000 0 0 +0.742905 0.772955 0.804674 0.988571 0.870321 0.798764 1.000000 0.806903 0.479551 0.856061 1.000000 0 0 +0.804674 0.829716 0.861436 0.806903 0.479551 0.856061 1.000000 0.994286 0.873405 0.686057 1.000000 0 0 +0.861436 0.892857 0.911519 0.994286 0.873405 0.686057 1.000000 0.997143 0.927343 0.955263 1.000000 0 0 +0.911519 0.964286 1.000000 0.997143 0.927343 0.955263 1.000000 1.000000 0.748380 0.866107 1.000000 0 0 diff --git a/chalk/data/gradients/Purples.ggr b/chalk/data/gradients/Purples.ggr new file mode 100644 index 00000000..6c6ce689 --- /dev/null +++ b/chalk/data/gradients/Purples.ggr @@ -0,0 +1,10 @@ +GIMP Gradient +Name: Purples +7 +0.000000 0.057596 0.098497 0.303030 0.109635 0.273088 1.000000 0.514411 0.279242 0.734848 1.000000 0 0 +0.098497 0.176962 0.228715 0.514411 0.279242 0.734848 1.000000 0.604602 0.331500 0.650000 1.000000 0 0 +0.228715 0.347245 0.404006 0.604602 0.331500 0.650000 1.000000 0.200503 0.169888 0.393939 1.000000 0 0 +0.404006 0.480801 0.544241 0.200503 0.169888 0.393939 1.000000 0.500537 0.323300 0.530000 1.000000 0 0 +0.544241 0.628761 0.713283 0.500537 0.323300 0.530000 1.000000 0.600648 0.445741 0.681667 1.000000 0 0 +0.713283 0.766491 0.819699 0.600648 0.445741 0.681667 1.000000 0.700758 0.568182 0.833333 1.000000 0 0 +0.819699 0.928214 1.000000 0.700758 0.568182 0.833333 1.000000 0.184745 0.149793 0.219697 1.000000 0 0 diff --git a/chalk/data/gradients/Radial_Eyeball_Blue.ggr b/chalk/data/gradients/Radial_Eyeball_Blue.ggr new file mode 100644 index 00000000..9a23068b --- /dev/null +++ b/chalk/data/gradients/Radial_Eyeball_Blue.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Radial Eyeball Blue +5 +0.000000 0.105175 0.198664 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.198664 0.352254 0.492487 0.000000 0.035294 0.729412 1.000000 0.000000 0.015686 0.376471 1.000000 0 0 +0.492487 0.636060 0.787980 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.787980 0.931553 0.996661 1.000000 1.000000 1.000000 1.000000 1.000000 0.619608 0.619608 1.000000 0 0 +0.996661 0.996661 1.000000 1.000000 0.619608 0.619608 0.000000 1.000000 0.619608 0.619608 0.000000 0 0 diff --git a/chalk/data/gradients/Radial_Eyeball_Brown.ggr b/chalk/data/gradients/Radial_Eyeball_Brown.ggr new file mode 100644 index 00000000..c9049440 --- /dev/null +++ b/chalk/data/gradients/Radial_Eyeball_Brown.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Radial Eyeball Brown +5 +0.000000 0.105175 0.198664 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.198664 0.352254 0.492487 0.478431 0.380392 0.000000 1.000000 0.298039 0.227451 0.000000 1.000000 0 0 +0.492487 0.636060 0.787980 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.787980 0.931553 0.996661 1.000000 1.000000 1.000000 1.000000 1.000000 0.619608 0.619608 1.000000 0 0 +0.996661 0.996661 1.000000 1.000000 0.619608 0.619608 0.000000 1.000000 0.619608 0.619608 0.000000 0 0 diff --git a/chalk/data/gradients/Radial_Eyeball_Green.ggr b/chalk/data/gradients/Radial_Eyeball_Green.ggr new file mode 100644 index 00000000..5352ec6f --- /dev/null +++ b/chalk/data/gradients/Radial_Eyeball_Green.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Radial Eyeball Green +5 +0.000000 0.105175 0.198664 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 +0.198664 0.352254 0.492487 0.000000 0.709804 0.423529 1.000000 0.000000 0.356863 0.094118 1.000000 0 0 +0.492487 0.636060 0.787980 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 0 +0.787980 0.931553 0.996661 1.000000 1.000000 1.000000 1.000000 1.000000 0.619608 0.619608 1.000000 0 0 +0.996661 0.996661 1.000000 1.000000 0.619608 0.619608 0.000000 1.000000 0.619608 0.619608 0.000000 0 0 diff --git a/chalk/data/gradients/Radial_Glow_1.ggr b/chalk/data/gradients/Radial_Glow_1.ggr new file mode 100644 index 00000000..7169c67b --- /dev/null +++ b/chalk/data/gradients/Radial_Glow_1.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Radial Glow 1 +5 +0.000000 0.173623 0.350584 1.000000 1.000000 1.000000 0.809524 1.000000 0.737255 0.737255 0.306122 2 0 +0.350584 0.375626 0.400668 1.000000 0.737255 0.737255 0.306122 1.000000 0.636060 0.636060 0.306122 0 0 +0.400668 0.417919 0.421223 1.000000 0.636060 0.636060 0.306122 1.000000 0.517647 0.517647 0.605442 1 0 +0.421223 0.425153 0.440735 1.000000 0.517647 0.517647 0.605442 0.988235 0.501961 0.501961 0.306122 1 0 +0.440735 0.720367 1.000000 0.988235 0.501961 0.501961 0.306122 1.000000 0.000000 0.000000 0.000000 0 0 diff --git a/chalk/data/gradients/Radial_Rainbow_Hoop.ggr b/chalk/data/gradients/Radial_Rainbow_Hoop.ggr new file mode 100644 index 00000000..b34ad915 --- /dev/null +++ b/chalk/data/gradients/Radial_Rainbow_Hoop.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Radial Rainbow Hoop +3 +0.000000 0.666110 0.699499 0.000000 1.000000 0.000000 0.000000 1.000000 0.113725 0.000000 1.000000 1 2 +0.699499 0.767947 0.849750 1.000000 0.113725 0.000000 1.000000 1.000000 0.000000 0.047059 1.000000 0 1 +0.849750 0.878130 1.000000 1.000000 0.000000 0.047059 1.000000 1.000000 0.431373 0.000000 0.000000 1 0 diff --git a/chalk/data/gradients/Romanian_flag.ggr b/chalk/data/gradients/Romanian_flag.ggr new file mode 100644 index 00000000..bcdb9bca --- /dev/null +++ b/chalk/data/gradients/Romanian_flag.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Romanian flag +3 +0.000000 0.166667 0.333333 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0 0 +0.333333 0.500000 0.666667 1.000000 1.000000 0.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 +0.666667 0.833333 1.000000 1.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Romanian_flag_smooth.ggr b/chalk/data/gradients/Romanian_flag_smooth.ggr new file mode 100644 index 00000000..08a3daeb --- /dev/null +++ b/chalk/data/gradients/Romanian_flag_smooth.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Romanian flag smooth +2 +0.000000 0.250000 0.500000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0 0 +0.500000 0.750000 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Rounded_edge.ggr b/chalk/data/gradients/Rounded_edge.ggr new file mode 100644 index 00000000..5cb2f6c6 --- /dev/null +++ b/chalk/data/gradients/Rounded_edge.ggr @@ -0,0 +1,10 @@ +GIMP Gradient +Name: Rounded edge +7 +0.000000 0.220339 0.440678 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0 1 +0.440678 0.487288 0.533898 1.000000 1.000000 1.000000 1.000000 0.833333 0.833333 0.833333 1.000000 0 2 +0.533898 0.580508 0.627119 0.833333 0.833333 0.833333 1.000000 0.666667 0.666667 0.666667 1.000000 0 2 +0.627119 0.673729 0.720339 0.666667 0.666667 0.666667 1.000000 0.500000 0.500000 0.500000 1.000000 0 2 +0.720339 0.766949 0.813559 0.500000 0.500000 0.500000 1.000000 0.333333 0.333333 0.333333 1.000000 0 2 +0.813559 0.860169 0.906780 0.333333 0.333333 0.333333 1.000000 0.166667 0.166667 0.166667 1.000000 0 2 +0.906780 0.953390 1.000000 0.166667 0.166667 0.166667 1.000000 0.000000 0.000000 0.000000 1.000000 0 2 diff --git a/chalk/data/gradients/Shadows_1.ggr b/chalk/data/gradients/Shadows_1.ggr new file mode 100644 index 00000000..14574edc --- /dev/null +++ b/chalk/data/gradients/Shadows_1.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Shadows 1 +5 +0.000000 0.221580 0.346912 0.113636 0.113636 0.113636 1.000000 0.643939 0.311237 0.107323 1.000000 0 0 +0.346912 0.449416 0.538564 0.643939 0.311237 0.107323 1.000000 0.871212 0.820000 0.820000 1.000000 0 0 +0.538564 0.617696 0.652755 0.871212 0.820000 0.820000 1.000000 0.340000 0.128091 0.107291 1.000000 0 0 +0.652755 0.747913 0.777963 0.340000 0.128091 0.107291 1.000000 1.000000 0.521990 0.220000 1.000000 1 0 +0.777963 0.854667 1.000000 1.000000 0.521990 0.220000 1.000000 0.204545 0.121376 0.046011 1.000000 0 0 diff --git a/chalk/data/gradients/Shadows_2.ggr b/chalk/data/gradients/Shadows_2.ggr new file mode 100644 index 00000000..31b4f7f2 --- /dev/null +++ b/chalk/data/gradients/Shadows_2.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Shadows 2 +5 +0.000000 0.048414 0.126878 0.462121 0.462121 0.462121 1.000000 0.940000 0.865112 0.817800 1.000000 0 0 +0.126878 0.368948 0.499165 0.940000 0.865112 0.817800 1.000000 0.380000 0.328734 0.231331 1.000000 0 0 +0.499165 0.602671 0.739566 0.380000 0.328734 0.231331 1.000000 0.553030 0.482304 0.336911 1.000000 0 0 +0.739566 0.766350 0.854758 0.553030 0.482304 0.336911 1.000000 0.007576 0.007576 0.007576 1.000000 0 0 +0.854758 0.968292 1.000000 0.007576 0.007576 0.007576 1.000000 0.659091 0.659091 0.659091 1.000000 1 0 diff --git a/chalk/data/gradients/Shadows_3.ggr b/chalk/data/gradients/Shadows_3.ggr new file mode 100644 index 00000000..eb9366d8 --- /dev/null +++ b/chalk/data/gradients/Shadows_3.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Shadows 3 +6 +0.000000 0.143573 0.297162 0.598485 0.598484 0.598484 1.000000 0.492424 0.303700 0.136994 1.000000 1 0 +0.297162 0.330551 0.365609 0.492424 0.303700 0.136994 1.000000 0.880909 0.584348 0.509475 1.000000 1 0 +0.365609 0.484140 0.549040 0.880909 0.584348 0.509475 1.000000 0.969697 0.673909 0.000000 1.000000 1 0 +0.549040 0.580290 0.611540 0.969697 0.673909 0.000000 1.000000 0.857935 0.931818 0.026245 1.000000 0 0 +0.611540 0.651085 0.699499 0.857935 0.931818 0.026245 1.000000 0.590000 0.660000 0.020000 1.000000 1 0 +0.699499 0.886477 1.000000 0.590000 0.660000 0.020000 1.000000 0.030000 0.050000 0.220000 1.000000 1 0 diff --git a/chalk/data/gradients/Skyline.ggr b/chalk/data/gradients/Skyline.ggr new file mode 100644 index 00000000..ba43e817 --- /dev/null +++ b/chalk/data/gradients/Skyline.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Skyline +5 +0.000000 0.051753 0.365609 0.000000 0.000000 0.000000 1.000000 0.109804 0.066667 0.568627 1.000000 3 0 +0.365609 0.602671 0.749583 0.109804 0.066667 0.568627 1.000000 0.917647 0.043137 0.043137 1.000000 0 0 +0.749583 0.789649 0.864775 0.917647 0.043137 0.043137 1.000000 1.000000 0.533333 0.000000 1.000000 0 0 +0.864775 0.896494 0.934891 1.000000 0.533333 0.000000 1.000000 0.937255 0.925490 0.215686 1.000000 0 0 +0.934891 0.958264 1.000000 0.537255 0.396078 0.031373 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Skyline_polluted.ggr b/chalk/data/gradients/Skyline_polluted.ggr new file mode 100644 index 00000000..5677742a --- /dev/null +++ b/chalk/data/gradients/Skyline_polluted.ggr @@ -0,0 +1,8 @@ +GIMP Gradient +Name: Skyline polluted +5 +0.000000 0.051753 0.365609 0.000000 0.000000 0.000000 1.000000 0.227451 0.207843 0.486275 1.000000 3 0 +0.365609 0.602671 0.749583 0.227451 0.207843 0.486275 1.000000 0.709804 0.098039 0.098039 1.000000 0 0 +0.749583 0.789649 0.864775 0.709804 0.098039 0.098039 1.000000 0.819608 0.505882 0.270588 1.000000 0 0 +0.864775 0.896494 0.934891 0.819608 0.505882 0.270588 1.000000 0.800000 0.784314 0.564706 1.000000 0 0 +0.934891 0.958264 1.000000 0.537255 0.396078 0.031373 1.000000 0.000000 0.000000 0.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Square_Wood_Frame.ggr b/chalk/data/gradients/Square_Wood_Frame.ggr new file mode 100644 index 00000000..3314e7b2 --- /dev/null +++ b/chalk/data/gradients/Square_Wood_Frame.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Square Wood Frame +6 +0.000000 0.394306 0.797162 0.348485 0.187023 0.027070 0.000000 0.348485 0.187023 0.027070 0.000000 0 0 +0.797162 0.813856 0.830551 0.348485 0.187023 0.027070 1.000000 0.598485 0.321191 0.046490 1.000000 0 0 +0.830551 0.880217 0.929883 0.757576 0.430331 0.081217 1.000000 0.757576 0.430331 0.081217 1.000000 0 0 +0.929883 0.939294 0.949647 0.757576 0.430331 0.081217 1.000000 1.000000 0.681967 0.420000 1.000000 1 0 +0.949647 0.962907 0.976169 1.000000 0.681967 0.420000 1.000000 0.757576 0.424126 0.068392 1.000000 1 0 +0.976169 0.988085 1.000000 0.757576 0.424126 0.068392 1.000000 0.481061 0.266950 0.042141 1.000000 0 0 diff --git a/chalk/data/gradients/Sunrise.ggr b/chalk/data/gradients/Sunrise.ggr new file mode 100644 index 00000000..2bb3beff --- /dev/null +++ b/chalk/data/gradients/Sunrise.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Sunrise +6 +0.000000 0.101798 0.203595 1.000000 1.000000 1.000000 1.000000 0.948165 0.969697 0.812122 1.000000 0 0 +0.203595 0.379143 0.487479 0.948165 0.969697 0.812122 1.000000 1.000000 0.552632 0.270000 1.000000 0 0 +0.487479 0.503577 0.529137 1.000000 0.552632 0.270000 1.000000 0.581721 0.096155 0.170043 1.000000 0 0 +0.529137 0.545165 0.562604 0.581721 0.096155 0.170043 1.000000 0.287879 0.155229 0.049835 1.000000 0 0 +0.562604 0.609349 0.697830 0.287879 0.155229 0.049835 1.000000 0.336000 0.425966 0.800000 1.000000 0 0 +0.697830 0.845064 1.000000 0.336000 0.425966 0.800000 1.000000 0.852165 0.985930 1.000000 1.000000 0 0 diff --git a/chalk/data/gradients/Three_bars_sin.ggr b/chalk/data/gradients/Three_bars_sin.ggr new file mode 100644 index 00000000..564d15c7 --- /dev/null +++ b/chalk/data/gradients/Three_bars_sin.ggr @@ -0,0 +1,9 @@ +GIMP Gradient +Name: Three bars sin +6 +0.000000 0.083333 0.166667 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2 0 +0.166667 0.250000 0.333333 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 +0.333333 0.416667 0.500000 0.000000 0.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2 0 +0.500000 0.583333 0.666667 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 +0.666667 0.750000 0.833333 0.000000 0.000000 0.000000 1.000000 0.833333 0.833333 0.833333 1.000000 2 0 +0.833333 0.916667 1.000000 0.833333 0.833333 0.833333 1.000000 0.000000 0.000000 0.000000 1.000000 2 0 diff --git a/chalk/data/gradients/Tropical_Colors.ggr b/chalk/data/gradients/Tropical_Colors.ggr new file mode 100644 index 00000000..bbb0fdac --- /dev/null +++ b/chalk/data/gradients/Tropical_Colors.ggr @@ -0,0 +1,12 @@ +GIMP Gradient +Name: Tropical Colors +9 +0.000000 0.055556 0.085142 0.036578 0.159091 0.015374 1.000000 0.007899 0.310606 0.000000 1.000000 0 0 +0.085142 0.138564 0.193656 0.007899 0.310606 0.000000 1.000000 0.195893 0.575758 0.085655 1.000000 0 0 +0.193656 0.233723 0.276572 0.195893 0.575758 0.085655 1.000000 0.924242 0.750598 0.192395 1.000000 0 0 +0.276572 0.332128 0.387683 0.924242 0.750598 0.192395 1.000000 0.954545 0.239854 0.132221 1.000000 0 0 +0.387683 0.510851 0.555556 0.954545 0.239854 0.132221 1.000000 0.530303 0.319349 0.236012 1.000000 0 0 +0.555556 0.611111 0.666667 0.530303 0.319349 0.236012 1.000000 0.472649 0.295792 1.000000 1.000000 0 0 +0.666667 0.772955 0.826377 0.472649 0.295792 1.000000 1.000000 0.644153 1.000000 0.957743 1.000000 0 0 +0.826377 0.866444 0.884808 0.644153 1.000000 0.957743 1.000000 0.408723 0.870000 0.278400 1.000000 0 0 +0.884808 0.953255 1.000000 0.408723 0.870000 0.278400 1.000000 0.363558 0.500000 0.000000 1.000000 1 0 diff --git a/chalk/data/gradients/Tube_Red.ggr b/chalk/data/gradients/Tube_Red.ggr new file mode 100644 index 00000000..379fe1cc --- /dev/null +++ b/chalk/data/gradients/Tube_Red.ggr @@ -0,0 +1,10 @@ +GIMP Gradient +Name: Tube Red +7 +0.000000 0.189482 0.378965 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0 0 +0.378965 0.624374 0.721202 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1 0 +0.721202 0.748748 0.776294 0.393939 0.091171 0.035564 1.000000 0.204545 0.047339 0.018466 1.000000 1 0 +0.776294 0.833723 0.859766 0.204545 0.047339 0.018466 1.000000 0.757576 0.175329 0.068392 1.000000 1 0 +0.859766 0.876461 0.893155 0.757576 0.175329 0.068392 1.000000 1.000000 0.501132 0.420000 1.000000 1 0 +0.893155 0.911519 0.928214 1.000000 0.501132 0.420000 1.000000 0.757576 0.175329 0.068392 1.000000 1 0 +0.928214 0.964107 1.000000 0.757576 0.175329 0.068392 0.000000 0.757576 0.175329 0.068392 0.000000 0 0 diff --git a/chalk/data/gradients/Wood_1.ggr b/chalk/data/gradients/Wood_1.ggr new file mode 100644 index 00000000..15fcd106 --- /dev/null +++ b/chalk/data/gradients/Wood_1.ggr @@ -0,0 +1,6 @@ +GIMP Gradient +Name: Wood 1 +3 +0.000000 0.252087 0.555927 1.000000 0.700000 0.400000 1.000000 0.920000 0.579600 0.239200 1.000000 3 0 +0.555927 0.834725 0.981636 0.920000 0.579600 0.239200 1.000000 0.000000 0.000000 0.000000 1.000000 4 0 +0.981636 0.991653 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 4 0 diff --git a/chalk/data/gradients/Wood_2.ggr b/chalk/data/gradients/Wood_2.ggr new file mode 100644 index 00000000..b23ea06a --- /dev/null +++ b/chalk/data/gradients/Wood_2.ggr @@ -0,0 +1,12 @@ +GIMP Gradient +Name: Wood 2 +9 +0.000000 0.069491 0.138982 1.000000 0.700000 0.400000 1.000000 0.944844 0.616991 0.289137 1.000000 3 0 +0.138982 0.208472 0.277963 0.800000 0.522406 0.244813 1.000000 0.928860 0.592934 0.257008 1.000000 3 0 +0.277963 0.347454 0.416945 0.820000 0.523444 0.226888 1.000000 0.922120 0.582791 0.243462 1.000000 3 0 +0.416945 0.486436 0.555927 0.770000 0.486649 0.203299 1.000000 0.920000 0.579600 0.239200 1.000000 3 0 +0.555927 0.609140 0.662354 0.780000 0.491400 0.202800 1.000000 0.903086 0.568944 0.234802 1.000000 4 0 +0.662354 0.715568 0.768781 0.810000 0.510300 0.210600 1.000000 0.850329 0.535708 0.221086 1.000000 4 0 +0.768781 0.821995 0.875209 0.760000 0.478800 0.197600 1.000000 0.708598 0.446417 0.184235 1.000000 4 0 +0.875209 0.928422 0.981636 0.620000 0.390600 0.161200 1.000000 0.000000 0.000000 0.000000 1.000000 4 0 +0.981636 0.991653 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 4 0 diff --git a/chalk/data/gradients/Yellow_Contrast.ggr b/chalk/data/gradients/Yellow_Contrast.ggr new file mode 100644 index 00000000..dd3d89fb --- /dev/null +++ b/chalk/data/gradients/Yellow_Contrast.ggr @@ -0,0 +1,10 @@ +GIMP Gradient +Name: Yellow Contrast +7 +0.000000 0.088481 0.161937 0.000000 0.000000 0.000000 1.000000 0.969697 0.639354 0.000000 1.000000 1 0 +0.161937 0.202003 0.247078 0.969697 0.639354 0.000000 1.000000 1.000000 0.988712 0.000000 1.000000 1 0 +0.247078 0.258765 0.287145 1.000000 0.988712 0.000000 1.000000 0.166667 0.157690 0.000000 1.000000 1 0 +0.287145 0.323038 0.363940 0.166667 0.157690 0.000000 1.000000 0.007576 0.007576 0.007576 1.000000 1 0 +0.363940 0.544240 0.592654 0.007576 0.007576 0.007576 1.000000 1.000000 1.000000 1.000000 1.000000 1 0 +0.592654 0.767947 0.803005 1.000000 1.000000 1.000000 1.000000 0.857143 0.843870 0.030851 1.000000 1 0 +0.803005 0.901503 1.000000 0.857143 0.843870 0.030851 1.000000 0.333333 0.194690 0.180622 1.000000 1 0 diff --git a/chalk/data/gradients/Yellow_Orange.ggr b/chalk/data/gradients/Yellow_Orange.ggr new file mode 100644 index 00000000..ac1fe233 --- /dev/null +++ b/chalk/data/gradients/Yellow_Orange.ggr @@ -0,0 +1,5 @@ +GIMP Gradient +Name: Yellow Orange +2 +0.000000 0.135225 0.565943 1.000000 0.892593 0.000000 1.000000 1.000000 0.534703 0.000000 1.000000 0 0 +0.565943 0.948247 1.000000 1.000000 0.534703 0.000000 1.000000 0.901515 0.428701 0.114311 1.000000 0 0 diff --git a/chalk/data/images/Azay-Le-Rideau.jpg b/chalk/data/images/Azay-Le-Rideau.jpg new file mode 100644 index 00000000..eb189459 Binary files /dev/null and b/chalk/data/images/Azay-Le-Rideau.jpg differ diff --git a/chalk/data/images/Makefile.am b/chalk/data/images/Makefile.am new file mode 100644 index 00000000..f9f8e4d9 --- /dev/null +++ b/chalk/data/images/Makefile.am @@ -0,0 +1,6 @@ + +chalkimagesdir = $(prefix)/share/apps/chalk/images + +# chalkimages_DATA = evenings.jpg hakonepa.jpg hiro_awate.jpg Azay-Le-Rideau.jpg previewfilter.png +chalkimages_DATA = previewfilter.png + diff --git a/chalk/data/images/WeyDesc.png b/chalk/data/images/WeyDesc.png new file mode 100644 index 00000000..77e97ed6 Binary files /dev/null and b/chalk/data/images/WeyDesc.png differ diff --git a/chalk/data/images/evenings.jpg b/chalk/data/images/evenings.jpg new file mode 100644 index 00000000..5880f18e Binary files /dev/null and b/chalk/data/images/evenings.jpg differ diff --git a/chalk/data/images/hakonepa.jpg b/chalk/data/images/hakonepa.jpg new file mode 100644 index 00000000..9f33cbab Binary files /dev/null and b/chalk/data/images/hakonepa.jpg differ diff --git a/chalk/data/images/hiro_awate.jpg b/chalk/data/images/hiro_awate.jpg new file mode 100644 index 00000000..26fc42aa Binary files /dev/null and b/chalk/data/images/hiro_awate.jpg differ diff --git a/chalk/data/images/paintbrush.png b/chalk/data/images/paintbrush.png new file mode 100644 index 00000000..88e4be87 Binary files /dev/null and b/chalk/data/images/paintbrush.png differ diff --git a/chalk/data/images/previewfilter.png b/chalk/data/images/previewfilter.png new file mode 100644 index 00000000..7a115b24 Binary files /dev/null and b/chalk/data/images/previewfilter.png differ diff --git a/chalk/data/palettes/40_Colors.gpl b/chalk/data/palettes/40_Colors.gpl new file mode 100644 index 00000000..97d98c37 --- /dev/null +++ b/chalk/data/palettes/40_Colors.gpl @@ -0,0 +1,43 @@ +GIMP Palette +Name: 40_Colors +# + 0 0 0 Black + 48 48 48 Almost black + 88 88 88 Very dark gray +128 128 128 Dark gray +160 160 160 Mid gray +195 195 195 Light gray +220 220 220 Very light gray +255 255 255 White + 64 0 0 Very dark red +128 0 0 Dark red +192 0 0 Mid red +255 0 0 Red +255 192 192 Light red + 0 64 0 Very dark green + 0 128 0 Dark green + 0 192 0 Mid green + 0 255 0 Green +192 255 192 Light green + 0 0 128 Dark blue + 0 0 192 Mid blue + 0 0 255 Blue +192 192 255 Light blue + 64 64 0 Very dark yellow +128 128 0 Dark yellow +192 192 0 Mid yellow +255 255 0 Yellow +255 255 192 Light yellow + 0 64 64 Very dark cyan + 0 128 128 Dark cyan + 0 192 192 Mid cyan + 0 255 255 Cyan +192 255 255 Light cyan +128 0 128 Dark magenta +192 0 192 Mid magenta +255 0 255 Magenta +255 192 255 Light magenta +192 88 0 Dark orange +255 128 0 Orange +255 168 88 Light orange +255 220 168 Very light orange diff --git a/chalk/data/palettes/Anchor.gpl b/chalk/data/palettes/Anchor.gpl new file mode 100644 index 00000000..590838b1 --- /dev/null +++ b/chalk/data/palettes/Anchor.gpl @@ -0,0 +1,448 @@ +GIMP Palette +Name: Anchor +# +253 251 255 1 Snow White +250 250 250 2 White +251 187 167 6 Salmon - VY LT +248 165 151 8 Salmon - LT +244 138 125 9 Salmon - MED LT +225 90 82 10 Salmon - MED +225 62 41 11 Salmon - MED DK +178 16 18 13 Salmon - DK +164 0 43 19 Burgundy - MED +121 12 20 20 Burgundy - MED DK + 89 9 31 22 Burgundy - VY DK +251 190 195 23 Baby Pink +250 166 171 24 Carnation - VY LT +244 154 169 25 Carnation - LT +245 105 136 26 Carnation - MED LT +247 107 132 27 Carnation - MED +239 59 88 28 Carnation - MED +204 10 34 29 Carnation - DK +247 124 138 31 Blush - LT +248 90 101 33 Blush - MED +234 49 56 35 Blush - DK +245 147 158 36 Blossom Pink - LT +225 58 95 38 Blossom Pink - MED +177 21 32 39 Blossom Pink - DK +241 89 129 40 Carmine Rose - LT +218 59 95 41 Carmine Rose - MED LT +180 10 62 42 Carmine Rose - MED +125 20 40 43 Carmine Rose - MED DK + 97 0 33 44 Carmine Rose - DK + 95 15 20 45 Carmine Rose - VY DK +211 5 13 46 Crimson Red +172 0 35 47 Carmine Red +249 196 206 48 China Rose - VY LT +236 181 189 49 China Rose - LT +245 153 175 50 China Rose - MED +255 164 194 51 Nelke Dunkel +244 98 147 52 China Rose - MED DK +224 40 98 54 China Rose - DK +242 121 163 55 Beauty Rose - LT +218 27 91 57 Beauty Rose - MED +168 6 70 59 China Rose +233 159 190 60 Magenta - LT +235 93 138 62 Magenta - MED +225 32 104 63 Magenta - DK +152 12 71 65 Antique Rose - VY DK +233 135 173 66 Raspberry - LT +194 79 119 68 Raspberry - MED LT +150 36 75 69 Raspberry - MED +106 11 50 70 Raspberry - DK + 85 9 37 72 Raspberry - VY DK +252 195 204 73 Antique Rose - VY LT +244 155 175 74 Antique Rose - LT +242 133 163 75 Antique Rose - MED LT +208 92 119 76 Antique Rose - MED +182 48 99 77 Antique Rose - MED DK +168 18 88 78 Antique Rose - DK +233 159 200 85 Orchid - LT +221 120 177 86 Orchid - MED LT +199 55 132 87 Orchid - MED +174 17 100 88 Orchid - MED DK +175 13 100 89 Orchid - DK +208 149 179 90 Plum - LT +161 73 152 92 Plum - MED +131 24 106 94 Plum - DK +215 167 201 95 Violet - VY LT +209 142 183 96 Violet - LT +182 106 166 97 Violet - MED LT +159 83 140 98 Violet - MED +135 56 118 99 Violet +122 40 98 100 Violet - MED DK + 90 0 92 101 Violet - DK + 69 8 68 102 Violet - VY DK +227 186 210 103 Plum - VY LT +194 159 208 108 Lavender - LT +165 122 175 109 Lavender - MED LT +122 82 165 110 Lavender - MED + 93 46 132 111 Lavender - MED DK + 84 34 121 112 Lavender - DK +153 169 201 117 Thistle - LT +121 120 182 118 Thistle - MED + 80 54 130 119 Thistle - MED +179 197 223 120 Blueberry - LT +116 139 184 121 Blueberry - MED LT + 82 95 145 122 Blueberry - MED + 44 48 106 123 Blueberry - DK + 0 0 63 127 Indigo +199 222 233 128 Blue - LT +136 170 203 129 Blue +121 156 198 130 Blue - MED LT + 62 95 157 131 Blue - MED + 16 62 133 132 Blue - MED DK + 20 51 116 133 Blue - DK + 8 23 100 134 Blue - VY DK + 91 130 172 136 Wedgewood - LT + 49 97 161 137 Wedgewood - MED + 13 60 120 139 Wedgewood - DK +127 165 200 140 Copen Blue - LT + 22 91 164 142 Copen Blue - MED + 12 67 134 143 Copen Blue - DK +157 189 207 144 Delft Blue - VY LT +113 145 188 145 Delft Blue - LT + 56 112 169 146 Delft Blue + 7 77 142 147 Delft Blue - MED LT + 8 45 99 148 Delft Blue - MED + 9 32 86 149 Delft Blue - MED DK + 21 34 71 150 Delft Blue - DK + 15 18 50 152 Delft Blue - VY DK +206 233 233 158 Sapphire - VY LT +170 202 226 159 Sapphire - LT +158 205 221 160 Sapphire - MED LT + 67 137 168 161 Sapphire - MED + 11 101 140 162 Sapphire - MED DK + 9 66 100 164 Sapphire - DK +142 204 211 167 Surf Blue - VY LT + 89 158 169 168 Surf Blue - LT + 21 113 139 169 Surf Blue - MED + 0 85 108 170 Surf Blue - DK +123 157 193 175 Ocean Blue - LT +100 125 166 176 Ocean Blue + 71 82 153 177 Ocean Blue - MED + 47 43 103 178 Ocean Blue - DK +129 214 196 185 Sea Green - LT + 82 191 172 186 Sea Green - MED LT + 43 168 153 187 Sea Green - MED + 7 139 129 188 Sea Green - MED DK + 14 125 113 189 Sea Green - DK +124 192 140 203 Mint Green - LT +100 187 135 204 Mint Green - MED + 52 149 104 205 Mint Green - DK +166 206 164 206 Spruce - LT + 99 174 128 208 Spruce - MED LT + 73 161 112 209 Spruce + 40 117 72 210 Spruce - MED + 11 96 51 211 Spruce - MED DK + 20 82 54 212 Spruce - DK +186 204 171 213 Juniper - VY LT +153 183 134 214 Juniper - LT +106 142 100 215 Juniper - MED LT + 81 124 96 216 Juniper - MED + 52 101 68 217 Juniper - MED DK + 21 71 37 218 Juniper - DK +100 181 93 225 Emerald - LT + 65 153 55 226 Emerald - MED LT + 28 133 50 227 Emerald - MED + 10 118 47 228 Emerald - MED DK + 7 111 47 229 Emerald - DK + 2 119 78 230 Mint Green - VY DK +192 176 170 231 Rose Gray - LT +169 151 147 232 Rose Gray - MED +130 110 109 233 Rose Gray +205 208 205 234 Charcoal Gray - LT +111 113 119 235 Charcoal Gray - MED + 53 50 55 236 Charcoal Gray - DK + 96 173 54 238 Spring Green - MED + 67 156 23 239 Spring Green - DK +159 205 136 240 Grass Green - LT +135 198 119 241 Grass Green +115 168 94 242 Grass Green - MED LT + 88 146 74 243 Grass Green - MED + 55 119 57 244 Grass Green - MED DK + 21 104 23 245 Grass Green - DK + 20 76 25 246 Grass Green - VY DK +207 224 128 253 Parrot Green - VY LT +199 221 99 254 Parrot Green - LT +139 175 34 255 Parrot Green - MED LT + 92 150 25 256 Parrot Green - MED + 71 135 25 257 Parrot Green - MED DK + 53 115 22 258 Parrot Green - DK +222 233 165 259 Loden Green - VY LT +159 180 118 260 Loden Green - LT +136 159 114 261 Loden Green - MED LT + 70 102 51 262 Loden Green - MED + 43 69 30 263 Loden Green - DK +181 195 130 264 Avocado - VY LT +152 180 90 265 Avocado - LT +112 139 58 266 Avocado - MED LT + 85 111 31 267 Avocado - MED + 58 88 24 268 Avocado - MED DK + 55 70 30 269 Avocado - DK +253 226 221 271 Soft Carnation + 85 77 58 273 Stone Gray - DK +199 209 202 274 Blue Mist - LT +251 241 206 275 Citrus - LT +239 217 187 276 Pearl +124 88 21 277 Desert - VY DK +207 203 103 278 Olive Green - LT +191 175 75 279 Olive Green - MED LT +155 142 62 280 Olive Green - MED +117 103 44 281 Olive Green - DK +251 235 105 288 Canary Yellow - LT +251 233 80 289 Canary Yellow - MED +253 214 16 290 Canary Yellow - MED +252 205 13 291 Canary Yellow - DK +252 236 160 292 Jonquil - VY LT +252 227 120 293 Jonquil - LT +253 217 81 295 Jonquil - MED LT +252 208 29 297 Jonquil - MED +251 181 30 298 Jonquil - DK +247 221 159 300 Citrus - LT +245 212 132 301 Citrus +250 189 72 302 Citrus - MED LT +250 149 23 303 Citrus - MED +247 123 13 304 Citrus - DK +249 198 84 305 Topaz - LT +237 162 49 306 Topaz - MED LT +222 142 23 307 Topaz - MED +189 110 26 308 Topaz - MED DK +173 95 38 309 Topaz - DK +148 76 34 310 Topaz - VY DK +243 186 113 311 Tangerine - VY LT +250 170 85 313 Tangerine - LT +245 137 22 314 Tangerine - MED LT +250 112 23 316 Tangerine - DK +249 136 79 323 Apricot - LT +237 110 50 324 Apricot - MED +207 70 15 326 Apricot - DK +252 142 117 328 Melon - LT +248 110 69 329 Melon - DK +247 93 31 330 Melon - DK +246 69 31 332 Blaze - LT +230 39 20 333 Blaze - MED LT +232 19 15 334 Blaze - MED +225 9 13 335 Blaze - DK +239 158 121 336 Terra Cotta - LT +226 139 110 337 Terra Cotta - MED LT +202 110 88 338 Terra Cotta +177 63 40 339 Terra Cotta - MED +157 48 34 340 Terra Cotta - MED DK +141 36 25 341 Terra Cotta - DK +217 190 221 342 Lilac - LT +140 162 180 343 Slate Blue +208 146 92 347 Bark - LT +170 85 27 349 Bark - MED +140 47 24 351 Bark - MED DK +109 24 21 352 Bark - DK +147 66 26 355 Mocha - MED +116 43 17 357 Mocha - DK +117 55 26 358 Coffee +104 45 18 359 Coffee - MED + 83 43 25 360 Coffee - DK +238 195 138 361 Nutmeg - LT +225 162 102 362 Nutmeg - MED LT +224 150 56 363 Nutmeg - MED +169 96 20 365 Nutmeg - DK +233 199 151 366 Spice - VY LT +227 179 134 367 Spice - LT +210 154 100 368 Spice - MED LT +184 114 67 369 Spice - MED +151 73 27 370 Spice - MED DK +130 58 23 371 Spice - DK +227 187 133 372 Desert - LT +196 151 94 373 Desert - MED +163 110 54 374 Desert - MED +136 90 35 375 Desert - DK +215 173 152 376 Fawn - LT +166 128 104 378 Fawn - MED +141 97 73 379 Fawn - DK + 71 33 23 380 Fudge + 61 29 17 381 Fudge - MED + 54 28 17 382 Fudge - DK +245 231 201 386 Citrus - VY LT +239 218 182 387 Ecru +201 179 151 388 Ecru - MED +229 215 184 390 Linen - LT +202 186 160 391 Linen +163 139 108 392 Linen - MED +118 97 57 393 Linen - DK +197 193 179 397 Gray - LT +175 176 173 398 Gray +146 146 147 399 Gray - MED LT + 88 86 90 400 Gray - MED + 62 58 65 401 Gray - DK + 0 0 0 403 Black + 0 120 169 410 Ice Blue - DK + 0 166 222 433 Ice Blue + 85 87 51 681 Forest - DK + 31 67 58 683 Turf Green +238 198 171 778 Flesh - LT + 77 120 123 779 Blue Mist - MED DK +209 191 158 830 Sierra - VY LT +198 174 138 831 Sierra - LT +157 131 96 832 Sierra - MED +193 184 121 842 Fern Green - LT +138 137 72 843 Fern Green +129 119 49 844 Fern Green - MED + 97 91 32 845 Fern Green - MED DK + 70 65 11 846 Fern Green - DK +214 222 215 847 Blue Mist - VY LT +175 191 186 848 Blue Mist +156 170 171 849 Blue Mist - MED LT +122 139 140 850 Blue Mist - MED + 41 80 86 851 Blue Mist - DK +227 207 159 852 Turf - VY LT +190 169 117 853 Turf - LT +162 141 83 854 Turf - MED LT +153 127 67 855 Turf - MED +124 106 47 856 Turf - DK +163 174 143 858 Laurel Green - LT +139 149 112 859 Laurel Green +114 126 91 860 Laurel Green - MED LT + 74 89 55 861 Laurel Green - MED + 49 68 36 862 Laurel Green - DK +234 166 142 868 Flesh - MED +196 176 185 869 Amethyst - LT +171 146 168 870 Amethyst - MED LT +129 97 117 871 Amethyst - MED LT +116 79 104 872 Amethyst - MED + 88 49 71 873 Amethyst - DK +214 175 92 874 Saffron - MED +146 182 159 875 Pine - LT + 96 144 121 876 Pine + 65 113 96 877 Pine - MED + 43 84 70 878 Pine - MED DK + 17 76 56 879 Pine - DK +226 192 165 880 Copper - LT +233 186 152 881 Copper +220 148 118 882 Copper - MED LT +189 114 85 883 Copper - MED +154 67 46 884 Copper - DK +245 226 180 885 Sand Stone - LT +231 206 135 886 Sand Stone +213 180 113 887 Sand Stone - MED LT +169 128 56 888 Sand Stone - MED DK +111 75 26 889 Sand Stone - MED DK +209 148 63 890 Brass - LT +234 189 111 891 Brass +243 211 197 892 Rose Wine - LT +238 179 167 893 Rose Wine +223 154 151 894 Rose Wine - MED LT +209 113 122 895 Rose Wine - MED +162 66 79 896 Rose Wine - DK +112 26 36 897 Rose Wine - VY DK +135 107 62 898 Sierra +178 155 126 899 Tawny - LT +169 169 149 900 Pewter - LT +182 122 39 901 Tawny - MED +137 112 80 903 Tawny - MED + 95 77 49 904 Mocha Brown - DK + 65 50 28 905 Tawny - DK +106 72 13 906 Brass - DK +182 139 40 907 Saffron - DK +193 123 93 914 Flesh - MED DK +114 141 158 920 Denim - LT + 86 112 128 921 Denim - MED + 65 89 106 922 Denim - DK + 0 93 48 923 Emerald - VY DK + 94 89 14 924 Olive Green - VY DK +233 82 7 925 Tangerine Very +249 237 210 926 Ecru - VY LT +170 217 223 928 Larkspur - LT +240 207 179 933 Fawn - VY LT +127 61 38 936 Fawn - VY DK +121 130 169 939 Stormy Blue - MED + 60 80 144 940 Stormy Blue - MED DK + 60 71 125 941 Stormy Blue - VY DK +234 195 129 942 Wheat - LT +201 157 87 943 Wheat - MED +133 78 28 944 Wheat - DK +190 165 88 945 Harvest - MED +209 191 139 956 Harvest - LT +229 172 170 968 Wineberry - LT +206 143 148 969 Wineberry - MED +171 93 116 970 Wineberry - MED +138 48 89 972 Wineberry - DK +170 197 203 975 Sea Blue - LT +141 172 185 976 Sea Blue - MED LT + 97 137 170 977 Sea Blue - MED + 70 113 150 978 Sea Blue - MED DK + 24 80 115 979 Sea Blue - DK +210 108 16 1001 Antique Gold - MED +237 139 29 1002 Antique Gold - LT +221 108 54 1003 Amberglow +165 61 20 1004 Apricot - VY DK +141 8 33 1005 Cherry Red - MED +155 0 24 1006 Cherry Red +160 89 69 1007 Chicory - DK +207 146 120 1008 Chicory - MED +247 220 194 1009 Copper - VY LT +253 217 180 1010 Cinnamon - VY LT +248 220 198 1011 Flesh - VY LT +245 192 166 1012 Chicory - LT +198 112 94 1013 Brick - MED +158 31 33 1014 Brick - VY DK +144 9 17 1015 Brick - DK +211 155 167 1016 Antique Mauve - LT +190 123 142 1017 Antique +156 89 101 1018 Antique Mauve - DK +134 63 80 1019 Antique Mauve - VY DK +241 190 182 1020 Peony - VY LT +233 171 165 1021 Peony - LT +228 132 125 1022 Peony - MED LT +214 107 113 1023 Peony +198 86 86 1024 Peony - MED +173 17 35 1025 Peony - MED DK +247 206 196 1026 Wineberry - VY LT +188 89 94 1027 Rose Wine - MED DK +124 28 65 1028 Raspberry - MED DK +134 16 61 1029 Antique Rose - DK +115 99 166 1030 Thistle - MED DK +201 220 227 1031 Antique Blue - LT +171 194 207 1032 Antique Blue - VY LT +141 161 180 1033 Antique Blue - LT + 93 117 140 1034 Antique + 45 63 84 1035 Antique Blue - DK + 35 56 86 1036 Antique Blue - VY DK +222 235 236 1037 Sea Blue - VY LT +139 189 199 1038 Glacier Blue - MED + 87 156 177 1039 Glacier Blue - MED DK +136 129 112 1040 Pewter - MED + 60 54 43 1041 Stone Gray - VY DK +191 218 192 1042 Pine - VY LT +206 229 173 1043 Grass Green - VY LT + 23 61 19 1044 Grass Green - DK +202 135 76 1045 Toast - LT +172 100 31 1046 Toast +243 159 100 1047 Cinnamon - LT +212 107 52 1048 Cinnamon - MED +174 80 35 1049 Cinnamon +105 66 40 1050 Tawnyu - MED DK +158 198 205 1060 Blue Violet - VY LT + 99 146 161 1062 Peacock Blue + 75 130 151 1064 Wedgewood - LT + 27 87 106 1066 Wedgewood - DK + 0 68 87 1068 Wedgewood - VY DK + 84 172 153 1070 Sea Green - MED + 48 156 132 1072 Sea Green - MED DK + 0 131 115 1074 Sea Green - DK + 0 114 101 1076 Misty Green - DK +200 166 137 1080 Mocha Beige - LT +159 129 108 1082 Mocha Beige - MED +132 101 80 1084 Mocha Brown - MED + 92 70 54 1086 Mocha Brown - DK + 61 44 35 1088 Mocha Brown - VY DK + 0 136 211 1089 Electric Blue - MED + 62 169 234 1090 Electric Blue +153 216 210 1092 Turquoise - LT +252 158 197 1094 Cranberry - VY LT +159 179 193 1096 Blue Violet - LT +212 24 41 1098 Bright Red +234 186 164 4146 Sportsman Flesh +182 82 69 5975 Brick - DK +121 114 94 8581 Stone Gray +198 0 25 9046 Christmas Red +183 218 228 9159 Glacier Blue +220 148 121 9575 Brick - MED LT diff --git a/chalk/data/palettes/Bears.gpl b/chalk/data/palettes/Bears.gpl new file mode 100644 index 00000000..189d4cfd --- /dev/null +++ b/chalk/data/palettes/Bears.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Bears +# + 8 8 8 grey3 + 68 44 44 Untitled + 80 8 12 Untitled + 72 56 56 Untitled +104 84 68 Untitled +116 96 80 Untitled + 84 56 44 Untitled +140 104 88 Untitled +172 116 92 Untitled + 68 44 56 Untitled + 88 72 68 Untitled +112 84 76 Untitled + 8 8 28 Untitled +104 96 84 Untitled +128 116 96 Untitled +164 136 104 Untitled +120 116 116 Untitled +136 128 108 Untitled +204 160 112 Untitled +220 184 124 Untitled +104 100 108 Untitled +120 116 140 Untitled +128 124 140 Untitled +128 132 152 Untitled +132 144 164 Untitled +204 172 124 Untitled +144 152 168 Untitled +224 196 136 Untitled +136 152 172 Untitled +144 156 176 Untitled +204 184 152 Untitled +148 164 184 Untitled +228 212 164 Untitled + 96 8 8 Untitled +116 112 128 Untitled +144 116 96 Untitled +132 132 124 Untitled +224 220 192 Untitled +128 104 84 Untitled + 56 40 40 Untitled + 84 56 56 Untitled +228 208 148 Untitled +196 144 108 Untitled +160 124 100 Untitled + 96 80 76 Untitled + 56 24 24 Untitled +148 96 80 Untitled +140 56 16 Untitled + 60 8 12 Untitled +224 216 176 Untitled +160 168 184 Untitled + 60 52 52 Untitled +152 152 160 Untitled +208 184 136 Untitled +184 152 112 Untitled +216 172 116 Untitled +220 200 152 Untitled + 88 8 32 Untitled + 92 56 68 Untitled + 68 12 44 Untitled + 24 8 8 Untitled +128 84 76 Untitled +192 120 20 Untitled + 24 12 28 Untitled + 56 24 40 Untitled +236 232 192 Untitled +148 148 128 Untitled +148 136 112 Untitled +112 108 96 Untitled +140 40 44 Untitled + 80 12 48 Untitled +136 100 72 Untitled + 80 44 48 Untitled +112 104 116 Untitled + 72 12 36 Untitled +124 36 32 Untitled + 44 20 40 Untitled +104 72 68 Untitled + 56 40 24 Untitled +132 92 80 Untitled +140 132 148 Untitled +104 68 56 Untitled +184 64 8 Untitled + 44 8 8 Untitled + 68 44 28 Untitled +112 8 12 Untitled + 28 24 40 Untitled + 92 40 44 Untitled + 40 8 24 Untitled +112 68 68 Untitled + 56 8 36 Untitled +128 84 56 Untitled +144 104 72 Untitled +100 32 12 Untitled +176 28 8 Untitled + 68 36 44 Untitled +152 108 80 Untitled +120 96 64 Untitled +116 8 36 Untitled + 88 44 56 Untitled +220 208 184 Untitled + 92 68 56 Untitled +228 228 204 Untitled +124 56 44 Untitled +180 136 104 Untitled +204 136 16 Untitled +152 96 72 Untitled + 80 40 8 Untitled + 88 12 60 Untitled + 80 60 68 Untitled +172 172 172 Untitled +164 116 84 Untitled +140 140 156 Untitled +124 88 68 Untitled +156 112 92 Untitled +124 120 132 Untitled + 76 44 56 Untitled +124 36 8 Untitled +120 72 44 Untitled + 72 56 64 Untitled +240 244 212 Untitled +172 128 92 Untitled +216 204 168 Untitled +176 92 12 Untitled + 92 56 56 Untitled + 44 24 24 Untitled +136 76 64 Untitled +116 68 56 Untitled + 44 40 40 Untitled +232 240 236 Untitled + 96 60 48 Untitled +168 116 72 Untitled +124 60 20 Untitled +100 40 56 Untitled +112 76 60 Untitled + 24 8 40 Untitled + 72 56 44 Untitled +192 168 132 Untitled +152 160 172 Untitled +232 224 176 Untitled +248 252 236 Untitled +156 56 8 Untitled +160 100 84 Untitled +140 116 84 Untitled + 8 8 48 Untitled +136 68 44 Untitled +104 12 48 Untitled +120 76 68 Untitled +228 228 220 Untitled +176 172 156 Untitled +188 140 96 Untitled +172 80 40 Untitled + 44 28 40 Untitled +124 36 60 Untitled +140 28 76 Untitled + 88 72 80 Untitled + 44 8 40 Untitled +184 104 60 Untitled +132 88 64 Untitled +160 104 72 Untitled +124 76 64 Untitled + 92 12 48 Untitled +184 180 180 Untitled +104 72 48 Untitled + 44 40 28 Untitled + 56 44 56 Untitled + 36 12 48 Untitled + 96 44 36 Untitled +192 192 192 Untitled +164 176 192 Untitled +188 128 96 Untitled +160 84 72 Untitled +108 56 52 Untitled +172 156 128 Untitled +148 72 24 Untitled +164 160 164 Untitled + 80 36 56 Untitled +156 84 8 Untitled +152 128 92 Untitled +144 16 48 Untitled +152 8 8 Untitled + 76 52 28 Untitled +148 40 12 Untitled +220 220 208 Untitled +104 56 60 Untitled +128 64 64 Untitled + 68 28 56 Untitled +208 192 160 Untitled +136 136 140 Untitled + 44 36 56 Untitled + 44 40 16 Untitled +148 80 56 Untitled +120 72 12 Untitled + 80 68 56 Untitled +148 92 44 Untitled +188 184 160 Untitled +156 160 140 Untitled +112 20 40 Untitled +144 88 76 Untitled +192 180 144 Untitled +180 200 188 Untitled + 56 56 60 Untitled + 72 68 72 Untitled +104 60 32 Untitled +148 64 68 Untitled +172 112 36 Untitled +212 204 192 Untitled +144 96 60 Untitled +112 36 44 Untitled + 56 36 56 Untitled +116 56 64 Untitled +148 144 148 Untitled +172 160 144 Untitled + 12 60 72 Untitled + 96 64 8 Untitled +128 72 72 Untitled + 36 40 40 Untitled +116 48 12 Untitled +112 40 56 Untitled +168 96 60 Untitled +196 192 172 Untitled +184 168 128 Untitled + 96 92 100 Untitled +204 212 188 Untitled + 92 24 40 Untitled +132 100 16 Untitled +204 216 204 Untitled +188 124 68 Untitled +156 60 44 Untitled + 76 28 24 Untitled + 92 88 84 Untitled +204 152 100 Untitled +136 52 64 Untitled + 84 80 72 Untitled + 92 76 32 Untitled + 28 36 16 Untitled +140 84 68 Untitled + 56 12 56 Untitled +132 84 16 Untitled + 84 40 28 Untitled + 44 72 80 Untitled +196 136 88 Untitled +172 96 80 Untitled +132 12 12 Untitled +120 12 56 Untitled +180 116 84 Untitled +204 196 176 Untitled +164 148 116 Untitled +136 80 76 Untitled + 8 32 44 Untitled +204 8 20 Untitled + 0 0 0 grey0 + 40 0 0 Untitled + 0 56 92 Untitled + 0 0 4 Untitled + 0 0 0 grey0 diff --git a/chalk/data/palettes/Bgold.gpl b/chalk/data/palettes/Bgold.gpl new file mode 100644 index 00000000..3e8e8068 --- /dev/null +++ b/chalk/data/palettes/Bgold.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Bgold +# +236 216 20 Untitled +236 216 20 Untitled +236 216 20 Untitled +236 212 20 Untitled +236 212 20 Untitled +236 208 24 Untitled +236 208 24 Untitled +232 204 24 Untitled +232 204 24 Untitled +232 204 24 Untitled +232 200 24 Untitled +232 200 24 Untitled +232 196 24 Untitled +232 196 24 Untitled +228 192 24 Untitled +228 192 28 Untitled +228 188 28 Untitled +228 188 28 Untitled +228 184 28 Untitled +228 184 28 Untitled +228 184 28 Untitled +224 180 28 Untitled +224 180 28 Untitled +224 176 28 Untitled +224 176 28 Untitled +224 172 32 Untitled +224 172 32 Untitled +224 168 32 Untitled +224 168 32 Untitled +220 164 32 Untitled +220 164 32 Untitled +220 164 32 Untitled +220 160 32 Untitled +220 160 32 Untitled +220 156 32 Untitled +220 156 36 Untitled +216 152 36 Untitled +216 152 36 Untitled +216 148 36 Untitled +216 148 36 Untitled +216 144 36 Untitled +216 144 36 Untitled +216 144 36 Untitled +212 140 36 Untitled +212 140 36 Untitled +212 136 40 Untitled +212 136 40 Untitled +212 132 40 Untitled +212 132 40 Untitled +212 128 40 Untitled +208 128 40 Untitled +208 124 40 Untitled +208 124 40 Untitled +208 124 40 Untitled +208 120 40 Untitled +208 120 44 Untitled +208 116 44 Untitled +204 116 44 Untitled +204 112 44 Untitled +204 112 44 Untitled +204 108 44 Untitled +204 108 44 Untitled +204 104 44 Untitled +204 104 44 Untitled +204 104 44 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 108 40 Untitled +200 112 40 Untitled +200 112 40 Untitled +200 112 36 Untitled +200 112 36 Untitled +200 112 36 Untitled +200 112 36 Untitled +200 112 36 Untitled +200 116 36 Untitled +200 116 36 Untitled +200 116 36 Untitled +200 116 36 Untitled +200 116 36 Untitled +196 116 32 Untitled +196 116 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 120 32 Untitled +196 124 32 Untitled +196 124 28 Untitled +196 124 28 Untitled +196 124 28 Untitled +196 124 28 Untitled +196 124 28 Untitled +196 124 28 Untitled +196 128 28 Untitled +196 128 28 Untitled +196 128 28 Untitled +196 128 28 Untitled +192 128 24 Untitled +192 128 24 Untitled +192 128 24 Untitled +192 132 24 Untitled +192 132 24 Untitled +192 132 24 Untitled +192 132 24 Untitled +192 132 24 Untitled +192 132 24 Untitled +192 132 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 136 20 Untitled +192 140 20 Untitled +192 140 20 Untitled +188 140 16 Untitled +188 140 16 Untitled +188 140 16 Untitled +188 140 16 Untitled +188 140 16 Untitled +188 144 16 Untitled +188 144 16 Untitled +188 144 16 Untitled +188 144 16 Untitled +188 144 16 Untitled +188 144 12 Untitled +188 144 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +188 148 12 Untitled +148 136 60 Untitled +112 124 108 Untitled +116 128 112 Untitled +116 128 112 Untitled +116 128 116 Untitled +120 128 116 Untitled +120 128 120 Untitled +120 128 120 Untitled +120 128 124 Untitled +124 132 124 Untitled +124 132 128 Untitled +124 132 128 Untitled +124 132 132 Untitled +128 132 132 Untitled +128 132 136 Untitled +128 132 136 Untitled +132 136 140 Untitled +132 136 140 Untitled +132 136 144 Untitled +132 136 144 Untitled +136 136 148 Untitled +136 136 148 Untitled +136 136 152 Untitled +136 136 152 Untitled +140 140 156 Untitled +140 140 156 Untitled +140 140 160 Untitled +144 140 160 Untitled +144 140 164 Untitled +144 140 164 Untitled +144 140 168 Untitled +148 144 168 Untitled +148 144 172 Untitled +148 144 172 Untitled +148 144 176 Untitled +152 144 176 Untitled +152 144 180 Untitled +152 144 180 Untitled +156 148 184 Untitled +156 148 184 Untitled +156 148 188 Untitled +156 148 188 Untitled +160 148 192 Untitled +160 148 192 Untitled +160 148 196 Untitled +160 148 196 Untitled +164 152 200 Untitled +164 152 200 Untitled +164 152 204 Untitled +168 152 204 Untitled +168 152 208 Untitled +168 152 208 Untitled +168 152 212 Untitled +172 156 212 Untitled +172 156 216 Untitled +172 156 216 Untitled +172 156 220 Untitled +176 156 220 Untitled +176 156 224 Untitled +176 156 224 Untitled +176 156 224 Untitled +168 152 220 Untitled +164 148 216 Untitled +156 148 212 Untitled +152 144 212 Untitled +148 144 208 Untitled +140 140 204 Untitled +136 140 204 Untitled +132 136 200 Untitled +124 136 196 Untitled +120 132 196 Untitled +116 132 192 Untitled +108 128 188 Untitled +104 128 188 Untitled +100 124 184 Untitled + 92 124 180 Untitled + 88 120 180 Untitled + 80 120 176 Untitled + 76 116 172 Untitled + 72 116 172 Untitled + 64 112 168 Untitled + 60 112 164 Untitled + 56 108 164 Untitled + 48 108 160 Untitled + 44 104 156 Untitled + 40 104 156 Untitled + 32 100 152 Untitled + 28 100 148 Untitled + 24 96 148 Untitled + 16 96 144 Untitled + 12 92 140 Untitled + 8 92 140 Untitled + 12 88 136 Untitled + 16 88 136 Untitled + 20 88 136 Untitled + 20 88 132 Untitled + 24 84 132 Untitled + 28 84 132 Untitled + 28 84 128 Untitled + 32 84 128 Untitled + 36 84 128 Untitled + 36 80 128 Untitled + 40 80 124 Untitled + 44 80 124 Untitled + 44 80 124 Untitled + 48 76 120 Untitled + 52 76 120 Untitled + 52 76 120 Untitled + 56 76 116 Untitled + 60 76 116 Untitled + 60 72 116 Untitled + 64 72 116 Untitled + 68 72 112 Untitled diff --git a/chalk/data/palettes/Blues.gpl b/chalk/data/palettes/Blues.gpl new file mode 100644 index 00000000..33fcfc08 --- /dev/null +++ b/chalk/data/palettes/Blues.gpl @@ -0,0 +1,261 @@ +GIMP Palette +Name: Blues +# +# For them rainy days ... by Daniel Egnor +# + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 4 Untitled + 0 0 12 Untitled + 0 0 16 Untitled + 0 0 24 Untitled + 0 0 32 Untitled + 0 0 36 Untitled + 0 0 44 Untitled + 0 0 48 Untitled + 0 0 56 Untitled + 0 0 64 Untitled + 0 0 68 Untitled + 0 0 76 Untitled + 0 0 80 Untitled + 0 0 88 Untitled + 0 0 96 Untitled + 0 0 100 Untitled + 0 0 108 Untitled + 0 0 116 Untitled + 0 0 120 Untitled + 0 0 128 NavyBlue + 0 0 132 Untitled + 0 0 140 Untitled + 0 0 148 Untitled + 0 0 152 Untitled + 0 0 160 Untitled + 0 0 164 Untitled + 0 0 172 Untitled + 0 0 180 Untitled + 0 0 184 Untitled + 0 0 192 Untitled + 0 0 200 Untitled + 0 4 200 Untitled + 0 12 200 Untitled + 0 16 204 Untitled + 0 24 204 Untitled + 0 28 208 Untitled + 0 36 208 Untitled + 0 40 208 Untitled + 0 48 212 Untitled + 0 56 212 Untitled + 0 60 216 Untitled + 0 68 216 Untitled + 0 72 216 Untitled + 0 80 220 Untitled + 0 84 220 Untitled + 0 92 224 Untitled + 0 100 224 Untitled + 0 104 224 Untitled + 0 112 228 Untitled + 0 116 228 Untitled + 0 124 232 Untitled + 0 128 232 Untitled + 0 136 232 Untitled + 0 140 236 Untitled + 0 148 236 Untitled + 0 156 240 Untitled + 0 160 240 Untitled + 0 168 240 Untitled + 0 172 244 Untitled + 0 180 244 Untitled + 0 184 248 Untitled + 0 192 248 Untitled + 0 200 252 Untitled + 4 200 252 Untitled + 12 200 252 Untitled + 20 204 252 Untitled + 28 204 252 Untitled + 36 208 252 Untitled + 44 208 252 Untitled + 52 208 252 Untitled + 60 212 252 Untitled + 68 212 252 Untitled + 76 216 252 Untitled + 84 216 252 Untitled + 92 216 252 Untitled +100 220 252 Untitled +108 220 252 Untitled +116 224 252 Untitled +124 224 252 Untitled +132 224 252 Untitled +140 228 252 Untitled +148 228 252 Untitled +156 232 252 Untitled +164 232 252 Untitled +172 232 252 Untitled +180 236 252 Untitled +188 236 252 Untitled +196 240 252 Untitled +204 240 252 Untitled +212 240 252 Untitled +220 244 252 Untitled +228 244 252 Untitled +236 248 252 Untitled +244 248 252 Untitled +252 252 252 grey99 +248 252 252 Untitled +244 252 252 Untitled +240 252 252 Untitled +232 252 252 Untitled +228 252 252 Untitled +224 252 252 Untitled +216 252 252 Untitled +212 252 252 Untitled +208 252 252 Untitled +200 252 252 Untitled +196 252 252 Untitled +192 252 252 Untitled +184 252 252 Untitled +180 252 252 Untitled +176 252 252 Untitled +168 252 252 Untitled +164 252 252 Untitled +160 252 252 Untitled +156 252 252 Untitled +148 252 252 Untitled +144 252 252 Untitled +140 252 252 Untitled +132 252 252 Untitled +128 252 252 Untitled +124 252 252 Untitled +116 252 252 Untitled +112 252 252 Untitled +108 252 252 Untitled +100 252 252 Untitled + 96 252 252 Untitled + 92 252 252 Untitled + 84 252 252 Untitled + 80 252 252 Untitled + 76 252 252 Untitled + 72 252 252 Untitled + 64 252 252 Untitled + 60 252 252 Untitled + 56 252 252 Untitled + 48 252 252 Untitled + 44 252 252 Untitled + 40 252 252 Untitled + 32 252 252 Untitled + 28 252 252 Untitled + 24 252 252 Untitled + 16 252 252 Untitled + 12 252 252 Untitled + 8 252 252 Untitled + 0 252 252 Untitled + 0 248 252 Untitled + 0 244 252 Untitled + 0 240 252 Untitled + 0 232 252 Untitled + 0 228 252 Untitled + 0 224 252 Untitled + 0 216 252 Untitled + 0 212 252 Untitled + 0 208 252 Untitled + 0 200 252 Untitled + 0 196 252 Untitled + 0 192 252 Untitled + 0 184 252 Untitled + 0 180 252 Untitled + 0 176 252 Untitled + 0 168 252 Untitled + 0 164 252 Untitled + 0 160 252 Untitled + 0 156 252 Untitled + 0 148 252 Untitled + 0 144 252 Untitled + 0 140 252 Untitled + 0 132 252 Untitled + 0 128 252 Untitled + 0 124 252 Untitled + 0 116 252 Untitled + 0 112 252 Untitled + 0 108 252 Untitled + 0 100 252 Untitled + 0 96 252 Untitled + 0 92 252 Untitled + 0 84 252 Untitled + 0 80 252 Untitled + 0 76 252 Untitled + 0 72 252 Untitled + 0 64 252 Untitled + 0 60 252 Untitled + 0 56 252 Untitled + 0 48 252 Untitled + 0 44 252 Untitled + 0 40 252 Untitled + 0 32 252 Untitled + 0 28 252 Untitled + 0 24 252 Untitled + 0 16 252 Untitled + 0 12 252 Untitled + 0 8 252 Untitled + 0 0 252 Untitled + 0 0 248 Untitled + 0 0 244 Untitled + 0 0 240 Untitled + 0 0 236 Untitled + 0 0 232 Untitled + 0 0 228 Untitled + 0 0 224 Untitled + 0 0 220 Untitled + 0 0 216 Untitled + 0 0 212 Untitled + 0 0 208 Untitled + 0 0 204 Untitled + 0 0 200 Untitled + 0 0 196 Untitled + 0 0 192 Untitled + 0 0 188 Untitled + 0 0 184 Untitled + 0 0 180 Untitled + 0 0 176 Untitled + 0 0 172 Untitled + 0 0 168 Untitled + 0 0 164 Untitled + 0 0 160 Untitled + 0 0 156 Untitled + 0 0 152 Untitled + 0 0 148 Untitled + 0 0 144 Untitled + 0 0 140 Untitled + 0 0 136 Untitled + 0 0 132 Untitled + 0 0 128 NavyBlue + 0 0 124 Untitled + 0 0 120 Untitled + 0 0 116 Untitled + 0 0 112 Untitled + 0 0 108 Untitled + 0 0 104 Untitled + 0 0 100 Untitled + 0 0 96 Untitled + 0 0 92 Untitled + 0 0 88 Untitled + 0 0 84 Untitled + 0 0 80 Untitled + 0 0 76 Untitled + 0 0 72 Untitled + 0 0 68 Untitled + 0 0 64 Untitled + 0 0 60 Untitled + 0 0 56 Untitled + 0 0 52 Untitled + 0 0 48 Untitled + 0 0 44 Untitled + 0 0 40 Untitled + 0 0 36 Untitled + 0 0 32 Untitled + 0 0 28 Untitled + 0 0 24 Untitled + 0 0 20 Untitled + 0 0 16 Untitled + 0 0 12 Untitled + 0 0 8 Untitled + 0 0 0 grey0 + 0 0 0 grey0 diff --git a/chalk/data/palettes/Borders.gpl b/chalk/data/palettes/Borders.gpl new file mode 100644 index 00000000..424d6b6d --- /dev/null +++ b/chalk/data/palettes/Borders.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Borders +# +204 52 180 Untitled +204 52 180 Untitled +204 52 184 Untitled +204 48 188 Untitled +200 48 192 Untitled +200 44 200 Untitled +200 44 204 Untitled +196 40 208 Untitled +196 40 212 Untitled +196 36 220 Untitled +192 36 224 Untitled +192 32 228 Untitled +192 32 232 Untitled +188 28 240 Untitled +188 28 244 Untitled +188 24 248 Untitled +188 24 252 Untitled +192 28 248 Untitled +192 32 248 Untitled +196 36 248 Untitled +196 40 244 Untitled +200 44 244 Untitled +200 48 244 Untitled +204 48 240 Untitled +204 52 240 Untitled +208 56 240 Untitled +208 60 236 Untitled +212 64 236 Untitled +212 68 236 Untitled +216 72 236 Untitled +216 72 232 Untitled +220 76 232 Untitled +220 80 232 Untitled +224 84 228 Untitled +224 88 228 Untitled +228 92 228 Untitled +228 92 224 Untitled +232 96 224 Untitled +232 100 224 Untitled +236 104 224 Untitled +236 108 220 Untitled +240 112 220 Untitled +240 116 220 Untitled +244 116 216 Untitled +244 120 216 Untitled +248 124 216 Untitled +248 128 212 Untitled +252 132 212 Untitled +252 136 212 Untitled +252 136 212 Untitled +244 132 208 Untitled +236 128 204 Untitled +232 124 200 Untitled +224 120 196 Untitled +216 116 192 Untitled +212 112 188 Untitled +204 112 184 Untitled +200 108 180 Untitled +192 104 176 Untitled +184 100 172 Untitled +180 96 168 Untitled +172 92 164 Untitled +168 92 160 Untitled +160 88 156 Untitled +152 84 152 Untitled +148 80 148 Untitled +140 76 144 Untitled +132 72 140 Untitled +128 68 136 Untitled +120 68 132 Untitled +116 64 128 Untitled +108 60 124 Untitled +100 56 120 Untitled + 96 52 116 Untitled + 88 48 112 Untitled + 84 48 108 Untitled + 76 44 104 Untitled + 68 40 100 Untitled + 64 36 96 Untitled + 56 32 92 Untitled + 48 28 88 Untitled + 44 24 84 Untitled + 36 24 80 Untitled + 32 20 76 Untitled + 24 16 72 Untitled + 16 12 68 Untitled + 12 8 64 Untitled + 4 4 60 Untitled + 0 4 60 Untitled + 4 12 56 Untitled + 8 16 56 Untitled + 8 20 56 Untitled + 12 28 52 Untitled + 12 32 52 Untitled + 16 36 52 Untitled + 16 40 48 Untitled + 20 48 48 Untitled + 20 52 48 Untitled + 24 56 44 Untitled + 24 64 44 Untitled + 28 68 44 Untitled + 28 72 40 Untitled + 32 76 40 Untitled + 32 84 40 Untitled + 36 88 36 Untitled + 36 92 36 Untitled + 40 100 36 Untitled + 40 104 36 Untitled + 44 108 32 Untitled + 44 112 32 Untitled +172 24 56 Untitled +160 20 52 Untitled +152 20 52 Untitled +144 20 48 Untitled +136 16 48 Untitled +128 16 44 Untitled +120 16 44 Untitled +108 16 40 Untitled +100 12 40 Untitled + 92 12 40 Untitled + 84 12 36 Untitled + 76 8 36 Untitled + 68 8 32 Untitled + 56 8 32 Untitled + 48 8 28 Untitled + 40 4 28 Untitled + 32 4 24 Untitled + 24 4 24 Untitled + 16 4 24 Untitled + 20 12 28 Untitled + 24 16 32 Untitled + 24 20 36 Untitled + 28 24 40 Untitled + 32 28 44 Untitled + 32 32 48 Untitled + 36 36 52 Untitled + 36 40 56 Untitled + 40 44 56 Untitled + 44 48 60 Untitled + 44 52 64 Untitled + 48 56 68 Untitled + 48 60 72 Untitled + 52 64 76 Untitled + 56 68 80 Untitled + 56 72 84 Untitled + 60 76 88 Untitled + 60 80 88 Untitled + 64 88 92 Untitled + 68 92 96 Untitled + 68 96 100 Untitled + 72 100 104 Untitled + 76 104 108 Untitled + 76 108 112 Untitled + 80 112 116 Untitled + 80 116 120 Untitled + 84 120 120 Untitled + 88 124 124 Untitled + 88 128 128 Untitled + 92 132 132 Untitled + 92 136 136 Untitled + 96 140 140 Untitled +100 144 144 Untitled +100 148 148 Untitled +104 152 152 Untitled +104 156 152 Untitled + 96 148 148 Untitled + 88 144 148 Untitled + 84 140 144 Untitled + 76 136 144 Untitled + 72 132 140 Untitled + 64 128 140 Untitled + 60 124 136 Untitled + 52 120 136 Untitled + 44 116 136 Untitled + 40 112 132 Untitled + 32 108 132 Untitled + 28 104 128 Untitled + 20 100 128 Untitled + 16 96 124 Untitled + 8 92 124 Untitled + 4 88 124 Untitled + 12 92 120 Untitled + 16 92 116 Untitled + 24 92 116 Untitled + 28 92 112 Untitled + 32 92 112 Untitled + 40 96 108 Untitled + 44 96 104 Untitled + 48 96 104 Untitled + 56 96 100 Untitled + 60 96 100 Untitled + 64 96 96 Untitled + 72 100 96 Untitled + 76 100 92 Untitled + 80 100 88 Untitled + 88 100 88 Untitled + 92 100 84 Untitled +100 104 84 Untitled +104 104 80 Untitled +108 104 80 Untitled +116 104 76 Untitled +120 104 72 Untitled +124 104 72 Untitled +132 108 68 Untitled +136 108 68 Untitled +140 108 64 Untitled +148 108 60 Untitled +152 108 60 Untitled +156 108 56 Untitled +164 112 56 Untitled +168 112 52 Untitled +176 112 52 Untitled +180 112 48 Untitled +184 112 44 Untitled +192 116 44 Untitled +196 116 40 Untitled +200 116 40 Untitled +208 116 36 Untitled +212 116 36 Untitled +216 116 32 Untitled +224 120 28 Untitled +228 120 28 Untitled +232 120 24 Untitled +240 120 24 Untitled +244 120 20 Untitled +248 120 20 Untitled +244 116 28 Untitled +244 112 32 Untitled +244 112 36 Untitled +240 108 44 Untitled +240 108 48 Untitled +240 104 52 Untitled +236 104 56 Untitled +236 100 64 Untitled +236 100 68 Untitled +232 96 72 Untitled +232 96 76 Untitled +232 92 84 Untitled +228 92 88 Untitled +228 88 92 Untitled +228 88 96 Untitled +224 84 104 Untitled +224 84 108 Untitled +224 80 112 Untitled +220 80 116 Untitled +220 76 124 Untitled +220 76 128 Untitled +216 72 132 Untitled +216 72 136 Untitled +216 68 144 Untitled +212 64 148 Untitled +212 64 152 Untitled +212 60 160 Untitled +208 60 164 Untitled +208 56 168 Untitled +208 56 172 Untitled diff --git a/chalk/data/palettes/Browns_And_Yellows.gpl b/chalk/data/palettes/Browns_And_Yellows.gpl new file mode 100644 index 00000000..bd100e27 --- /dev/null +++ b/chalk/data/palettes/Browns_And_Yellows.gpl @@ -0,0 +1,25 @@ +GIMP Palette +Name: Browns and Yellows +# +189 183 107 Dark Khaki +240 230 140 Khaki +238 232 170 Pale Goldenrod +250 250 210 Light Goldenrod Yellow +255 255 224 Light Yellow +255 255 0 Yellow +255 215 0 Gold +238 221 130 Light Goldenrod +218 165 32 Goldenrod +184 134 11 Dark Goldenrod +188 143 143 Rosy Brown +139 69 19 Saddle Brown +160 82 45 Sienna +205 133 63 Peru +222 184 135 Burlywood +245 245 220 Beige +245 222 179 Wheat +244 164 96 Sandy Brown +210 180 140 Tan +210 105 30 Chocolate +255 165 0 Orange +255 140 0 Dark Orange diff --git a/chalk/data/palettes/Caramel.gpl b/chalk/data/palettes/Caramel.gpl new file mode 100644 index 00000000..2ee783de --- /dev/null +++ b/chalk/data/palettes/Caramel.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Caramel +# + 48 48 48 grey19 +164 136 192 Untitled +172 140 192 Untitled +180 144 192 Untitled +188 148 192 Untitled +196 152 192 Untitled +204 152 192 Untitled +212 156 192 Untitled +220 160 192 Untitled +228 164 192 Untitled +236 168 192 Untitled +228 160 188 Untitled +216 148 184 Untitled +204 136 180 Untitled +192 124 176 Untitled +180 112 168 Untitled +168 104 164 Untitled +156 92 160 Untitled +144 80 156 Untitled +132 68 152 Untitled +120 56 144 Untitled +140 84 140 Untitled +160 116 132 Untitled +180 144 128 Untitled +200 176 120 Untitled +224 208 112 Untitled +212 200 120 Untitled +196 188 132 Untitled +184 176 144 Untitled +168 168 156 Untitled +156 156 164 Untitled +140 144 176 Untitled +128 136 188 Untitled +112 124 200 Untitled + 96 112 212 Untitled +108 112 192 Untitled +124 116 172 Untitled +136 116 148 Untitled +152 120 128 Untitled +168 120 108 Untitled +180 124 84 Untitled +196 124 64 Untitled +212 128 40 Untitled +212 128 44 Untitled +212 132 48 Untitled +212 136 52 Untitled +212 140 56 Untitled +216 144 60 Untitled +216 148 64 Untitled +216 148 68 Untitled +216 152 72 Untitled +220 156 76 Untitled +220 160 80 Untitled +220 164 84 Untitled +220 168 88 Untitled +224 168 92 Untitled +224 172 96 Untitled +224 176 100 Untitled +224 180 104 Untitled +228 184 108 Untitled +228 188 112 Untitled +228 188 116 Untitled +228 192 120 Untitled +232 196 124 Untitled +232 200 128 Untitled +232 204 132 Untitled +232 208 136 Untitled +236 212 140 Untitled +232 208 140 Untitled +224 204 140 Untitled +216 196 140 Untitled +208 192 136 Untitled +200 188 136 Untitled +192 180 136 Untitled +188 176 132 Untitled +180 172 132 Untitled +172 164 132 Untitled +164 160 128 Untitled +156 156 128 Untitled +148 148 128 Untitled +144 144 124 Untitled +136 136 124 Untitled +128 132 124 Untitled +120 128 120 Untitled +112 120 120 Untitled +104 116 120 Untitled +100 112 116 Untitled + 92 104 116 Untitled + 84 100 116 Untitled + 76 96 112 Untitled + 68 88 112 Untitled + 60 84 112 Untitled + 52 76 108 Untitled + 56 80 108 Untitled + 60 88 108 Untitled + 64 96 108 Untitled + 72 100 108 Untitled + 76 108 108 Untitled + 80 116 108 Untitled + 88 120 108 Untitled + 92 128 108 Untitled + 96 136 108 Untitled +104 144 104 Untitled +108 148 104 Untitled +112 156 104 Untitled +116 164 104 Untitled +124 168 104 Untitled +128 176 104 Untitled +132 184 104 Untitled +140 188 104 Untitled +144 196 104 Untitled +148 204 104 Untitled +156 212 100 Untitled +156 208 100 Untitled +156 204 100 Untitled +156 200 96 Untitled +156 196 96 Untitled +156 192 92 Untitled +156 188 92 Untitled +156 184 88 Untitled +156 180 88 Untitled +156 176 84 Untitled +156 172 84 Untitled +156 168 80 Untitled +156 164 80 Untitled +156 160 76 Untitled +156 156 76 Untitled +156 152 72 Untitled +156 148 72 Untitled +156 144 68 Untitled +156 140 68 Untitled +156 136 64 Untitled +156 132 64 Untitled +156 124 60 Untitled +160 124 72 Untitled +164 128 84 Untitled +168 132 96 Untitled +176 136 112 Untitled +180 136 124 Untitled +184 140 136 Untitled +188 144 148 Untitled +196 148 164 Untitled +196 148 164 Untitled +196 148 160 Untitled +196 144 156 Untitled +196 144 152 Untitled +192 140 148 Untitled +192 140 144 Untitled +192 140 140 Untitled +192 136 136 Untitled +192 136 132 Untitled +188 132 128 Untitled +188 132 124 Untitled +188 132 120 Untitled +188 128 116 Untitled +184 128 112 Untitled +184 124 108 Untitled +184 124 104 Untitled +184 124 104 Untitled +184 120 100 Untitled +180 120 96 Untitled +180 116 92 Untitled +180 116 88 Untitled +180 116 84 Untitled +176 112 80 Untitled +176 112 76 Untitled +176 108 72 Untitled +176 108 68 Untitled +176 108 64 Untitled +172 104 60 Untitled +172 104 56 Untitled +172 100 52 Untitled +172 100 48 Untitled +168 96 44 Untitled +160 96 44 Untitled +152 96 48 Untitled +140 100 52 Untitled +132 100 56 Untitled +120 100 60 Untitled +112 104 60 Untitled +100 104 64 Untitled + 92 104 68 Untitled + 80 108 72 Untitled + 72 108 76 Untitled + 60 108 80 Untitled + 52 112 80 Untitled + 40 112 84 Untitled + 32 112 88 Untitled + 20 116 92 Untitled + 12 116 96 Untitled + 0 120 100 Untitled + 0 120 100 Untitled + 0 116 100 Untitled + 0 112 104 Untitled + 0 112 104 Untitled + 0 108 104 Untitled + 0 104 108 Untitled + 0 104 108 Untitled + 0 100 112 Untitled + 0 96 112 Untitled + 0 96 112 Untitled + 0 92 116 Untitled + 4 88 116 Untitled + 4 84 120 Untitled + 4 84 120 Untitled + 4 80 120 Untitled + 4 76 124 Untitled + 4 76 124 Untitled + 4 72 128 Untitled + 4 68 128 Untitled + 4 68 128 Untitled + 4 64 132 Untitled + 4 60 132 Untitled + 8 56 136 Untitled + 28 60 136 Untitled + 48 68 140 Untitled + 72 76 144 Untitled + 92 80 148 Untitled +116 88 152 Untitled +136 96 156 Untitled +160 100 160 Untitled +180 108 164 Untitled +204 116 168 Untitled +204 116 168 Untitled +204 120 168 Untitled +200 124 168 Untitled +200 128 168 Untitled +200 128 168 Untitled +196 132 168 Untitled +196 136 168 Untitled +192 140 168 Untitled +192 140 168 Untitled +192 144 168 Untitled +188 148 168 Untitled +188 152 168 Untitled +184 156 168 Untitled +184 156 168 Untitled +184 160 168 Untitled +180 164 168 Untitled +180 168 168 Untitled +180 168 168 Untitled +176 172 168 Untitled +176 176 168 Untitled +172 180 168 Untitled +172 184 168 Untitled +172 184 168 Untitled +168 188 168 Untitled +168 192 168 Untitled +164 196 168 Untitled +164 196 168 Untitled +164 200 168 Untitled +160 204 168 Untitled +160 208 168 Untitled +156 212 164 Untitled +148 212 168 Untitled +136 216 176 Untitled diff --git a/chalk/data/palettes/Cascade.gpl b/chalk/data/palettes/Cascade.gpl new file mode 100644 index 00000000..1c8e7e59 --- /dev/null +++ b/chalk/data/palettes/Cascade.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Cascade +# +108 88 128 Untitled +108 88 128 Untitled +108 88 128 Untitled +104 92 132 Untitled +104 92 132 Untitled +100 92 132 Untitled + 96 92 132 Untitled + 96 96 136 Untitled + 92 96 136 Untitled + 92 96 136 Untitled + 88 96 136 Untitled + 84 100 140 Untitled + 84 100 140 Untitled + 80 100 140 Untitled + 76 96 136 Untitled + 80 100 140 Untitled + 84 104 144 Untitled + 88 104 148 Untitled + 92 108 148 Untitled + 96 112 152 Untitled +100 112 156 Untitled +104 116 160 Untitled +108 116 160 Untitled +112 120 164 Untitled +116 124 168 Untitled +120 124 168 Untitled +124 128 172 Untitled +128 128 176 Untitled +132 132 180 Untitled +136 136 180 Untitled +140 136 184 Untitled +144 140 188 Untitled +148 140 188 Untitled +152 144 192 Untitled +156 148 196 Untitled +160 148 200 Untitled +164 152 200 Untitled +168 156 204 Untitled +172 156 208 Untitled +176 160 212 Untitled +180 160 212 Untitled +184 164 216 Untitled +188 168 220 Untitled +192 168 220 Untitled +196 172 224 Untitled +200 172 228 Untitled +204 176 232 Untitled +208 180 232 Untitled +212 180 236 Untitled +216 184 240 Untitled +220 184 240 Untitled +216 180 236 Untitled +216 180 236 Untitled +216 180 236 Untitled +212 180 236 Untitled +212 180 236 Untitled +212 180 236 Untitled +212 180 236 Untitled +208 180 232 Untitled +208 176 232 Untitled +208 176 232 Untitled +208 176 232 Untitled +204 176 232 Untitled +204 176 232 Untitled +204 176 232 Untitled +200 176 232 Untitled +200 176 228 Untitled +200 176 228 Untitled +200 172 228 Untitled +196 172 228 Untitled +196 172 228 Untitled +196 172 228 Untitled +196 172 228 Untitled +192 172 228 Untitled +192 172 224 Untitled +192 172 224 Untitled +188 172 224 Untitled +188 168 224 Untitled +188 168 224 Untitled +188 168 224 Untitled +184 168 224 Untitled +184 168 224 Untitled +184 168 220 Untitled +184 168 220 Untitled +180 168 220 Untitled +180 168 220 Untitled +180 164 220 Untitled +176 164 220 Untitled +176 164 220 Untitled +176 164 220 Untitled +176 164 216 Untitled +172 164 216 Untitled +172 164 216 Untitled +172 164 216 Untitled +172 160 216 Untitled +168 160 216 Untitled +168 160 216 Untitled +168 160 216 Untitled +164 160 212 Untitled +164 160 212 Untitled +164 160 212 Untitled +164 160 212 Untitled +160 160 212 Untitled +160 156 212 Untitled +160 156 212 Untitled +160 156 212 Untitled +156 156 208 Untitled +156 156 208 Untitled +156 156 208 Untitled +152 156 208 Untitled +152 156 208 Untitled +152 156 208 Untitled +152 152 208 Untitled +148 152 208 Untitled +148 152 204 Untitled +148 152 204 Untitled +148 152 204 Untitled +144 152 204 Untitled +144 152 204 Untitled +144 152 204 Untitled +140 152 204 Untitled +140 148 204 Untitled +140 148 200 Untitled +140 148 200 Untitled +136 148 200 Untitled +136 148 200 Untitled +136 148 200 Untitled +136 148 200 Untitled +132 148 200 Untitled +132 148 200 Untitled +132 144 196 Untitled +128 144 196 Untitled +128 144 196 Untitled +128 144 196 Untitled +128 144 196 Untitled +124 144 196 Untitled +124 144 196 Untitled +124 144 192 Untitled +124 140 192 Untitled +120 140 192 Untitled +120 140 192 Untitled +120 140 192 Untitled +116 140 192 Untitled +116 140 192 Untitled +116 140 192 Untitled +116 140 188 Untitled +112 140 188 Untitled +112 136 188 Untitled +112 136 188 Untitled +112 136 188 Untitled +108 136 188 Untitled +108 136 188 Untitled +108 136 188 Untitled +104 136 184 Untitled +104 136 184 Untitled +104 136 184 Untitled +104 132 184 Untitled +100 132 184 Untitled +100 132 184 Untitled +100 132 184 Untitled +100 132 184 Untitled + 96 132 180 Untitled + 96 132 180 Untitled + 96 132 180 Untitled + 92 132 180 Untitled + 92 128 180 Untitled + 92 128 180 Untitled + 92 128 180 Untitled + 88 128 180 Untitled + 88 128 176 Untitled + 88 128 176 Untitled + 88 128 176 Untitled + 84 128 176 Untitled + 84 124 176 Untitled + 84 124 176 Untitled + 80 124 176 Untitled + 80 124 176 Untitled + 80 124 172 Untitled + 80 124 172 Untitled + 76 124 172 Untitled + 76 124 172 Untitled + 76 124 172 Untitled + 76 120 172 Untitled + 72 120 172 Untitled + 72 120 172 Untitled + 72 120 168 Untitled + 68 120 168 Untitled + 68 120 168 Untitled + 68 120 168 Untitled + 68 120 168 Untitled + 64 120 168 Untitled + 64 116 168 Untitled + 64 116 168 Untitled + 64 116 164 Untitled + 60 116 164 Untitled + 60 116 164 Untitled + 60 116 164 Untitled + 56 116 164 Untitled + 56 116 164 Untitled + 56 116 164 Untitled + 56 112 164 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 44 116 156 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 48 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 52 112 160 Untitled + 56 112 160 Untitled + 56 112 160 Untitled + 56 112 160 Untitled + 56 112 160 Untitled + 56 112 160 Untitled +160 68 108 Untitled +156 68 108 Untitled +156 68 108 Untitled +152 72 112 Untitled +152 72 112 Untitled +148 72 112 Untitled +144 72 112 Untitled +144 76 116 Untitled +140 76 116 Untitled +140 76 116 Untitled +136 76 116 Untitled +132 80 120 Untitled +132 80 120 Untitled +128 80 120 Untitled +128 80 120 Untitled +124 84 124 Untitled +120 84 124 Untitled +120 84 124 Untitled +116 84 124 Untitled +116 88 128 Untitled +112 88 128 Untitled diff --git a/chalk/data/palettes/China.gpl b/chalk/data/palettes/China.gpl new file mode 100644 index 00000000..670578ad --- /dev/null +++ b/chalk/data/palettes/China.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: China +# +224 76 240 Untitled +224 76 240 Untitled +224 80 240 Untitled +224 84 240 Untitled +228 88 240 Untitled +228 92 240 Untitled +228 96 240 Untitled +228 96 240 Untitled +228 100 240 Untitled +228 104 240 Untitled +228 108 240 Untitled +232 112 240 Untitled +232 116 240 Untitled +232 120 240 Untitled +232 120 240 Untitled +232 124 240 Untitled +232 128 240 Untitled +232 132 240 Untitled +232 136 240 Untitled +236 140 240 Untitled +236 140 240 Untitled +236 144 240 Untitled +236 148 240 Untitled +236 152 240 Untitled +236 156 240 Untitled +236 160 240 Untitled +240 164 240 Untitled +232 156 236 Untitled +220 148 232 Untitled +208 140 228 Untitled +196 128 220 Untitled +184 120 216 Untitled +172 112 212 Untitled +160 104 208 Untitled +148 92 200 Untitled +136 68 204 Untitled +124 40 208 Untitled +108 12 216 Untitled +108 12 216 Untitled +108 12 216 Untitled +108 12 216 Untitled +108 12 216 Untitled +112 8 216 Untitled +112 8 216 Untitled +112 8 216 Untitled +112 8 216 Untitled +112 8 216 Untitled +116 4 216 Untitled +116 4 216 Untitled +116 4 216 Untitled +116 4 216 Untitled +120 0 216 Untitled +120 12 216 Untitled +124 24 220 Untitled +128 36 224 Untitled +128 48 228 Untitled +132 64 232 Untitled +136 76 232 Untitled +136 88 236 Untitled +140 100 240 Untitled +144 112 244 Untitled +148 128 248 Untitled +148 128 248 Untitled +148 128 248 Untitled +148 132 248 Untitled +148 132 248 Untitled +148 132 248 Untitled +148 136 248 Untitled +148 136 248 Untitled +144 136 248 Untitled +144 140 248 Untitled +144 140 248 Untitled +144 140 248 Untitled +144 144 248 Untitled +144 144 248 Untitled +144 144 248 Untitled +144 148 248 Untitled +140 148 248 Untitled +140 152 248 Untitled +140 152 248 Untitled +140 152 248 Untitled +140 156 248 Untitled +140 156 248 Untitled +140 156 248 Untitled +140 160 248 Untitled +136 160 248 Untitled +136 160 248 Untitled +136 164 248 Untitled +136 164 248 Untitled +136 164 248 Untitled +136 168 248 Untitled +136 168 248 Untitled +132 172 244 Untitled +132 168 244 Untitled +128 164 244 Untitled +128 160 244 Untitled +124 156 244 Untitled +124 152 244 Untitled +120 148 244 Untitled +120 144 244 Untitled +116 136 244 Untitled +116 132 244 Untitled +112 128 244 Untitled +112 124 244 Untitled +108 120 244 Untitled +108 116 244 Untitled +104 112 244 Untitled +104 108 244 Untitled +100 100 244 Untitled +100 96 244 Untitled + 96 92 244 Untitled + 96 88 244 Untitled + 92 84 244 Untitled + 92 80 244 Untitled + 88 76 244 Untitled + 88 68 244 Untitled + 84 64 244 Untitled + 84 60 244 Untitled + 80 56 244 Untitled + 80 52 244 Untitled + 76 48 244 Untitled + 76 44 244 Untitled + 72 40 244 Untitled + 72 32 244 Untitled + 68 28 244 Untitled + 68 24 244 Untitled + 64 20 244 Untitled + 64 16 244 Untitled + 60 12 244 Untitled + 60 8 244 Untitled + 56 0 248 Untitled + 56 4 248 Untitled + 56 8 244 Untitled + 52 16 240 Untitled + 52 20 236 Untitled + 52 28 232 Untitled + 48 32 228 Untitled + 48 40 228 Untitled + 44 44 224 Untitled + 44 52 220 Untitled + 44 56 216 Untitled + 40 64 212 Untitled + 40 68 208 Untitled + 36 76 204 Untitled + 36 80 204 Untitled + 36 84 200 Untitled + 32 92 196 Untitled + 32 96 192 Untitled + 32 104 188 Untitled + 28 108 184 Untitled + 28 116 184 Untitled + 24 120 180 Untitled + 24 128 176 Untitled + 24 132 172 Untitled + 20 140 168 Untitled + 20 144 164 Untitled + 16 152 160 Untitled + 20 152 160 Untitled + 24 152 160 Untitled + 28 152 160 Untitled + 32 152 160 Untitled + 40 148 164 Untitled + 44 148 164 Untitled + 48 148 164 Untitled + 52 148 164 Untitled + 56 148 168 Untitled + 64 144 168 Untitled + 68 144 168 Untitled + 72 144 168 Untitled + 76 144 172 Untitled + 80 144 172 Untitled + 88 140 172 Untitled + 92 140 172 Untitled + 96 140 176 Untitled +100 140 176 Untitled +108 136 176 Untitled +112 136 176 Untitled +116 136 176 Untitled +120 136 180 Untitled +124 136 180 Untitled +132 132 180 Untitled +136 132 180 Untitled +140 132 184 Untitled +144 132 184 Untitled +148 132 184 Untitled +156 128 184 Untitled +160 128 188 Untitled +164 128 188 Untitled +168 128 188 Untitled +172 128 188 Untitled +180 124 192 Untitled +184 124 192 Untitled +188 124 192 Untitled +192 124 192 Untitled +200 120 196 Untitled +160 132 176 Untitled +116 148 152 Untitled + 76 160 128 Untitled + 32 176 104 Untitled + 32 176 104 Untitled + 36 172 104 Untitled + 40 168 108 Untitled + 44 164 108 Untitled + 48 160 108 Untitled + 52 156 112 Untitled + 56 152 112 Untitled + 60 148 112 Untitled + 64 144 116 Untitled + 68 140 116 Untitled + 72 136 120 Untitled + 76 132 120 Untitled + 80 128 120 Untitled + 84 124 124 Untitled + 88 120 124 Untitled + 92 116 124 Untitled + 96 112 128 Untitled +100 108 128 Untitled +104 104 128 Untitled +108 100 132 Untitled +108 100 132 Untitled +112 96 136 Untitled +116 92 136 Untitled +120 88 136 Untitled +124 84 140 Untitled +128 80 140 Untitled +132 76 140 Untitled +136 72 144 Untitled +140 68 144 Untitled +144 64 144 Untitled +148 60 148 Untitled +152 56 148 Untitled +156 52 152 Untitled +160 48 152 Untitled +164 44 152 Untitled +168 40 156 Untitled +172 36 156 Untitled +176 32 156 Untitled +180 28 160 Untitled +184 24 160 Untitled +188 20 164 Untitled +188 24 164 Untitled +184 28 164 Untitled +180 32 164 Untitled +176 36 164 Untitled +176 40 164 Untitled +172 48 164 Untitled +168 52 164 Untitled +164 56 164 Untitled +164 60 164 Untitled +160 64 164 Untitled +156 72 164 Untitled +152 76 164 Untitled +152 80 164 Untitled +148 84 164 Untitled +144 88 164 Untitled +140 96 168 Untitled diff --git a/chalk/data/palettes/Coldfire.gpl b/chalk/data/palettes/Coldfire.gpl new file mode 100644 index 00000000..6c25698a --- /dev/null +++ b/chalk/data/palettes/Coldfire.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Coldfire +# + 0 172 252 Untitled + 0 172 252 Untitled + 0 172 252 Untitled + 0 168 252 Untitled + 0 164 252 Untitled + 0 160 252 Untitled + 0 156 252 Untitled + 0 152 252 Untitled + 0 152 252 Untitled + 0 148 252 Untitled + 0 144 252 Untitled + 0 140 252 Untitled + 0 136 252 Untitled + 0 132 252 Untitled + 0 132 252 Untitled + 0 128 252 Untitled + 0 124 252 Untitled + 0 120 252 Untitled + 0 116 252 Untitled + 0 112 252 Untitled + 0 112 252 Untitled + 0 108 252 Untitled + 0 104 252 Untitled + 0 100 252 Untitled + 0 96 252 Untitled + 0 92 252 Untitled + 0 92 252 Untitled + 0 88 252 Untitled + 0 84 252 Untitled + 0 80 252 Untitled + 0 76 252 Untitled + 0 72 252 Untitled + 0 68 252 Untitled + 0 64 252 Untitled + 0 60 252 Untitled + 0 56 252 Untitled + 0 52 252 Untitled + 0 48 252 Untitled + 0 44 252 Untitled + 0 40 252 Untitled + 0 36 252 Untitled + 0 32 252 Untitled + 0 28 252 Untitled + 0 24 252 Untitled + 0 20 252 Untitled + 0 16 252 Untitled + 0 12 252 Untitled + 0 8 252 Untitled + 0 4 252 Untitled + 0 4 252 Untitled + 4 4 248 Untitled + 4 4 248 Untitled + 8 4 244 Untitled + 8 8 240 Untitled + 12 8 240 Untitled + 12 8 236 Untitled + 16 8 232 Untitled + 16 12 232 Untitled + 20 12 228 Untitled + 20 12 224 Untitled + 24 12 224 Untitled + 24 16 220 Untitled + 28 16 216 Untitled + 28 16 216 Untitled + 32 16 212 Untitled + 32 20 212 Untitled + 36 20 208 Untitled + 36 20 204 Untitled + 40 20 204 Untitled + 40 24 200 Untitled + 44 24 196 Untitled + 44 24 196 Untitled + 48 24 192 Untitled + 48 24 188 Untitled + 52 28 188 Untitled + 52 28 184 Untitled + 56 28 180 Untitled + 56 28 180 Untitled + 60 32 176 Untitled + 60 32 172 Untitled + 64 32 172 Untitled + 64 32 168 Untitled + 68 36 168 Untitled + 68 36 164 Untitled + 72 36 160 Untitled + 72 36 160 Untitled + 76 40 156 Untitled + 76 40 152 Untitled + 80 40 152 Untitled + 80 40 148 Untitled + 84 44 144 Untitled + 84 44 144 Untitled + 88 44 140 Untitled + 88 44 136 Untitled + 92 48 136 Untitled + 92 48 132 Untitled + 96 48 128 Untitled +100 48 128 Untitled +100 48 124 Untitled +104 52 124 Untitled +104 52 120 Untitled +108 52 116 Untitled +108 52 116 Untitled +112 56 112 Untitled +112 56 108 Untitled +116 56 108 Untitled +116 56 104 Untitled +120 60 100 Untitled +120 60 100 Untitled +124 60 96 Untitled +124 60 92 Untitled +128 64 92 Untitled +128 64 88 Untitled +132 64 88 Untitled +132 64 84 Untitled +136 68 80 Untitled +136 68 80 Untitled +140 68 76 Untitled +140 68 72 Untitled +144 72 72 Untitled +144 72 68 Untitled +148 72 64 Untitled +148 72 64 Untitled +152 72 60 Untitled +152 76 56 Untitled +156 76 56 Untitled +156 76 52 Untitled +160 76 48 Untitled +160 80 48 Untitled +164 80 44 Untitled +164 80 44 Untitled +168 80 40 Untitled +168 84 36 Untitled +172 84 36 Untitled +172 84 32 Untitled +176 84 28 Untitled +176 88 28 Untitled +180 88 24 Untitled +180 88 20 Untitled +184 88 20 Untitled +184 92 16 Untitled +188 92 12 Untitled +188 92 12 Untitled +192 92 8 Untitled +196 96 4 Untitled +196 96 4 Untitled +196 100 4 Untitled +196 100 4 Untitled +196 104 4 Untitled +200 108 4 Untitled +200 108 4 Untitled +200 112 4 Untitled +200 112 4 Untitled +200 116 4 Untitled +204 120 4 Untitled +204 120 4 Untitled +204 124 4 Untitled +204 124 4 Untitled +208 128 4 Untitled +208 132 4 Untitled +208 132 4 Untitled +208 136 4 Untitled +208 136 4 Untitled +212 140 4 Untitled +212 144 4 Untitled +212 144 4 Untitled +212 148 4 Untitled +216 152 4 Untitled +216 152 4 Untitled +216 156 4 Untitled +216 156 4 Untitled +216 160 4 Untitled +220 164 4 Untitled +220 164 4 Untitled +220 168 4 Untitled +220 168 4 Untitled +224 172 4 Untitled +224 176 4 Untitled +224 176 4 Untitled +224 180 4 Untitled +224 180 4 Untitled +228 184 4 Untitled +228 188 4 Untitled +228 188 4 Untitled +228 192 4 Untitled +228 192 4 Untitled +232 196 4 Untitled +232 200 4 Untitled +232 200 4 Untitled +232 204 4 Untitled +236 208 4 Untitled +236 208 4 Untitled +236 212 4 Untitled +236 212 4 Untitled +236 216 4 Untitled +240 220 4 Untitled +240 220 4 Untitled +240 224 4 Untitled +240 224 4 Untitled +244 228 4 Untitled +244 232 4 Untitled +244 232 4 Untitled +244 236 4 Untitled +244 236 4 Untitled +248 240 4 Untitled +248 244 4 Untitled +248 244 4 Untitled +248 248 4 Untitled +252 252 0 Untitled +252 252 104 Untitled +252 252 104 Untitled +252 252 108 Untitled +252 252 112 Untitled +252 252 116 Untitled +252 252 120 Untitled +252 252 120 Untitled +252 252 124 Untitled +252 252 128 Untitled +252 252 132 Untitled +252 252 136 Untitled +252 252 136 Untitled +252 252 140 Untitled +252 252 144 Untitled +252 252 148 Untitled +252 252 152 Untitled +252 252 152 Untitled +252 252 156 Untitled +252 252 160 Untitled +252 252 164 Untitled +252 252 168 Untitled +252 252 168 Untitled +252 252 172 Untitled +252 252 176 Untitled +252 252 180 Untitled +252 252 184 Untitled +252 252 184 Untitled +252 252 188 Untitled +252 252 192 Untitled +252 252 196 Untitled +252 252 200 Untitled +252 252 200 Untitled +252 252 204 Untitled +252 252 208 Untitled +252 252 212 Untitled +252 252 216 Untitled +252 252 216 Untitled +252 252 220 Untitled +252 252 224 Untitled +252 252 228 Untitled +252 252 232 Untitled +252 252 232 Untitled +252 252 236 Untitled +252 252 240 Untitled +252 252 244 Untitled +252 252 248 Untitled +252 252 252 grey99 diff --git a/chalk/data/palettes/Cool_Colors.gpl b/chalk/data/palettes/Cool_Colors.gpl new file mode 100644 index 00000000..3a1b83a5 --- /dev/null +++ b/chalk/data/palettes/Cool_Colors.gpl @@ -0,0 +1,11 @@ +GIMP Palette +Name: Cool Colors +# + 17 42 198 Untitled + 83 155 226 Untitled + 22 16 102 Untitled + 64 35 76 Untitled + 7 63 147 Untitled + 44 108 204 Untitled + 38 81 33 Untitled + 4 66 44 Untitled diff --git a/chalk/data/palettes/Cranes.gpl b/chalk/data/palettes/Cranes.gpl new file mode 100644 index 00000000..6ea0714e --- /dev/null +++ b/chalk/data/palettes/Cranes.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Cranes +# + 8 8 8 grey3 +192 176 144 Untitled +192 164 128 Untitled + 80 72 68 Untitled +112 140 88 Untitled +104 132 96 Untitled + 92 104 84 Untitled + 24 8 12 Untitled + 96 108 92 Untitled +128 104 76 Untitled + 44 28 24 Untitled +156 140 116 Untitled +156 148 116 Untitled + 68 68 60 Untitled +212 196 148 Untitled +144 136 108 Untitled +160 148 128 Untitled +216 220 216 Untitled + 44 28 40 Untitled + 68 12 16 Untitled + 12 8 32 Untitled + 56 8 48 Untitled + 48 8 40 Untitled + 44 20 40 Untitled +104 104 92 Untitled + 52 28 48 Untitled +156 176 124 Untitled +124 160 96 Untitled + 44 40 24 Untitled +168 168 172 Untitled +196 188 168 Untitled + 8 28 20 Untitled +160 60 60 Untitled +180 144 100 Untitled +192 144 112 Untitled +132 40 60 Untitled + 48 8 24 Untitled +156 176 144 Untitled + 80 84 64 Untitled +136 148 136 Untitled +120 160 116 Untitled + 44 20 24 Untitled +128 84 80 Untitled +128 20 56 Untitled +168 68 76 Untitled + 64 56 44 Untitled + 56 40 40 Untitled +156 172 164 Untitled +100 92 72 Untitled +124 116 88 Untitled + 32 8 28 Untitled +176 180 180 Untitled +156 44 68 Untitled +172 176 156 Untitled +176 168 144 Untitled +188 8 88 Untitled +148 8 52 Untitled + 20 48 52 Untitled + 68 60 68 Untitled +216 204 160 Untitled +140 160 112 Untitled +112 116 88 Untitled +152 160 164 Untitled +116 156 104 Untitled +192 192 184 Untitled + 80 84 72 Untitled + 56 24 24 Untitled + 24 36 40 Untitled + 48 56 52 Untitled + 92 84 64 Untitled +180 160 120 Untitled +112 100 76 Untitled +156 120 88 Untitled + 96 96 84 Untitled +148 160 152 Untitled +192 200 144 Untitled + 68 56 56 Untitled +100 48 96 Untitled +108 144 100 Untitled +188 180 160 Untitled + 60 48 68 Untitled + 80 48 52 Untitled +188 56 72 Untitled +196 176 128 Untitled +220 180 164 Untitled +132 116 100 Untitled + 68 36 52 Untitled +168 132 100 Untitled +180 168 132 Untitled +148 156 140 Untitled +120 128 108 Untitled +108 12 48 Untitled +108 80 68 Untitled + 44 40 56 Untitled +140 124 104 Untitled + 24 28 20 Untitled +204 172 120 Untitled +164 156 132 Untitled +116 104 96 Untitled +144 152 148 Untitled + 84 92 72 Untitled +120 148 100 Untitled +120 112 108 Untitled + 60 64 56 Untitled +204 176 140 Untitled +212 140 128 Untitled + 80 56 64 Untitled +152 140 108 Untitled + 72 72 76 Untitled + 20 12 48 Untitled +140 152 128 Untitled +208 100 88 Untitled + 8 36 48 Untitled + 80 104 68 Untitled + 44 40 8 Untitled + 76 60 84 Untitled + 56 40 24 Untitled +112 52 64 Untitled +212 124 112 Untitled +152 72 76 Untitled +212 124 128 Untitled + 88 88 96 Untitled + 16 68 8 Untitled + 36 8 40 Untitled +128 168 112 Untitled +208 212 196 Untitled +216 208 176 Untitled + 76 68 56 Untitled + 40 44 28 Untitled + 32 20 80 Untitled +136 64 68 Untitled + 60 76 64 Untitled +200 104 96 Untitled + 92 84 80 Untitled +164 148 116 Untitled +116 108 84 Untitled +148 128 100 Untitled + 80 80 84 Untitled +136 140 128 Untitled + 88 16 76 Untitled +124 12 8 Untitled +100 96 104 Untitled +132 52 36 Untitled + 56 28 40 Untitled +196 96 88 Untitled + 64 84 44 Untitled +164 188 132 Untitled +204 196 168 Untitled +216 220 208 Untitled +136 172 100 Untitled +148 188 124 Untitled + 52 72 32 Untitled +108 108 116 Untitled +136 172 132 Untitled + 60 60 64 Untitled +108 92 92 Untitled +216 156 144 Untitled +104 96 84 Untitled +172 180 172 Untitled +140 108 88 Untitled +160 164 156 Untitled +148 132 108 Untitled +128 140 120 Untitled + 40 84 56 Untitled +132 56 108 Untitled + 96 32 56 Untitled +164 88 84 Untitled + 96 104 72 Untitled +172 192 152 Untitled +192 196 172 Untitled +208 108 100 Untitled + 68 84 72 Untitled +140 128 96 Untitled +224 228 224 Untitled +128 128 132 Untitled + 76 96 56 Untitled + 88 76 100 Untitled + 72 12 52 Untitled + 56 44 56 Untitled + 68 48 68 Untitled + 60 20 64 Untitled + 44 12 56 Untitled + 84 68 76 Untitled + 44 8 8 Untitled +148 136 100 Untitled +148 180 108 Untitled +184 52 20 Untitled + 0 0 0 grey0 + 40 0 0 Untitled + 0 56 92 Untitled + 0 0 4 Untitled + 0 0 0 grey0 + 60 56 56 Untitled + 56 20 40 Untitled +192 28 36 Untitled + 72 80 60 Untitled + 72 92 68 Untitled + 88 100 76 Untitled + 88 116 72 Untitled + 0 0 0 grey0 + 56 40 56 Untitled + 72 76 68 Untitled +128 48 52 Untitled +168 36 60 Untitled + 76 96 76 Untitled + 80 108 80 Untitled +128 120 108 Untitled +184 72 80 Untitled +104 128 84 Untitled +136 132 108 Untitled +148 140 116 Untitled +112 152 92 Untitled +208 184 132 Untitled +104 116 100 Untitled +132 128 116 Untitled +136 120 88 Untitled + 0 0 0 grey0 +116 124 120 Untitled +136 152 152 Untitled +144 156 160 Untitled +156 168 176 Untitled +184 184 176 Untitled +152 172 184 Untitled +184 188 188 Untitled +196 200 196 Untitled +212 212 208 Untitled +148 164 172 Untitled + 84 96 84 Untitled + 96 8 20 Untitled +100 116 80 Untitled + 96 120 92 Untitled +164 176 184 Untitled +204 188 152 Untitled +128 128 100 Untitled + 44 40 40 Untitled +204 204 188 Untitled + 92 128 80 Untitled +100 140 88 Untitled + 56 48 44 Untitled +128 148 112 Untitled + 36 28 40 Untitled +196 160 112 Untitled +124 116 96 Untitled +104 104 84 Untitled +132 140 140 Untitled +140 132 116 Untitled +204 208 200 Untitled +196 80 84 Untitled +116 112 96 Untitled + 88 116 84 Untitled + 64 44 56 Untitled + 44 24 8 Untitled +196 116 116 Untitled +180 148 116 Untitled +136 176 116 Untitled +148 140 124 Untitled diff --git a/chalk/data/palettes/DMC.gpl b/chalk/data/palettes/DMC.gpl new file mode 100644 index 00000000..7e9a0c0c --- /dev/null +++ b/chalk/data/palettes/DMC.gpl @@ -0,0 +1,458 @@ +GIMP Palette +Name: DMC +# +255 255 255 BLANC +255 247 231 ECRU +207 0 83 150 Bright Red +255 203 215 151 Pink +225 161 161 152 Flesh - DK +234 197 235 153 Lilac + 75 35 58 154 Red - VY DK +151 116 182 155 Forget-me-not Blue +133 119 180 156 Blue - MED +181 184 234 157 Blue - LT + 57 48 104 158 Blue - DK +188 181 222 159 Petrol Blue - LT +129 120 169 160 Petrol Blue - MED + 96 86 139 161 Petrol Blue - DK +202 231 240 162 Baby Blue - LT + 85 122 96 163 Green +186 228 182 164 Green - LT +225 244 119 165 Green - BRIGHT +173 194 56 166 Lime Green +133 93 49 167 Khaki Brown +177 174 183 168 Silver Grey +130 125 125 169 Pewter Grey +148 91 128 208 Lavender - VY DK +206 148 186 209 Lavender - DK +236 207 225 210 Lavender - MED +243 218 228 211 Lavender - LT +156 41 74 221 Shell Pink - VY DK +219 128 115 223 Shell Pink - LT +255 199 176 224 Shell Pink - VY LT +255 240 228 225 Shell Pink - ULT VY LT +143 57 38 300 Mahogany - VY DK +209 102 84 301 Mahogany - MED +188 0 97 304 Christmas Red - MED +255 231 109 307 Lemon +214 43 91 309 Rose - DEEP + 0 0 0 310 Black + 0 79 97 311 Navy Blue - MED + 58 84 103 312 Navy Blue - LT +163 90 91 315 Antique Mauve - VY DK +220 141 141 316 Antique Mauve - MED +167 139 136 317 Pewter Grey +197 198 190 318 Steel Grey - LT + 85 95 82 319 Pistachio Green - VY DK +138 153 120 320 Pistachio Green - MED +231 18 97 321 Christmas Red + 81 109 135 322 Navy Blue - VY LT +188 22 65 326 Rose - VY DEEP + 61 0 103 327 Violet - DK +127 84 130 333 Blue Violet - VY DK +115 140 170 334 Baby Blue - MED +219 36 79 335 Rose + 36 73 103 336 Navy Blue +162 121 164 340 Blue Violet - MED +145 180 197 341 Blue Violet - LT +194 36 67 347 Salmon - VY DK +220 61 91 349 Coral - DK +237 69 90 350 Coral - MED +255 128 135 351 Coral +255 157 144 352 Coral - LT +255 196 184 353 Peach Flesh +189 73 47 355 Terracotta - DK +226 114 91 356 Terracotta - MED + 95 112 91 367 Pistachio Green - DK +181 206 162 368 Pistachio Green - LT +243 250 209 369 Pistachio Green - VY LT +184 138 87 370 Mustard - MED +196 155 100 371 Mustard +203 162 107 372 Mustard - LT +157 60 39 400 Mahogany - DK +255 190 164 402 Mahogany - VY LT +194 101 76 407 Sportsman Flesh - VY DK +109 95 95 413 Pewter Grey - DK +167 139 136 414 Steel Grey - DK +221 221 218 415 Pearl Grey +140 91 43 420 Hazelnut Brown - DK +237 172 123 422 Hazelnut Brown - LT +151 84 20 433 Brown - MED +178 103 70 434 Brown - LT +187 107 57 435 Brown - VY LT +231 152 115 436 Tan +238 171 121 437 Tan - LT +255 176 0 444 Lemon - DK +255 255 190 445 Lemon - LT +179 151 143 451 Shell Grey - DK +210 185 175 452 Shell Grey - MED +235 207 185 453 Shell Grey - LT +116 114 92 469 Avocado Green +133 143 108 470 Avocado Green - LT +176 187 140 471 Avocado Green - VY LT +238 255 182 472 Avocado Green - ULT LT +187 0 97 498 Christmas Red - LT + 43 57 41 500 Blue Green - VY DK + 67 85 73 501 Blue Green - DK +134 158 134 502 Blue Green +195 206 183 503 Blue Green - MED +206 221 193 504 Blue Green - LT + 58 99 64 505 Grass Green - DK + 16 127 135 517 Wedgwood - MED +102 148 154 518 Wedgwood - LT +194 209 207 519 Sky Blue + 55 73 18 520 Fern Green - DK +159 169 142 522 Fern Green +172 183 142 523 Fern Green - LT +205 182 158 524 Fern Green - VY LT + 85 85 89 535 Ash Grey - VY LT +239 214 188 543 Beige Brown - ULT VY LT +109 18 97 550 Violet - VY LT +146 85 130 552 Violet - MED +160 100 146 553 Violet +243 206 225 554 Violet - LT + 59 96 76 561 Jade - VY DK + 97 134 97 562 Jade - MED +182 212 180 563 Jade - LT +214 230 204 564 Jade - VY LT + 0 103 0 580 Moss Green - DK +151 152 49 581 Moss Green +128 151 132 597 Turquoise +208 223 205 598 Turquoise - LT +208 57 106 600 Cranberry - VY DK +222 57 105 601 Cranberry - DK +231 84 122 602 Cranberry - MED +255 115 140 603 Cranberry +255 189 202 604 Cranberry - LT +255 207 214 605 Cranberry - VY LT +255 0 0 606 Bright Orange-Red +255 91 0 608 Bright Orange +151 104 84 610 Drab Brown - VY DK +158 109 91 611 Drab Brown - DK +203 152 103 612 Drab Brown - MED +219 176 122 613 Drab Brown - LT +162 77 52 632 Negro Flesh - MED +163 163 157 640 Beige Grey - VY DK +174 176 170 642 Beige Grey - DK +224 224 215 644 Beige Grey - MED +113 113 113 645 Beaver Grey - VY DK +121 121 121 646 Beaver Grey - DK +190 190 185 647 Beaver Grey - MED +202 202 202 648 Beaver Grey - LT +213 39 86 666 Christmas Red - LT +255 206 158 676 Old Gold - LT +255 231 182 677 Old Gold - VY LT +209 140 103 680 Old Gold - DK + 0 91 6 699 Christmas Green + 0 96 47 700 Christmas Green - BRIGHT + 79 108 69 701 Christmas Green - LT + 79 121 66 702 Kelly Green +121 144 76 703 Chartreuse +165 164 103 704 Chartreuse - BRIGHT +245 240 219 712 Cream +219 55 121 718 Plum +200 36 43 720 Orange Spice - DK +255 115 97 721 Orange Spice - MED +255 146 109 722 Orange Spice - LT +255 200 124 725 Topaz +255 224 128 726 Topaz - LT +255 235 168 727 Topaz - VY LT +242 174 63 728 Golden Yellow +243 176 128 729 Old Gold - MED +132 102 0 730 Olive Green - VY DK +140 103 0 731 Olive Green - DK +145 104 0 732 Olive Green +206 155 97 733 Olive Green - MED +221 166 107 734 Olive Green - LT +244 195 139 738 Tan - VY LT +244 233 202 739 Tan - ULT VY LT +255 131 19 740 Tangerine +255 142 4 741 Tangerine - MED +255 183 85 742 Tangerine - LT +255 230 146 743 Yellow - MED +255 239 170 744 Yellow - PALE +255 240 197 745 Yellow - LT PALE +246 234 219 746 Off White +240 247 239 747 Sky Blue - VY LT +251 227 209 754 Peach Flesh - LT +255 177 147 758 Terracotta - VY LT +249 160 146 760 Salmon +255 201 188 761 Salmon - LT +232 232 229 762 Pearl Grey - VY LT +231 249 203 772 Pine Green - LT +247 246 248 775 Baby Blue - VY LT +255 177 174 776 Pink - MED +155 0 66 777 Red - DEEP +255 199 184 778 Antique Mauve - VY LT + 83 51 45 779 Brown +181 98 46 780 Topaz - ULT VY DK +181 107 56 781 Topaz - VY DK +204 119 66 782 Topaz - DK +225 146 85 783 Topaz - MED + 71 55 93 791 Cornflower Blue - VY DK + 97 97 128 792 Cornflower Blue - DK +147 139 164 793 Cornflower Blue - MED +187 208 218 794 Cornflower Blue - LT + 30 58 95 796 Royal Blue - DK + 30 66 99 797 Royal Blue +103 115 141 798 Delft - DK +132 156 182 799 Delft - MED +233 238 233 800 Delft - PALE +123 71 20 801 Coffee Brown - DK + 32 39 84 803 Blue - DEEP + 30 130 133 806 Peacock Blue - DK +128 167 160 807 Peacock Blue +190 193 205 809 Delft +175 195 205 813 Blue - LT +162 0 88 814 Garnet - DK +166 0 91 815 Garnet - MED +179 0 91 816 Garnet +219 24 85 817 Coral Red - VY DK +255 234 235 818 Baby Pink +248 247 221 819 Baby Pink - LT + 30 54 85 820 Royal Blue - VY DK +242 234 219 822 Beige Grey - LT + 0 0 73 823 Navy Blue - DK + 71 97 116 824 Blue - VY DK + 85 108 128 825 Blue - DK +115 138 153 826 Blue - MED +213 231 232 827 Blue - VY LT +237 247 238 828 Blue - ULT VY LT +130 90 8 829 Golden Olive - VY DK +136 95 18 830 Golden Olive - DK +144 103 18 831 Golden Olive - MED +178 119 55 832 Golden Olive +219 182 128 833 Golden Olive - LT +242 209 142 834 Golden Olive - VY LT + 94 56 27 838 Beige Brown - VY DK +109 66 39 839 Beige Brown - DK +128 85 30 840 Beige Brown - MED +188 134 107 841 Beige Brown - LT +219 194 164 842 Beige Brown - VY LT +107 103 102 844 Beaver Brown - ULT DK +153 92 48 868 Hazelnut Brown - VY DK +153 92 48 869 Hazelnut Brown - VY DK + 79 86 76 890 Pistachio Green - ULT DK +241 49 84 891 Carnation - DK +249 90 97 892 Carnation - MED +243 149 157 893 Carnation - LT +255 194 191 894 Carnation - VY LT + 89 92 78 895 Hunter Green - VY DK +118 55 19 898 Coffee Brown - VY DK +233 109 115 899 Rose - MED +206 43 0 900 Burnt Orange - DK +138 24 77 902 Garnet - VY DK + 78 95 57 904 Parrot Green - VY DK + 98 119 57 905 Parrot Green - DK +143 163 89 906 Parrot Green - MED +185 200 102 907 Parrot Green - LT + 49 105 85 909 Emerald Green - VY DK + 48 116 91 910 Emerald Green - DK + 49 128 97 911 Emerald Green - MED +115 158 115 912 Emerald Green - LT +153 188 149 913 Nile Green - MED +170 24 91 915 Plum - DK +171 22 95 917 Plum - MED +168 68 76 918 Red Copper - DK +180 75 82 919 Red Copper +197 94 88 920 Copper - MED +206 103 91 921 Copper +237 134 115 922 Copper - LT + 86 99 100 924 Grey Green - VY DK + 96 116 115 926 Grey Green - DK +200 198 194 927 Grey Green - LT +225 224 216 928 Grey Green - VY LT +102 122 140 930 Antique Blue - DK +124 135 145 931 Antique Blue - MED +182 186 194 932 Antique Blue - LT + 62 59 40 934 Black Avocado Green + 67 63 47 935 Avocado Green - DK + 69 69 49 936 Avocado Green - VY DK + 73 86 55 937 Avocado Green - MED + 99 39 16 938 Coffee Brown - ULT DK + 0 0 49 939 Navy Blue - VY DK + 0 162 117 943 Aquamarine - MED +255 206 164 945 Flesh - MED +244 73 0 946 Burnt Orange - MED +255 91 0 947 Burnt Orange +255 243 231 948 Peach Flesh - VY LT +239 162 127 950 Sportsman Flesh +255 229 188 951 Flesh +170 213 164 954 Nile Green +214 230 204 955 Nile Green - LT +255 109 115 956 Geranium +255 204 208 957 Geranium - PALE + 0 160 130 958 Sea Green - DK +171 206 177 959 Sea Green - MED +243 108 123 961 Dusty Rose - DK +253 134 141 962 Dusty Rose - MED +255 233 233 963 Dusty Rose - ULT VY LT +208 224 210 964 Sea Green - LT +206 213 176 966 Baby Green - MED +255 194 172 967 Peach - LT +255 117 24 970 Pumpkin - LT +255 106 0 971 Pumpkin +255 146 0 972 Canary - DEEP +255 194 67 973 Canary - BRIGHT +158 67 18 975 Golden Brown - DK +246 141 57 976 Golden Brown - MED +255 164 73 977 Golden Brown - LT + 58 82 65 986 Forest Green - VY DK + 83 97 73 987 Forest Green - DK +134 145 110 988 Forest Green - MED +134 153 110 989 Forest Green + 47 91 73 991 Aquamarine - DK +146 183 165 992 Aquamarine +192 224 200 993 Aquamarine - LT + 0 123 134 995 Electric Blue - DK +170 222 225 996 Electric Blue - MED +123 91 64 3011 Khaki Green - DK +170 134 103 3012 Khaki Green - MED +208 195 164 3013 Khaki Green - LT +115 91 93 3021 Brown Grey - VY DK +172 172 170 3022 Brown Grey - MED +198 190 173 3023 Brown Grey - LT +210 208 205 3024 Brown Grey - VY LT + 84 56 23 3031 Mocha Brown - VY DK +188 156 120 3032 Mocha Brown - MED +239 219 190 3033 Mocha Brown - VY LT +190 155 167 3041 Antique Violet - MED +225 205 200 3042 Antique Violet - LT +216 151 105 3045 Yellow Beige - DK +229 193 139 3046 Yellow Beige - MED +255 236 211 3047 Yellow Beige - LT + 85 73 0 3051 Green Grey - DK +137 141 114 3052 Green Grey - MED +187 179 148 3053 Green Grey +194 101 76 3064 Sportsman Flesh - VY DK +233 233 223 3072 Beaver Grey - VY LT +255 255 220 3078 Golden Yellow - VY LT +202 226 229 3325 Baby Blue - LT +255 157 150 3326 Rose - LT +188 64 85 3328 Salmon - DK +255 123 103 3340 Apricot - MED +255 172 162 3341 Apricot + 97 100 82 3345 Hunter Green - DK +120 134 107 3346 Hunter Green +128 152 115 3347 Yellow Green - MED +225 249 190 3348 Yellow Green - LT +201 79 91 3350 Dusty Rose - ULT DK +255 214 209 3354 Dusty Rose - LT + 96 95 84 3362 Pine Green - DK +116 127 96 3363 Pine Green - MED +161 167 135 3364 Pine Green + 83 37 16 3371 Black Brown +231 79 134 3607 Plum - LT +247 152 182 3608 Plum - VY LT +255 214 229 3609 Plum - ULT LT +161 53 79 3685 Mauve - DK +203 78 97 3687 Mauve +250 151 144 3688 Mauve - MED +255 213 216 3689 Mauve - LT +255 85 91 3705 Melon - DK +255 128 109 3706 Melon - MED +254 212 219 3708 Melon - LT +230 101 107 3712 Salmon - MED +253 229 217 3713 Salmon - VY LT +255 211 212 3716 Dusty Rose - VY LT +184 75 77 3721 Shell Pink - DK +184 89 88 3722 Shell Pink - MED +195 118 123 3726 Antique Mauve - DK +255 199 196 3727 Antique Mauve - LT +209 93 103 3731 Dusty Rose - VY DK +255 154 148 3733 Dusty Rose +156 125 133 3740 Antique Violet - DK +235 235 231 3743 Antique Violet - VY LT +149 102 162 3746 Blue Violet - DK +230 236 232 3747 Blue Violet - VY LT + 12 91 108 3750 Antique Blue - VY DK +194 209 206 3752 Antique Blue - VY LT +237 247 247 3753 Antique Blue - ULT VY LT +158 176 206 3755 Baby Blue +248 248 252 3756 Baby Blue - ULT VY LT +102 142 152 3760 Wedgwood +227 234 230 3761 Sky Blue - LT + 24 128 134 3765 Peacock Blue - VY DK + 24 101 111 3766 Peacock Blue - LT + 92 110 108 3768 Grey Green - DK +255 250 224 3770 Flesh - VY LT +232 172 155 3771 Peach - DK +173 83 62 3772 Negro Flesh +231 134 103 3773 Sportsman Flesh - MED +255 220 193 3774 Sportsman Flesh - VY LT +221 109 91 3776 Mahogany - LT +191 64 36 3777 Terracotta - VY DK +237 122 100 3778 Terracotta - LT +255 177 152 3779 Terracotta - ULT VY LT +113 71 42 3781 Mocha Brown - DK +206 175 144 3782 Mocha Brown - LT +139 109 115 3787 Brown Grey - DK +140 117 109 3790 Beige Grey - ULT DK + 81 76 83 3799 Pewter Grey - VY DK +231 71 79 3801 Christmas Red - LT +127 43 59 3802 Antique Mauve - VY DK +171 51 87 3803 Mauve - MED +231 59 127 3804 Cyclamen Pink - DK +243 71 139 3805 Cyclamen Pink +255 87 155 3806 Cyclamen Pink - LT + 59 75 131 3807 Cornflower Blue + 11 83 95 3808 Turquoise - ULT VY DK + 31 107 123 3809 Turquoise - VY DK + 59 135 151 3810 Turquoise - DK +187 227 235 3811 Turquoise - VY LT + 23 147 119 3812 Sea Green - VY DK +151 195 171 3813 Blue Green - LT + 35 143 107 3814 Aquamarine + 99 127 107 3815 Celadon Green - DK +135 167 147 3816 Celadon Green +175 207 191 3817 Celadon Green - LT + 0 107 46 3818 Emerald Green - ULT VY DK +231 235 123 3819 Moss Green - LT +231 179 75 3820 Straw - DK +243 195 91 3821 Straw +255 211 107 3822 Straw - LT +255 251 227 3823 Yellow - ULT PALE +247 191 183 3824 Apricot - LT +255 171 131 3825 Pumpkin - PALE +227 155 79 3826 Golden Brown +247 187 119 3827 Golden Brown - PALE +187 135 63 3828 Hazelnut Brown +203 111 0 3829 Old Gold - VY DK +199 79 71 3830 Terracotta +170 68 77 3831 Raspberry - DK +215 95 104 3832 Raspberry - MED +224 124 134 3833 Raspberry - LT + 76 50 69 3834 Grape - DK +113 80 105 3835 Grape - MED +175 130 158 3836 Grape - LT +109 69 137 3837 Lavender - ULT DK + 80 90 162 3838 Lavender Blue - DK +107 123 189 3839 Lavender Blue - MED +162 186 238 3840 Lavender Blue - LT +199 221 235 3841 Baby Blue - PALE + 12 65 88 3842 Wedgwood - DK + 12 170 224 3843 Electric Blue + 43 91 155 3844 Bright Turquoise - DK + 63 145 213 3845 Bright Turquoise - MED + 82 173 234 3846 Bright Turquoise - LT + 48 77 68 3847 Teal Green - DK + 65 105 97 3848 Teal Green - MED + 90 165 140 3849 Teal Green - LT + 50 125 100 3850 Bright Green - DK + 90 165 140 3851 Bright Green - LT +220 163 59 3852 Straw - VY DK +229 121 75 3853 Autumn Gold - DK +248 171 99 3854 Autumn Gold - MED +253 228 174 3855 Autumn Gold - LT +255 190 130 3856 Mahogany - ULT VY LT + 72 43 47 3857 Rosewood - DK +102 63 65 3858 Rosewood - MED +177 114 106 3859 Rosewood - LT + 98 77 76 3860 Cocoa +146 121 120 3861 Cocoa - LT +107 83 71 3862 Mocha Beige - DK +134 106 88 3863 Mocha Beige - MED +196 166 141 3864 Mocha Beige - LT +255 251 244 3865 Winter White +245 233 213 3866 Mocha Brown - ULT VY LT +255 255 255 B5200 Bright Wite diff --git a/chalk/data/palettes/Dark_pastels.gpl b/chalk/data/palettes/Dark_pastels.gpl new file mode 100644 index 00000000..3802cd00 --- /dev/null +++ b/chalk/data/palettes/Dark_pastels.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Dark Pastels +# + 56 104 184 Untitled + 52 104 180 Untitled + 52 104 180 Untitled + 52 104 176 Untitled + 52 104 176 Untitled + 48 104 172 Untitled + 48 104 172 Untitled + 48 100 168 Untitled + 48 100 168 Untitled + 44 100 164 Untitled + 44 100 164 Untitled + 44 100 164 Untitled + 44 100 160 Untitled + 44 100 160 Untitled + 40 100 156 Untitled + 40 100 156 Untitled + 40 96 152 Untitled + 40 96 152 Untitled + 36 96 148 Untitled + 36 96 148 Untitled + 36 96 144 Untitled + 36 96 144 Untitled + 32 96 140 Untitled + 32 96 140 Untitled + 32 96 136 Untitled + 32 92 136 Untitled + 28 92 132 Untitled + 28 92 132 Untitled + 28 92 128 Untitled + 28 92 128 Untitled + 24 92 124 Untitled + 24 92 124 Untitled + 24 92 120 Untitled + 24 92 120 Untitled + 24 92 120 Untitled + 60 108 112 Untitled + 96 120 104 Untitled +128 132 100 Untitled +164 148 92 Untitled +200 160 84 Untitled +232 172 80 Untitled +228 168 84 Untitled +228 164 88 Untitled +224 160 88 Untitled +224 156 92 Untitled +224 152 92 Untitled +220 148 96 Untitled +220 144 96 Untitled +220 144 100 Untitled +216 140 100 Untitled +216 136 104 Untitled +216 132 104 Untitled +212 128 108 Untitled +212 124 112 Untitled +208 120 112 Untitled +208 120 116 Untitled +208 116 116 Untitled +204 112 120 Untitled +204 108 120 Untitled +204 104 124 Untitled +200 100 124 Untitled +200 96 128 Untitled +200 96 128 Untitled +196 100 124 Untitled +192 104 124 Untitled +188 108 124 Untitled +184 112 124 Untitled + 76 196 112 Untitled + 72 200 112 Untitled + 64 204 108 Untitled + 60 208 108 Untitled + 56 208 108 Untitled + 60 204 112 Untitled + 64 204 112 Untitled + 64 204 116 Untitled + 68 200 116 Untitled + 68 200 120 Untitled + 72 200 120 Untitled + 76 200 124 Untitled + 76 196 124 Untitled + 80 196 128 Untitled + 80 196 128 Untitled + 84 196 132 Untitled + 88 192 132 Untitled + 88 192 132 Untitled + 92 192 136 Untitled + 92 192 136 Untitled + 96 188 140 Untitled +100 188 140 Untitled +100 188 144 Untitled +104 188 144 Untitled +104 184 148 Untitled +108 184 148 Untitled +112 184 152 Untitled +112 180 152 Untitled +116 180 156 Untitled +116 180 156 Untitled +120 180 156 Untitled +120 176 160 Untitled +124 176 160 Untitled +128 176 164 Untitled +128 176 164 Untitled +132 172 168 Untitled +132 172 168 Untitled +136 172 172 Untitled +140 172 172 Untitled +140 168 176 Untitled +144 168 176 Untitled +144 168 180 Untitled +148 168 180 Untitled +152 164 180 Untitled +152 164 184 Untitled +156 164 184 Untitled +156 160 188 Untitled +160 160 188 Untitled +164 160 192 Untitled +164 160 192 Untitled +168 156 196 Untitled +168 156 196 Untitled +172 156 200 Untitled +176 156 200 Untitled +176 152 204 Untitled +180 152 204 Untitled +180 152 204 Untitled +184 152 208 Untitled +184 148 208 Untitled +188 148 212 Untitled +192 148 212 Untitled +192 148 216 Untitled +196 144 216 Untitled +196 144 220 Untitled +200 144 220 Untitled +204 140 224 Untitled +204 140 224 Untitled +208 140 228 Untitled +208 140 228 Untitled +212 136 228 Untitled +216 136 232 Untitled +216 136 232 Untitled +220 136 236 Untitled +220 132 236 Untitled +224 132 240 Untitled +228 132 240 Untitled +228 132 244 Untitled +232 128 244 Untitled +232 128 248 Untitled +236 128 248 Untitled +236 128 248 Untitled +232 124 240 Untitled +228 124 236 Untitled +224 124 232 Untitled +220 120 224 Untitled +216 120 220 Untitled +212 120 216 Untitled +212 116 212 Untitled +208 116 204 Untitled +204 116 200 Untitled +200 112 196 Untitled +196 112 192 Untitled +192 112 184 Untitled +188 108 180 Untitled +188 108 176 Untitled +184 108 168 Untitled +180 104 164 Untitled +176 104 160 Untitled +172 104 156 Untitled +168 100 148 Untitled +164 100 144 Untitled +164 100 140 Untitled +160 100 136 Untitled +156 96 128 Untitled +152 96 124 Untitled +148 96 120 Untitled +144 92 116 Untitled +140 92 108 Untitled +140 92 104 Untitled +136 88 100 Untitled +132 88 92 Untitled +128 88 88 Untitled +124 84 84 Untitled +120 84 80 Untitled +116 84 72 Untitled +116 80 68 Untitled +112 80 64 Untitled +108 80 60 Untitled +104 76 52 Untitled +100 76 48 Untitled + 96 76 44 Untitled + 96 76 40 Untitled + 92 80 44 Untitled + 92 80 48 Untitled + 92 80 52 Untitled + 92 80 56 Untitled + 92 80 56 Untitled + 92 80 60 Untitled + 92 84 64 Untitled + 88 84 68 Untitled + 88 84 68 Untitled + 88 84 72 Untitled + 88 84 76 Untitled + 88 84 80 Untitled + 88 88 80 Untitled + 88 88 84 Untitled + 88 88 88 Untitled + 84 88 92 Untitled + 84 88 92 Untitled + 84 88 96 Untitled + 84 92 100 Untitled + 84 92 104 Untitled + 84 92 108 Untitled + 84 92 108 Untitled + 84 92 112 Untitled + 80 92 116 Untitled + 80 96 120 Untitled + 80 96 120 Untitled + 80 96 124 Untitled + 80 96 128 Untitled + 80 96 132 Untitled + 80 96 132 Untitled + 80 100 136 Untitled + 76 100 140 Untitled + 76 100 144 Untitled + 76 100 144 Untitled + 76 100 148 Untitled + 76 100 152 Untitled + 76 104 156 Untitled + 76 104 160 Untitled + 76 104 160 Untitled + 72 104 164 Untitled + 72 104 168 Untitled + 72 104 172 Untitled + 72 108 172 Untitled + 72 108 176 Untitled + 72 108 180 Untitled + 72 108 184 Untitled + 72 108 184 Untitled + 68 108 188 Untitled + 68 112 192 Untitled + 68 112 196 Untitled + 68 112 196 Untitled + 68 112 200 Untitled + 68 112 204 Untitled + 68 112 208 Untitled + 68 112 208 Untitled + 64 108 204 Untitled + 64 108 204 Untitled + 64 108 200 Untitled + 64 108 200 Untitled + 60 108 196 Untitled + 60 108 196 Untitled + 60 108 192 Untitled + 60 108 192 Untitled + 56 108 188 Untitled + 56 104 188 Untitled + 56 104 184 Untitled + 56 104 184 Untitled diff --git a/chalk/data/palettes/Default.gpl b/chalk/data/palettes/Default.gpl new file mode 100644 index 00000000..b2541c35 --- /dev/null +++ b/chalk/data/palettes/Default.gpl @@ -0,0 +1,26 @@ +GIMP Palette +Name: Default +# +255 0 0 Red +255 0 255 Magenta + 0 0 255 Blue + 0 255 255 Cyan + 0 255 0 Green +255 255 0 Yellow +127 0 0 Dark Red +127 0 127 Dark Magenta + 0 0 127 Dark Blue + 0 127 127 Dark Cyan + 0 127 0 Dark Green +130 127 0 Dark Yellow + 0 0 0 Black + 25 25 25 Gray 10% + 51 51 51 Gray 20% + 76 76 76 Gray 30% +102 102 102 Gray 40% +127 127 127 Gray 50% +153 153 153 Gray 60% +178 178 178 Gray 70% +204 204 204 Gray 80% +229 229 229 Gray 90% +255 255 255 White diff --git a/chalk/data/palettes/Ega.gpl b/chalk/data/palettes/Ega.gpl new file mode 100644 index 00000000..80b6d06d --- /dev/null +++ b/chalk/data/palettes/Ega.gpl @@ -0,0 +1,244 @@ +GIMP Palette +Name: Ega +Columns: 16 +# + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 + 0 0 0 grey0 +168 0 168 Untitled +252 84 84 Untitled +252 84 168 Untitled +252 84 252 Untitled +252 168 252 Untitled +252 252 0 Untitled +252 252 168 Untitled +252 252 252 grey99 +168 252 252 Untitled + 0 252 252 Untitled + 84 168 252 Untitled + 0 0 252 Untitled + 0 84 168 Untitled + 0 0 84 Untitled + 84 84 84 grey33 diff --git a/chalk/data/palettes/Firecode.gpl b/chalk/data/palettes/Firecode.gpl new file mode 100644 index 00000000..252b738e --- /dev/null +++ b/chalk/data/palettes/Firecode.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Firecode +# + 0 0 0 grey0 + 0 0 24 Untitled + 0 0 24 Untitled + 0 0 28 Untitled + 0 0 32 Untitled + 0 0 32 Untitled + 0 0 36 Untitled + 0 0 40 Untitled + 8 0 40 Untitled + 16 0 36 Untitled + 24 0 36 Untitled + 32 0 32 Untitled + 40 0 28 Untitled + 48 0 28 Untitled + 56 0 24 Untitled + 64 0 20 Untitled + 72 0 20 Untitled + 80 0 16 Untitled + 88 0 16 Untitled + 96 0 12 Untitled +104 0 8 Untitled +112 0 8 Untitled +120 0 4 Untitled +128 0 0 Untitled +128 0 0 Untitled +132 0 0 Untitled +136 0 0 Untitled +140 0 0 Untitled +144 0 0 Untitled +144 0 0 Untitled +148 0 0 Untitled +152 0 0 Untitled +156 0 0 Untitled +160 0 0 Untitled +160 0 0 Untitled +164 0 0 Untitled +168 0 0 Untitled +172 0 0 Untitled +176 0 0 Untitled +180 0 0 Untitled +184 4 0 Untitled +188 4 0 Untitled +192 8 0 Untitled +196 8 0 Untitled +200 12 0 Untitled +204 12 0 Untitled +208 16 0 Untitled +212 16 0 Untitled +216 20 0 Untitled +220 20 0 Untitled +224 24 0 Untitled +228 24 0 Untitled +232 28 0 Untitled +236 28 0 Untitled +240 32 0 Untitled +244 32 0 Untitled +252 36 0 Untitled +252 36 0 Untitled +252 40 0 Untitled +252 40 0 Untitled +252 44 0 Untitled +252 44 0 Untitled +252 48 0 Untitled +252 48 0 Untitled +252 52 0 Untitled +252 52 0 Untitled +252 56 0 Untitled +252 56 0 Untitled +252 60 0 Untitled +252 60 0 Untitled +252 64 0 Untitled +252 64 0 Untitled +252 68 0 Untitled +252 68 0 Untitled +252 72 0 Untitled +252 72 0 Untitled +252 76 0 Untitled +252 76 0 Untitled +252 80 0 Untitled +252 80 0 Untitled +252 84 0 Untitled +252 84 0 Untitled +252 88 0 Untitled +252 88 0 Untitled +252 92 0 Untitled +252 96 0 Untitled +252 96 0 Untitled +252 100 0 Untitled +252 100 0 Untitled +252 104 0 Untitled +252 104 0 Untitled +252 108 0 Untitled +252 108 0 Untitled +252 112 0 Untitled +252 112 0 Untitled +252 116 0 Untitled +252 116 0 Untitled +252 120 0 Untitled +252 120 0 Untitled +252 124 0 Untitled +252 124 0 Untitled +252 128 0 Untitled +252 128 0 Untitled +252 132 0 Untitled +252 132 0 Untitled +252 136 0 Untitled +252 136 0 Untitled +252 140 0 Untitled +252 140 0 Untitled +252 144 0 Untitled +252 144 0 Untitled +252 148 0 Untitled +252 152 0 Untitled +252 152 0 Untitled +252 156 0 Untitled +252 156 0 Untitled +252 160 0 Untitled +252 160 0 Untitled +252 164 0 Untitled +252 164 0 Untitled +252 168 0 Untitled +252 168 0 Untitled +252 172 0 Untitled +252 172 0 Untitled +252 176 0 Untitled +252 176 0 Untitled +252 180 0 Untitled +252 180 0 Untitled +252 184 0 Untitled +252 184 0 Untitled +252 188 0 Untitled +252 188 0 Untitled +252 192 0 Untitled +252 192 0 Untitled +252 196 0 Untitled +252 196 0 Untitled +252 200 0 Untitled +252 200 0 Untitled +252 204 0 Untitled +252 208 0 Untitled +252 208 0 Untitled +252 208 0 Untitled +252 208 0 Untitled +252 208 0 Untitled +252 212 0 Untitled +252 212 0 Untitled +252 212 0 Untitled +252 212 0 Untitled +252 216 0 Untitled +252 216 0 Untitled +252 216 0 Untitled +252 216 0 Untitled +252 216 0 Untitled +252 220 0 Untitled +252 220 0 Untitled +252 220 0 Untitled +252 220 0 Untitled +252 224 0 Untitled +252 224 0 Untitled +252 224 0 Untitled +252 224 0 Untitled +252 228 0 Untitled +252 228 0 Untitled +252 228 0 Untitled +252 228 0 Untitled +252 228 0 Untitled +252 232 0 Untitled +252 232 0 Untitled +252 232 0 Untitled +252 232 0 Untitled +252 236 0 Untitled +252 236 0 Untitled +252 236 0 Untitled +252 236 0 Untitled +252 240 0 Untitled +252 240 0 Untitled +252 240 0 Untitled +252 240 0 Untitled +252 240 0 Untitled +252 244 0 Untitled +252 244 0 Untitled +252 244 0 Untitled +252 244 0 Untitled +252 248 0 Untitled +252 248 0 Untitled +252 248 0 Untitled +252 248 0 Untitled +252 252 0 Untitled +252 252 4 Untitled +252 252 8 Untitled +252 252 12 Untitled +252 252 16 Untitled +252 252 20 Untitled +252 252 24 Untitled +252 252 28 Untitled +252 252 32 Untitled +252 252 36 Untitled +252 252 40 Untitled +252 252 40 Untitled +252 252 44 Untitled +252 252 48 Untitled +252 252 52 Untitled +252 252 56 Untitled +252 252 60 Untitled +252 252 64 Untitled +252 252 68 Untitled +252 252 72 Untitled +252 252 76 Untitled +252 252 80 Untitled +252 252 84 Untitled +252 252 84 Untitled +252 252 88 Untitled +252 252 92 Untitled +252 252 96 Untitled +252 252 100 Untitled +252 252 104 Untitled +252 252 108 Untitled +252 252 112 Untitled +252 252 116 Untitled +252 252 120 Untitled +252 252 124 Untitled +252 252 124 Untitled +252 252 128 Untitled +252 252 132 Untitled +252 252 136 Untitled +252 252 140 Untitled +252 252 144 Untitled +252 252 148 Untitled +252 252 152 Untitled +252 252 156 Untitled +252 252 160 Untitled +252 252 164 Untitled +252 252 168 Untitled +252 252 168 Untitled +252 252 172 Untitled +252 252 176 Untitled +252 252 180 Untitled +252 252 184 Untitled +252 252 188 Untitled +252 252 192 Untitled +252 252 196 Untitled +252 252 200 Untitled +252 252 204 Untitled +252 252 208 Untitled +252 252 208 Untitled +252 252 212 Untitled +252 252 216 Untitled +252 252 220 Untitled +252 252 224 Untitled +252 252 228 Untitled +252 252 232 Untitled +252 252 236 Untitled +252 252 240 Untitled +252 252 244 Untitled +252 252 248 Untitled +252 252 252 grey99 diff --git a/chalk/data/palettes/Gold.gpl b/chalk/data/palettes/Gold.gpl new file mode 100644 index 00000000..86ccca81 --- /dev/null +++ b/chalk/data/palettes/Gold.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Gold +# +252 252 128 Untitled +252 252 128 Untitled +252 248 124 Untitled +252 248 124 Untitled +252 244 120 Untitled +248 244 120 Untitled +248 240 116 Untitled +248 240 112 Untitled +248 236 112 Untitled +244 236 108 Untitled +244 232 108 Untitled +244 232 104 Untitled +244 228 104 Untitled +240 228 100 Untitled +240 224 96 Untitled +240 224 96 Untitled +240 220 92 Untitled +236 220 92 Untitled +236 216 88 Untitled +236 216 84 Untitled +236 212 84 Untitled +236 212 80 Untitled +232 208 80 Untitled +232 208 76 Untitled +232 204 76 Untitled +232 204 72 Untitled +228 200 68 Untitled +228 200 68 Untitled +228 196 64 Untitled +228 196 64 Untitled +224 192 60 Untitled +224 192 56 Untitled +224 188 56 Untitled +224 188 52 Untitled +220 184 52 Untitled +220 184 48 Untitled +220 180 48 Untitled +220 180 44 Untitled +220 176 40 Untitled +216 176 40 Untitled +216 172 36 Untitled +216 172 36 Untitled +216 168 32 Untitled +212 168 28 Untitled +212 164 28 Untitled +212 164 24 Untitled +212 160 24 Untitled +208 160 20 Untitled +208 156 20 Untitled +208 156 16 Untitled +208 152 12 Untitled +204 152 12 Untitled +204 148 8 Untitled +204 148 8 Untitled +204 144 4 Untitled +200 140 0 Untitled +196 136 0 Untitled +196 136 0 Untitled +196 136 0 Untitled +196 136 0 Untitled +192 132 0 Untitled +192 132 0 Untitled +192 132 0 Untitled +192 132 0 Untitled +188 128 0 Untitled +188 128 0 Untitled +188 128 0 Untitled +188 128 0 Untitled +184 124 0 Untitled +184 124 0 Untitled +184 124 0 Untitled +184 124 0 Untitled +180 120 0 Untitled +180 120 0 Untitled +180 120 0 Untitled +180 120 0 Untitled +176 116 0 Untitled +176 116 0 Untitled +176 116 0 Untitled +176 116 0 Untitled +172 112 0 Untitled +172 112 0 Untitled +172 112 0 Untitled +172 112 0 Untitled +168 108 0 Untitled +168 108 0 Untitled +168 108 0 Untitled +168 108 0 Untitled +164 104 0 Untitled +164 104 0 Untitled +164 104 0 Untitled +164 104 0 Untitled +160 100 0 Untitled +160 100 0 Untitled +160 100 0 Untitled +160 100 0 Untitled +156 96 0 Untitled +156 96 0 Untitled +156 96 0 Untitled +156 96 0 Untitled +152 92 0 Untitled +152 92 0 Untitled +152 92 0 Untitled +152 92 0 Untitled +148 88 0 Untitled +148 88 0 Untitled +148 88 0 Untitled +148 88 0 Untitled +144 84 0 Untitled +144 84 0 Untitled +144 84 0 Untitled +144 84 0 Untitled +140 80 0 Untitled +140 80 0 Untitled +140 80 0 Untitled +140 80 0 Untitled +136 76 0 Untitled +136 76 0 Untitled +136 76 0 Untitled +136 76 0 Untitled +132 72 0 Untitled +132 72 0 Untitled +132 72 0 Untitled +132 72 0 Untitled +128 68 0 Untitled +128 68 0 Untitled +128 68 0 Untitled +128 68 0 Untitled +124 64 0 Untitled +124 64 0 Untitled +124 64 0 Untitled +124 64 0 Untitled +120 60 0 Untitled +120 60 0 Untitled +120 60 0 Untitled +120 60 0 Untitled +116 56 0 Untitled +116 56 0 Untitled +116 56 0 Untitled +116 56 0 Untitled +112 52 0 Untitled +112 52 0 Untitled +112 52 0 Untitled +112 52 0 Untitled +108 48 0 Untitled +108 48 0 Untitled +108 48 0 Untitled +108 48 0 Untitled +104 44 0 Untitled +104 44 0 Untitled +104 44 0 Untitled +104 44 0 Untitled +100 40 0 Untitled +100 40 0 Untitled +100 40 0 Untitled +100 40 0 Untitled + 96 36 0 Untitled + 96 36 0 Untitled + 96 36 0 Untitled + 96 36 0 Untitled + 92 32 0 Untitled + 92 32 0 Untitled + 92 32 0 Untitled + 92 32 0 Untitled + 88 28 0 Untitled + 88 28 0 Untitled + 88 28 0 Untitled + 88 28 0 Untitled + 84 24 0 Untitled + 84 24 0 Untitled + 84 24 0 Untitled + 84 24 0 Untitled + 80 20 0 Untitled + 80 20 0 Untitled + 80 20 0 Untitled + 80 20 0 Untitled + 76 16 0 Untitled + 76 16 0 Untitled + 76 16 0 Untitled + 76 16 0 Untitled + 72 12 0 Untitled + 72 12 0 Untitled + 72 12 0 Untitled + 72 12 0 Untitled + 68 8 0 Untitled + 68 8 0 Untitled + 68 8 0 Untitled + 68 8 0 Untitled + 64 4 0 Untitled + 64 4 0 Untitled + 64 4 0 Untitled + 64 4 0 Untitled + 60 0 0 Untitled + 60 0 0 Untitled + 60 0 0 Untitled + 60 0 0 Untitled + 56 0 0 Untitled + 56 0 0 Untitled + 56 0 0 Untitled + 56 0 0 Untitled + 52 0 0 Untitled + 52 0 0 Untitled + 52 0 0 Untitled + 52 0 0 Untitled + 48 0 0 Untitled + 48 0 0 Untitled + 48 0 0 Untitled + 48 0 0 Untitled + 44 0 0 Untitled + 44 0 0 Untitled + 44 0 0 Untitled + 44 0 0 Untitled + 40 0 0 Untitled + 40 0 0 Untitled + 40 0 0 Untitled + 40 0 0 Untitled + 36 0 0 Untitled + 36 0 0 Untitled + 36 0 0 Untitled + 36 0 0 Untitled + 32 0 0 Untitled + 32 0 0 Untitled + 32 0 0 Untitled + 32 0 0 Untitled + 28 0 0 Untitled + 28 0 0 Untitled + 28 0 0 Untitled + 28 0 0 Untitled + 24 0 0 Untitled + 24 0 0 Untitled + 24 0 0 Untitled + 24 0 0 Untitled + 20 0 0 Untitled + 20 0 0 Untitled + 20 0 0 Untitled + 20 0 0 Untitled + 16 0 0 Untitled + 16 0 0 Untitled + 16 0 0 Untitled + 16 0 0 Untitled + 12 0 0 Untitled + 12 0 0 Untitled + 12 0 0 Untitled + 12 0 0 Untitled + 8 0 0 Untitled + 8 0 0 Untitled + 8 0 0 Untitled + 8 0 0 Untitled + 4 0 0 Untitled + 4 0 0 Untitled + 4 0 0 Untitled + 4 0 0 Untitled + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 diff --git a/chalk/data/palettes/GrayViolet.gpl b/chalk/data/palettes/GrayViolet.gpl new file mode 100644 index 00000000..9bc34021 --- /dev/null +++ b/chalk/data/palettes/GrayViolet.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: GrayViolet +# + 0 0 0 grey0 + 0 0 0 grey0 + 4 4 4 Untitled + 4 4 4 Untitled + 8 8 8 grey3 + 8 8 8 grey3 + 12 12 12 Untitled + 12 12 12 Untitled + 16 16 16 Untitled + 16 16 16 Untitled + 20 20 20 grey8 + 20 20 20 grey8 + 20 24 24 Untitled + 24 24 24 Untitled + 24 28 28 Untitled + 28 28 28 grey11 + 28 32 32 Untitled + 32 32 32 Untitled + 32 32 36 Untitled + 36 36 36 grey14 + 36 36 40 Untitled + 40 40 40 Untitled + 40 40 44 Untitled + 40 44 44 Untitled + 44 44 48 Untitled + 44 48 48 Untitled + 48 48 52 Untitled + 48 52 52 Untitled + 52 52 56 Untitled + 52 56 56 Untitled + 56 56 60 Untitled + 56 60 60 Untitled + 56 60 64 Untitled + 60 64 64 Untitled + 60 64 68 Untitled + 64 64 68 Untitled + 64 68 72 Untitled + 68 68 72 Untitled + 68 72 76 Untitled + 72 72 76 Untitled + 72 76 80 Untitled + 76 76 80 Untitled + 76 80 84 Untitled + 76 80 84 Untitled + 80 84 88 Untitled + 80 84 88 Untitled + 84 88 92 Untitled + 84 88 92 Untitled + 88 92 96 Untitled + 88 92 96 Untitled + 92 96 100 Untitled + 92 96 100 Untitled + 96 96 104 Untitled + 96 100 104 Untitled + 96 100 108 Untitled +100 104 108 Untitled +100 104 112 Untitled +104 108 112 Untitled +104 108 116 Untitled +108 112 116 Untitled +108 112 120 Untitled +112 116 120 Untitled +112 116 124 Untitled +116 120 124 Untitled +116 120 128 Untitled +116 124 128 Untitled +120 124 132 Untitled +120 124 132 Untitled +124 128 136 Untitled +124 128 136 Untitled +128 132 140 Untitled +128 132 140 Untitled +132 136 144 Untitled +132 136 144 Untitled +136 140 148 Untitled +136 140 148 Untitled +136 144 152 Untitled +140 144 152 Untitled +140 148 156 Untitled +144 148 156 Untitled +144 152 160 Untitled +148 152 160 Untitled +148 156 164 Untitled +152 156 164 Untitled +152 156 168 Untitled +156 160 168 Untitled +156 160 172 Untitled +156 164 172 Untitled +160 164 176 Untitled +160 168 176 Untitled +164 168 180 Untitled +164 172 180 Untitled +168 172 184 Untitled +168 176 184 Untitled +172 176 188 Untitled +172 180 188 Untitled +172 180 192 Untitled +176 184 192 Untitled +176 184 196 Untitled +180 188 196 Untitled +180 188 200 Untitled +184 188 200 Untitled +184 192 204 Untitled +188 192 204 Untitled +188 196 208 Untitled +192 196 208 Untitled +192 200 212 Untitled +192 200 212 Untitled +196 204 216 Untitled +196 204 216 Untitled +200 208 220 Untitled +200 208 220 Untitled +204 212 224 Untitled +204 212 224 Untitled +208 216 228 Untitled +208 216 228 Untitled +212 220 232 Untitled +212 220 232 Untitled +240 240 252 Untitled +228 232 244 Untitled +240 240 252 Untitled +224 232 244 Untitled +236 236 248 Untitled +220 228 240 Untitled +232 236 248 Untitled +220 228 236 Untitled +228 232 244 Untitled +216 224 236 Untitled +224 232 244 Untitled +212 220 232 Untitled +220 228 240 Untitled +208 220 232 Untitled +220 228 236 Untitled +204 216 228 Untitled +216 224 236 Untitled +200 216 224 Untitled +212 220 232 Untitled +200 212 224 Untitled +208 220 232 Untitled +196 212 220 Untitled +204 216 228 Untitled +192 208 220 Untitled +200 216 224 Untitled +188 208 216 Untitled +200 212 224 Untitled +180 204 216 Untitled +196 212 220 Untitled +188 208 216 Untitled +196 212 220 Untitled +184 204 212 Untitled +192 208 216 Untitled +180 200 208 Untitled +188 208 216 Untitled +180 200 208 Untitled +184 204 212 Untitled +180 196 204 Untitled +180 200 208 Untitled +176 192 200 Untitled +180 200 208 Untitled +176 188 196 Untitled +180 196 204 Untitled +172 184 192 Untitled +176 192 200 Untitled +172 180 192 Untitled +176 188 196 Untitled +168 176 188 Untitled +172 184 192 Untitled +168 172 184 Untitled +172 180 192 Untitled +164 168 180 Untitled +168 176 188 Untitled +164 164 176 Untitled +168 172 184 Untitled +160 160 176 Untitled +164 168 180 Untitled +160 156 172 Untitled +164 164 176 Untitled +156 152 168 Untitled +160 160 176 Untitled +156 148 164 Untitled +160 156 172 Untitled +152 144 160 Untitled +156 152 168 Untitled +152 140 160 Untitled +156 148 164 Untitled +148 136 156 Untitled +152 144 160 Untitled +148 132 152 Untitled +152 140 160 Untitled +144 128 148 Untitled +148 136 156 Untitled +144 124 144 Untitled +148 132 152 Untitled +140 120 144 Untitled +144 128 148 Untitled +140 116 140 Untitled +144 124 144 Untitled +136 112 136 Untitled +140 120 144 Untitled +136 108 132 Untitled +140 116 140 Untitled +132 104 128 Untitled +136 112 136 Untitled +132 100 124 Untitled +136 108 132 Untitled +128 96 124 Untitled +132 104 128 Untitled +128 92 120 Untitled +132 100 124 Untitled +124 88 116 Untitled +128 96 124 Untitled +124 84 112 Untitled +128 92 120 Untitled +120 80 108 Untitled +124 88 116 Untitled +120 76 108 Untitled +124 84 112 Untitled +116 72 104 Untitled +120 80 108 Untitled +116 68 100 Untitled +120 76 108 Untitled +112 64 96 Untitled +116 72 104 Untitled +112 60 92 Untitled +116 68 100 Untitled +108 56 92 Untitled +112 64 96 Untitled +108 52 88 Untitled +112 60 92 Untitled +104 48 84 Untitled +108 56 92 Untitled +104 44 80 Untitled +108 52 88 Untitled +100 40 76 Untitled +104 48 84 Untitled +100 36 76 Untitled +104 44 80 Untitled + 96 32 72 Untitled +100 40 76 Untitled + 96 28 68 Untitled +100 36 76 Untitled + 92 24 64 Untitled + 96 32 72 Untitled + 96 28 68 Untitled + 76 24 60 Untitled + 92 24 64 Untitled + 56 28 52 Untitled + 76 24 60 Untitled + 48 28 48 Untitled + 56 28 52 Untitled + 28 32 40 Untitled + 36 28 44 Untitled + 8 36 32 Untitled + 20 32 36 Untitled + 16 24 24 Untitled + 8 12 12 Untitled diff --git a/chalk/data/palettes/Grayblue.gpl b/chalk/data/palettes/Grayblue.gpl new file mode 100644 index 00000000..982749dc --- /dev/null +++ b/chalk/data/palettes/Grayblue.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Grayblue +# +124 164 128 Untitled +124 164 128 Untitled +124 164 124 Untitled +124 160 124 Untitled +124 160 124 Untitled +120 160 124 Untitled +120 160 124 Untitled +120 156 124 Untitled +120 156 124 Untitled +120 156 120 Untitled +116 156 120 Untitled +116 152 120 Untitled +116 152 120 Untitled +116 152 120 Untitled +116 152 120 Untitled +112 148 116 Untitled +112 148 116 Untitled +112 148 116 Untitled +112 148 116 Untitled +112 144 116 Untitled +108 144 116 Untitled +108 144 112 Untitled +108 144 112 Untitled +108 140 112 Untitled +108 140 112 Untitled +104 140 112 Untitled +104 140 112 Untitled +104 136 108 Untitled +104 136 108 Untitled +100 136 108 Untitled +100 136 108 Untitled +100 132 108 Untitled +100 132 108 Untitled +100 132 104 Untitled + 96 132 104 Untitled + 96 128 104 Untitled + 96 128 104 Untitled + 96 128 104 Untitled + 96 128 104 Untitled + 92 124 100 Untitled + 92 124 100 Untitled + 92 124 100 Untitled + 92 124 100 Untitled + 92 120 100 Untitled + 88 120 100 Untitled + 88 120 96 Untitled + 88 120 96 Untitled + 88 116 96 Untitled + 88 116 96 Untitled + 84 116 96 Untitled + 84 116 96 Untitled + 84 112 96 Untitled + 84 112 92 Untitled + 80 112 92 Untitled + 80 112 92 Untitled + 80 108 92 Untitled + 80 108 92 Untitled + 80 108 92 Untitled + 76 108 88 Untitled + 76 104 88 Untitled + 76 104 88 Untitled + 76 104 88 Untitled + 76 100 88 Untitled + 72 100 88 Untitled + 72 100 84 Untitled + 72 100 84 Untitled + 72 96 84 Untitled + 72 96 84 Untitled + 68 96 84 Untitled + 68 96 84 Untitled + 68 92 80 Untitled + 68 92 80 Untitled + 68 92 80 Untitled + 64 92 80 Untitled + 64 88 80 Untitled + 64 88 80 Untitled + 64 88 76 Untitled + 60 88 76 Untitled + 60 84 76 Untitled + 60 84 76 Untitled + 60 84 76 Untitled + 60 84 76 Untitled + 56 80 72 Untitled + 56 80 72 Untitled + 56 80 72 Untitled + 56 80 72 Untitled + 56 76 72 Untitled + 52 76 72 Untitled + 52 76 72 Untitled + 52 76 68 Untitled + 52 72 68 Untitled + 52 72 68 Untitled + 48 72 68 Untitled + 48 72 68 Untitled + 48 68 68 Untitled + 48 68 64 Untitled + 48 68 64 Untitled + 44 68 64 Untitled + 44 64 64 Untitled + 44 64 64 Untitled + 44 64 64 Untitled + 40 64 60 Untitled + 40 60 60 Untitled + 40 60 60 Untitled + 40 60 60 Untitled + 40 60 60 Untitled + 36 56 60 Untitled + 36 56 56 Untitled + 36 56 56 Untitled + 36 56 56 Untitled + 36 52 56 Untitled + 32 52 56 Untitled + 32 52 56 Untitled + 32 52 52 Untitled + 32 48 52 Untitled + 32 48 52 Untitled + 28 48 52 Untitled + 28 48 52 Untitled + 28 44 52 Untitled + 28 44 48 Untitled + 28 44 48 Untitled + 24 44 48 Untitled + 24 40 48 Untitled + 24 40 48 Untitled + 24 40 48 Untitled + 20 36 44 Untitled + 24 40 48 Untitled + 24 40 48 Untitled + 24 40 48 Untitled + 24 40 48 Untitled + 24 40 52 Untitled + 24 40 52 Untitled + 24 40 52 Untitled + 28 44 52 Untitled + 28 44 56 Untitled + 28 44 56 Untitled + 28 44 56 Untitled + 28 44 56 Untitled + 28 44 56 Untitled + 28 44 60 Untitled + 28 48 60 Untitled + 32 48 60 Untitled + 32 48 60 Untitled + 32 48 64 Untitled + 32 48 64 Untitled + 32 48 64 Untitled + 32 48 64 Untitled + 32 52 64 Untitled + 36 52 68 Untitled + 36 52 68 Untitled + 36 52 68 Untitled + 36 52 68 Untitled + 36 52 72 Untitled + 36 52 72 Untitled + 36 52 72 Untitled + 36 56 72 Untitled + 40 56 72 Untitled + 40 56 76 Untitled + 40 56 76 Untitled + 40 56 76 Untitled + 40 56 76 Untitled + 40 56 80 Untitled + 40 60 80 Untitled + 44 60 80 Untitled + 44 60 80 Untitled + 44 60 80 Untitled + 44 60 84 Untitled + 44 60 84 Untitled + 44 60 84 Untitled + 44 64 84 Untitled + 44 64 88 Untitled + 48 64 88 Untitled + 48 64 88 Untitled + 48 64 88 Untitled + 48 64 88 Untitled + 48 64 92 Untitled + 48 64 92 Untitled + 48 68 92 Untitled + 48 68 92 Untitled + 52 68 96 Untitled + 52 68 96 Untitled + 52 68 96 Untitled + 52 68 96 Untitled + 52 68 96 Untitled + 52 72 100 Untitled + 52 72 100 Untitled + 56 72 100 Untitled + 56 72 100 Untitled + 56 72 104 Untitled + 56 72 104 Untitled + 56 72 104 Untitled + 56 76 104 Untitled + 56 76 104 Untitled + 56 76 108 Untitled + 60 76 108 Untitled + 60 76 108 Untitled + 60 76 108 Untitled + 60 76 112 Untitled + 60 80 112 Untitled + 60 80 112 Untitled + 60 80 112 Untitled + 64 80 112 Untitled + 64 80 116 Untitled + 64 80 116 Untitled + 64 80 116 Untitled + 64 80 116 Untitled + 64 84 120 Untitled + 64 84 120 Untitled + 64 84 120 Untitled + 68 84 120 Untitled + 68 84 120 Untitled + 68 84 124 Untitled + 68 84 124 Untitled + 68 88 124 Untitled + 68 88 124 Untitled + 68 88 128 Untitled + 72 88 128 Untitled + 72 88 128 Untitled + 72 88 128 Untitled + 72 88 128 Untitled + 72 92 132 Untitled + 72 92 132 Untitled + 72 92 132 Untitled + 72 92 132 Untitled + 76 92 136 Untitled + 76 92 136 Untitled + 76 92 136 Untitled + 76 92 136 Untitled + 76 96 140 Untitled + 76 96 140 Untitled + 76 96 140 Untitled + 76 96 140 Untitled + 80 96 140 Untitled + 80 96 144 Untitled + 80 96 144 Untitled + 80 100 144 Untitled + 80 100 144 Untitled + 80 100 148 Untitled + 80 100 148 Untitled + 84 100 148 Untitled + 84 100 148 Untitled + 84 100 148 Untitled + 84 104 152 Untitled + 84 104 152 Untitled + 84 104 152 Untitled + 84 104 152 Untitled + 84 104 156 Untitled + 88 104 156 Untitled + 88 104 156 Untitled + 88 104 156 Untitled + 88 108 156 Untitled + 88 108 160 Untitled + 88 108 160 Untitled + 88 108 160 Untitled + 92 108 160 Untitled + 92 108 164 Untitled diff --git a/chalk/data/palettes/Grays.gpl b/chalk/data/palettes/Grays.gpl new file mode 100644 index 00000000..49050b22 --- /dev/null +++ b/chalk/data/palettes/Grays.gpl @@ -0,0 +1,34 @@ +GIMP Palette +Name: Grays + 0 0 0 gray0 + 7 7 7 gray3 + 15 15 15 gray6 + 23 23 23 gray9 + 31 31 31 gray12 + 39 39 39 gray15 + 47 47 47 gray18 + 55 55 55 gray21 + 63 63 63 gray25 + 71 71 71 gray28 + 79 79 79 gray31 + 87 87 87 gray34 + 95 95 95 gray37 +103 103 103 gray40 +111 111 111 gray43 +119 119 119 gray46 +127 127 127 gray50 +135 135 135 gray53 +143 143 143 gray56 +151 151 151 gray59 +159 159 159 gray62 +167 167 167 gray65 +175 175 175 gray68 +183 183 183 gray71 +191 191 191 gray75 +199 199 199 gray78 +207 207 207 gray81 +215 215 215 gray84 +223 223 223 gray87 +231 231 231 gray90 +239 239 239 gray93 +247 247 247 gray96 diff --git a/chalk/data/palettes/Greens.gpl b/chalk/data/palettes/Greens.gpl new file mode 100644 index 00000000..9da819b4 --- /dev/null +++ b/chalk/data/palettes/Greens.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Greens +# + 0 0 0 grey0 + 0 0 0 grey0 + 0 4 0 Untitled + 0 12 0 Untitled + 0 16 0 Untitled + 0 24 0 Untitled + 0 32 0 Untitled + 0 36 0 Untitled + 0 44 0 Untitled + 0 48 0 Untitled + 0 56 0 Untitled + 0 64 0 Untitled + 0 68 0 Untitled + 0 76 0 Untitled + 0 80 0 Untitled + 0 88 0 Untitled + 0 96 0 Untitled + 0 100 0 DarkGreen + 0 108 0 Untitled + 0 116 0 Untitled + 0 120 0 Untitled + 0 128 0 Untitled + 0 132 0 Untitled + 0 140 0 Untitled + 0 148 0 Untitled + 0 152 0 Untitled + 0 160 0 Untitled + 0 164 0 Untitled + 0 172 0 Untitled + 0 180 0 Untitled + 0 184 0 Untitled + 0 192 0 Untitled + 0 200 0 Untitled + 4 200 0 Untitled + 12 200 0 Untitled + 16 204 0 Untitled + 24 204 0 Untitled + 28 208 0 Untitled + 36 208 0 Untitled + 40 208 0 Untitled + 48 212 0 Untitled + 56 212 0 Untitled + 60 216 0 Untitled + 68 216 0 Untitled + 72 216 0 Untitled + 80 220 0 Untitled + 84 220 0 Untitled + 92 224 0 Untitled +100 224 0 Untitled +104 224 0 Untitled +112 228 0 Untitled +116 228 0 Untitled +124 232 0 Untitled +128 232 0 Untitled +136 232 0 Untitled +140 236 0 Untitled +148 236 0 Untitled +156 240 0 Untitled +160 240 0 Untitled +168 240 0 Untitled +172 244 0 Untitled +180 244 0 Untitled +184 248 0 Untitled +192 248 0 Untitled +200 252 0 Untitled +200 252 4 Untitled +200 252 12 Untitled +204 252 20 Untitled +204 252 28 Untitled +208 252 36 Untitled +208 252 44 Untitled +208 252 52 Untitled +212 252 60 Untitled +212 252 68 Untitled +216 252 76 Untitled +216 252 84 Untitled +216 252 92 Untitled +220 252 100 Untitled +220 252 108 Untitled +224 252 116 Untitled +224 252 124 Untitled +224 252 132 Untitled +228 252 140 Untitled +228 252 148 Untitled +232 252 156 Untitled +232 252 164 Untitled +232 252 172 Untitled +236 252 180 Untitled +236 252 188 Untitled +240 252 196 Untitled +240 252 204 Untitled +240 252 212 Untitled +244 252 220 Untitled +244 252 228 Untitled +248 252 236 Untitled +248 252 244 Untitled +252 252 252 grey99 +252 252 248 Untitled +252 252 244 Untitled +252 252 240 Untitled +252 252 232 Untitled +252 252 228 Untitled +252 252 224 Untitled +252 252 216 Untitled +252 252 212 Untitled +252 252 208 Untitled +252 252 200 Untitled +252 252 196 Untitled +252 252 192 Untitled +252 252 184 Untitled +252 252 180 Untitled +252 252 176 Untitled +252 252 168 Untitled +252 252 164 Untitled +252 252 160 Untitled +252 252 156 Untitled +252 252 148 Untitled +252 252 144 Untitled +252 252 140 Untitled +252 252 132 Untitled +252 252 128 Untitled +252 252 124 Untitled +252 252 116 Untitled +252 252 112 Untitled +252 252 108 Untitled +252 252 100 Untitled +252 252 96 Untitled +252 252 92 Untitled +252 252 84 Untitled +252 252 80 Untitled +252 252 76 Untitled +252 252 72 Untitled +252 252 64 Untitled +252 252 60 Untitled +252 252 56 Untitled +252 252 48 Untitled +252 252 44 Untitled +252 252 40 Untitled +252 252 32 Untitled +252 252 28 Untitled +252 252 24 Untitled +252 252 16 Untitled +252 252 12 Untitled +252 252 8 Untitled +252 252 0 Untitled +248 252 0 Untitled +244 252 0 Untitled +240 252 0 Untitled +232 252 0 Untitled +228 252 0 Untitled +224 252 0 Untitled +216 252 0 Untitled +212 252 0 Untitled +208 252 0 Untitled +200 252 0 Untitled +196 252 0 Untitled +192 252 0 Untitled +184 252 0 Untitled +180 252 0 Untitled +176 252 0 Untitled +168 252 0 Untitled +164 252 0 Untitled +160 252 0 Untitled +156 252 0 Untitled +148 252 0 Untitled +144 252 0 Untitled +140 252 0 Untitled +132 252 0 Untitled +128 252 0 Untitled +124 252 0 LawnGreen +116 252 0 Untitled +112 252 0 Untitled +108 252 0 Untitled +100 252 0 Untitled + 96 252 0 Untitled + 92 252 0 Untitled + 84 252 0 Untitled + 80 252 0 Untitled + 76 252 0 Untitled + 72 252 0 Untitled + 64 252 0 Untitled + 60 252 0 Untitled + 56 252 0 Untitled + 48 252 0 Untitled + 44 252 0 Untitled + 40 252 0 Untitled + 32 252 0 Untitled + 28 252 0 Untitled + 24 252 0 Untitled + 16 252 0 Untitled + 12 252 0 Untitled + 8 252 0 Untitled + 0 252 0 Untitled + 0 248 0 Untitled + 0 244 0 Untitled + 0 240 0 Untitled + 0 236 0 Untitled + 0 232 0 Untitled + 0 228 0 Untitled + 0 224 0 Untitled + 0 220 0 Untitled + 0 216 0 Untitled + 0 212 0 Untitled + 0 208 0 Untitled + 0 204 0 Untitled + 0 200 0 Untitled + 0 196 0 Untitled + 0 192 0 Untitled + 0 188 0 Untitled + 0 184 0 Untitled + 0 180 0 Untitled + 0 176 0 Untitled + 0 172 0 Untitled + 0 168 0 Untitled + 0 164 0 Untitled + 0 160 0 Untitled + 0 156 0 Untitled + 0 152 0 Untitled + 0 148 0 Untitled + 0 144 0 Untitled + 0 140 0 Untitled + 0 136 0 Untitled + 0 132 0 Untitled + 0 128 0 Untitled + 0 124 0 Untitled + 0 120 0 Untitled + 0 116 0 Untitled + 0 112 0 Untitled + 0 108 0 Untitled + 0 104 0 Untitled + 0 100 0 DarkGreen + 0 96 0 Untitled + 0 92 0 Untitled + 0 88 0 Untitled + 0 84 0 Untitled + 0 80 0 Untitled + 0 76 0 Untitled + 0 72 0 Untitled + 0 68 0 Untitled + 0 64 0 Untitled + 0 60 0 Untitled + 0 56 0 Untitled + 0 52 0 Untitled + 0 48 0 Untitled + 0 44 0 Untitled + 0 40 0 Untitled + 0 36 0 Untitled + 0 32 0 Untitled + 0 28 0 Untitled + 0 24 0 Untitled + 0 20 0 Untitled + 0 16 0 Untitled + 0 12 0 Untitled + 0 8 0 Untitled + 0 0 0 grey0 + 0 0 0 grey0 diff --git a/chalk/data/palettes/Hilite.gpl b/chalk/data/palettes/Hilite.gpl new file mode 100644 index 00000000..74b28684 --- /dev/null +++ b/chalk/data/palettes/Hilite.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Hilite +# +164 144 180 Untitled +160 144 180 Untitled +160 144 180 Untitled +160 144 176 Untitled +160 144 176 Untitled +160 140 172 Untitled +160 140 172 Untitled +160 140 168 Untitled +160 140 168 Untitled +160 140 168 Untitled +160 140 164 Untitled +160 136 164 Untitled +156 136 160 Untitled +156 136 160 Untitled +156 136 156 Untitled +156 136 156 Untitled +156 136 156 Untitled +156 132 152 Untitled +156 132 152 Untitled +156 132 148 Untitled +156 132 148 Untitled +156 132 144 Untitled +156 132 144 Untitled +152 128 144 Untitled +152 128 140 Untitled +152 128 140 Untitled +152 128 136 Untitled +152 128 136 Untitled +152 128 132 Untitled +152 128 132 Untitled +152 124 132 Untitled +152 124 128 Untitled +152 124 128 Untitled +152 124 124 Untitled +148 124 124 Untitled +148 124 120 Untitled +148 120 120 Untitled +148 120 120 Untitled +148 120 116 Untitled +148 120 116 Untitled +148 120 112 Untitled +148 120 112 Untitled +148 116 108 Untitled +148 116 108 Untitled +144 116 108 Untitled +144 116 104 Untitled +144 116 104 Untitled +144 116 100 Untitled +144 112 100 Untitled +144 112 96 Untitled +144 112 96 Untitled +144 112 96 Untitled +144 112 92 Untitled +144 112 92 Untitled +144 112 88 Untitled +140 108 88 Untitled +140 108 84 Untitled +140 108 84 Untitled +140 108 84 Untitled +140 108 80 Untitled +140 108 80 Untitled +140 104 76 Untitled +140 104 76 Untitled +140 104 72 Untitled +140 104 72 Untitled +140 104 72 Untitled +136 104 68 Untitled +136 100 68 Untitled +136 100 64 Untitled +136 100 64 Untitled +136 100 60 Untitled +136 100 60 Untitled +136 100 60 Untitled +136 96 56 Untitled +136 96 56 Untitled +136 96 52 Untitled +136 96 52 Untitled +132 96 48 Untitled +132 96 48 Untitled +132 96 48 Untitled +132 92 44 Untitled +132 92 44 Untitled +132 92 40 Untitled +132 92 40 Untitled +132 92 36 Untitled +132 92 36 Untitled +132 88 36 Untitled +132 88 32 Untitled +128 88 32 Untitled +128 88 28 Untitled +128 88 28 Untitled +128 88 24 Untitled +128 84 24 Untitled +128 84 24 Untitled +128 84 20 Untitled +128 84 20 Untitled +128 84 16 Untitled +128 84 16 Untitled +124 80 12 Untitled +124 80 12 Untitled +124 80 12 Untitled +124 84 16 Untitled +128 84 16 Untitled +128 88 20 Untitled +128 88 20 Untitled +128 92 24 Untitled +132 92 24 Untitled +132 92 28 Untitled +132 96 28 Untitled +136 96 32 Untitled +136 100 32 Untitled +136 100 32 Untitled +136 104 36 Untitled +140 104 36 Untitled +140 108 40 Untitled +140 108 40 Untitled +144 108 44 Untitled +144 112 44 Untitled +144 112 48 Untitled +144 116 48 Untitled +148 116 52 Untitled +148 120 52 Untitled +148 120 56 Untitled +152 120 56 Untitled +152 124 56 Untitled +152 124 60 Untitled +152 128 60 Untitled +156 128 64 Untitled +156 132 64 Untitled +156 132 68 Untitled +160 136 68 Untitled +160 136 72 Untitled +160 136 72 Untitled +160 140 76 Untitled +164 140 76 Untitled +164 144 76 Untitled +164 144 80 Untitled +164 148 80 Untitled +168 148 84 Untitled +168 148 84 Untitled +168 152 88 Untitled +172 152 88 Untitled +172 156 92 Untitled +172 156 92 Untitled +172 160 96 Untitled +176 160 96 Untitled +176 164 100 Untitled +176 164 100 Untitled +180 164 100 Untitled +180 168 104 Untitled +180 168 104 Untitled +180 172 108 Untitled +184 172 108 Untitled +184 176 112 Untitled +184 176 112 Untitled +188 176 116 Untitled +188 180 116 Untitled +188 180 120 Untitled +188 184 120 Untitled +192 184 120 Untitled +192 188 124 Untitled +192 188 124 Untitled +196 192 128 Untitled +196 192 128 Untitled +196 192 132 Untitled +196 196 132 Untitled +200 196 136 Untitled +200 200 136 Untitled +200 200 140 Untitled +200 204 140 Untitled +204 204 144 Untitled +204 204 144 Untitled +204 208 144 Untitled +208 208 148 Untitled +208 212 148 Untitled +208 212 152 Untitled +208 216 152 Untitled +212 216 156 Untitled +212 220 156 Untitled +212 220 160 Untitled +216 220 160 Untitled +216 224 164 Untitled +216 224 164 Untitled +216 228 164 Untitled +220 228 168 Untitled +220 232 168 Untitled +220 232 172 Untitled +224 232 172 Untitled +224 236 176 Untitled +224 236 176 Untitled +224 240 180 Untitled +228 240 180 Untitled +228 244 184 Untitled +228 244 184 Untitled +232 248 188 Untitled +232 248 188 Untitled +232 248 188 Untitled +232 248 188 Untitled +228 244 188 Untitled +228 244 188 Untitled +228 244 188 Untitled +224 244 188 Untitled +224 240 188 Untitled +224 240 188 Untitled +220 240 188 Untitled +220 236 188 Untitled +220 236 188 Untitled +216 236 188 Untitled +216 236 188 Untitled +216 232 188 Untitled +212 232 188 Untitled +212 232 184 Untitled +212 228 184 Untitled +208 228 184 Untitled +208 228 184 Untitled +208 228 184 Untitled +204 224 184 Untitled +204 224 184 Untitled +204 224 184 Untitled +204 220 184 Untitled +200 220 184 Untitled +200 220 184 Untitled +200 220 184 Untitled +196 216 184 Untitled +196 216 184 Untitled +196 216 184 Untitled +192 212 184 Untitled +192 212 184 Untitled +192 212 180 Untitled +188 212 180 Untitled +188 208 180 Untitled +188 208 180 Untitled +184 208 180 Untitled +184 204 180 Untitled +184 204 180 Untitled +180 204 180 Untitled +180 204 180 Untitled +180 200 180 Untitled +176 200 180 Untitled +176 200 180 Untitled +176 196 180 Untitled +172 196 180 Untitled +172 196 180 Untitled +172 196 180 Untitled +172 192 180 Untitled +168 192 176 Untitled +168 192 176 Untitled +168 188 176 Untitled +164 188 176 Untitled +164 188 176 Untitled +164 188 176 Untitled +160 184 176 Untitled +160 184 176 Untitled +160 184 176 Untitled +156 180 176 Untitled +156 180 176 Untitled diff --git a/chalk/data/palettes/Khaki.gpl b/chalk/data/palettes/Khaki.gpl new file mode 100644 index 00000000..88ea2238 --- /dev/null +++ b/chalk/data/palettes/Khaki.gpl @@ -0,0 +1,258 @@ +GIMP Palette +Name: Khaki +# +144 132 108 Untitled +144 132 112 Untitled +144 132 112 Untitled +144 132 116 Untitled +144 136 116 Untitled +144 136 120 Untitled +144 136 120 Untitled +144 140 120 Untitled +144 140 124 Untitled +144 140 124 Untitled +144 140 128 Untitled +144 144 128 Untitled +144 144 132 Untitled +144 144 132 Untitled +144 144 136 Untitled +144 148 136 Untitled +144 148 136 Untitled +144 148 140 Untitled +144 152 140 Untitled +144 152 144 Untitled +144 152 144 Untitled +144 152 148 Untitled +144 156 148 Untitled +144 156 152 Untitled +144 156 152 Untitled +144 160 152 Untitled +144 160 156 Untitled +144 160 156 Untitled +144 160 160 Untitled +144 164 160 Untitled +144 164 164 Untitled +144 164 164 Untitled +144 164 168 Untitled +144 168 168 Untitled +144 168 168 Untitled +144 168 172 Untitled +144 172 172 Untitled +144 172 176 Untitled +144 172 176 Untitled +144 172 180 Untitled +144 176 180 Untitled +144 176 184 Untitled +144 176 184 Untitled +144 180 184 Untitled +144 180 188 Untitled +144 180 188 Untitled +144 180 192 Untitled +144 184 192 Untitled +144 184 196 Untitled +144 184 196 Untitled +144 184 196 Untitled +148 188 192 Untitled +148 188 192 Untitled +152 188 192 Untitled +152 188 192 Untitled +152 188 188 Untitled +156 188 188 Untitled +156 188 188 Untitled +156 188 188 Untitled +160 188 184 Untitled +160 188 184 Untitled +160 188 184 Untitled +164 188 184 Untitled +164 188 180 Untitled +164 192 180 Untitled +168 192 180 Untitled +168 192 180 Untitled +168 192 180 Untitled +172 192 176 Untitled +172 192 176 Untitled +172 192 176 Untitled +176 192 176 Untitled +176 192 172 Untitled +176 192 172 Untitled +180 192 172 Untitled +180 192 172 Untitled +180 192 168 Untitled +184 192 168 Untitled +184 196 168 Untitled +184 196 168 Untitled +188 196 164 Untitled +188 196 164 Untitled +188 196 164 Untitled +192 196 164 Untitled +192 196 164 Untitled +192 196 160 Untitled +196 196 160 Untitled +196 196 160 Untitled +196 196 160 Untitled +200 196 156 Untitled +200 196 156 Untitled +200 200 156 Untitled +204 200 156 Untitled +204 200 152 Untitled +204 200 152 Untitled +208 200 152 Untitled +208 200 152 Untitled +208 200 148 Untitled +212 200 148 Untitled +212 200 148 Untitled +212 200 148 Untitled +216 200 148 Untitled +216 200 144 Untitled +216 200 144 Untitled +220 200 144 Untitled +220 204 144 Untitled +220 204 140 Untitled +224 204 140 Untitled +224 204 140 Untitled +224 204 140 Untitled +228 204 136 Untitled +228 204 136 Untitled +228 204 136 Untitled +232 204 136 Untitled +232 204 132 Untitled +232 204 132 Untitled +236 204 132 Untitled +236 204 132 Untitled +236 204 132 Untitled +232 200 128 Untitled +232 200 128 Untitled +232 200 128 Untitled +228 200 128 Untitled +228 196 128 Untitled +228 196 124 Untitled +224 196 124 Untitled +224 196 124 Untitled +224 196 124 Untitled +220 192 124 Untitled +220 192 124 Untitled +220 192 120 Untitled +216 192 120 Untitled +216 192 120 Untitled +216 188 120 Untitled +212 188 120 Untitled +212 188 120 Untitled +212 188 116 Untitled +208 188 116 Untitled +208 184 116 Untitled +208 184 116 Untitled +204 184 116 Untitled +204 184 116 Untitled +204 184 112 Untitled +204 180 112 Untitled +200 180 112 Untitled +200 180 112 Untitled +200 180 112 Untitled +196 180 108 Untitled +196 176 108 Untitled +196 176 108 Untitled +192 176 108 Untitled +192 176 108 Untitled +192 176 108 Untitled +188 172 104 Untitled +188 172 104 Untitled +188 172 104 Untitled +184 172 104 Untitled +184 172 104 Untitled +184 168 104 Untitled +180 168 100 Untitled +180 168 100 Untitled +180 168 100 Untitled +176 168 100 Untitled +176 164 100 Untitled +176 164 100 Untitled +176 164 96 Untitled +172 164 96 Untitled +172 164 96 Untitled +172 160 96 Untitled +168 160 96 Untitled +168 160 92 Untitled +168 160 92 Untitled +164 160 92 Untitled +164 156 92 Untitled +164 156 92 Untitled +160 156 92 Untitled +160 156 88 Untitled +160 156 88 Untitled +156 152 88 Untitled +156 152 88 Untitled +156 152 88 Untitled +152 152 88 Untitled +152 152 84 Untitled +152 148 84 Untitled +148 148 84 Untitled +148 148 84 Untitled +148 148 84 Untitled +148 148 84 Untitled +144 144 80 Untitled +144 144 80 Untitled +144 144 80 Untitled +140 144 80 Untitled +140 140 80 Untitled +140 140 76 Untitled +136 140 76 Untitled +136 140 76 Untitled +136 140 76 Untitled +132 136 76 Untitled +132 136 76 Untitled +132 136 72 Untitled +128 136 72 Untitled +128 136 72 Untitled +128 132 72 Untitled +124 132 72 Untitled +124 132 72 Untitled +124 132 68 Untitled +120 132 68 Untitled +120 128 68 Untitled +120 128 68 Untitled +116 128 68 Untitled +116 128 68 Untitled +116 128 64 Untitled +116 124 64 Untitled +112 124 64 Untitled +112 124 64 Untitled +112 124 64 Untitled +108 124 60 Untitled +108 120 60 Untitled +108 120 60 Untitled +104 120 60 Untitled +104 120 60 Untitled +104 120 60 Untitled +100 116 56 Untitled +100 116 56 Untitled +100 116 56 Untitled + 96 116 56 Untitled + 96 116 56 Untitled + 96 112 56 Untitled + 92 112 52 Untitled + 92 112 52 Untitled + 92 112 52 Untitled + 88 112 52 Untitled + 88 108 52 Untitled + 88 108 52 Untitled + 88 108 48 Untitled + 84 108 48 Untitled + 84 108 48 Untitled + 84 104 48 Untitled + 80 104 48 Untitled + 80 104 44 Untitled + 80 104 44 Untitled + 76 104 44 Untitled + 76 100 44 Untitled + 76 100 44 Untitled + 72 100 44 Untitled + 72 100 40 Untitled + 72 100 40 Untitled + 68 96 40 Untitled + 68 96 40 Untitled + 68 96 40 Untitled + 64 96 40 Untitled + 64 96 36 Untitled + 64 92 36 Untitled + 60 92 36 Untitled + 60 92 36 Untitled diff --git a/chalk/data/palettes/Lights.gpl b/chalk/data/palettes/Lights.gpl new file mode 100644 index 00000000..d2330496 --- /dev/null +++ b/chalk/data/palettes/Lights.gpl @@ -0,0 +1,28 @@ +GIMP Palette +Name: Lights +# +255 250 250 Snow +248 248 255 Ghost White +245 245 245 White Smoke +220 220 220 Gainsboro +255 250 240 Floral White +253 245 230 Old Lace +250 240 230 Linen +250 235 215 Antique White +255 239 213 Papaya Whip +255 235 205 Blanched Almond +255 228 196 Bisque +255 218 185 Peach Puff +255 222 173 Navajo White +255 228 181 Moccasin +255 248 220 Cornsilk +255 255 240 Ivory +255 250 205 Lemon Chiffon +255 245 238 Seashell +240 255 240 Honeydew +245 255 250 Mint Cream +240 255 255 Azure +240 248 255 Alice Blue +230 230 250 Lavender +255 228 225 Misty Rose +255 255 255 White diff --git a/chalk/data/palettes/Madeira.gpl b/chalk/data/palettes/Madeira.gpl new file mode 100644 index 00000000..fbf7c30a --- /dev/null +++ b/chalk/data/palettes/Madeira.gpl @@ -0,0 +1,372 @@ +GIMP Palette +Name: Madeira +# + 0 0 0 Black Black +243 232 209 Ecru Ecru +252 252 252 White White +249 247 219 101 Lemon - VY LT +249 245 182 102 Lemon - LT +247 230 127 103 Lemon - MED +255 222 68 104 Lemon - DK +255 212 37 105 Lemon - VY DK +255 196 16 106 Canary Yellow - BRIGHT +255 175 5 107 Topaz - MED +255 203 63 108 Topaz - LT +255 209 73 109 Topaz - VY LT +255 221 104 110 Topaz - ULT VY LT +255 232 135 111 Yellow - VY LT +255 217 126 112 Yellow - LT +255 188 35 113 Yellow - MED +245 136 52 114 Yellow - DK +245 115 0 201 Tangerine - LT +245 105 0 202 Tangerine +245 94 0 203 Tangerine - MED +245 84 0 204 Tangerine - DK +250 63 0 205 Tangerine - VY DK +245 5 5 206 Orange Red +244 42 42 207 Orange +206 0 21 208 Orange - DK +226 0 21 209 Orange - VY DK +212 0 21 210 Christmas Red - LT +191 0 21 211 Christmas Red - BRIGHT +207 0 40 212 Christmas Red - DK +236 17 67 213 Coral - DK +236 65 77 214 Coral - MED +245 102 73 301 Peach - MED +245 123 94 302 Peach - LT +245 112 105 303 Coral +245 177 177 304 Coral - LT +234 201 191 305 Coral - VY LT +244 211 191 306 Coral - ULT VY LT +236 118 73 307 Copper - ULT VY LT +236 108 63 308 Copper - VY LT +236 82 37 309 Copper - LT +215 108 73 310 Copper - MED LT +215 87 52 311 Copper - MED +173 34 21 312 Copper - MED DK +163 7 21 313 Copper - DK +121 7 21 314 Copper - VY DK +152 41 45 401 Terracotta +174 79 65 402 Terracotta - MED LT +216 131 117 403 Terracotta - LT +239 168 169 404 Salmon - LT +218 127 137 405 Salmon - MED +201 74 82 406 Salmon - DK +152 0 0 407 Salmon - VY DK +248 112 143 408 Rose +244 81 111 409 Rose - MED +213 52 64 410 Rose - DK +224 31 53 411 Pink - VY DK +224 42 74 412 Pink - DK +235 63 111 413 Pink - MED +235 105 137 414 Pink +250 209 202 501 Baby Pink - VY LT +253 200 205 502 Baby Pink - LT +253 190 205 503 Baby Pink - MED LT +255 123 165 504 Baby Pink - MED +236 112 154 505 Baby Pink - DK +215 70 112 506 Baby Pink - VY DK +184 0 60 507 Red +157 0 39 508 Red - MED DK +147 0 17 509 Red - DK +180 0 21 510 Christmas Red +159 0 31 511 Garnet +149 0 31 512 Garnet - MED +128 0 31 513 Garnet - DK + 96 0 31 514 Garnet - VY DK + 81 0 5 601 Plum - VY DK +116 20 49 602 Plum - DK +148 39 66 603 Plum - MED +168 59 91 604 Plum +205 107 137 605 Plum - LT +248 160 185 606 Plum - VY LT +253 186 200 607 Plum - ULT VY LT +250 213 216 608 Plum - PALE +220 95 115 609 Dusty Rose - DK +199 74 94 610 Dusty Rose - VY DK +221 64 94 611 Rose - MED DK +235 117 151 612 Rose - MED LT +236 149 182 613 Rose - LT +236 133 182 614 Rose - VY LT +215 76 132 701 Cerise - LT +215 7 111 702 Cerise +184 0 90 703 Cerise - DK +163 0 69 704 Cerise - VY DK +131 0 69 705 Mauve - VY DK +158 0 108 706 Mauve - DK +179 0 118 707 Mauve - MED DK +190 52 129 708 Mauve - MED +216 102 173 709 Mauve - LT +227 144 194 710 Mauve - VY LT +179 121 185 711 Violet - LT +127 37 132 712 Violet - MED +106 16 111 713 Violet - DK + 64 0 69 714 Violet - VY DK +201 165 203 801 Lavender - VY LT +175 123 177 802 Lavender - LT +159 107 177 803 Lavender - DK +117 54 146 804 Lavender - VY DK +105 0 73 805 Purple +112 83 87 806 Antique Violet - DK +175 143 155 807 Antique Violet - LT +220 182 184 808 Antique Mauve - LT +186 115 126 809 Antique Mauve - MED +123 42 52 810 Antique Mauve - DK +123 5 21 811 Shell Pink - MED DK +195 86 95 812 Shell Pink - MED +227 117 127 813 Shell Pink +247 207 206 814 Shell Pink - LT +175 178 211 901 Blue Violet - VY LT +112 115 169 902 Blue Violet - LT + 58 42 106 903 Blue Violet - MED + 0 21 95 904 Cornflower Blue - VY DK + 52 73 137 905 Cornflower Blue - DK + 79 100 143 906 Cornflower Blue - MED +121 142 174 907 Cornflower Blue - LT +165 196 195 908 Blue - ULT VY LT +144 165 195 909 Delft + 86 128 164 910 Delft - MED +23 96 158 911 Delft - DK + 0 53 110 912 Royal Blue - MED + 0 32 100 913 Royal Blue - DK + 21 32 89 914 Royal Blue - VY DK +187 210 215 1001 Antique Blue - VY LT +152 181 195 1002 Antique Blue - LT + 89 127 158 1003 Antique Blue + 58 106 140 1004 Antique Blue - MED + 16 74 109 1005 Antique Blue - DK + 5 43 88 1006 Antique Blue - VY DK + 0 28 73 1007 Blue - MED DK + 0 7 42 1008 Blue - DK + 0 0 31 1009 Blue - VY DK + 0 81 132 1010 Blue - VY DK + 0 81 122 1011 Blue - DK + 23 107 143 1012 Blue - MED +107 149 174 1013 Blue +163 191 195 1014 Blue - LT +173 201 203 1101 Blue - VY LT + 0 84 215 1102 Electric Blue - DK + 0 147 215 1103 Electric Blue - MED +189 228 233 1104 Wedgewood - ULT VY LT +107 169 188 1105 Wedgewood - LT + 75 137 156 1106 Wedgewood - MED + 44 106 146 1107 Wedgewood - DK + 23 117 135 1108 Misty Blue - DK + 52 138 146 1109 Misty Blue - MED + 63 149 156 1110 Misty Blue - MED LT +105 149 156 1111 Misty Blue - LT +129 205 186 1112 Turquoise - VY LT + 97 194 175 1113 Turquoise - LT + 7 163 144 1114 Turquoise - MED DK + 97 194 165 1201 Turquoise - MED + 5 142 96 1202 Turquoise - DK + 0 131 91 1203 Turquoise - VY DK + 0 73 65 1204 Turquoise - ULT VY DK + 0 84 60 1205 Blue Green + 21 108 52 1206 Jade - DK + 94 159 117 1207 Jade - MED +189 233 212 1208 Jade - LT +178 202 156 1209 Yellow Green - ULT VY LT +189 233 201 1210 Leaf Green - VY LT +152 207 165 1211 Leaf Green - LT + 95 157 107 1212 Leaf Green - MED + 47 133 81 1213 Leaf Green - DK + 31 112 60 1214 Leaf Green - VY DK + 0 123 60 1301 Emerald Green + 0 112 60 1302 Emerald Green - DK + 0 102 48 1303 Christmas Green - DK + 0 102 40 1304 Christmas Green - BRIGHT + 0 105 0 1305 Christmas Green - MED + 66 158 54 1306 Chartreuse +118 200 96 1307 Chartreuse - LT +165 184 67 1308 Yellow Green +226 236 219 1309 Pistachio Green - VY LT +115 142 109 1310 Pistachio Green - LT + 84 110 77 1311 Pistachio Green - MED + 52 89 51 1312 Pistachio Green - DK + 31 68 14 1313 Pistachio Green - VY DK + 0 28 24 1314 Pistachio Green - ULT VY DK +147 175 115 1401 Green - VY LT +100 136 54 1402 Green - LT + 58 105 17 1403 Green + 0 80 31 1404 Hunter Green - VY DK + 0 69 31 1405 Hunter Green - DK + 47 94 23 1406 Hunter Green - MED + 68 105 23 1407 Hunter Green + 89 105 23 1408 Hunter Green - LT +178 185 107 1409 Forest Green - VY LT +150 168 0 1410 Forest Green - LT +114 146 0 1411 Forest Green - MED +100 147 0 1412 Forest Green - DK + 68 126 21 1413 Forest Green - VY DK +193 178 91 1414 Avocado Green - PALE +185 195 103 1501 Avocado Green - VY LT +133 153 50 1502 Avocado Green - LT +123 143 50 1503 Avocado Green - MED LT + 91 111 19 1504 Avocado Green - MED + 49 38 0 1505 Fern Green - ULT VY DK + 60 48 42 1506 Fern Green - VY DK + 63 63 0 1507 Fern Green - DK + 68 68 5 1508 Fern Green - MED +130 128 91 1509 Fern Green - LT +140 138 96 1510 Fern Green - VY LT +180 176 157 1511 Gray Green - VY LT +149 160 136 1512 Gray Green - LT +123 134 100 1513 Gray Green - MED + 60 82 47 1514 Gray Green - DK + 60 92 47 1601 Laurel Green - DK + 81 103 47 1602 Laurel Green - MED +144 166 89 1603 Laurel Green - LT +175 187 131 1604 Laurel Green - VY LT +165 155 89 1605 Khaki Green - LT +129 119 53 1606 Khaki Green - MED +108 93 43 1607 Khaki Green - DK + 97 101 0 1608 Green - DK +147 147 0 1609 Green - MED +200 170 68 1610 Sage Green - VY LT +161 147 0 1611 Sage Green - LT +115 98 0 1612 Sage Green +126 109 0 1613 Sage Green - MED + 94 77 0 1614 Sage Green - DK +169 180 165 1701 Sea Foam Green - LT +137 159 144 1702 Sea Foam Green + 95 117 102 1703 Sea Foam Green - MED + 74 96 81 1704 Sea Foam Green - DK + 21 63 42 1705 Sea Foam Green - ULT DK + 0 63 73 1706 Blue Gray - DK + 73 105 115 1707 Blue Gray - MED +175 185 193 1708 Blue Gray - LT +175 170 159 1709 Blue Gray - VY LT +146 164 179 1710 Dusty Blue - LT + 72 111 127 1711 Dusty Blue - MED + 51 90 116 1712 Dusty Blue - DK + 21 0 42 1713 Blue - BLACK + 97 88 105 1714 Steel Gray - DK +108 98 108 1801 Steel Gray - MED +134 130 139 1802 Steel Gray - LT +153 140 150 1803 Steel Gray - VY LT +213 208 212 1804 Pearl Gray - VY LT +213 217 212 1805 Gray Green - ULT VY LT +166 143 151 1806 Shell Gray - LT +157 143 151 1807 Shell Gray - MED +132 111 119 1808 Shell Gray - DK + 79 69 67 1809 Shell Gray - VY DK + 58 38 46 1810 Shell Gray - ULT VY DK + 91 82 67 1811 Beaver Gray - DK +123 115 98 1812 Beaver Gray - MED +138 137 119 1813 Beaver Gray - LT +178 172 156 1814 Beaver Gray - VY LT +205 203 195 1901 Beige Gray - LT +179 169 153 1902 Beige Gray - MED +148 127 111 1903 Beige Gray - DK + 64 43 27 1904 Beige Gray - ULT VY DK +106 85 59 1905 Beige Gray - VY DK +153 127 101 1906 Beige Gray +216 190 174 1907 Beige Gray - MED LT +237 221 206 1908 Beige Brown - ULT VY LT +216 191 176 1909 Beige Brown - VY LT +213 179 164 1910 Beige Brown - LT +171 137 122 1911 Beige Brown - MED +150 112 96 1912 Beige Brown - DK +118 81 65 1913 Beige Brown - VY DK + 87 49 17 1914 Beige Brown - ULT VY DK +216 200 185 2001 Mocha Brown - LT +150 127 90 2002 Mocha Brown - MED + 54 23 0 2003 Brown - DK + 42 21 0 2004 Black Brown + 73 26 0 2005 Chocolate + 63 26 0 2006 Tan - ULT VY DK + 84 37 31 2007 Tan - VY DK +110 52 31 2008 Tan - DK +131 63 21 2009 Tan - MED DK +173 94 52 2010 Tan - MED +199 126 73 2011 Tan +231 168 94 2012 Tan - LT +241 188 126 2013 Tan - VY LT +248 219 178 2014 Tan - ULT VY LT +255 247 231 2101 Cream +220 166 105 2102 Hazelnut Brown - LT +178 124 63 2103 Hazelnut Brown - LT +157 102 42 2104 Hazelnut Brown - MED +110 64 5 2105 Hazelnut Brown - DK + 79 43 5 2106 Drab Brown - VY DK + 90 63 5 2107 Drab Brown - DK +159 124 84 2108 Drab Brown - MED +212 181 147 2109 Drab Brown - LT +170 160 105 2110 Avocado - LT +160 129 63 2111 Avocado - MED +118 97 31 2112 Avocado - DK +103 55 0 2113 Hazelnut Brown - VY DK +103 66 0 2114 Avocado - VY DK +145 97 0 2201 Old Gold - DK +155 118 0 2202 Old Gold - MED +197 139 42 2203 Old Gold +208 150 52 2204 Old Gold - LT +246 229 168 2205 Old Gold - VY LT +213 186 110 2206 Avocado - VY LT +249 228 163 2207 Gold - VY LT +229 181 105 2208 Gold - LT +197 139 52 2209 Gold - MED +187 118 21 2210 Gold - DK +197 97 0 2211 Topaz - MED DK +197 113 21 2212 Topaz - DK +155 82 0 2213 Topaz - VY DK +134 71 0 2214 Topaz - ULT VY DK +229 132 68 2301 Golden Brown - VY LT +218 101 42 2302 Golden Brown - LT +155 50 0 2303 Golden Brown - MED +145 50 42 2304 Mahogany - DK +171 29 0 2305 Mahogany - MED +181 61 31 2306 Mahogany - LT +236 145 65 2307 Mahogany - VY LT +255 220 199 2308 Flesh - LT +245 189 168 2309 Flesh - MED +217 116 119 2310 Flesh - DK +127 55 63 2311 Peach Flesh - VY DK +193 107 93 2312 Peach Flesh - MED +241 169 148 2313 Peach Flesh +255 236 215 2314 Golden Brown - VY LT +248 248 248 2402 Off White +253 253 248 2403 Winter White +100 0 31 2501 Bright Terracotta - DK +148 0 42 2502 Bright Terracotta - MED +255 175 146 2503 Bright Terracotta - LT +224 236 226 2504 Wedgewood - VY LT + 0 89 112 2505 Wedgewood - VY DK + 0 131 136 2506 Misty Green - BRIGHT + 0 105 95 2507 Misty Green - DK + 90 142 144 2508 Misty Green - MED +234 171 73 2509 Golden Yellow - BRIGHT +196 157 76 2510 Golden Yellow - DK +238 229 193 2511 Golden Yellow - LT +238 223 182 2512 Golden Brown - LT +244 166 93 2513 Golden Brown - BRIGHT +213 134 72 2514 Golden Brown - MED +153 110 100 2601 Coffee Brown - VY LT +110 42 21 2602 Coffee Brown - LT + 63 89 52 2603 Nile Green - LT +136 178 136 2604 Nile Green - DK +245 175 156 2605 Peach - VY LT + 89 0 31 2606 Peach - ULT VY DK + 58 0 31 2607 Antique Plum - VY DK + 79 0 42 2608 Antique Plum - DK +121 31 84 2609 Antique Plum - MED +215 163 175 2610 Antique Plum - LT +179 169 169 2611 Dusty Violet - LT +164 149 164 2612 Dusty Violet - MED +136 110 136 2613 Dusty Violet - DK + 94 68 94 2614 Dusty Violet - VY DK + 0 0 52 2701 Blue Violet - DK + 77 96 147 2702 Blue Violet - VY DK +199 189 42 2703 Yellow Green - LT + 0 69 35 2704 Christmas Green - DK + 0 91 87 2705 Misty Turquoise - MED + 0 133 118 2706 Misty Turquoise - DK +243 117 154 2707 Bright Pink - LT +216 0 56 2708 Bright Pink - MED + 47 0 84 2709 Antique Lavender - LT + 79 31 115 2710 Antique Lavender - MED +152 136 178 2711 Antique Lavender - DK +227 185 195 2712 Pink Purple - LT +190 131 157 2713 Pink Purple - MED +115 31 98 2714 Pink Purple - DK diff --git a/chalk/data/palettes/Makefile.am b/chalk/data/palettes/Makefile.am new file mode 100644 index 00000000..c454af14 --- /dev/null +++ b/chalk/data/palettes/Makefile.am @@ -0,0 +1,50 @@ +chalkpalettesdir = $(prefix)/share/apps/chalk/palettes + +chalkpalettes_DATA = \ + 40_Colors.gpl \ + Anchor.gpl \ + Bears.gpl \ + Bgold.gpl \ + Blues.gpl \ + Borders.gpl \ + Browns_And_Yellows.gpl \ + Caramel.gpl \ + Cascade.gpl \ + China.gpl \ + Coldfire.gpl \ + Cool_Colors.gpl \ + Cranes.gpl \ + Dark_pastels.gpl \ + Default.gpl \ + DMC.gpl \ + Ega.gpl \ + Firecode.gpl \ + Gold.gpl \ + Grayblue.gpl \ + Grays.gpl \ + GrayViolet.gpl \ + Greens.gpl \ + Hilite.gpl \ + Khaki.gpl \ + Lights.gpl \ + Madeira.gpl \ + Makefile.am \ + Makefile.in \ + Muted.gpl \ + Named_Colors.gpl \ + new_kde.gpl \ + News3.gpl \ + Op2.gpl \ + Paintjet.gpl \ + Pantone_Coated_Approx.gpl \ + Pastels.gpl \ + Plasma.gpl \ + Reds_And_Purples.gpl \ + Reds.gpl \ + Royal.gpl \ + Topographic.gpl \ + Visibone_2.gpl \ + Visibone.gpl \ + Volcano.gpl \ + Warm_Colors.gpl \ + Web.gpl diff --git a/chalk/data/palettes/Muted.gpl b/chalk/data/palettes/Muted.gpl new file mode 100644 index 00000000..9d32a02d --- /dev/null +++ b/chalk/data/palettes/Muted.gpl @@ -0,0 +1,81 @@ +GIMP Palette +Name: Muted +# +139 137 137 Snow +139 134 130 Seashell +139 131 120 Antique White +139 125 107 Bisque +139 119 101 Peach Puff +139 121 94 Navajo White +139 137 112 Lemon Chiffon +139 136 120 Cornsilk +139 139 131 Ivory +131 139 131 Honeydew +139 131 134 Lavender Blush +139 125 123 Misty Rose +131 139 139 Azure + 71 60 139 Slate Blue + 39 64 139 Royal Blue + 0 0 139 Blue + 16 78 139 Dodger Blue + 54 100 139 Steel Blue + 0 104 139 Deep Sky Blue + 74 112 139 Sky Blue + 96 123 139 Light Sky Blue +108 123 139 Slate Gray +110 123 139 Light Steel Blue +104 131 139 Light Blue +122 139 139 Light Cyan +102 139 139 Pale Turquoise + 83 134 139 Cadet Blue + 0 134 139 Turquoise + 0 139 139 Cyan + 82 139 139 Dark Slate Gray + 69 139 116 Aquamarine +105 139 105 Dark Sea Green + 46 139 87 Sea Green + 84 139 84 Pale Green + 0 139 69 Spring Green + 0 139 0 Green + 69 139 0 Chartreuse +105 139 34 Olive Drab +110 139 61 Dark Olive Green +139 134 78 Khaki +139 129 76 Light Goldenrod +139 139 122 Light Yellow +139 139 0 Yellow +139 117 0 Gold +139 105 20 Goldenrod +139 101 8 Dark Goldenrod +139 105 105 Rosy Brown +139 58 58 Indian Red +139 71 38 Sienna +139 115 85 Burlywood +139 126 102 Wheat +139 90 43 Tan +139 69 19 Chocolate +139 26 26 Firebrick +139 35 35 Brown +139 76 57 Salmon +139 87 66 Light Salmon +139 90 0 Orange +139 69 0 Dark Orange +139 62 47 Coral +139 54 38 Tomato +139 37 0 Orange Red +139 0 0 Red +139 10 80 Deep Pink +139 58 98 Hot Pink +139 99 108 Pink +139 95 101 Light Pink +139 71 93 Pale Violet Red +139 28 98 Maroon +139 34 82 Violet Red +139 0 139 Magenta +139 71 137 Orchid +139 102 139 Plum +122 55 139 Medium Orchid +104 34 139 Dark Orchid + 85 26 139 Purple + 93 71 139 Medium Purple +139 123 139 Thistle diff --git a/chalk/data/palettes/Named_Colors.gpl b/chalk/data/palettes/Named_Colors.gpl new file mode 100644 index 00000000..ce7af023 --- /dev/null +++ b/chalk/data/palettes/Named_Colors.gpl @@ -0,0 +1,452 @@ +GIMP Palette +Name: Named Colors +Columns: 16 +# +255 250 250 snow (255 250 250) +248 248 255 ghost white (248 248 255) +245 245 245 white smoke (245 245 245) +220 220 220 gainsboro (220 220 220) +255 250 240 floral white (255 250 240) +253 245 230 old lace (253 245 230) +250 240 230 linen (250 240 230) +250 235 215 antique white (250 235 215) +255 239 213 papaya whip (255 239 213) +255 235 205 blanched almond (255 235 205) +255 228 196 bisque (255 228 196) +255 218 185 peach puff (255 218 185) +255 222 173 navajo white (255 222 173) +255 228 181 tqmoccasin (255 228 181) +255 248 220 cornsilk (255 248 220) +255 255 240 ivory (255 255 240) +255 250 205 lemon chiffon (255 250 205) +255 245 238 seashell (255 245 238) +240 255 240 honeydew (240 255 240) +245 255 250 mint cream (245 255 250) +240 255 255 azure (240 255 255) +240 248 255 alice blue (240 248 255) +230 230 250 lavender (230 230 250) +255 240 245 lavender blush (255 240 245) +255 228 225 misty rose (255 228 225) +255 255 255 white (255 255 255) + 0 0 0 black ( 0 0 0) + 47 79 79 dark slate gray ( 47 79 79) +105 105 105 dim gray (105 105 105) +112 128 144 slate gray (112 128 144) +119 136 153 light slate gray (119 136 153) +190 190 190 gray (190 190 190) +211 211 211 light gray (211 211 211) + 25 25 112 midnight blue ( 25 25 112) + 0 0 128 navy blue ( 0 0 128) +100 149 237 cornflower blue (100 149 237) + 72 61 139 dark slate blue ( 72 61 139) +106 90 205 slate blue (106 90 205) +123 104 238 medium slate blue (123 104 238) +132 112 255 light slate blue (132 112 255) + 0 0 205 medium blue ( 0 0 205) + 65 105 225 royal blue ( 65 105 225) + 0 0 255 blue ( 0 0 255) + 30 144 255 dodger blue ( 30 144 255) + 0 191 255 deep sky blue ( 0 191 255) +135 206 235 sky blue (135 206 235) +135 206 250 light sky blue (135 206 250) + 70 130 180 steel blue ( 70 130 180) +176 196 222 light steel blue (176 196 222) +173 216 230 light blue (173 216 230) +176 224 230 powder blue (176 224 230) +175 238 238 pale turquoise (175 238 238) + 0 206 209 dark turquoise ( 0 206 209) + 72 209 204 medium turquoise ( 72 209 204) + 64 224 208 turquoise ( 64 224 208) + 0 255 255 cyan ( 0 255 255) +224 255 255 light cyan (224 255 255) + 95 158 160 cadet blue ( 95 158 160) +102 205 170 medium aquamarine (102 205 170) +127 255 212 aquamarine (127 255 212) + 0 100 0 dark green ( 0 100 0) + 85 107 47 dark olive green ( 85 107 47) +143 188 143 dark sea green (143 188 143) + 46 139 87 sea green ( 46 139 87) + 60 179 113 medium sea green ( 60 179 113) + 32 178 170 light sea green ( 32 178 170) +152 251 152 pale green (152 251 152) + 0 255 127 spring green ( 0 255 127) +124 252 0 lawn green (124 252 0) + 0 255 0 green ( 0 255 0) +127 255 0 chartreuse (127 255 0) + 0 250 154 medium spring green ( 0 250 154) +173 255 47 green yellow (173 255 47) + 50 205 50 lime green ( 50 205 50) +154 205 50 yellow green (154 205 50) + 34 139 34 forest green ( 34 139 34) +107 142 35 olive drab (107 142 35) +189 183 107 dark khaki (189 183 107) +240 230 140 khaki (240 230 140) +238 232 170 pale goldenrod (238 232 170) +250 250 210 light goldenrod yellow (250 250 210) +255 255 224 light yellow (255 255 224) +255 255 0 yellow (255 255 0) +255 215 0 gold (255 215 0 ) +238 221 130 light goldenrod (238 221 130) +218 165 32 goldenrod (218 165 32) +184 134 11 dark goldenrod (184 134 11) +188 143 143 rosy brown (188 143 143) +205 92 92 indian red (205 92 92) +139 69 19 saddle brown (139 69 19) +160 82 45 sienna (160 82 45) +205 133 63 peru (205 133 63) +222 184 135 burlywood (222 184 135) +245 245 220 beige (245 245 220) +245 222 179 wheat (245 222 179) +244 164 96 sandy brown (244 164 96) +210 180 140 tan (210 180 140) +210 105 30 chocolate (210 105 30) +178 34 34 firebrick (178 34 34) +165 42 42 brown (165 42 42) +233 150 122 dark salmon (233 150 122) +250 128 114 salmon (250 128 114) +255 160 122 light salmon (255 160 122) +255 165 0 orange (255 165 0) +255 140 0 dark orange (255 140 0) +255 127 80 coral (255 127 80) +240 128 128 light coral (240 128 128) +255 99 71 tomato (255 99 71) +255 69 0 orange red (255 69 0) +255 0 0 red (255 0 0) +255 105 180 hot pink (255 105 180) +255 20 147 deep pink (255 20 147) +255 192 203 pink (255 192 203) +255 182 193 light pink (255 182 193) +219 112 147 pale violet red (219 112 147) +176 48 96 maroon (176 48 96) +199 21 133 medium violet red (199 21 133) +208 32 144 violet red (208 32 144) +255 0 255 magenta (255 0 255) +238 130 238 violet (238 130 238) +221 160 221 plum (221 160 221) +218 112 214 orchid (218 112 214) +186 85 211 medium orchid (186 85 211) +153 50 204 dark orchid (153 50 204) +148 0 211 dark violet (148 0 211) +138 43 226 blue violet (138 43 226) +160 32 240 purple (160 32 240) +147 112 219 medium purple (147 112 219) +216 191 216 thistle (216 191 216) +255 250 250 snow 1 (255 250 250) +238 233 233 snow 2 (238 233 233) +205 201 201 snow 3 (205 201 201) +139 137 137 snow 4 (139 137 137) +255 245 238 seashell 1 (255 245 238) +238 229 222 seashell 2 (238 229 222) +205 197 191 seashell 3 (205 197 191) +139 134 130 seashell 4 (139 134 130) +255 239 219 antique white 1 (255 239 219) +238 223 204 antique white 2 (238 223 204) +205 192 176 antique white 3 (205 192 176) +139 131 120 antique white 4 (139 131 120) +255 228 196 bisque 1 (255 228 196) +238 213 183 bisque 2 (238 213 183) +205 183 158 bisque 3 (205 183 158) +139 125 107 bisque 4 (139 125 107) +255 218 185 peach puff 1 (255 218 185) +238 203 173 peach puff 2 (238 203 173) +205 175 149 peach puff 3 (205 175 149) +139 119 101 peach puff 4 (139 119 101) +255 222 173 navajo white 1 (255 222 173) +238 207 161 navajo white 2 (238 207 161) +205 179 139 navajo white 3 (205 179 139) +139 121 94 navajo white 4 (139 121 94) +255 250 205 lemon chiffon 1 (255 250 205) +238 233 191 lemon chiffon 2 (238 233 191) +205 201 165 lemon chiffon 3 (205 201 165) +139 137 112 lemon chiffon 4 (139 137 112) +255 248 220 cornsilk 1 (255 248 220) +238 232 205 cornsilk 2 (238 232 205) +205 200 177 cornsilk 3 (205 200 177) +139 136 120 cornsilk 4 (139 136 120) +255 255 240 ivory 1 (255 255 240) +238 238 224 ivory 2 (238 238 224) +205 205 193 ivory 3 (205 205 193) +139 139 131 ivory 4 (139 139 131) +240 255 240 honeydew 1 (240 255 240) +224 238 224 honeydew 2 (224 238 224) +193 205 193 honeydew 3 (193 205 193) +131 139 131 honeydew 4 (131 139 131) +255 240 245 lavender blush 1 (255 240 245) +238 224 229 lavender blush 2 (238 224 229) +205 193 197 lavender blush 3 (205 193 197) +139 131 134 lavender blush 4 (139 131 134) +255 228 225 misty rose 1 (255 228 225) +238 213 210 misty rose 2 (238 213 210) +205 183 181 misty rose 3 (205 183 181) +139 125 123 misty rose 4 (139 125 123) +240 255 255 azure 1 (240 255 255) +224 238 238 azure 2 (224 238 238) +193 205 205 azure 3 (193 205 205) +131 139 139 azure 4 (131 139 139) +131 111 255 slate blue 1 (131 111 255) +122 103 238 slate blue 2 (122 103 238) +105 89 205 slate blue 3 (105 89 205) + 71 60 139 slate blue 4 ( 71 60 139) + 72 118 255 royal blue 1 ( 72 118 255) + 67 110 238 royal blue 2 ( 67 110 238) + 58 95 205 royal blue 3 ( 58 95 205) + 39 64 139 royal blue 4 ( 39 64 139) + 0 0 255 blue 1 ( 0 0 255) + 0 0 238 blue 2 ( 0 0 238) + 0 0 205 blue 3 ( 0 0 205) + 0 0 139 blue 4 ( 0 0 139) + 30 144 255 dodger blue 1 ( 30 144 255) + 28 134 238 dodger blue 2 ( 28 134 238) + 24 116 205 dodger blue 3 ( 24 116 205) + 16 78 139 dodger blue 4 ( 16 78 139) + 99 184 255 steel blue 1 ( 99 184 255) + 92 172 238 steel blue 2 ( 92 172 238) + 79 148 205 steel blue 3 ( 79 148 205) + 54 100 139 steel blue 4 ( 54 100 139) + 0 191 255 deep sky blue 1 ( 0 191 255) + 0 178 238 deep sky blue 2 ( 0 178 238) + 0 154 205 deep sky blue 3 ( 0 154 205) + 0 104 139 deep sky blue 4 ( 0 104 139) +135 206 255 sky blue 1 (135 206 255) +126 192 238 sky blue 2 (126 192 238) +108 166 205 sky blue 3 (108 166 205) + 74 112 139 sky blue 4 ( 74 112 139) +176 226 255 light sky blue 1 (176 226 255) +164 211 238 light sky blue 2 (164 211 238) +141 182 205 light sky blue 3 (141 182 205) + 96 123 139 light sky blue 4 ( 96 123 139) +198 226 255 slate gray 1 (198 226 255) +185 211 238 slate gray 2 (185 211 238) +159 182 205 slate gray 3 (159 182 205) +108 123 139 slate gray 4 (108 123 139) +202 225 255 light steel blue 1 (202 225 255) +188 210 238 light steel blue 2 (188 210 238) +162 181 205 light steel blue 3 (162 181 205) +110 123 139 light steel blue 4 (110 123 139) +191 239 255 light blue 1 (191 239 255) +178 223 238 light blue 2 (178 223 238) +154 192 205 light blue 3 (154 192 205) +104 131 139 light blue 4 (104 131 139) +224 255 255 light cyan 1 (224 255 255) +209 238 238 light cyan 2 (209 238 238) +180 205 205 light cyan 3 (180 205 205) +122 139 139 light cyan 4 (122 139 139) +187 255 255 pale turquoise 1 (187 255 255) +174 238 238 pale turquoise 2 (174 238 238) +150 205 205 pale turquoise 3 (150 205 205) +102 139 139 pale turquoise 4 (102 139 139) +152 245 255 cadet blue 1 (152 245 255) +142 229 238 cadet blue 2 (142 229 238) +122 197 205 cadet blue 3 (122 197 205) + 83 134 139 cadet blue 4 ( 83 134 139) + 0 245 255 turquoise 1 ( 0 245 255) + 0 229 238 turquoise 2 ( 0 229 238) + 0 197 205 turquoise 3 ( 0 197 205) + 0 134 139 turquoise 4 ( 0 134 139) + 0 255 255 cyan 1 ( 0 255 255) + 0 238 238 cyan 2 ( 0 238 238) + 0 205 205 cyan 3 ( 0 205 205) + 0 139 139 cyan 4 ( 0 139 139) +151 255 255 dark slate gray 1 (151 255 255) +141 238 238 dark slate gray 2 (141 238 238) +121 205 205 dark slate gray 3 (121 205 205) + 82 139 139 dark slate gray 4 ( 82 139 139) +127 255 212 aquamarine 1 (127 255 212) +118 238 198 aquamarine 2 (118 238 198) +102 205 170 aquamarine 3 (102 205 170) + 69 139 116 aquamarine 4 ( 69 139 116) +193 255 193 dark sea green 1 (193 255 193) +180 238 180 dark sea green 2 (180 238 180) +155 205 155 dark sea green 3 (155 205 155) +105 139 105 dark sea green 4 (105 139 105) + 84 255 159 sea green 1 ( 84 255 159) + 78 238 148 sea green 2 ( 78 238 148) + 67 205 128 sea green 3 ( 67 205 128) + 46 139 87 sea green 4 ( 46 139) +154 255 154 pale green 1 (154 255 154) +144 238 144 pale green 2 (144 238 144) +124 205 124 pale green 3 (124 205 124) + 84 139 84 pale green 4 ( 84 139) + 0 255 127 spring green 1 ( 0 255 127) + 0 238 118 spring green 2 ( 0 238 118) + 0 205 102 spring green 3 ( 0 205 102) + 0 139 69 spring green 4 ( 0 139 69) + 0 255 0 green 1 ( 0 255 0) + 0 238 0 green 2 ( 0 238 0) + 0 205 0 green 3 ( 0 205 0) + 0 139 0 green 4 ( 0 139 0) +127 255 0 chartreuse 1 (127 255 0) +118 238 0 chartreuse 2 (118 238 0) +102 205 0 chartreuse 3 (102 205 0) + 69 139 0 chartreuse 4 ( 69 139 0) +192 255 62 olive drab 1 (192 255 62) +179 238 58 olive drab 2 (179 238 58) +154 205 50 olive drab 3 (154 205 50) +105 139 34 olive drab 4 (105 139 34) +202 255 112 dark olive green 1 (202 255 112) +188 238 104 dark olive green 2 (188 238 104) +162 205 90 dark olive green 3 (162 205) +110 139 61 dark olive green 4 (110 139) +255 246 143 khaki 1 (255 246 143) +238 230 133 khaki 2 (238 230 133) +205 198 115 khaki 3 (205 198 115) +139 134 78 khaki 4 (139 134 78) +255 236 139 light goldenrod 1 (255 236 139) +238 220 130 light goldenrod 2 (238 220 130) +205 190 112 light goldenrod 3 (205 190 112) +139 129 76 light goldenrod 4 (139 129 76) +255 255 224 light yellow 1 (255 255 224) +238 238 209 light yellow 2 (238 238 209) +205 205 180 light yellow 3 (205 205 180) +139 139 122 light yellow 4 (139 139 122) +255 255 0 yellow 1 (255 255 0) +238 238 0 yellow 2 (238 238 0) +205 205 0 yellow 3 (205 205 0) +139 139 0 yellow 4 (139 139 0) +255 215 0 gold 1 (255 215 0) +238 201 0 gold 2 (238 201 0) +205 173 0 gold 3 (205 173 0) +139 117 0 gold 4 (139 117 0) +255 193 37 goldenrod 1 (255 193 37) +238 180 34 goldenrod 2 (238 180 34) +205 155 29 goldenrod 3 (205 155 29) +139 105 20 goldenrod 4 (139 105 20) +255 185 15 dark goldenrod 1 (255 185 15) +238 173 14 dark goldenrod 2 (238 173 14) +205 149 12 dark goldenrod 3 (205 149 12) +139 101 8 dark goldenrod 4 (139 101 8) +255 193 193 rosy brown 1 (255 193 193) +238 180 180 rosy brown 2 (238 180 180) +205 155 155 rosy brown 3 (205 155 155) +139 105 105 rosy brown 4 (139 105 105) +255 106 106 indian red 1 (255 106 106) +238 99 99 indian red 2 (238 99 99) +205 85 85 indian red 3 (205 85 85) +139 58 58 indian red 4 (139 58 58) +255 130 71 sienna 1 (255 130 71) +238 121 66 sienna 2 (238 121 66) +205 104 57 sienna 3 (205 104 57) +139 71 38 sienna 4 (139 71 38) +255 211 155 burlywood 1 (255 211 155) +238 197 145 burlywood 2 (238 197 145) +205 170 125 burlywood 3 (205 170 125) +139 115 85 burlywood 4 (139 115) +255 231 186 wheat 1 (255 231 186) +238 216 174 wheat 2 (238 216 174) +205 186 150 wheat 3 (205 186 150) +139 126 102 wheat 4 (139 126 102) +255 165 79 tan 1 (255 165 79) +238 154 73 tan 2 (238 154 73) +205 133 63 tan 3 (205 133 63) +139 90 43 tan 4 (139 90 43) +255 127 36 chocolate 1 (255 127 36) +238 118 33 chocolate 2 (238 118 33) +205 102 29 chocolate 3 (205 102 29) +139 69 19 chocolate 4 (139 69 19) +255 48 48 firebrick 1 (255 48 48) +238 44 44 firebrick 2 (238 44 44) +205 38 38 firebrick 3 (205 38 38) +139 26 26 firebrick 4 (139 26 26) +255 64 64 brown 1 (255 64 64) +238 59 59 brown 2 (238 59 59) +205 51 51 brown 3 (205 51 51) +139 35 35 brown 4 (139 35 35) +255 140 105 salmon 1 (255 140 105) +238 130 98 salmon 2 (238 130 98) +205 112 84 salmon 3 (205 112 84) +139 76 57 salmon 4 (139 76 57) +255 160 122 light salmon 1 (255 160 122) +238 149 114 light salmon 2 (238 149 114) +205 129 98 light salmon 3 (205 129 98) +139 87 66 light salmon 4 (139 87 66) +255 165 0 orange 1 (255 165 0) +238 154 0 orange 2 (238 154 0) +205 133 0 orange 3 (205 133 0) +139 90 0 orange 4 (139 90 0) +255 127 0 dark orange 1 (255 127 0) +238 118 0 dark orange 2 (238 118 0) +205 102 0 dark orange 3 (205 102 0) +139 69 0 dark orange 4 (139 69 0) +255 114 86 coral 1 (255 114 86) +238 106 80 coral 2 (238 106 80) +205 91 69 coral 3 (205 91 69) +139 62 47 coral 4 (139 62 47) +255 99 71 tomato 1 (255 99 71) +238 92 66 tomato 2 (238 92 66) +205 79 57 tomato 3 (205 79 57) +139 54 38 tomato 4 (139 54 38) +255 69 0 orange red 1 (255 69 0) +238 64 0 orange red 2 (238 64 0) +205 55 0 orange red 3 (205 55 0) +139 37 0 orange red 4 (139 37 0) +255 0 0 red 1 (255 0 0) +238 0 0 red 2 (238 0 0) +205 0 0 red 3 (205 0 0) +139 0 0 red 4 (139 0 0) +255 20 147 deep pink 1 (255 20 147) +238 18 137 deep pink 2 (238 18 137) +205 16 118 deep pink 3 (205 16 118) +139 10 80 deep pink 4 (139 10 80) +255 110 180 hot pink 1 (255 110 180) +238 106 167 hot pink 2 (238 106 167) +205 96 144 hot pink 3 (205 96 144) +139 58 98 hot pink 4 (139 58 98) +255 181 197 pink 1 (255 181 197) +238 169 184 pink 2 (238 169 184) +205 145 158 pink 3 (205 145 158) +139 99 108 pink 4 (139 99 108) +255 174 185 light pink 1 (255 174 185) +238 162 173 light pink 2 (238 162 173) +205 140 149 light pink 3 (205 140 149) +139 95 101 light pink 4 (139 95 101) +255 130 171 pale violet red 1 (255 130 171) +238 121 159 pale violet red 2 (238 121 159) +205 104 137 pale violet red 3 (205 104 137) +139 71 93 pale violet red 4 (139 71 93) +255 52 179 maroon 1 (255 52 179) +238 48 167 maroon 2 (238 48 167) +205 41 144 maroon 3 (205 41 144) +139 28 98 maroon 4 (139 28 98) +255 62 150 violet red 1 (255 62 150) +238 58 140 violet red 2 (238 58 140) +205 50 120 violet red 3 (205 50 120) +139 34 82 violet red 4 (139 34 82) +255 0 255 magenta 1 (255 0 255) +238 0 238 magenta 2 (238 0 238) +205 0 205 magenta 3 (205 0 205) +139 0 139 magenta 4 (139 0 139) +255 131 250 orchid 1 (255 131 250) +238 122 233 orchid 2 (238 122 233) +205 105 201 orchid 3 (205 105 201) +139 71 137 orchid 4 (139 71 137) +255 187 255 plum 1 (255 187 255) +238 174 238 plum 2 (238 174 238) +205 150 205 plum 3 (205 150 205) +139 102 139 plum 4 (139 102 139) +224 102 255 medium orchid 1 (224 102 255) +209 95 238 medium orchid 2 (209 95 238) +180 82 205 medium orchid 3 (180 82 205) +122 55 139 medium orchid 4 (122 55 139) +191 62 255 dark orchid 1 (191 62 255) +178 58 238 dark orchid 2 (178 58 238) +154 50 205 dark orchid 3 (154 50 205) +104 34 139 dark orchid 4 (104 34 139) +155 48 255 purple 1 (155 48 255) +145 44 238 purple 2 (145 44 238) +125 38 205 purple 3 (125 38 205) + 85 26 139 purple 4 ( 85 26 139) +171 130 255 medium purple 1 (171 130 255) +159 121 238 medium purple 2 (159 121 238) +137 104 205 medium purple 3 (137 104 205) + 93 71 139 medium purple 4 ( 93 71 139) +255 225 255 thistle 1 (255 225 255) +238 210 238 thistle 2 (238 210 238) +205 181 205 thistle 3 (205 181 205) +139 123 139 thistle 4 (139 123 139) +169 169 169 dark grey (169 169 169) +169 169 169 dark gray (169 169 169) + 0 0 139 dark blue (0 0 139) + 0 139 139 dark cyan (0 139 139) +139 0 139 dark magenta (139 0 139) +139 0 0 dark red (139 0 0) +144 238 144 light green (144 238 144) diff --git a/chalk/data/palettes/News3.gpl b/chalk/data/palettes/News3.gpl new file mode 100644 index 00000000..2fb44378 --- /dev/null +++ b/chalk/data/palettes/News3.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: News3 +# +236 232 4 Untitled +236 232 4 Untitled +232 232 4 Untitled +228 232 4 Untitled +228 232 4 Untitled +224 232 4 Untitled +220 232 4 Untitled +220 232 4 Untitled +216 232 4 Untitled +212 228 4 Untitled +212 228 4 Untitled +208 228 4 Untitled +204 228 4 Untitled +204 228 4 Untitled +200 228 4 Untitled +196 228 4 Untitled +196 228 4 Untitled +192 228 4 Untitled +188 228 4 Untitled +188 228 4 Untitled +184 228 4 Untitled +180 224 4 Untitled +180 224 4 Untitled +176 224 4 Untitled +172 224 4 Untitled +172 224 4 Untitled +168 224 4 Untitled +164 224 4 Untitled +164 224 8 Untitled +160 224 8 Untitled +156 224 8 Untitled +156 224 8 Untitled +152 220 8 Untitled +148 220 8 Untitled +148 220 8 Untitled +144 220 8 Untitled +140 220 8 Untitled +140 220 8 Untitled +136 220 8 Untitled +132 220 8 Untitled +132 220 8 Untitled +128 220 8 Untitled +124 220 8 Untitled +124 220 8 Untitled +120 216 8 Untitled +116 216 8 Untitled +112 216 8 Untitled +112 216 8 Untitled +108 216 8 Untitled +104 216 8 Untitled +104 216 8 Untitled +100 216 8 Untitled + 96 216 8 Untitled + 96 216 8 Untitled + 92 216 8 Untitled + 88 212 8 Untitled + 88 212 8 Untitled + 84 212 8 Untitled + 80 212 8 Untitled + 80 212 12 Untitled + 76 212 12 Untitled + 72 212 12 Untitled + 72 212 12 Untitled + 68 212 12 Untitled + 64 212 12 Untitled + 64 212 12 Untitled + 60 212 12 Untitled + 56 208 12 Untitled + 56 208 12 Untitled + 52 208 12 Untitled + 48 208 12 Untitled + 48 208 12 Untitled + 44 208 12 Untitled + 40 208 12 Untitled + 40 208 12 Untitled + 36 208 12 Untitled + 32 208 12 Untitled + 32 208 12 Untitled + 28 204 12 Untitled + 24 204 12 Untitled + 24 204 12 Untitled + 20 204 12 Untitled + 16 204 12 Untitled + 16 204 12 Untitled + 12 204 12 Untitled + 8 204 12 Untitled + 8 204 12 Untitled + 4 204 12 Untitled + 0 204 12 Untitled + 0 204 12 Untitled + 8 200 28 Untitled + 16 196 40 Untitled + 24 192 52 Untitled + 32 188 64 Untitled + 40 188 76 Untitled + 48 184 88 Untitled + 56 180 100 Untitled + 64 176 112 Untitled + 72 176 124 Untitled + 68 184 120 Untitled + 64 188 120 Untitled + 60 192 116 Untitled + 56 196 116 Untitled + 52 204 116 Untitled + 48 208 112 Untitled + 44 212 112 Untitled + 40 216 112 Untitled + 36 212 116 Untitled + 36 212 120 Untitled + 32 212 124 Untitled + 32 208 124 Untitled + 28 208 128 Untitled + 28 208 132 Untitled + 28 204 136 Untitled + 24 204 136 Untitled + 24 204 140 Untitled + 20 200 144 Untitled + 20 200 144 Untitled + 20 200 148 Untitled + 16 196 152 Untitled + 16 196 156 Untitled + 12 196 156 Untitled + 12 192 160 Untitled + 12 192 164 Untitled + 8 192 168 Untitled + 8 188 168 Untitled + 4 188 172 Untitled + 4 188 176 Untitled + 4 188 176 Untitled + 8 180 172 Untitled + 12 172 168 Untitled + 12 164 168 Untitled + 16 156 164 Untitled + 16 148 164 Untitled + 20 140 160 Untitled + 20 132 160 Untitled + 24 124 156 Untitled + 24 116 156 Untitled + 28 108 152 Untitled + 28 100 152 Untitled + 32 92 148 Untitled + 32 84 148 Untitled + 36 76 144 Untitled + 36 68 144 Untitled + 40 60 140 Untitled + 40 52 140 Untitled + 44 44 136 Untitled + 44 40 136 Untitled + 48 36 132 Untitled + 48 36 132 Untitled + 48 36 128 Untitled + 48 36 128 Untitled + 48 36 128 Untitled + 48 36 124 Untitled + 48 36 124 Untitled + 48 36 124 Untitled + 48 36 120 Untitled + 48 36 120 Untitled + 48 32 116 Untitled + 48 32 116 Untitled + 48 32 116 Untitled + 48 32 112 Untitled + 48 32 112 Untitled + 48 32 112 Untitled + 52 32 108 Untitled + 52 32 108 Untitled + 52 32 104 Untitled + 52 32 104 Untitled + 52 32 104 Untitled + 52 28 100 Untitled + 52 28 100 Untitled + 52 28 100 Untitled + 52 28 96 Untitled + 52 28 96 Untitled + 52 28 96 Untitled + 52 28 92 Untitled + 52 28 92 Untitled + 52 28 88 Untitled + 52 28 88 Untitled + 52 24 88 Untitled + 52 24 84 Untitled + 56 24 84 Untitled + 56 24 84 Untitled + 56 24 80 Untitled + 56 24 80 Untitled + 56 24 76 Untitled + 56 24 76 Untitled + 56 24 76 Untitled + 56 24 72 Untitled + 56 24 72 Untitled + 56 20 72 Untitled + 56 20 68 Untitled + 56 20 68 Untitled + 56 20 68 Untitled + 56 20 64 Untitled + 56 20 64 Untitled + 56 20 60 Untitled + 56 20 60 Untitled + 60 20 60 Untitled + 60 20 56 Untitled + 60 16 56 Untitled + 60 16 56 Untitled + 60 16 52 Untitled + 60 16 52 Untitled + 60 16 48 Untitled + 60 16 48 Untitled + 60 16 48 Untitled + 60 16 44 Untitled + 60 16 44 Untitled + 60 16 44 Untitled + 60 16 40 Untitled + 60 12 40 Untitled + 60 12 40 Untitled + 60 12 36 Untitled + 60 12 36 Untitled + 64 12 32 Untitled + 64 12 32 Untitled + 64 12 32 Untitled + 64 12 28 Untitled + 64 12 28 Untitled + 64 12 28 Untitled + 64 8 24 Untitled + 64 8 24 Untitled + 64 8 20 Untitled + 64 8 20 Untitled + 64 8 20 Untitled + 64 8 16 Untitled + 64 8 16 Untitled + 64 8 16 Untitled + 64 8 12 Untitled + 64 8 12 Untitled + 64 8 12 Untitled + 68 12 16 Untitled + 68 16 16 Untitled + 68 16 16 Untitled + 68 20 16 Untitled + 68 20 20 Untitled + 72 24 20 Untitled + 72 24 20 Untitled + 72 28 20 Untitled + 72 28 24 Untitled + 72 32 24 Untitled + 76 32 24 Untitled + 76 36 24 Untitled + 76 36 28 Untitled + 76 40 28 Untitled + 76 44 28 Untitled + 80 44 28 Untitled + 80 48 32 Untitled + 80 48 32 Untitled + 80 52 32 Untitled + 80 52 32 Untitled + 84 56 36 Untitled + 84 56 36 Untitled + 84 60 36 Untitled + 84 60 36 Untitled diff --git a/chalk/data/palettes/Op2.gpl b/chalk/data/palettes/Op2.gpl new file mode 100644 index 00000000..891f1fb4 --- /dev/null +++ b/chalk/data/palettes/Op2.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Op2 +# +204 144 100 Untitled +204 144 100 Untitled +200 148 104 Untitled +200 152 108 Untitled +200 152 112 Untitled +196 156 116 Untitled +196 160 120 Untitled +192 164 124 Untitled +172 212 180 Untitled +192 168 128 Untitled +192 172 132 Untitled +188 176 136 Untitled +188 180 140 Untitled +184 184 144 Untitled +184 184 148 Untitled +180 188 152 Untitled +180 192 156 Untitled +180 196 160 Untitled +176 200 164 Untitled +176 204 168 Untitled +172 208 172 Untitled +172 212 176 Untitled +248 88 24 Untitled +244 92 28 Untitled +244 96 32 Untitled +240 96 36 Untitled +240 100 36 Untitled +240 100 40 Untitled +236 104 44 Untitled +236 104 44 Untitled +236 108 48 Untitled +232 108 52 Untitled +232 112 52 Untitled +232 116 56 Untitled +228 116 60 Untitled +228 120 64 Untitled +228 120 64 Untitled +224 124 68 Untitled +224 124 72 Untitled +224 128 72 Untitled +220 128 76 Untitled +220 132 80 Untitled +220 136 80 Untitled +216 136 84 Untitled +216 140 88 Untitled +216 140 92 Untitled +212 144 92 Untitled +212 144 96 Untitled +212 148 100 Untitled +208 148 100 Untitled +208 152 104 Untitled +208 156 108 Untitled +204 156 108 Untitled +204 160 112 Untitled +204 160 116 Untitled +200 164 116 Untitled +200 164 120 Untitled +200 168 124 Untitled +196 168 128 Untitled +196 172 128 Untitled +196 176 132 Untitled +192 176 136 Untitled +192 180 136 Untitled +192 180 140 Untitled +188 184 144 Untitled +188 184 144 Untitled +188 188 148 Untitled +184 188 152 Untitled +184 192 156 Untitled +184 196 156 Untitled +180 196 160 Untitled +180 200 164 Untitled +180 200 164 Untitled +176 204 168 Untitled +176 204 172 Untitled +176 208 172 Untitled +172 208 176 Untitled +172 212 180 Untitled + 12 0 120 Untitled + 16 4 124 Untitled + 16 8 124 Untitled + 20 8 124 Untitled + 20 12 124 Untitled + 24 16 124 Untitled + 24 16 128 Untitled + 28 20 128 Untitled + 28 24 128 Untitled + 32 24 128 Untitled + 32 28 128 Untitled + 36 32 132 Untitled + 36 32 132 Untitled + 40 36 132 Untitled + 40 40 132 Untitled + 44 40 132 Untitled + 44 44 132 Untitled + 48 48 136 Untitled + 48 48 136 Untitled + 52 52 136 Untitled + 52 56 136 Untitled + 56 56 136 Untitled + 56 60 140 Untitled + 60 64 140 Untitled + 60 64 140 Untitled + 64 68 140 Untitled + 64 72 140 Untitled + 68 72 144 Untitled + 68 76 144 Untitled + 72 80 144 Untitled + 72 80 144 Untitled + 76 84 144 Untitled + 76 88 144 Untitled + 80 88 148 Untitled + 80 92 148 Untitled + 84 96 148 Untitled + 84 96 148 Untitled + 88 100 148 Untitled + 88 104 152 Untitled + 92 104 152 Untitled + 92 108 152 Untitled + 96 112 152 Untitled + 96 112 152 Untitled +100 116 156 Untitled +100 120 156 Untitled +104 120 156 Untitled +104 124 156 Untitled +108 128 156 Untitled +108 128 156 Untitled +112 132 160 Untitled +112 136 160 Untitled +116 136 160 Untitled +116 140 160 Untitled +120 144 160 Untitled +120 144 164 Untitled +124 148 164 Untitled +124 152 164 Untitled +128 152 164 Untitled +128 156 164 Untitled +132 160 168 Untitled +132 160 168 Untitled +136 164 168 Untitled +136 168 168 Untitled +140 168 168 Untitled +140 172 168 Untitled +144 176 172 Untitled +144 176 172 Untitled +148 180 172 Untitled +148 184 172 Untitled +152 184 172 Untitled +152 188 176 Untitled +156 192 176 Untitled +156 192 176 Untitled +160 196 176 Untitled +160 200 176 Untitled +164 200 180 Untitled +164 204 180 Untitled +168 208 180 Untitled +168 208 180 Untitled +172 212 180 Untitled +240 172 224 Untitled +236 176 220 Untitled +236 176 220 Untitled +236 176 220 Untitled +236 176 220 Untitled +236 176 220 Untitled +236 176 220 Untitled +232 176 220 Untitled +232 176 220 Untitled +232 176 220 Untitled +232 176 216 Untitled +232 180 216 Untitled +232 180 216 Untitled +228 180 216 Untitled +228 180 216 Untitled +228 180 216 Untitled +228 180 216 Untitled +228 180 216 Untitled +228 180 216 Untitled +224 180 216 Untitled +224 180 212 Untitled +224 180 212 Untitled +224 184 212 Untitled +224 184 212 Untitled +224 184 212 Untitled +220 184 212 Untitled +220 184 212 Untitled +220 184 212 Untitled +220 184 212 Untitled +220 184 208 Untitled +220 184 208 Untitled +220 184 208 Untitled +216 188 208 Untitled +216 188 208 Untitled +216 188 208 Untitled +216 188 208 Untitled +216 188 208 Untitled +216 188 208 Untitled +212 188 208 Untitled +212 188 204 Untitled +212 188 204 Untitled +212 188 204 Untitled +212 188 204 Untitled +212 192 204 Untitled +208 192 204 Untitled +208 192 204 Untitled +208 192 204 Untitled +208 192 204 Untitled +208 192 204 Untitled +208 192 200 Untitled +204 192 200 Untitled +204 192 200 Untitled +204 192 200 Untitled +204 192 200 Untitled +204 196 200 Untitled +204 196 200 Untitled +204 196 200 Untitled +200 196 200 Untitled +200 196 196 Untitled +200 196 196 Untitled +200 196 196 Untitled +200 196 196 Untitled +200 196 196 Untitled +196 196 196 grey77 +196 200 196 Untitled +196 200 196 Untitled +196 200 196 Untitled +196 200 196 Untitled +196 200 192 Untitled +192 200 192 Untitled +192 200 192 Untitled +192 200 192 Untitled +192 200 192 Untitled +192 200 192 Untitled +192 200 192 Untitled +188 204 192 Untitled +188 204 192 Untitled +188 204 192 Untitled +188 204 188 Untitled +188 204 188 Untitled +188 204 188 Untitled +188 204 188 Untitled +184 204 188 Untitled +184 204 188 Untitled +184 204 188 Untitled +184 208 188 Untitled +184 208 188 Untitled +184 208 184 Untitled +180 208 184 Untitled +180 208 184 Untitled +180 208 184 Untitled +180 208 184 Untitled +180 208 184 Untitled +180 208 184 Untitled +176 208 184 Untitled +176 208 184 Untitled +176 212 184 Untitled +176 212 180 Untitled diff --git a/chalk/data/palettes/Paintjet.gpl b/chalk/data/palettes/Paintjet.gpl new file mode 100644 index 00000000..c061b6c5 --- /dev/null +++ b/chalk/data/palettes/Paintjet.gpl @@ -0,0 +1,22 @@ +GIMP Palette +Name: Paintjet +# +# A map with the PaintJet's 8 primary colors repeated twice. +# Use these colors for 180dpi PaintJet images. +# + 24 20 12 Untitled +244 240 232 Untitled +196 68 72 Untitled + 48 132 92 Untitled +240 232 72 Untitled + 52 48 116 Untitled +188 48 108 Untitled + 40 116 196 Untitled + 24 20 12 Untitled +244 240 232 Untitled +196 68 72 Untitled + 48 132 92 Untitled +240 232 72 Untitled + 52 48 116 Untitled +188 48 108 Untitled + 40 116 196 Untitled diff --git a/chalk/data/palettes/Pantone_Coated_Approx.gpl b/chalk/data/palettes/Pantone_Coated_Approx.gpl new file mode 100644 index 00000000..5ddb0d46 --- /dev/null +++ b/chalk/data/palettes/Pantone_Coated_Approx.gpl @@ -0,0 +1,949 @@ +GIMP Palette +Name: Pantone_Coated_Approx +Columns: 16 +# +244 228 0 Process Yellow +193 0 89 Process Magenta + 0 143 216 Process Cyan + 31 31 33 Process Black +243 53 0 Orange 021 +216 0 29 Red 032 + 9 0 139 Blue 072 +240 233 124 100 +243 232 59 101 +247 228 0 102 +251 217 0 Yellow +186 160 0 103 +157 139 0 104 +109 97 0 105 +244 228 73 106 +246 223 22 107 +247 217 0 108 +250 203 0 109 +209 167 0 110 +156 130 0 111 +134 115 0 112 +245 221 66 113 +246 219 45 114 +246 218 36 115 +253 160 0 116 +186 143 0 117 +159 126 0 118 +116 100 10 119 +244 221 102 120 +245 217 87 121 +247 205 42 122 +250 183 0 123 +214 148 0 124 +162 120 0 125 +142 113 0 126 +241 227 172 1205 +244 218 131 1215 +250 187 38 1225 +251 157 0 1235 +179 130 0 1245 +144 108 0 1255 +104 80 12 1265 +239 218 110 127 +238 210 82 128 +236 190 25 129 +226 112 0 130 +187 121 0 131 +145 107 0 132 + 92 75 12 133 +246 207 111 134 +250 186 60 135 +251 169 15 136 +251 139 0 137 +210 108 0 138 +155 93 0 139 +105 78 16 140 +246 203 126 1345 +248 189 97 1355 +250 163 49 1365 +250 121 0 1375 +190 94 0 1385 +128 75 0 1395 + 86 58 17 1405 +235 194 91 141 +232 170 50 142 +231 162 38 143 +223 108 0 144 +187 101 0 145 +136 83 0 146 + 90 73 28 147 +247 201 139 148 +249 189 116 149 +251 146 43 150 +248 89 0 151 +210 86 0 152 +164 81 0 153 +128 68 0 154 +254 169 96 1485 +255 134 29 1495 +254 98 0 1505 +243 53 0 Orange 021 +170 53 0 1525 +121 50 0 1535 + 54 28 13 1545 +235 208 165 155 +231 182 125 156 +224 130 59 157 +215 80 8 158 +182 64 0 159 +137 60 10 160 + 76 44 20 161 +249 173 131 1555 +250 143 90 1565 +249 105 42 1575 +244 72 0 1585 +189 63 0 1595 +136 59 19 1605 +109 48 17 1615 +248 185 158 162 +251 126 83 163 +248 92 38 164 +236 16 0 165 +203 52 0 166 +161 54 10 167 + 86 36 17 168 +250 150 128 1625 +250 118 93 1635 +247 86 52 1645 +240 53 0 1655 +209 51 9 1665 +146 47 21 1675 +115 45 26 1685 +250 168 162 169 +250 104 92 170 +245 63 44 171 +236 30 0 172 +189 46 23 173 +118 31 17 174 + 82 35 27 175 +249 150 163 176 +249 93 111 177 +243 53 68 178 +225 0 0 Warm Red +203 33 37 179 +166 39 42 180 +102 33 34 181 +245 132 157 1765 +243 105 135 1775 +235 54 89 1785 +212 0 0 1788 +192 0 39 1795 +154 24 43 1805 +105 27 37 1815 +240 162 181 1767 +236 72 107 1777 +228 16 62 1787 +216 0 29 Red 032 +180 22 44 1797 +128 29 40 1807 + 66 37 36 1817 +243 175 197 182 +239 107 145 183 +230 52 100 184 +204 0 0 185 +181 0 39 186 +145 10 43 187 +100 31 45 188 +238 135 174 189 +232 84 135 190 +224 37 98 191 +210 0 57 192 +163 0 48 193 +129 25 55 194 + 92 36 50 195 +237 164 197 1895 +234 125 171 1905 +222 44 114 1915 +206 0 66 1925 +173 0 52 1935 +139 0 53 1945 +125 25 60 1955 +230 186 202 196 +223 134 165 197 +211 59 105 198 +198 0 60 199 +169 0 52 200 +137 21 54 201 +115 29 52 202 +226 160 198 203 +218 101 160 204 +209 52 124 205 +194 0 68 206 +154 0 64 207 +117 27 64 208 + 96 34 59 209 +240 132 188 210 +234 86 159 211 +225 44 132 212 +208 0 95 213 +178 0 77 214 +135 0 63 215 +100 30 59 216 +228 173 215 217 +216 90 174 218 +205 18 131 219 +181 0 49 Rubine Red +145 0 70 220 +122 0 64 221 + 86 24 56 222 +227 129 201 223 +219 73 173 224 +209 15 143 225 +192 0 103 226 +145 0 81 227 +112 0 72 228 + 85 29 59 229 +238 145 212 230 +229 77 185 231 +221 41 168 232 +190 0 106 Rhodamine Red +177 0 114 233 +138 0 90 234 +116 6 76 235 +232 149 215 236 +220 93 194 237 +207 45 173 238 +172 0 117 239 +161 0 126 240 +139 0 107 241 + 95 20 72 242 +231 182 224 2365 +205 76 193 2375 +187 0 166 2385 +164 0 131 2395 +133 0 112 2405 +119 0 101 2415 +105 9 90 2425 +224 166 223 243 +217 138 217 244 +204 99 203 245 +172 0 158 246 +150 0 138 247 +127 0 118 248 +101 32 91 249 +223 189 229 250 +203 136 221 251 +181 76 203 252 +135 0 153 Purple +146 0 160 253 +127 24 140 254 + 95 36 98 255 +209 179 219 256 +188 144 204 257 +126 59 147 258 + 86 17 102 259 + 76 22 83 260 + 73 30 76 261 + 65 31 64 262 +193 150 226 2562 +166 106 215 2572 +130 50 191 2582 +103 0 164 2592 + 92 6 138 2602 + 78 24 103 2612 + 73 40 80 2622 +170 123 203 2563 +142 84 183 2573 +111 46 156 2583 + 86 17 125 2593 + 74 15 101 2603 + 71 18 92 2613 + 67 17 83 2623 +161 122 207 2567 +131 84 188 2577 + 99 43 160 2587 + 68 10 126 2597 + 63 15 109 2607 + 59 20 96 2617 + 53 21 79 2627 +208 194 229 263 +169 146 224 264 +107 73 200 265 + 65 25 167 266 + 54 20 135 267 + 51 25 98 268 + 47 26 75 269 +173 156 225 2635 +144 122 216 2645 +112 84 201 2655 + 91 53 183 2665 + 29 0 99 Violet + 50 13 123 2685 + 49 31 80 2695 +168 164 217 270 +136 131 203 271 +107 101 187 272 + 37 27 115 273 + 36 26 97 274 + 32 23 79 275 + 38 31 62 276 +143 135 220 2705 +109 99 206 2715 + 74 58 187 2725 + 41 10 146 2735 + 35 14 118 2745 + 35 21 103 2755 + 37 26 87 2765 +187 192 230 2706 +129 139 219 2716 + 62 69 186 2726 + 43 37 163 2736 + 36 36 138 2746 + 34 37 102 2756 + 34 36 79 2766 +169 188 231 2707 +129 158 230 2717 + 39 84 211 2727 + 9 0 139 Blue 072 + 8 16 83 2747 + 11 18 60 2757 + 16 19 33 2767 +154 174 224 2708 + 65 96 199 2718 + 22 48 166 2728 + 13 15 132 2738 + 14 27 100 2748 + 15 25 79 2758 + 16 22 50 2768 +172 196 229 277 +136 173 227 278 + 66 120 211 279 + 0 14 120 Reflex Blue + 0 35 105 280 + 0 28 77 281 + 12 30 60 282 +141 182 228 283 +101 155 223 284 + 17 96 198 285 + 0 45 154 286 + 0 37 119 287 + 0 35 100 288 + 11 32 58 289 +175 207 232 290 +133 184 232 291 + 87 155 225 292 + 0 65 173 293 + 0 53 116 294 + 0 46 89 295 + 17 39 56 296 +133 187 228 2905 + 83 158 222 2915 + 15 122 209 2925 + 0 68 173 2935 + 0 60 135 2945 + 0 45 84 2955 + 7 36 56 2965 +123 192 232 297 + 62 161 226 298 + 0 100 196 299 + 0 79 179 300 + 0 63 128 301 + 0 54 87 302 + 12 53 70 303 +154 210 231 2975 + 65 172 227 2985 + 0 142 216 2995 + 0 104 195 3005 + 0 88 147 3015 + 0 66 94 3025 + 10 56 70 3035 +151 213 229 304 + 92 193 231 305 + 0 148 216 306 + 0 95 185 Process Blue + 0 101 165 307 + 0 72 107 308 + 11 60 70 309 + 98 197 224 310 + 58 184 219 311 + 0 154 203 312 + 0 121 177 313 + 0 97 138 314 + 0 76 100 315 + 13 61 68 316 +120 206 219 3105 + 55 184 209 3115 + 0 168 198 3125 + 0 135 172 3135 + 0 112 135 3145 + 0 93 110 3155 + 0 71 80 3165 +183 226 224 317 +134 214 219 318 + 64 192 203 319 + 0 110 127 320 + 0 116 128 321 + 0 97 104 322 + 0 84 87 323 +159 216 215 324 + 87 191 189 325 + 0 161 155 326 + 0 94 75 327 + 0 101 92 328 + 0 90 82 329 + 25 73 68 330 +133 217 209 3242 + 82 203 194 3252 + 0 182 173 3262 + 0 155 145 3272 + 0 119 110 3282 + 0 77 69 3292 + 17 56 50 3302 +132 219 204 3245 + 78 206 186 3255 + 0 185 162 3265 + 0 163 137 3275 + 0 133 113 3285 + 0 113 96 3295 + 25 68 57 3305 +125 204 189 3248 + 70 183 160 3258 + 0 158 128 3268 + 0 137 103 3278 + 0 113 87 3288 + 0 86 68 3298 + 21 54 44 3308 +181 230 216 331 +147 226 206 332 + 83 212 183 333 + 0 131 86 Green + 0 136 100 334 + 0 108 82 335 + 13 87 67 336 +145 211 188 337 +106 198 165 338 + 12 163 115 339 + 0 133 79 340 + 0 97 63 341 + 9 83 57 342 + 29 69 51 343 +142 225 192 3375 + 98 214 168 3385 + 29 195 133 3395 + 0 169 95 3405 + 0 111 70 3415 + 22 90 59 3425 + 25 62 42 3435 +163 217 178 344 +133 207 155 345 + 95 191 127 346 + 0 136 52 347 + 0 112 48 348 + 21 85 43 349 + 37 62 40 350 +170 229 186 351 +142 224 165 352 +116 218 146 353 + 0 139 13 354 + 0 138 41 355 + 13 105 40 356 + 42 80 46 357 +158 214 122 358 +144 208 107 359 + 94 185 53 360 + 53 162 17 361 + 61 138 26 362 + 63 123 28 363 + 59 101 29 364 +202 227 148 365 +183 221 117 366 +154 210 77 367 + 40 149 0 368 + 79 151 0 369 + 77 121 0 370 + 70 85 26 371 +209 233 132 372 +195 230 101 373 +174 226 57 374 + 79 186 0 375 +112 175 0 376 + 98 134 0 377 + 71 82 17 378 +220 229 87 379 +210 225 49 380 +197 219 0 381 +143 190 0 382 +150 162 0 383 +132 139 0 384 +101 99 20 385 +225 232 67 386 +219 230 31 387 +207 226 0 388 +193 220 0 389 +168 183 0 390 +141 143 0 391 +116 114 0 392 +236 233 107 393 +232 231 31 394 +226 228 0 395 +214 222 0 396 +181 181 0 397 +163 159 0 398 +142 135 0 399 +239 232 76 3935 +237 227 0 3945 +230 218 0 3955 +227 214 0 3965 +169 154 0 3975 +131 118 0 3985 + 85 75 0 3995 +193 186 176 400 +170 162 152 401 +145 137 127 402 +128 120 109 403 +103 95 84 404 + 83 75 66 405 + 49 46 43 Black +189 178 172 406 +166 154 148 407 +145 133 127 408 +130 117 112 409 +107 94 88 410 + 85 72 67 411 + 43 36 34 412 +183 182 171 413 +165 164 153 414 +146 145 134 415 +120 120 108 416 + 98 98 86 417 + 79 79 68 418 + 39 40 34 419 +198 196 193 420 +178 177 174 421 +158 157 155 422 +133 133 131 423 +108 109 107 424 + 79 80 80 425 + 42 42 42 426 +209 209 207 427 +184 186 186 428 +150 154 156 429 +118 123 127 430 + 80 86 91 431 + 56 61 66 432 + 10 13 16 433 +205 193 196 434 +187 172 178 435 +160 142 150 436 +113 94 102 437 + 66 51 55 438 + 51 40 42 439 + 47 40 39 440 +191 198 196 441 +167 177 177 442 +140 151 154 443 +114 126 130 444 + 69 77 82 445 + 57 62 63 446 + 49 51 48 447 +216 209 198 Warm Gray 1 +202 194 184 Warm Gray 2 +184 175 165 Warm Gray 3 +170 160 151 Warm Gray 4 +159 149 139 Warm Gray 5 +149 138 129 Warm Gray 6 +137 126 117 Warm Gray 7 +126 116 106 Warm Gray 8 +116 105 95 Warm Gray 9 +107 96 87 Warm Gray 10 + 86 75 66 Warm Gray 11 +219 215 210 Cool Gray 1 +203 201 198 Cool Gray 2 +192 190 189 Cool Gray 3 +177 175 174 Cool Gray 4 +166 164 165 Cool Gray 5 +157 156 157 Cool Gray 6 +140 139 141 Cool Gray 7 +124 123 126 Cool Gray 8 +114 114 116 Cool Gray 9 + 93 93 96 Cool Gray 10 + 81 81 84 Cool Gray 11 + 65 57 39 448 + 72 62 38 449 + 79 70 40 450 +149 142 108 451 +175 169 139 452 +197 192 167 453 +211 207 186 454 + 71 56 17 4485 +108 91 35 4495 +137 121 64 4505 +168 154 102 4515 +187 175 130 4525 +207 197 162 4535 +218 210 179 4545 + 82 70 16 455 +130 110 0 456 +157 129 0 457 +206 187 78 458 +218 204 112 459 +226 215 142 460 +232 224 167 461 + 76 57 31 462 +103 70 33 463 + 93 49 16 464 +176 145 95 465 +197 173 129 466 +206 186 146 467 +217 201 167 468 + 58 30 18 4625 +111 65 34 4635 +152 107 76 4645 +179 138 110 4655 +200 165 141 4665 +214 185 164 4675 +223 200 182 4685 + 80 43 21 469 +128 57 17 470 +140 44 0 471 +221 147 106 472 +232 177 144 473 +236 194 166 474 +238 204 180 475 + 65 35 30 4695 +103 63 54 4705 +132 94 83 4715 +161 127 116 4725 +187 158 149 4735 +200 176 166 4745 +214 195 186 4755 + 73 46 37 476 + 82 40 32 477 + 99 44 36 478 +161 116 98 479 +196 165 150 480 +212 189 176 481 +221 204 192 482 + 91 41 34 483 +136 32 31 484 +192 0 0 485 +223 131 122 486 +228 165 157 487 +231 187 178 488 +233 203 195 489 + 71 28 33 490 + 98 30 38 491 +123 36 49 492 +199 107 131 493 +226 159 178 494 +232 176 190 495 +236 192 202 496 + 60 34 35 497 + 84 41 42 498 + 95 44 43 499 +180 115 128 500 +214 163 174 501 +227 188 196 502 +233 205 209 503 + 56 28 30 4975 +105 56 64 4985 +142 91 100 4995 +167 118 127 5005 +196 155 162 5015 +207 172 177 5025 +219 191 192 5035 + 64 25 34 504 + 85 25 42 505 +101 27 50 506 +187 106 139 507 +210 142 170 508 +223 169 190 509 +230 187 202 510 + 64 26 55 511 + 94 27 93 512 +115 28 125 513 +185 106 185 514 +207 141 202 515 +220 168 213 516 +228 190 219 517 + 62 30 54 5115 + 94 55 87 5125 +123 86 119 5135 +150 117 145 5145 +189 163 185 5155 +209 190 204 5165 +219 204 213 5175 + 61 38 61 518 + 74 39 85 519 + 79 39 100 520 +153 116 176 521 +173 141 192 522 +193 167 205 523 +209 189 214 524 + 50 32 44 5185 + 68 42 58 5195 +112 80 101 5205 +150 120 138 5215 +176 150 164 5225 +203 183 192 5235 +215 200 204 5245 + 60 32 74 525 + 70 27 112 526 + 80 23 148 527 +138 93 197 528 +177 140 217 529 +191 159 222 530 +206 181 224 531 + 38 31 59 5255 + 53 45 87 5265 + 75 67 111 5275 +115 109 148 5285 +153 147 178 5295 +179 173 197 5305 +200 194 209 5315 + 46 46 61 532 + 45 52 84 533 + 46 58 105 534 +131 142 181 535 +156 164 195 536 +180 186 208 537 +197 201 215 538 + 20 42 61 539 + 1 45 82 540 + 0 53 108 541 + 76 130 185 542 +126 166 209 543 +160 190 219 544 +180 202 222 545 + 21 38 53 5395 + 50 76 98 5405 + 81 106 127 5415 +113 135 154 5425 +151 168 183 5435 +181 192 202 5445 +203 209 215 5455 + 16 36 43 546 + 0 44 58 547 + 0 54 74 548 + 80 132 159 549 +118 161 184 550 +150 183 201 551 +187 206 216 552 + 21 50 54 5463 + 44 86 92 5473 + 87 128 133 5483 +125 160 164 5493 +159 185 188 5503 +191 208 208 5513 +208 219 217 5523 + 26 40 38 5467 + 53 73 69 5477 + 85 104 101 5487 +126 142 139 5497 +156 170 167 5507 +181 191 188 5517 +198 205 201 5527 + 39 60 45 553 + 39 79 58 554 + 36 91 64 555 +114 156 133 556 +150 182 165 557 +173 198 184 558 +194 210 198 559 + 33 52 43 5535 + 69 95 83 5545 +103 127 114 5555 +130 152 140 5565 +165 182 171 5575 +179 194 182 5585 +200 209 198 5595 + 41 64 56 560 + 40 87 78 561 + 41 110 102 562 +114 177 167 563 +145 197 187 564 +173 213 203 565 +198 223 214 566 + 30 43 33 5605 + 65 81 66 5615 + 97 112 97 5625 +139 151 138 5635 +168 177 165 5645 +186 193 182 5655 +205 209 199 5665 + 38 66 56 567 + 30 92 79 568 + 20 118 104 569 +109 187 173 570 +149 208 196 571 +175 219 208 572 +194 224 215 573 + 58 69 30 574 + 68 94 28 575 + 81 122 35 576 +160 187 116 577 +177 198 137 578 +192 208 155 579 +205 216 173 580 + 50 56 28 5743 + 76 82 42 5753 +100 105 64 5763 +138 143 104 5773 +163 166 131 5783 +189 191 162 5793 +208 208 185 5803 + 50 55 19 5747 + 87 92 34 5757 +120 125 64 5767 +152 155 99 5777 +185 186 141 5787 +203 203 167 5797 +214 212 182 5807 + 81 77 10 581 +117 119 0 582 +151 167 0 583 +199 208 57 584 +210 216 88 585 +217 221 112 586 +226 226 146 587 + 61 57 16 5815 + 98 92 30 5825 +140 135 72 5835 +163 158 101 5845 +191 186 138 5855 +202 198 155 5865 +214 209 174 5875 +237 233 183 600 +237 231 149 601 +235 228 120 602 +233 224 76 603 +228 214 0 604 +212 191 0 605 +207 185 0 606 +234 230 194 607 +233 228 175 608 +229 223 146 609 +221 213 108 610 +205 193 50 611 +188 173 0 612 +162 145 0 613 +223 217 179 614 +219 214 170 615 +212 205 150 616 +194 186 116 617 +166 156 72 618 +129 118 24 619 +118 107 19 620 +200 212 201 621 +179 197 185 622 +141 168 154 623 +107 139 124 624 + 72 108 92 625 + 28 60 47 626 + 18 39 30 627 +188 218 220 628 +165 208 216 629 +125 190 207 630 + 78 165 190 631 + 39 143 174 632 + 0 107 142 633 + 0 78 114 634 +174 217 226 635 +144 207 225 636 +106 192 222 637 + 45 167 211 638 + 0 141 196 639 + 0 119 180 640 + 0 102 165 641 +189 201 215 642 +173 189 209 643 +131 155 187 644 +103 131 169 645 + 73 104 146 646 + 32 65 108 647 + 17 43 81 648 +190 198 216 649 +165 179 206 650 +126 145 185 651 + 82 106 154 652 + 34 61 113 653 + 11 31 74 654 + 9 21 52 655 +198 207 229 656 +165 182 224 657 +127 153 215 658 + 84 117 198 659 + 41 80 174 660 + 11 48 144 661 + 0 23 103 662 +210 201 215 663 +193 182 204 664 +170 157 187 665 +137 122 161 666 + 96 80 125 667 + 71 53 100 668 + 51 36 76 669 +230 202 221 670 +227 189 217 671 +216 153 200 672 +204 119 180 673 +187 82 154 674 +162 35 116 675 +142 0 88 676 +227 206 216 677 +219 190 209 678 +211 173 199 679 +187 132 170 680 +156 88 134 681 +133 59 108 682 +102 31 72 683 +223 191 204 684 +214 173 194 685 +201 152 179 686 +175 115 150 687 +147 82 122 688 +114 46 87 689 + 82 28 57 690 +227 199 202 691 +218 178 185 692 +203 150 161 693 +185 123 137 694 +152 82 98 695 +116 46 61 696 + 98 36 45 697 +234 194 200 698 +230 171 184 699 +222 142 161 700 +207 108 132 701 +185 69 97 702 +149 29 53 703 +128 16 31 704 +240 214 218 705 +240 185 198 706 +238 148 170 707 +231 108 138 708 +220 65 101 709 +199 21 58 710 +183 6 41 711 +244 208 174 712 +245 196 152 713 +244 169 108 714 +238 141 64 715 +223 107 0 716 +202 78 0 717 +181 60 0 718 +233 203 173 719 +229 190 154 720 +216 164 118 721 +190 125 68 722 +172 104 43 723 +121 56 0 724 + 97 41 0 725 +222 194 164 726 +210 175 141 727 +196 155 116 728 +174 128 85 729 +148 97 51 730 + 83 41 5 731 + 70 35 9 732 + 48 44 33 Black 2 + 31 35 29 Black 3 + 40 33 26 Black 4 + 43 32 33 Black 5 + 25 31 37 Black 6 + 49 46 43 Black 7 diff --git a/chalk/data/palettes/Pastels.gpl b/chalk/data/palettes/Pastels.gpl new file mode 100644 index 00000000..bcfd9342 --- /dev/null +++ b/chalk/data/palettes/Pastels.gpl @@ -0,0 +1,21 @@ +GIMP Palette +Name: Pastels +# +226 145 145 Untitled +153 221 146 Untitled +147 216 185 Untitled +148 196 211 Untitled +148 154 206 Untitled +179 148 204 Untitled +204 150 177 Untitled +204 164 153 Untitled +223 229 146 Untitled +255 165 96 Untitled +107 255 99 Untitled +101 255 204 Untitled +101 196 255 Untitled +101 107 255 Untitled +173 101 255 Untitled +255 101 244 Untitled +255 101 132 Untitled +255 101 101 Untitled diff --git a/chalk/data/palettes/Plasma.gpl b/chalk/data/palettes/Plasma.gpl new file mode 100644 index 00000000..db3982bc --- /dev/null +++ b/chalk/data/palettes/Plasma.gpl @@ -0,0 +1,260 @@ +GIMP Palette +Name: Plasma +Columns: 16 +# +240 240 0 Untitled +240 224 0 Untitled +240 208 0 Untitled +240 192 0 Untitled +240 176 0 Untitled +240 160 0 Untitled +240 144 0 Untitled +240 128 0 Untitled +240 112 0 Untitled +240 96 0 Untitled +240 80 0 Untitled +240 64 0 Untitled +240 48 0 Untitled +240 32 0 Untitled +240 16 0 Untitled +240 0 0 Untitled +224 224 16 Untitled +224 212 16 Untitled +224 200 16 Untitled +224 184 16 Untitled +224 172 12 Untitled +224 156 12 Untitled +224 144 12 Untitled +224 128 12 Untitled +224 116 8 Untitled +224 100 8 Untitled +224 88 8 Untitled +224 72 8 Untitled +224 60 4 Untitled +224 44 4 Untitled +224 32 4 Untitled +224 16 0 Untitled +208 208 32 Untitled +208 200 32 Untitled +208 188 28 Untitled +208 176 28 Untitled +208 164 24 Untitled +208 152 24 Untitled +208 140 20 Untitled +208 128 20 Untitled +208 116 16 Untitled +208 104 16 Untitled +208 92 12 Untitled +208 80 12 Untitled +208 68 8 Untitled +208 56 8 Untitled +208 44 4 Untitled +208 32 0 Untitled +192 192 48 Untitled +192 184 48 Untitled +192 176 44 Untitled +192 164 40 Untitled +192 156 36 Untitled +192 144 32 Untitled +192 136 32 Untitled +192 128 28 Untitled +192 116 24 Untitled +192 108 20 Untitled +192 96 16 Untitled +192 88 16 Untitled +192 80 12 Untitled +192 68 8 Untitled +192 60 4 Untitled +192 48 0 Untitled +176 176 64 Untitled +176 172 60 Untitled +176 164 56 Untitled +176 156 52 Untitled +176 148 48 Untitled +176 140 44 Untitled +176 132 40 Untitled +176 124 36 Untitled +176 120 32 Untitled +176 112 28 Untitled +176 104 24 Untitled +176 96 20 Untitled +176 88 16 Untitled +176 80 12 Untitled +176 72 8 Untitled +176 64 0 Untitled +160 160 80 Untitled +160 156 76 Untitled +160 152 72 Untitled +160 144 64 Untitled +160 140 60 Untitled +160 136 56 Untitled +160 128 48 Untitled +160 124 44 Untitled +160 120 40 Untitled +160 112 32 Untitled +160 108 28 Untitled +160 104 24 Untitled +160 96 16 Untitled +160 92 12 Untitled +160 88 8 Untitled +160 80 0 Untitled +144 144 96 Untitled +144 144 92 Untitled +144 140 84 Untitled +144 136 80 Untitled +144 132 72 Untitled +144 128 64 Untitled +144 128 60 Untitled +144 124 52 Untitled +144 120 48 Untitled +144 116 40 Untitled +144 112 32 Untitled +144 112 28 Untitled +144 108 20 Untitled +144 104 16 Untitled +144 100 8 Untitled +144 96 0 Untitled +128 128 112 Untitled +128 128 108 Untitled +128 128 100 Untitled +128 128 92 Untitled +128 124 84 Untitled +128 124 76 Untitled +128 124 68 Untitled +128 124 60 Untitled +128 120 56 Untitled +128 120 48 Untitled +128 120 40 Untitled +128 120 32 Untitled +128 116 24 Untitled +128 116 16 Untitled +128 116 8 Untitled +128 112 0 Untitled +112 112 128 Untitled +112 112 120 Untitled +112 112 112 grey44 +112 112 104 Untitled +112 116 96 Untitled +112 116 88 Untitled +112 116 80 Untitled +112 116 72 Untitled +112 120 60 Untitled +112 120 52 Untitled +112 120 44 Untitled +112 120 36 Untitled +112 124 28 Untitled +112 124 20 Untitled +112 124 12 Untitled +112 128 0 Untitled + 96 96 144 Untitled + 96 96 136 Untitled + 96 100 128 Untitled + 96 104 116 Untitled + 96 108 108 Untitled + 96 112 96 Untitled + 96 112 88 Untitled + 96 116 80 Untitled + 96 120 68 Untitled + 96 124 60 Untitled + 96 128 48 Untitled + 96 128 40 Untitled + 96 132 32 Untitled + 96 136 20 Untitled + 96 140 12 Untitled + 96 144 0 Untitled + 80 80 160 Untitled + 80 84 152 Untitled + 80 88 140 Untitled + 80 96 128 Untitled + 80 100 120 Untitled + 80 104 108 Untitled + 80 112 96 Untitled + 80 116 88 Untitled + 80 120 76 Untitled + 80 128 64 Untitled + 80 132 56 Untitled + 80 136 44 Untitled + 80 144 32 Untitled + 80 148 24 Untitled + 80 152 12 Untitled + 80 160 0 Untitled + 64 64 176 Untitled + 64 68 168 Untitled + 64 76 156 Untitled + 64 84 144 Untitled + 64 92 132 Untitled + 64 100 120 Untitled + 64 108 108 Untitled + 64 116 96 Untitled + 64 120 84 Untitled + 64 128 72 Untitled + 64 136 60 Untitled + 64 144 48 Untitled + 64 152 36 Untitled + 64 160 24 Untitled + 64 168 12 Untitled + 64 176 0 Untitled + 48 48 192 Untitled + 48 56 180 Untitled + 48 64 168 Untitled + 48 76 156 Untitled + 48 84 144 Untitled + 48 96 128 Untitled + 48 104 116 Untitled + 48 112 104 Untitled + 48 124 92 Untitled + 48 132 80 Untitled + 48 144 64 Untitled + 48 152 52 Untitled + 48 160 40 Untitled + 48 172 28 Untitled + 48 180 16 Untitled + 48 192 0 Untitled + 32 32 208 Untitled + 32 40 196 Untitled + 32 52 184 Untitled + 32 64 168 Untitled + 32 76 156 Untitled + 32 88 140 Untitled + 32 100 128 Untitled + 32 112 112 Untitled + 32 124 100 Untitled + 32 136 84 Untitled + 32 148 72 Untitled + 32 160 56 Untitled + 32 172 44 Untitled + 32 184 28 Untitled + 32 196 16 Untitled + 32 208 0 Untitled + 16 16 224 Untitled + 16 28 212 Untitled + 16 40 196 Untitled + 16 56 180 Untitled + 16 68 168 Untitled + 16 84 152 Untitled + 16 96 136 Untitled + 16 112 120 Untitled + 16 124 108 Untitled + 16 140 92 Untitled + 16 152 76 Untitled + 16 168 60 Untitled + 16 180 48 Untitled + 16 196 32 Untitled + 16 208 16 Untitled + 16 224 0 Untitled + 0 0 240 Untitled + 0 16 224 Untitled + 0 32 208 Untitled + 0 48 192 Untitled + 0 64 176 Untitled + 0 80 160 Untitled + 0 96 144 Untitled + 0 112 128 Untitled + 0 128 112 Untitled + 0 144 96 Untitled + 0 160 80 Untitled + 0 176 64 Untitled + 0 192 48 Untitled + 0 208 32 Untitled + 0 224 16 Untitled + 0 240 0 Untitled diff --git a/chalk/data/palettes/Reds.gpl b/chalk/data/palettes/Reds.gpl new file mode 100644 index 00000000..8297e143 --- /dev/null +++ b/chalk/data/palettes/Reds.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Reds +# + 0 0 0 grey0 + 76 0 0 Untitled + 76 0 0 Untitled + 72 0 0 Untitled + 68 0 0 Untitled + 68 0 0 Untitled + 64 0 0 Untitled + 60 0 0 Untitled + 56 0 0 Untitled + 56 0 0 Untitled + 52 0 0 Untitled + 48 0 0 Untitled + 48 0 0 Untitled + 44 0 0 Untitled + 40 0 0 Untitled + 40 0 0 Untitled + 36 0 0 Untitled + 32 0 0 Untitled + 28 0 0 Untitled + 28 0 0 Untitled + 24 0 0 Untitled + 20 0 0 Untitled + 20 0 0 Untitled + 16 0 0 Untitled + 12 0 0 Untitled + 12 0 0 Untitled + 8 0 0 Untitled + 4 0 0 Untitled + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 + 4 0 0 Untitled + 4 0 0 Untitled + 4 4 4 Untitled + 8 4 4 Untitled + 8 4 4 Untitled + 8 4 4 Untitled + 12 8 8 Untitled + 12 8 8 Untitled + 16 8 8 Untitled + 16 8 8 Untitled + 16 12 12 Untitled + 20 12 12 Untitled + 20 12 12 Untitled + 20 12 12 Untitled + 24 16 16 Untitled + 24 16 16 Untitled + 28 16 16 Untitled + 28 16 16 Untitled + 28 20 20 Untitled + 32 20 20 Untitled + 32 20 20 Untitled + 32 20 20 Untitled + 36 24 24 Untitled + 36 24 24 Untitled + 36 24 24 Untitled + 40 24 24 Untitled + 40 28 28 Untitled + 44 28 28 Untitled + 44 28 28 Untitled + 44 28 28 Untitled + 48 32 32 Untitled + 48 32 32 Untitled + 48 32 32 Untitled + 52 32 32 Untitled + 52 36 36 Untitled + 56 36 36 Untitled + 56 36 36 Untitled + 56 36 36 Untitled + 60 40 40 Untitled + 60 40 40 Untitled + 60 40 40 Untitled + 64 40 40 Untitled + 64 44 44 Untitled + 64 44 44 Untitled + 68 44 44 Untitled + 68 44 44 Untitled + 72 48 48 Untitled + 72 48 48 Untitled + 72 48 48 Untitled + 76 48 48 Untitled + 76 52 52 Untitled + 76 52 52 Untitled + 80 52 52 Untitled + 80 52 52 Untitled + 84 56 56 Untitled + 84 56 56 Untitled + 84 56 56 Untitled + 88 56 56 Untitled + 88 60 60 Untitled + 88 60 60 Untitled + 92 60 60 Untitled + 92 60 60 Untitled + 92 64 64 Untitled + 96 64 64 Untitled + 96 64 64 Untitled +100 64 64 Untitled +100 68 68 Untitled +100 68 68 Untitled +104 68 68 Untitled +104 68 68 Untitled +104 72 72 Untitled +108 72 72 Untitled +108 72 72 Untitled +112 72 72 Untitled +112 76 76 Untitled +112 76 76 Untitled +116 76 76 Untitled +116 76 76 Untitled +116 80 80 Untitled +120 80 80 Untitled +120 80 80 Untitled +120 80 80 Untitled +124 84 84 Untitled +124 84 84 Untitled +128 84 84 Untitled +128 84 84 Untitled +128 88 88 Untitled +132 88 88 Untitled +132 88 88 Untitled +132 88 88 Untitled +252 252 252 grey99 +252 252 252 grey99 +252 248 248 Untitled +252 244 244 Untitled +252 240 240 Untitled +252 236 236 Untitled +252 232 232 Untitled +252 228 228 Untitled +252 224 224 Untitled +252 224 224 Untitled +252 220 220 Untitled +252 216 216 Untitled +252 212 212 Untitled +252 208 208 Untitled +252 204 204 Untitled +252 200 200 Untitled +252 196 196 Untitled +252 196 196 Untitled +252 192 192 Untitled +252 188 188 Untitled +252 184 184 Untitled +252 180 180 Untitled +252 176 176 Untitled +252 172 172 Untitled +252 168 168 Untitled +252 168 168 Untitled +252 164 164 Untitled +252 160 160 Untitled +252 156 156 Untitled +252 152 152 Untitled +252 148 148 Untitled +252 144 144 Untitled +252 140 140 Untitled +252 140 140 Untitled +252 136 136 Untitled +252 132 132 Untitled +252 128 128 Untitled +252 124 124 Untitled +252 120 120 Untitled +252 116 116 Untitled +252 112 112 Untitled +252 112 112 Untitled +252 108 108 Untitled +252 104 104 Untitled +252 100 100 Untitled +252 96 96 Untitled +252 92 92 Untitled +252 88 88 Untitled +252 84 84 Untitled +252 84 84 Untitled +252 80 80 Untitled +252 76 76 Untitled +252 72 72 Untitled +252 68 68 Untitled +252 64 64 Untitled +252 60 60 Untitled +252 56 56 Untitled +252 56 56 Untitled +252 52 52 Untitled +252 48 48 Untitled +252 44 44 Untitled +252 40 40 Untitled +252 36 36 Untitled +252 32 32 Untitled +252 28 28 Untitled +252 28 28 Untitled +252 24 24 Untitled +252 20 20 Untitled +252 16 16 Untitled +252 12 12 Untitled +252 8 8 Untitled +252 4 4 Untitled +252 0 0 Untitled +252 0 0 Untitled +248 0 0 Untitled +244 0 0 Untitled +244 0 0 Untitled +240 0 0 Untitled +236 0 0 Untitled +236 0 0 Untitled +232 0 0 Untitled +228 0 0 Untitled +224 0 0 Untitled +224 0 0 Untitled +220 0 0 Untitled +216 0 0 Untitled +216 0 0 Untitled +212 0 0 Untitled +208 0 0 Untitled +208 0 0 Untitled +204 0 0 Untitled +200 0 0 Untitled +196 0 0 Untitled +196 0 0 Untitled +192 0 0 Untitled +188 0 0 Untitled +188 0 0 Untitled +184 0 0 Untitled +180 0 0 Untitled +180 0 0 Untitled +176 0 0 Untitled +172 0 0 Untitled +168 0 0 Untitled +168 0 0 Untitled +164 0 0 Untitled +160 0 0 Untitled +160 0 0 Untitled +156 0 0 Untitled +152 0 0 Untitled +152 0 0 Untitled +148 0 0 Untitled +144 0 0 Untitled +140 0 0 Untitled +140 0 0 Untitled +136 0 0 Untitled +132 0 0 Untitled +132 0 0 Untitled +128 0 0 Untitled +124 0 0 Untitled +124 0 0 Untitled +120 0 0 Untitled +116 0 0 Untitled +112 0 0 Untitled +112 0 0 Untitled +108 0 0 Untitled +104 0 0 Untitled +104 0 0 Untitled +100 0 0 Untitled + 96 0 0 Untitled + 96 0 0 Untitled + 92 0 0 Untitled + 88 0 0 Untitled + 84 0 0 Untitled + 84 0 0 Untitled + 80 0 0 Untitled diff --git a/chalk/data/palettes/Reds_And_Purples.gpl b/chalk/data/palettes/Reds_And_Purples.gpl new file mode 100644 index 00000000..6096547c --- /dev/null +++ b/chalk/data/palettes/Reds_And_Purples.gpl @@ -0,0 +1,33 @@ +GIMP Palette +Name: Reds and Purples +# +205 92 92 Indian Red +178 34 34 Firebrick +165 42 42 Brown Red +233 150 122 Dark Salmon +250 128 114 Salmon +255 160 122 Light Salmon +255 127 80 Coral +240 128 128 Light Coral +255 99 71 Tomato +255 69 0 Orange Red +255 0 0 Red +255 105 180 Hot Pink +255 20 147 Deep Pink +255 192 203 Pink +255 182 193 Light Pink +219 112 147 Pale Violet Red +176 48 96 Maroon +199 21 133 Medium Violet Red +208 32 144 Violet Red +255 0 255 Magenta +238 130 238 Violet +221 160 221 Plum +218 112 214 Orchid +186 85 211 Medium Orchid +153 50 204 Dark Orchid +148 0 211 Dark Violet +138 43 226 Blue Violet +160 32 240 Purple +147 112 219 Medium Purple +216 191 216 Thistle diff --git a/chalk/data/palettes/Royal.gpl b/chalk/data/palettes/Royal.gpl new file mode 100644 index 00000000..67c5bbb7 --- /dev/null +++ b/chalk/data/palettes/Royal.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Royal +# + 0 0 0 grey0 + 60 0 80 Untitled + 60 0 80 Untitled + 60 0 84 Untitled + 64 0 84 Untitled + 64 0 84 Untitled + 64 0 88 Untitled + 64 0 88 Untitled + 68 0 88 Untitled + 68 0 92 Untitled + 68 0 92 Untitled + 68 0 92 Untitled + 72 0 96 Untitled + 72 0 96 Untitled + 72 0 96 Untitled + 72 0 100 Untitled + 76 0 100 Untitled + 76 0 100 Untitled + 76 0 104 Untitled + 76 0 104 Untitled + 76 0 104 Untitled + 80 0 104 Untitled + 80 0 108 Untitled + 80 0 108 Untitled + 80 0 108 Untitled + 84 0 112 Untitled + 84 0 112 Untitled + 84 0 112 Untitled + 84 0 116 Untitled + 88 0 116 Untitled + 88 0 116 Untitled + 88 0 120 Untitled + 88 0 120 Untitled + 92 0 120 Untitled + 92 0 124 Untitled + 92 0 124 Untitled + 92 0 124 Untitled + 96 0 128 Untitled + 96 0 128 Untitled + 96 0 128 Untitled + 96 0 132 Untitled + 96 0 132 Untitled +100 0 132 Untitled +100 0 132 Untitled +100 0 136 Untitled +100 0 136 Untitled +104 0 136 Untitled +104 0 140 Untitled +104 0 140 Untitled +104 0 140 Untitled +108 0 144 Untitled +108 0 144 Untitled +108 0 144 Untitled +108 0 148 Untitled +112 0 148 Untitled +112 0 148 Untitled +112 0 152 Untitled +112 0 152 Untitled +116 0 152 Untitled +116 0 156 Untitled +116 0 156 Untitled +116 0 156 Untitled +120 0 160 Untitled +120 0 160 Untitled +124 4 160 Untitled +124 8 164 Untitled +128 12 164 Untitled +128 16 164 Untitled +132 20 168 Untitled +132 24 168 Untitled +136 28 168 Untitled +136 32 172 Untitled +140 36 172 Untitled +140 40 172 Untitled +144 44 176 Untitled +144 48 176 Untitled +148 52 180 Untitled +148 56 180 Untitled +152 60 180 Untitled +152 64 184 Untitled +156 68 184 Untitled +156 72 184 Untitled +160 76 188 Untitled +160 80 188 Untitled +164 84 188 Untitled +164 88 192 Untitled +168 92 192 Untitled +168 96 192 Untitled +172 100 196 Untitled +172 104 196 Untitled +176 108 200 Untitled +176 112 200 Untitled +180 116 200 Untitled +180 120 204 Untitled +184 124 204 Untitled +188 128 204 Untitled +188 132 208 Untitled +192 136 208 Untitled +192 140 208 Untitled +196 144 212 Untitled +196 148 212 Untitled +200 152 216 Untitled +200 156 216 Untitled +204 160 216 Untitled +204 164 220 Untitled +208 168 220 Untitled +208 172 220 Untitled +212 176 224 Untitled +212 180 224 Untitled +216 184 224 Untitled +216 188 228 Untitled +220 192 228 Untitled +220 196 228 Untitled +224 200 232 Untitled +224 204 232 Untitled +228 208 236 Untitled +228 212 236 Untitled +232 216 236 Untitled +232 220 240 Untitled +236 224 240 Untitled +236 228 240 Untitled +240 232 244 Untitled +240 236 244 Untitled +244 240 244 Untitled +244 244 248 Untitled +248 248 248 Untitled +252 252 252 grey99 +252 252 252 grey99 +252 252 248 Untitled +252 252 244 Untitled +252 252 240 Untitled +252 252 236 Untitled +252 252 232 Untitled +252 252 228 Untitled +252 252 224 Untitled +252 252 220 Untitled +252 252 216 Untitled +252 252 212 Untitled +252 252 208 Untitled +252 252 204 Untitled +252 252 200 Untitled +252 252 196 Untitled +252 252 192 Untitled +252 252 188 Untitled +252 252 184 Untitled +252 252 180 Untitled +252 252 176 Untitled +252 252 172 Untitled +252 252 168 Untitled +252 252 164 Untitled +252 252 160 Untitled +252 252 156 Untitled +252 252 152 Untitled +252 252 148 Untitled +252 252 144 Untitled +252 252 140 Untitled +252 252 136 Untitled +252 252 132 Untitled +252 252 128 Untitled +252 252 124 Untitled +252 252 120 Untitled +252 252 116 Untitled +252 252 112 Untitled +252 252 108 Untitled +252 252 104 Untitled +252 252 100 Untitled +252 252 96 Untitled +252 252 92 Untitled +252 252 88 Untitled +252 252 84 Untitled +252 252 80 Untitled +252 252 76 Untitled +252 252 72 Untitled +252 252 68 Untitled +252 252 64 Untitled +252 252 60 Untitled +252 252 56 Untitled +252 252 52 Untitled +252 252 48 Untitled +252 252 44 Untitled +252 252 40 Untitled +252 252 36 Untitled +252 252 32 Untitled +252 252 28 Untitled +252 252 24 Untitled +252 252 20 Untitled +252 252 16 Untitled +252 252 12 Untitled +252 252 8 Untitled +252 252 4 Untitled +252 252 0 Untitled +252 248 0 Untitled +248 244 0 Untitled +244 240 0 Untitled +240 236 4 Untitled +240 232 4 Untitled +236 228 4 Untitled +232 224 8 Untitled +228 220 8 Untitled +228 216 8 Untitled +224 212 12 Untitled +220 208 12 Untitled +216 204 12 Untitled +212 200 16 Untitled +212 196 16 Untitled +208 192 16 Untitled +204 188 20 Untitled +200 184 20 Untitled +200 180 20 Untitled +196 176 24 Untitled +192 172 24 Untitled +188 168 24 Untitled +184 164 28 Untitled +184 160 28 Untitled +180 156 28 Untitled +176 152 32 Untitled +172 148 32 Untitled +172 144 32 Untitled +168 140 36 Untitled +164 136 36 Untitled +160 132 36 Untitled +160 128 36 Untitled +156 124 40 Untitled +152 120 40 Untitled +148 116 40 Untitled +144 112 44 Untitled +144 108 44 Untitled +140 104 44 Untitled +136 100 48 Untitled +132 96 48 Untitled +132 92 48 Untitled +128 88 52 Untitled +124 84 52 Untitled +120 80 52 Untitled +116 76 56 Untitled +116 72 56 Untitled +112 68 56 Untitled +108 64 60 Untitled +104 60 60 Untitled +104 56 60 Untitled +100 52 64 Untitled + 96 48 64 Untitled + 92 44 64 Untitled + 88 40 68 Untitled + 88 36 68 Untitled + 84 32 68 Untitled + 80 28 72 Untitled + 76 24 72 Untitled + 76 20 72 Untitled + 72 16 76 Untitled + 68 12 76 Untitled + 64 8 76 Untitled + 60 0 80 Untitled + 60 0 80 Untitled + 60 0 80 Untitled + 60 0 80 Untitled diff --git a/chalk/data/palettes/Topographic.gpl b/chalk/data/palettes/Topographic.gpl new file mode 100644 index 00000000..8361edc7 --- /dev/null +++ b/chalk/data/palettes/Topographic.gpl @@ -0,0 +1,265 @@ +GIMP Palette +Name: Topographic +# +# "Topographic" color map - M. Davis +# waterline +# Rocks +# Snow +# Rocks +# + 0 0 0 grey0 + 0 0 168 Untitled + 4 0 172 Untitled + 4 8 172 Untitled + 4 12 172 Untitled + 4 16 172 Untitled + 8 20 176 Untitled + 8 24 176 Untitled + 8 28 176 Untitled + 12 32 176 Untitled + 12 36 180 Untitled + 16 40 184 Untitled + 16 44 184 Untitled + 20 48 184 Untitled + 20 52 188 Untitled + 24 56 192 Untitled + 24 60 192 Untitled + 28 64 192 Untitled + 28 68 196 Untitled + 32 72 200 Untitled + 32 76 200 Untitled + 36 80 200 Untitled + 36 84 204 Untitled + 40 88 208 Untitled + 40 92 208 Untitled + 44 96 208 Untitled + 44 100 212 Untitled + 48 104 216 Untitled + 48 108 216 Untitled + 52 112 216 Untitled + 52 116 220 Untitled + 56 120 224 Untitled + 60 124 224 Untitled + 60 128 224 Untitled + 64 132 228 Untitled + 64 136 232 Untitled + 68 132 232 Untitled + 68 136 232 Untitled + 68 140 232 Untitled + 68 144 232 Untitled + 72 148 236 Untitled + 72 152 240 Untitled + 76 156 240 Untitled + 76 160 240 Untitled + 80 164 244 Untitled + 80 168 248 Untitled + 84 172 248 Untitled + 84 176 248 Untitled + 40 124 0 Untitled + 40 124 0 Untitled + 44 124 0 Untitled + 44 124 0 Untitled + 44 124 4 Untitled + 44 124 4 Untitled + 44 128 4 Untitled + 44 128 4 Untitled + 48 128 4 Untitled + 48 128 4 Untitled + 48 128 8 Untitled + 48 128 8 Untitled + 48 132 8 Untitled + 48 132 8 Untitled + 52 132 8 Untitled + 52 132 8 Untitled + 56 132 12 Untitled + 56 132 12 Untitled + 60 132 12 Untitled + 60 132 12 Untitled + 60 136 12 Untitled + 60 136 12 Untitled + 60 136 16 Untitled + 60 136 16 Untitled + 60 140 16 Untitled + 60 140 16 Untitled + 64 140 16 Untitled + 64 140 16 Untitled + 64 140 20 Untitled + 64 140 20 Untitled + 64 144 20 Untitled + 64 144 20 Untitled + 68 144 20 Untitled + 68 144 20 Untitled + 68 144 24 Untitled + 68 144 24 Untitled + 68 148 24 Untitled + 72 148 24 Untitled + 72 148 28 Untitled + 72 152 28 Untitled + 72 152 32 Untitled + 76 152 32 Untitled + 76 156 32 Untitled + 80 156 32 Untitled + 80 156 36 Untitled + 80 160 36 Untitled + 80 160 40 Untitled + 84 160 40 Untitled + 84 164 40 Untitled + 88 164 40 Untitled + 88 164 44 Untitled + 88 168 44 Untitled + 88 168 48 Untitled + 92 168 48 Untitled + 92 172 48 Untitled + 96 172 48 Untitled + 96 172 52 Untitled + 96 176 52 Untitled +100 176 52 Untitled +100 176 56 Untitled +100 180 56 Untitled +100 180 56 Untitled +104 180 60 Untitled +104 184 60 Untitled +104 184 64 Untitled +108 184 64 Untitled +108 188 64 Untitled +108 188 68 Untitled +112 188 68 Untitled +112 188 72 Untitled +112 192 72 Untitled +112 192 76 Untitled +116 192 76 Untitled +116 196 76 Untitled +116 196 80 Untitled +120 196 80 Untitled +120 200 80 Untitled +120 200 84 Untitled +124 200 84 Untitled +124 204 84 Untitled +124 204 88 Untitled +128 204 88 Untitled +128 208 88 Untitled +128 208 92 Untitled +132 208 92 Untitled +132 212 92 Untitled +136 212 92 Untitled +136 212 96 Untitled +136 216 96 Untitled +136 216 100 Untitled +140 216 100 Untitled +140 220 100 Untitled +140 220 104 Untitled +144 220 104 Untitled +144 224 104 Untitled +144 224 108 Untitled +148 224 108 Untitled +148 228 108 Untitled +152 228 108 Untitled +152 228 108 Untitled +156 228 108 Untitled +156 228 108 Untitled +160 228 108 Untitled +164 228 108 Untitled +168 228 108 Untitled +168 228 108 Untitled +172 228 108 Untitled +172 228 108 Untitled +176 228 108 Untitled +176 228 108 Untitled +180 228 108 Untitled +180 228 108 Untitled +184 228 108 Untitled +184 228 108 Untitled +188 228 108 Untitled +188 228 108 Untitled +192 228 108 Untitled +196 228 108 Untitled +196 228 108 Untitled +200 228 108 Untitled +204 228 108 Untitled +204 228 108 Untitled +208 228 108 Untitled +208 228 108 Untitled +212 228 108 Untitled +212 228 108 Untitled +216 228 108 Untitled +220 228 108 Untitled +220 228 108 Untitled +224 228 108 Untitled +228 228 108 Untitled +228 228 108 Untitled +232 228 108 Untitled +232 228 108 Untitled +232 228 104 Untitled +232 228 104 Untitled +232 228 100 Untitled +232 228 100 Untitled +232 228 96 Untitled +232 228 96 Untitled +232 228 92 Untitled +232 224 92 Untitled +232 224 92 Untitled +232 220 88 Untitled +232 216 84 Untitled +232 216 80 Untitled +232 212 80 Untitled +232 212 76 Untitled +232 208 76 Untitled +232 204 72 Untitled +232 204 68 Untitled +232 200 68 Untitled +232 200 64 Untitled +232 200 64 Untitled +232 196 64 Untitled +232 196 60 Untitled +232 192 60 Untitled +232 192 56 Untitled +232 188 56 Untitled +232 188 52 Untitled +232 184 52 Untitled +232 184 48 Untitled +232 180 48 Untitled +232 180 44 Untitled +232 180 44 Untitled +232 176 44 Untitled +232 176 44 Untitled +232 176 40 Untitled +232 176 40 Untitled +232 172 40 Untitled +232 172 36 Untitled +232 168 36 Untitled +232 168 36 Untitled +228 164 32 Untitled +228 164 32 Untitled +228 160 32 Untitled +228 160 32 Untitled +224 156 28 Untitled +224 152 24 Untitled +224 152 24 Untitled +224 148 20 Untitled +220 148 20 Untitled +220 140 16 Untitled +220 140 16 Untitled +220 132 16 Untitled +216 132 16 Untitled +216 124 8 Untitled +216 124 8 Untitled +216 116 8 Untitled +128 128 128 Untitled +128 128 128 Untitled +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +192 192 192 Untitled +192 192 192 Untitled +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 +252 252 252 grey99 diff --git a/chalk/data/palettes/Visibone.gpl b/chalk/data/palettes/Visibone.gpl new file mode 100644 index 00000000..17c357b9 --- /dev/null +++ b/chalk/data/palettes/Visibone.gpl @@ -0,0 +1,346 @@ +GIMP Palette +Name: Visibone +Columns: 16 +# +# Visibone -- GIMP Palette file +# +# Arrangement idea from www.visibone.com +# Conversion to GIMP Palette and addition of +# hex codes and color names by Tigert +# +255 255 255 #FFFFFF - White +204 204 204 #CCCCCC - Pale Gray +153 153 153 #999999 - Light Gray +102 102 102 #666666 - Dark Gray + 51 51 51 #333333 - Obscure Gray + 0 0 0 #000000 - Black +255 204 0 #FFCC00 - Yellow-Yellow-Orange +255 153 0 #FF9900 - Orange-Orange-Yellow +255 102 0 #FF6600 - Orange-Orange-Red +255 51 0 #FF3300 - Red-Red-Orange + 0 0 0 #000000 - Black + 51 51 51 #333333 - Obscure Gray +102 102 102 #666666 - Dark Gray +153 153 153 #999999 - Light Gray +204 204 204 #CCCCCC - Pale Gray +255 255 255 #FFFFFF - White + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 204 51 #FFCC33 - Light Yellow-Orange +255 204 102 #FFCC66 - Light Orange-Yellow +255 153 102 #FF9966 - Light Orange-Red +255 102 51 #FF6633 - Light Red-Orange + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +204 153 0 #CC9900 - Dark Yellow-Orange +204 153 51 #CC9933 - Medium Orange-Yellow +204 102 51 #CC6633 - Medium Orange-Red +204 51 0 #CC3300 - Dark Red-Orange + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 51 51 0 #333300 - Obscure Weak Yellow +102 102 0 #666600 - Obscure Dull Yellow +153 153 0 #999900 - Dark Faded Yellow +204 204 0 #CCCC00 - Dark Hard Yellow +255 255 0 #FFFF00 - Yellow +153 102 0 #996600 - Dark Orange-Yellow +153 51 0 #993300 - Dark Orange-Red + 51 0 0 #330000 - Obscure Weak Red +102 0 0 #660000 - Obscure Dull Red +153 0 0 #990000 - Dark Faded Red +204 0 0 #CC0000 - Dark Hard Red +255 0 0 #FF0000 - Red + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +204 255 0 #CCFF00 - Yellow-Yellow-Spring +204 255 51 #CCFF33 - Light Yellow-Spring +153 204 0 #99CC00 - Dark Yellow-Spring +102 102 51 #666633 - Dark Weak Yellow +153 153 51 #999933 - Dark Dull Yellow +204 204 51 #CCCC33 - Medium Faded Yellow +255 255 51 #FFFF33 - Light Hard Yellow +102 51 0 #663300 - Obscure Dull Orange + 0 0 0 #000000 - Black +102 51 51 #663333 - Dark Weak Red +153 51 51 #993333 - Dark Dull Red +204 51 51 #CC3333 - Medium Faded Red +255 51 51 #FF3333 - Light Hard Red +204 0 51 #CC0033 - Dark Red-Pink +255 51 102 #FF3366 - Light Red-Pink +255 0 51 #FF0033 - Red-Red-Pink +153 255 0 #99FF00 - Spring-Spring-Yellow +204 255 102 #CCFF66 - Light Spring-Yellow +153 204 51 #99CC33 - Medium Spring-Yellow +102 153 0 #669900 - Dark Spring-Yellow +153 153 102 #999966 - Medium Weak Yellow +204 204 102 #CCCC66 - Light Dull Yellow +255 255 102 #FFFF66 - Light Faded Yellow +153 102 51 #996633 - Dark Dull Orange +204 102 0 #CC6600 - Dark Hard Orange +153 102 102 #996666 - Medium Weak Red +204 102 102 #CC6666 - Light Dull Red +255 102 102 #FF6666 - Light Faded Red +153 0 51 #990033 - Dark Pink-Red +204 51 102 #CC3366 - Medium Pink-Red +255 102 153 #FF6699 - Light Pink-Red +255 0 102 #FF0066 - Pink-Pink-Red +102 255 0 #66FF00 - Spring-Spring-Green +153 255 102 #99FF66 - Light Spring-Green +102 204 51 #66CC33 - Medium Spring-Green + 51 153 0 #339900 - Dark Spring-Green + 0 0 0 #000000 - Black +204 204 153 #CCCC99 - Light Weak Yellow +255 255 153 #FFFF99 - Pale Dull Yellow +204 153 102 #CC9966 - Light Dull Orange +255 153 51 #FF9933 - Light Hard Orange +204 153 153 #CC9999 - Light Weak Red +255 153 153 #FF9999 - Pale Dull Red + 0 0 0 #000000 - Black +153 0 102 #990066 - Dark Pink-Magenta +204 51 153 #CC3399 - Medium Pink-Magenta +255 102 204 #FF66CC - Light Pink-Magenta +255 0 153 #FF0099 - Pink-Pink-Magenta + 51 255 0 #33FF00 - Green-Green-Spring +102 255 51 #66FF33 - Light Green-Spring + 51 204 0 #33CC00 - Dark Green-Spring + 51 102 0 #336600 - Obscure Dull Spring +102 204 0 #66CC00 - Dark Hard Spring +153 255 51 #99FF33 - Light Hard Spring +255 255 204 #FFFFCC - Pale Weak Yellow +255 204 153 #FFCC99 - Pale Dull Orange + 0 0 0 #000000 - Black +255 204 204 #FFCCCC - Pale Weak Red +204 102 153 #CC6699 - Light Dull Pink +153 51 102 #993366 - Dark Dull Pink +102 0 51 #660033 - Obscure Dull Pink +204 0 153 #CC0099 - Dark Magenta-Pink +255 51 204 #FF33CC - Light Magenta-Pink +255 0 204 #FF00CC - Magenta-Magenta-Pink + 0 255 0 #00FF00 - Green + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +102 153 51 #669933 - Dark Dull Spring +153 204 102 #99CC66 - Light Dull Spring +204 255 153 #CCFF99 - Pale Dull Spring + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 153 204 #FF99CC - Pale Dull Pink +255 51 153 #FF3399 - Light Hard Pink +204 0 102 #CC0066 - Dark Hard Pink + 0 0 0 #000000 - Black +102 51 102 #663366 - Dark Weak Magenta + 51 0 51 #330033 - Obscure Weak Magenta + 0 204 0 #00CC00 - Dark Hard Green + 51 255 51 #33FF33 - Light Hard Green +102 255 102 #66FF66 - Light Faded Green + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +204 153 204 #CC99CC - Light Weak Magenta +153 102 153 #996699 - Medium Weak Magenta +153 51 153 #993399 - Dark Dull Magenta +102 0 102 #660066 - Obscure Dull Magenta + 0 153 0 #009900 - Dark Faded Green + 51 204 51 #33CC33 - Medium Faded Green +102 204 102 #66CC66 - Light Dull Green +153 255 153 #99FF99 - Pale Dull Green +204 255 204 #CCFFCC - Pale Weak Green + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 204 255 #FFCCFF - Pale Weak Magenta +255 153 255 #FF99FF - Pale Dull Magenta +204 102 204 #CC66CC - Light Dull Magenta +204 51 204 #CC33CC - Medium Faded Magenta +153 0 153 #990099 - Dark Faded Magenta + 0 102 0 #006600 - Obscure Dull Green + 51 153 51 #339933 - Dark Dull Green +102 153 102 #669966 - Medium Weak Green +153 204 153 #99CC99 - Light Weak Green + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 102 255 #FF66FF - Light Faded Magenta +255 51 255 #FF33FF - Light Hard Magenta +204 0 204 #CC00CC - Dark Hard Magenta + 0 51 0 #003300 - Obscure Weak Green + 51 102 51 #336633 - Dark Weak Green + 0 0 0 #000000 - Black + 0 204 102 #00CC66 - Dark Hard Teal + 51 255 153 #33FF99 - Light Hard Teal +153 255 204 #99FFCC - Pale Dull Teal + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +204 153 255 #CC99FF - Pale Dull Violet +153 102 204 #9966CC - Light Dull Violet +102 51 153 #663399 - Dark Dull Violet + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 0 255 #FF00FF - Magenta + 0 255 51 #00FF33 - Green-Green-Teal + 51 255 102 #33FF66 - Light Green-Teal + 0 204 51 #00CC33 - Dark Green-Teal + 0 102 51 #006633 - Obscure Dull Teal + 51 153 102 #339966 - Dark Dull Teal +102 204 153 #66CC99 - Light Dull Teal +204 255 255 #CCFFFF - Pale Weak Cyan + 0 0 0 #000000 - Black +153 204 255 #99CCFF - Pale Dull Azure +204 204 255 #CCCCFF - Pale Weak Blue +153 51 255 #9933FF - Light Hard Violet +102 0 204 #6600CC - Dark Hard Violet + 51 0 102 #330066 - Obscure Dull Violet +153 0 204 #9900CC - Dark Magenta-Violet +204 51 255 #CC33FF - Light Magenta-Violet +204 0 255 #CC00FF - Magenta-Magenta-Violet + 0 255 102 #00FF66 - Teal-Teal-Green +102 255 153 #66FF99 - Light Teal-Green + 51 204 102 #33CC66 - Medium Teal-Green + 0 153 51 #009933 - Dark Teal-Green + 0 0 0 #000000 - Black +153 255 255 #99FFFF - Pale Dull Cyan +153 204 204 #99CCCC - Light Weak Cyan + 51 153 255 #3399FF - Light Hard Azure +102 153 204 #6699CC - Light Dull Azure +153 153 255 #9999FF - Pale Dull Blue +153 153 204 #9999CC - Light Weak Blue + 0 0 0 #000000 - Black +102 0 153 #660099 - Dark Violet-Magenta +153 51 204 #9933CC - Medium Violet-Magenta +204 102 255 #CC66FF - Light Violet-Magenta +153 0 255 #9900FF - Violet-Violet-Magenta + 0 255 153 #00FF99 - Teal-Teal-Cyan +102 255 204 #66FFCC - Light Teal-Cyan + 51 204 153 #33CC99 - Medium Teal-Cyan + 0 153 102 #009966 - Dark Teal-Cyan +102 255 255 #66FFFF - Light Faded Cyan +102 204 204 #66CCCC - Light Dull Cyan +102 153 153 #669999 - Medium Weak Cyan + 0 102 204 #0066CC - Dark Hard Azure + 51 102 153 #336699 - Dark Dull Azure +102 102 255 #6666FF - Light Faded Blue +102 102 204 #6666CC - Light Dull Blue +102 102 153 #666699 - Medium Weak Blue +102 0 153 #660099 - Dark Violet-Magenta +153 51 204 #9933CC - Medium Violet-Magenta +204 102 255 #CC66FF - Light Violet-Magenta +153 0 255 #9900FF - Violet-Violet-Magenta + 0 255 204 #00FFCC - Cyan-Cyan-Teal + 51 255 204 #33FFCC - Light Cyan-Teal + 0 204 153 #00CC99 - Dark Cyan-Teal + 51 255 255 #33FFFF - Light Hard Cyan + 51 204 204 #33CCCC - Medium Faded Cyan + 51 153 153 #339999 - Dark Dull Cyan + 51 102 102 #336666 - Dark Weak Cyan + 0 0 0 #000000 - Black + 0 51 102 #003366 - Obscure Dull Azure + 51 51 255 #3333FF - Light Hard Blue + 51 51 204 #3333CC - Medium Faded Blue + 51 51 153 #333399 - Dark Dull Blue + 51 51 102 #333366 - Dark Weak Blue + 51 0 204 #3300CC - Dark Blue-Violet +102 51 255 #6633FF - Light Blue-Violet + 51 0 255 #3300FF - Blue-Blue-Violet + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 255 255 #00FFFF - Cyan + 0 204 204 #00CCCC - Dark Hard Cyan + 0 153 153 #009999 - Dark Faded Cyan + 0 102 102 #006666 - Obscure Dull Cyan + 0 51 51 #003333 - Obscure Weak Cyan + 0 102 153 #006699 - Dark Azure-Cyan + 0 51 153 #003399 - Dark Azure-Blue + 0 0 255 #0000FF - Blue + 0 0 204 #0000CC - Dark Hard Blue + 0 0 153 #000099 - Dark Faded Blue + 0 0 102 #000066 - Obscure Dull Blue + 0 0 51 #000033 - Obscure Weak Blue + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 153 204 #0099CC - Dark Cyan-Azure + 51 153 204 #3399CC - Medium Azure-Cyan + 51 102 204 #3366CC - Medium Azure-Blue + 0 51 204 #0033CC - Dark Blue-Azure + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 51 204 255 #33CCFF - Light Cyan-Azure +102 204 255 #66CCFF - Light Azure-Cyan +102 153 255 #6699FF - Light Azure-Blue + 51 102 255 #3366FF - Light Blue-Azure + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black + 0 0 0 #000000 - Black +255 255 255 #FFFFFF - White +204 204 204 #CCCCCC - Pale Gray +153 153 153 #999999 - Light Gray +102 102 102 #666666 - Dark Gray + 51 51 51 #333333 - Obscure Gray + 0 0 0 #000000 - Black + 0 204 255 #00CCFF - Cyan-Cyan-Azure + 0 153 255 #0099FF - Azure-Azure-Cyan + 0 102 255 #0066FF - Azure-Azure-Blue + 0 51 255 #0033FF - Blue-Blue-Azure + 0 0 0 #000000 - Black + 51 51 51 #333333 - Obscure Gray +102 102 102 #666666 - Dark Gray +153 153 153 #999999 - Light Gray +204 204 204 #CCCCCC - Pale Gray +255 255 255 #FFFFFF - White diff --git a/chalk/data/palettes/Visibone_2.gpl b/chalk/data/palettes/Visibone_2.gpl new file mode 100644 index 00000000..affacd18 --- /dev/null +++ b/chalk/data/palettes/Visibone_2.gpl @@ -0,0 +1,266 @@ +GIMP Palette +Name: Visibone 2 +Columns: 16 +# +# Visibone 2 -- GIMP Palette file +# +# Arrangement idea from www.visibone.com +# Conversion to GIMP Palette and addition of +# RGB and hex codes by Carey Bunks +# +255 255 255 (255 255 255) #FFFFFF +204 204 204 (204 204 204) #CCCCCC +153 153 153 (153 153 153) #999999 +102 102 102 (102 102 102) #666666 + 51 51 51 ( 51 51 51) #333333 + 0 0 0 ( 0 0 0) #000000 +255 204 0 (255 204 0) #FFCC00 +255 153 0 (255 153 0) #FF9900 +255 102 0 (255 102 0) #FF6600 +255 51 0 (255 51 0) #FF3300 + 0 0 0 ( 0 0 0) #000000 + 51 51 51 ( 51 51 51) #333333 +102 102 102 (102 102 102) #666666 +153 153 153 (153 153 153) #999999 +204 204 204 (204 204 204) #CCCCCC +255 255 255 (255 255 255) #FFFFFF +153 204 0 (153 204 0) #99CC00 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 +204 153 0 (204 153 0) #CC9900 +255 204 51 (255 204 51) #FFCC33 +255 204 102 (255 204 102) #FFCC66 +255 153 102 (255 153 102) #FF9966 +255 102 51 (255 102 51) #FF6633 +204 51 0 (204 51 0) #CC3300 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 +204 0 51 (204 0 51) #CC0033 +204 255 0 (204 255 0) #CCFF00 +204 255 51 (204 255 51) #CCFF33 + 51 51 0 ( 51 51 0) #333300 +102 102 0 (102 102 0) #666600 +153 153 0 (153 153 0) #999900 +204 204 0 (204 204 0) #CCCC00 +255 255 0 (255 255 0) #FFFF00 +204 153 51 (204 153 51) #CC9933 +204 102 51 (204 102 51) #CC6633 + 51 0 0 ( 51 0 0) #330000 +102 0 0 (102 0 0) #660000 +153 0 0 (153 0 0) #990000 +204 0 0 (204 0 0) #CC0000 +255 0 0 (255 0 0) #FF0000 +255 51 102 (255 51 102) #FF3366 +255 0 51 (255 0 51) #FF0033 +153 255 0 (153 255 0) #99FF00 +204 255 102 (204 255 102) #CCFF66 +153 204 51 (153 204 51) #99CC33 +102 102 51 (102 102 51) #666633 +153 153 51 (153 153 51) #999933 +204 204 51 (204 204 51) #CCCC33 +255 255 51 (255 255 51) #FFFF33 +153 102 0 (153 102 0) #996600 +153 51 0 (153 51 0) #993300 +102 51 51 (102 51 51) #663333 +153 51 51 (153 51 51) #993333 +204 51 51 (204 51 51) #CC3333 +255 51 51 (255 51 51) #FF3333 +204 51 102 (204 51 102) #CC3366 +255 102 153 (255 102 153) #FF6699 +255 0 102 (255 0 102) #FF0066 +102 255 0 (102 255 0) #66FF00 +153 255 102 (153 255 102) #99FF66 +102 204 51 (102 204 51) #66CC33 +102 153 0 (102 153 0) #669900 +153 153 102 (153 153 102) #999966 +204 204 102 (204 204 102) #CCCC66 +255 255 102 (255 255 102) #FFFF66 +153 102 51 (153 102 51) #996633 +102 51 0 (102 51 0) #663300 +153 102 102 (153 102 102) #996666 +204 102 102 (204 102 102) #CC6666 +255 102 102 (255 102 102) #FF6666 +153 0 51 (153 0 51) #990033 +204 51 153 (204 51 153) #CC3399 +255 102 204 (255 102 204) #FF66CC +255 0 153 (255 0 153) #FF0099 + 51 255 0 ( 51 255 0) #33FF00 +102 255 51 (102 255 51) #66FF33 + 51 153 0 ( 51 153 0) #339900 +102 204 0 (102 204 0) #66CC00 +153 255 51 (153 255 51) #99FF33 +204 204 153 (204 204 153) #CCCC99 +255 255 153 (255 255 153) #FFFF99 +204 153 102 (204 153 102) #CC9966 +204 102 0 (204 102 0) #CC6600 +204 153 153 (204 153 153) #CC9999 +255 153 153 (255 153 153) #FF9999 +255 51 153 (255 51 153) #FF3399 +204 0 102 (204 0 102) #CC0066 +153 0 102 (153 0 102) #990066 +255 51 204 (255 51 204) #FF33CC +255 0 204 (255 0 204) #FF00CC + 0 204 0 ( 0 204 0) #00CC00 + 51 204 0 ( 51 204 0) #33CC00 + 51 102 0 ( 51 102 0) #336600 +102 153 51 (102 153 51) #669933 +153 204 102 (153 204 102) #99CC66 +204 255 153 (204 255 153) #CCFF99 +255 255 204 (255 255 204) #FFFFCC +255 204 153 (255 204 153) #FFCC99 +255 153 51 (255 153 51) #FF9933 +255 204 204 (255 204 204) #FFCCCC +255 153 204 (255 153 204) #FF99CC +204 102 153 (204 102 153) #CC6699 +153 51 102 (153 51 102) #993366 +102 0 51 (102 0 51) #660033 +204 0 153 (204 0 153) #CC0099 + 51 0 51 ( 51 0 51) #330033 + 51 204 51 ( 51 204 51) #33CC33 +102 204 102 (102 204 102) #66CC66 + 0 255 0 ( 0 255 0) #00FF00 + 51 255 51 ( 51 255 51) #33FF33 +102 255 102 (102 255 102) #66FF66 +153 255 153 (153 255 153) #99FF99 +204 255 204 (204 255 204) #CCFFCC + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 +204 153 204 (204 153 204) #CC99CC +153 102 153 (153 102 153) #996699 +153 51 153 (153 51 153) #993399 +153 0 153 (153 0 153) #990099 +102 51 102 (102 51 102) #663366 +102 0 102 (102 0 102) #660066 + 0 102 0 ( 0 102 0) #006600 + 51 102 51 ( 51 102 51) #336633 + 0 153 0 ( 0 153 0) #009900 + 51 153 51 ( 51 153 51) #339933 +102 153 102 (102 153 102) #669966 +153 204 153 (153 204 153) #99CC99 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 +255 204 255 (255 204 255) #FFCCFF +255 153 255 (255 153 255) #FF99FF +255 102 255 (255 102 255) #FF66FF +255 51 255 (255 51 255) #FF33FF +255 0 255 (255 0 255) #FF00FF +204 102 204 (204 102 204) #CC66CC +204 51 204 (204 51 204) #CC33CC + 0 51 0 ( 0 51 0) #003300 + 0 204 51 ( 0 204 51) #00CC33 + 0 102 51 ( 0 102 51) #006633 + 51 153 102 ( 51 153 102) #339966 +102 204 153 (102 204 153) #66CC99 +153 255 204 (153 255 204) #99FFCC +204 255 255 (204 255 255) #CCFFFF + 51 153 255 ( 51 153 255) #3399FF +153 204 255 (153 204 255) #99CCFF +204 204 255 (204 204 255) #CCCCFF +204 153 255 (204 153 255) #CC99FF +153 102 204 (153 102 204) #9966CC +102 51 153 (102 51 153) #663399 + 51 0 102 ( 51 0 102) #330066 +153 0 204 (153 0 204) #9900CC +204 0 204 (204 0 204) #CC00CC + 0 255 51 ( 0 255 51) #00FF33 + 51 255 102 ( 51 255 102) #33FF66 + 0 153 51 ( 0 153 51) #009933 + 0 204 102 ( 0 204 102) #00CC66 + 51 255 153 ( 51 255 153) #33FF99 +153 255 255 (153 255 255) #99FFFF +153 204 204 (153 204 204) #99CCCC + 0 102 204 ( 0 102 204) #0066CC +102 153 204 (102 153 204) #6699CC +153 153 255 (153 153 255) #9999FF +153 153 204 (153 153 204) #9999CC +153 51 255 (153 51 255) #9933FF +102 0 204 (102 0 204) #6600CC +102 0 153 (102 0 153) #660099 +204 51 255 (204 51 255) #CC33FF +204 0 255 (204 0 255) #CC00FF + 0 255 102 ( 0 255 102) #00FF66 +102 255 153 (102 255 153) #66FF99 + 51 204 102 ( 51 204 102) #33CC66 + 0 153 102 ( 0 153 102) #009966 +102 255 255 (102 255 255) #66FFFF +102 204 204 (102 204 204) #66CCCC +102 153 153 (102 153 153) #669999 + 0 51 102 ( 0 51 102) #003366 + 51 102 153 ( 51 102 153) #336699 +102 102 255 (102 102 255) #6666FF +102 102 204 (102 102 204) #6666CC +102 102 153 (102 102 153) #666699 + 51 0 153 ( 51 0 153) #330099 +153 51 204 (153 51 204) #9933CC +204 102 255 (204 102 255) #CC66FF +153 0 255 (153 0 255) #9900FF + 0 255 153 ( 0 255 153) #00FF99 +102 255 204 (102 255 204) #66FFCC + 51 204 153 ( 51 204 153) #33CC99 + 51 255 255 ( 51 255 255) #33FFFF + 51 204 204 ( 51 204 204) #33CCCC + 51 153 153 ( 51 153 153) #339999 + 51 102 102 ( 51 102 102) #336666 + 0 102 153 ( 0 102 153) #006699 + 0 51 153 ( 0 51 153) #003399 + 51 51 255 ( 51 51 255) #3333FF + 51 51 204 ( 51 51 204) #3333CC + 51 51 153 ( 51 51 153) #333399 + 51 51 102 ( 51 51 102) #333366 +102 51 204 (102 51 204) #6633CC +153 102 255 (153 102 255) #9966FF +102 0 255 (102 0 255) #6600FF + 0 255 204 ( 0 255 204) #00FFCC + 51 255 204 ( 51 255 204) #33FFCC + 0 255 255 ( 0 255 255) #00FFFF + 0 204 204 ( 0 204 204) #00CCCC + 0 153 153 ( 0 153 153) #009999 + 0 102 102 ( 0 102 102) #006666 + 0 51 51 ( 0 51 51) #003333 + 51 153 204 ( 51 153 204) #3399CC + 51 102 204 ( 51 102 204) #3366CC + 0 0 255 ( 0 0 255) #0000FF + 0 0 204 ( 0 0 204) #0000CC + 0 0 153 ( 0 0 153) #000099 + 0 0 102 ( 0 0 102) #000066 + 0 0 51 ( 0 0 51) #000033 +102 51 255 (102 51 255) #6633FF + 51 0 255 ( 51 0 255) #3300FF + 0 204 153 ( 0 204 153) #00CC99 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 153 202 ( 0 153 202) #0099CA + 51 204 255 ( 51 204 255) #33CCFF +102 204 255 (102 204 255) #66CCFF +102 153 255 (102 153 255) #6699FF + 51 102 255 ( 51 102 255) #3366FF + 0 51 204 ( 0 51 204) #0033CC + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 0 0 0 ( 0 0 0) #000000 + 51 0 204 ( 51 0 204) #3300CC +255 255 255 (255 255 255) #FFFFFF +204 204 204 (204 204 204) #CCCCCC +153 153 153 (153 153 153) #999999 +102 102 102 (102 102 102) #666666 + 51 51 51 ( 51 51 51) #333333 + 0 0 0 ( 0 0 0) #000000 + 0 204 255 ( 0 204 255) #00CCFF + 0 153 255 ( 0 153 255) #0099FF + 0 102 255 ( 0 102 255) #0066FF + 0 51 255 ( 0 51 255) #0033FF + 0 0 0 ( 0 0 0) #000000 + 51 51 51 ( 51 51 51) #333333 +102 102 102 (102 102 102) #666666 +153 153 153 (153 153 153) #999999 +204 204 204 (204 204 204) #CCCCCC +255 255 255 (255 255 255) #FFFFFF diff --git a/chalk/data/palettes/Volcano.gpl b/chalk/data/palettes/Volcano.gpl new file mode 100644 index 00000000..f9031e3d --- /dev/null +++ b/chalk/data/palettes/Volcano.gpl @@ -0,0 +1,259 @@ +GIMP Palette +Name: Volcano +# + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 8 Untitled + 0 0 16 Untitled + 0 0 24 Untitled + 0 0 32 Untitled + 0 0 40 Untitled + 0 0 48 Untitled + 0 0 56 Untitled + 0 0 64 Untitled + 0 0 72 Untitled + 0 0 84 Untitled + 0 0 92 Untitled + 0 0 100 Untitled + 0 0 108 Untitled + 0 0 116 Untitled + 0 0 124 Untitled + 0 0 132 Untitled + 0 0 140 Untitled + 0 0 148 Untitled + 0 0 156 Untitled + 0 0 168 Untitled + 0 0 176 Untitled + 0 0 184 Untitled + 0 0 192 Untitled + 0 0 200 Untitled + 0 0 208 Untitled + 0 0 216 Untitled + 0 0 224 Untitled + 0 0 232 Untitled + 0 0 240 Untitled + 0 0 252 Untitled + 8 0 252 Untitled + 16 0 252 Untitled + 24 0 252 Untitled + 32 0 252 Untitled + 40 0 252 Untitled + 48 0 252 Untitled + 56 0 252 Untitled + 64 0 252 Untitled + 72 0 252 Untitled + 84 0 252 Untitled + 92 0 252 Untitled +100 0 252 Untitled +108 0 252 Untitled +116 0 252 Untitled +124 0 252 Untitled +132 0 252 Untitled +140 0 252 Untitled +148 0 252 Untitled +156 0 252 Untitled +168 0 252 Untitled +176 0 252 Untitled +184 0 252 Untitled +192 0 252 Untitled +200 0 252 Untitled +208 0 252 Untitled +216 0 252 Untitled +224 0 252 Untitled +232 0 252 Untitled +240 0 252 Untitled +252 0 252 Untitled +252 0 244 Untitled +252 0 236 Untitled +252 0 228 Untitled +252 0 220 Untitled +252 0 212 Untitled +252 0 200 Untitled +252 0 192 Untitled +252 0 184 Untitled +252 0 176 Untitled +252 0 168 Untitled +252 0 160 Untitled +252 0 148 Untitled +252 0 140 Untitled +252 0 132 Untitled +252 0 124 Untitled +252 0 116 Untitled +252 0 108 Untitled +252 0 96 Untitled +252 0 88 Untitled +252 0 80 Untitled +252 0 72 Untitled +252 0 64 Untitled +252 0 56 Untitled +252 0 44 Untitled +252 0 36 Untitled +252 0 28 Untitled +252 0 20 Untitled +252 0 12 Untitled +252 0 0 Untitled +252 8 0 Untitled +252 16 0 Untitled +252 24 0 Untitled +252 32 0 Untitled +252 40 0 Untitled +252 48 0 Untitled +252 56 0 Untitled +252 64 0 Untitled +252 72 0 Untitled +252 80 0 Untitled +252 88 0 Untitled +252 96 0 Untitled +252 104 0 Untitled +252 112 0 Untitled +252 120 0 Untitled +252 128 0 Untitled +252 128 0 Untitled +252 132 0 Untitled +252 136 0 Untitled +252 140 0 Untitled +252 144 0 Untitled +252 148 0 Untitled +252 152 0 Untitled +252 156 0 Untitled +252 160 0 Untitled +252 164 0 Untitled +252 168 0 Untitled +252 172 0 Untitled +252 176 0 Untitled +252 180 0 Untitled +252 184 0 Untitled +252 188 0 Untitled +252 192 0 Untitled +252 196 0 Untitled +252 200 0 Untitled +252 204 0 Untitled +252 208 0 Untitled +252 212 0 Untitled +252 216 0 Untitled +252 220 0 Untitled +252 224 0 Untitled +252 228 0 Untitled +252 232 0 Untitled +252 236 0 Untitled +252 240 0 Untitled +252 244 0 Untitled +252 248 0 Untitled +252 252 0 Untitled +248 252 0 Untitled +240 252 0 Untitled +232 252 0 Untitled +224 252 0 Untitled +216 252 0 Untitled +208 252 0 Untitled +200 252 0 Untitled +192 252 0 Untitled +184 252 0 Untitled +176 252 0 Untitled +168 252 0 Untitled +160 252 0 Untitled +152 252 0 Untitled +144 252 0 Untitled +136 252 0 Untitled +128 252 0 Untitled +124 252 0 LawnGreen +116 252 0 Untitled +108 252 0 Untitled +100 252 0 Untitled + 92 252 0 Untitled + 84 252 0 Untitled + 76 252 0 Untitled + 68 252 0 Untitled + 60 252 0 Untitled + 52 252 0 Untitled + 44 252 0 Untitled + 36 252 0 Untitled + 28 252 0 Untitled + 20 252 0 Untitled + 12 252 0 Untitled + 4 252 0 Untitled + 12 252 0 Untitled + 20 252 0 Untitled + 28 252 0 Untitled + 36 252 0 Untitled + 44 252 0 Untitled + 52 252 0 Untitled + 60 252 0 Untitled + 68 252 0 Untitled + 76 252 0 Untitled + 84 252 0 Untitled + 92 252 0 Untitled +100 252 0 Untitled +108 252 0 Untitled +116 252 0 Untitled +124 252 0 LawnGreen +128 252 0 Untitled +132 252 0 Untitled +136 252 0 Untitled +140 252 0 Untitled +144 252 0 Untitled +148 252 0 Untitled +152 252 0 Untitled +156 252 0 Untitled +160 252 0 Untitled +164 252 0 Untitled +168 252 0 Untitled +172 252 0 Untitled +176 252 0 Untitled +180 252 0 Untitled +184 252 0 Untitled +188 252 0 Untitled +192 252 0 Untitled +196 252 0 Untitled +200 252 0 Untitled +204 252 0 Untitled +208 252 0 Untitled +212 252 0 Untitled +216 252 0 Untitled +220 252 0 Untitled +224 252 0 Untitled +228 252 0 Untitled +232 252 0 Untitled +236 252 0 Untitled +240 252 0 Untitled +244 252 0 Untitled +248 252 0 Untitled +252 252 0 Untitled +252 232 0 Untitled +252 208 0 Untitled +252 184 0 Untitled +252 164 0 Untitled +252 140 0 Untitled +252 116 0 Untitled +252 92 0 Untitled +252 72 0 Untitled +252 48 0 Untitled +252 24 0 Untitled +252 0 0 Untitled +252 8 0 Untitled +252 20 0 Untitled +252 32 0 Untitled +252 44 0 Untitled +252 56 0 Untitled +252 68 0 Untitled +252 80 0 Untitled +252 88 0 Untitled +252 100 0 Untitled +252 112 0 Untitled +252 124 0 Untitled +252 136 0 Untitled +252 148 0 Untitled +252 160 0 Untitled +252 168 0 Untitled +252 180 0 Untitled +252 192 0 Untitled +252 204 0 Untitled +252 216 0 Untitled +252 228 0 Untitled +252 240 0 Untitled +252 252 0 Untitled + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 + 0 0 0 grey0 diff --git a/chalk/data/palettes/Warm_Colors.gpl b/chalk/data/palettes/Warm_Colors.gpl new file mode 100644 index 00000000..654ad5da --- /dev/null +++ b/chalk/data/palettes/Warm_Colors.gpl @@ -0,0 +1,10 @@ +GIMP Palette +Name: Warm Colors +# +196 9 9 Untitled +216 213 8 Untitled +237 110 0 Untitled +232 0 50 Untitled +140 11 11 Untitled +228 170 4 Untitled +117 0 0 Untitled diff --git a/chalk/data/palettes/Web.gpl b/chalk/data/palettes/Web.gpl new file mode 100644 index 00000000..0b907f79 --- /dev/null +++ b/chalk/data/palettes/Web.gpl @@ -0,0 +1,220 @@ +GIMP Palette +Name: Web +Columns: 6 +# +255 255 255 Untitled +255 255 204 Untitled +255 255 153 Untitled +255 255 102 Untitled +255 255 51 Untitled +255 255 0 Untitled +255 204 255 Untitled +255 204 204 Untitled +255 204 153 Untitled +255 204 102 Untitled +255 204 51 Untitled +255 204 0 Untitled +255 153 255 Untitled +255 153 204 Untitled +255 153 153 Untitled +255 153 102 Untitled +255 153 51 Untitled +255 153 0 Untitled +255 102 255 Untitled +255 102 204 Untitled +255 102 153 Untitled +255 102 102 Untitled +255 102 51 Untitled +255 102 0 Untitled +255 51 255 Untitled +255 51 204 Untitled +255 51 153 Untitled +255 51 102 Untitled +255 51 51 Untitled +255 51 0 Untitled +255 0 255 Untitled +255 0 204 Untitled +255 0 153 Untitled +255 0 102 Untitled +255 0 51 Untitled +255 0 0 Untitled +204 255 255 Untitled +204 255 204 Untitled +204 255 153 Untitled +204 255 102 Untitled +204 255 51 Untitled +204 255 0 Untitled +204 204 255 Untitled +204 204 204 Untitled +204 204 153 Untitled +204 204 102 Untitled +204 204 51 Untitled +204 204 0 Untitled +204 153 255 Untitled +204 153 204 Untitled +204 153 153 Untitled +204 153 102 Untitled +204 153 51 Untitled +204 153 0 Untitled +204 102 255 Untitled +204 102 204 Untitled +204 102 153 Untitled +204 102 102 Untitled +204 102 51 Untitled +204 102 0 Untitled +204 51 255 Untitled +204 51 204 Untitled +204 51 153 Untitled +204 51 102 Untitled +204 51 51 Untitled +204 51 0 Untitled +204 0 255 Untitled +204 0 204 Untitled +204 0 153 Untitled +204 0 102 Untitled +204 0 51 Untitled +204 0 0 Untitled +153 255 255 Untitled +153 255 204 Untitled +153 255 153 Untitled +153 255 102 Untitled +153 255 51 Untitled +153 255 0 Untitled +153 204 255 Untitled +153 204 204 Untitled +153 204 153 Untitled +153 204 102 Untitled +153 204 51 Untitled +153 204 0 Untitled +153 153 255 Untitled +153 153 204 Untitled +153 153 153 Untitled +153 153 102 Untitled +153 153 51 Untitled +153 153 0 Untitled +153 102 255 Untitled +153 102 204 Untitled +153 102 153 Untitled +153 102 102 Untitled +153 102 51 Untitled +153 102 0 Untitled +153 51 255 Untitled +153 51 204 Untitled +153 51 153 Untitled +153 51 102 Untitled +153 51 51 Untitled +153 51 0 Untitled +153 0 255 Untitled +153 0 204 Untitled +153 0 153 Untitled +153 0 102 Untitled +153 0 51 Untitled +153 0 0 Untitled +102 255 255 Untitled +102 255 204 Untitled +102 255 153 Untitled +102 255 102 Untitled +102 255 51 Untitled +102 255 0 Untitled +102 204 255 Untitled +102 204 204 Untitled +102 204 153 Untitled +102 204 102 Untitled +102 204 51 Untitled +102 204 0 Untitled +102 153 255 Untitled +102 153 204 Untitled +102 153 153 Untitled +102 153 102 Untitled +102 153 51 Untitled +102 153 0 Untitled +102 102 255 Untitled +102 102 204 Untitled +102 102 153 Untitled +102 102 102 Untitled +102 102 51 Untitled +102 102 0 Untitled +102 51 255 Untitled +102 51 204 Untitled +102 51 153 Untitled +102 51 102 Untitled +102 51 51 Untitled +102 51 0 Untitled +102 0 255 Untitled +102 0 204 Untitled +102 0 153 Untitled +102 0 102 Untitled +102 0 51 Untitled +102 0 0 Untitled + 51 255 255 Untitled + 51 255 204 Untitled + 51 255 153 Untitled + 51 255 102 Untitled + 51 255 51 Untitled + 51 255 0 Untitled + 51 204 255 Untitled + 51 204 204 Untitled + 51 204 153 Untitled + 51 204 102 Untitled + 51 204 51 Untitled + 51 204 0 Untitled + 51 153 255 Untitled + 51 153 204 Untitled + 51 153 153 Untitled + 51 153 102 Untitled + 51 153 51 Untitled + 51 153 0 Untitled + 51 102 255 Untitled + 51 102 204 Untitled + 51 102 153 Untitled + 51 102 102 Untitled + 51 102 51 Untitled + 51 102 0 Untitled + 51 51 255 Untitled + 51 51 204 Untitled + 51 51 153 Untitled + 51 51 102 Untitled + 51 51 51 Untitled + 51 51 0 Untitled + 51 0 255 Untitled + 51 0 204 Untitled + 51 0 153 Untitled + 51 0 102 Untitled + 51 0 51 Untitled + 51 0 0 Untitled + 0 255 255 Untitled + 0 255 204 Untitled + 0 255 153 Untitled + 0 255 102 Untitled + 0 255 51 Untitled + 0 255 0 Untitled + 0 204 255 Untitled + 0 204 204 Untitled + 0 204 153 Untitled + 0 204 102 Untitled + 0 204 51 Untitled + 0 204 0 Untitled + 0 153 255 Untitled + 0 153 204 Untitled + 0 153 153 Untitled + 0 153 102 Untitled + 0 153 51 Untitled + 0 153 0 Untitled + 0 102 255 Untitled + 0 102 204 Untitled + 0 102 153 Untitled + 0 102 102 Untitled + 0 102 51 Untitled + 0 102 0 Untitled + 0 51 255 Untitled + 0 51 204 Untitled + 0 51 153 Untitled + 0 51 102 Untitled + 0 51 51 Untitled + 0 51 0 Untitled + 0 0 255 Untitled + 0 0 204 Untitled + 0 0 153 Untitled + 0 0 102 Untitled + 0 0 51 Untitled + 0 0 0 Untitled diff --git a/chalk/data/palettes/new_kde.gpl b/chalk/data/palettes/new_kde.gpl new file mode 100644 index 00000000..33647606 --- /dev/null +++ b/chalk/data/palettes/new_kde.gpl @@ -0,0 +1,48 @@ +GIMP Palette +Name: KDE (new) +Columns: 4 +# +82 34 0 +159 95 0 +217 174 126 +243 223 198 +181 0 47 +231 35 0 +240 164 185 +246 207 221 +249 186 7 +255 220 0 +255 233 68 +255 245 146 +83 147 22 +99 176 31 +127 187 86 +180 213 151 +0 102 47 +0 151 84 +128 195 155 +171 215 188 +0 65 136 +0 113 188 +0 148 213 +179 221 245 +27 45 131 +74 108 179 +95 143 203 +197 217 240 +85 18 123 +121 103 171 +164 158 205 +191 184 216 +123 12 130 +155 87 159 +186 144 192 +209 176 210 +0 0 28 +11 17 45 +68 78 90 +109 113 121 +157 161 166 +187 191 195 +218 221 224 +235 236 237 \ No newline at end of file diff --git a/chalk/data/patterns/3dgreen.pat b/chalk/data/patterns/3dgreen.pat new file mode 100644 index 00000000..763f912b Binary files /dev/null and b/chalk/data/patterns/3dgreen.pat differ diff --git a/chalk/data/patterns/Craters.pat b/chalk/data/patterns/Craters.pat new file mode 100644 index 00000000..4590349d Binary files /dev/null and b/chalk/data/patterns/Craters.pat differ diff --git a/chalk/data/patterns/Makefile.am b/chalk/data/patterns/Makefile.am new file mode 100644 index 00000000..1225aee8 --- /dev/null +++ b/chalk/data/patterns/Makefile.am @@ -0,0 +1,5 @@ + +chalkpatternsdir = $(prefix)/share/apps/chalk/patterns + +chalkpatterns_DATA = 3dgreen.pat Craters.pat Moonfoot.pat Stripes1px.pat Stripes2px.pat amethyst.pat bark.pat blue.pat bluegrid.pat bluesquares.pat blueweb.pat brick.pat burlap.pat burlwood.pat choc_swirl.pat corkboard.pat cracked.pat crinklepaper.pat electric.pat fibers.pat granite1.pat ground1.pat ice.pat java.pat leather.pat leaves.pat leopard.pat lightning.pat marble1.pat marble2.pat marble3.pat nops.pat paper.pat parque1.pat parque2.pat parque3.pat pastel.pat pine.pat pink_marble.pat pool.pat qube1.pat rain.pat recessed.pat redcube.pat rock.pat sky.pat slate.pat sm_squares.pat starfield.pat stone33.pat terra.pat walnut.pat warning.pat wood1.pat wood2.pat wood3.pat wood4.pat wood5.pat + diff --git a/chalk/data/patterns/Moonfoot.pat b/chalk/data/patterns/Moonfoot.pat new file mode 100644 index 00000000..4c9236c6 Binary files /dev/null and b/chalk/data/patterns/Moonfoot.pat differ diff --git a/chalk/data/patterns/Stripes1px.pat b/chalk/data/patterns/Stripes1px.pat new file mode 100644 index 00000000..ddfd0c70 Binary files /dev/null and b/chalk/data/patterns/Stripes1px.pat differ diff --git a/chalk/data/patterns/Stripes2px.pat b/chalk/data/patterns/Stripes2px.pat new file mode 100644 index 00000000..411e1b34 Binary files /dev/null and b/chalk/data/patterns/Stripes2px.pat differ diff --git a/chalk/data/patterns/amethyst.pat b/chalk/data/patterns/amethyst.pat new file mode 100644 index 00000000..f83eb861 Binary files /dev/null and b/chalk/data/patterns/amethyst.pat differ diff --git a/chalk/data/patterns/bark.pat b/chalk/data/patterns/bark.pat new file mode 100644 index 00000000..ba137b12 Binary files /dev/null and b/chalk/data/patterns/bark.pat differ diff --git a/chalk/data/patterns/blue.pat b/chalk/data/patterns/blue.pat new file mode 100644 index 00000000..f1320954 Binary files /dev/null and b/chalk/data/patterns/blue.pat differ diff --git a/chalk/data/patterns/bluegrid.pat b/chalk/data/patterns/bluegrid.pat new file mode 100644 index 00000000..33bf092c Binary files /dev/null and b/chalk/data/patterns/bluegrid.pat differ diff --git a/chalk/data/patterns/bluesquares.pat b/chalk/data/patterns/bluesquares.pat new file mode 100644 index 00000000..2bce749f Binary files /dev/null and b/chalk/data/patterns/bluesquares.pat differ diff --git a/chalk/data/patterns/blueweb.pat b/chalk/data/patterns/blueweb.pat new file mode 100644 index 00000000..fce2c1f6 Binary files /dev/null and b/chalk/data/patterns/blueweb.pat differ diff --git a/chalk/data/patterns/brick.pat b/chalk/data/patterns/brick.pat new file mode 100644 index 00000000..9e018230 Binary files /dev/null and b/chalk/data/patterns/brick.pat differ diff --git a/chalk/data/patterns/burlap.pat b/chalk/data/patterns/burlap.pat new file mode 100644 index 00000000..f2fc3c4e Binary files /dev/null and b/chalk/data/patterns/burlap.pat differ diff --git a/chalk/data/patterns/burlwood.pat b/chalk/data/patterns/burlwood.pat new file mode 100644 index 00000000..2d89ba14 Binary files /dev/null and b/chalk/data/patterns/burlwood.pat differ diff --git a/chalk/data/patterns/choc_swirl.pat b/chalk/data/patterns/choc_swirl.pat new file mode 100644 index 00000000..b6551129 Binary files /dev/null and b/chalk/data/patterns/choc_swirl.pat differ diff --git a/chalk/data/patterns/corkboard.pat b/chalk/data/patterns/corkboard.pat new file mode 100644 index 00000000..ffb912e5 Binary files /dev/null and b/chalk/data/patterns/corkboard.pat differ diff --git a/chalk/data/patterns/cracked.pat b/chalk/data/patterns/cracked.pat new file mode 100644 index 00000000..a13cc556 Binary files /dev/null and b/chalk/data/patterns/cracked.pat differ diff --git a/chalk/data/patterns/crinklepaper.pat b/chalk/data/patterns/crinklepaper.pat new file mode 100644 index 00000000..2efa9f76 Binary files /dev/null and b/chalk/data/patterns/crinklepaper.pat differ diff --git a/chalk/data/patterns/electric.pat b/chalk/data/patterns/electric.pat new file mode 100644 index 00000000..34263300 Binary files /dev/null and b/chalk/data/patterns/electric.pat differ diff --git a/chalk/data/patterns/fibers.pat b/chalk/data/patterns/fibers.pat new file mode 100644 index 00000000..66d74337 Binary files /dev/null and b/chalk/data/patterns/fibers.pat differ diff --git a/chalk/data/patterns/granite1.pat b/chalk/data/patterns/granite1.pat new file mode 100644 index 00000000..e798a389 Binary files /dev/null and b/chalk/data/patterns/granite1.pat differ diff --git a/chalk/data/patterns/ground1.pat b/chalk/data/patterns/ground1.pat new file mode 100644 index 00000000..88874598 Binary files /dev/null and b/chalk/data/patterns/ground1.pat differ diff --git a/chalk/data/patterns/ice.pat b/chalk/data/patterns/ice.pat new file mode 100644 index 00000000..ffb8439f Binary files /dev/null and b/chalk/data/patterns/ice.pat differ diff --git a/chalk/data/patterns/java.pat b/chalk/data/patterns/java.pat new file mode 100644 index 00000000..60f8d2ca Binary files /dev/null and b/chalk/data/patterns/java.pat differ diff --git a/chalk/data/patterns/leather.pat b/chalk/data/patterns/leather.pat new file mode 100644 index 00000000..133c9c15 Binary files /dev/null and b/chalk/data/patterns/leather.pat differ diff --git a/chalk/data/patterns/leaves.pat b/chalk/data/patterns/leaves.pat new file mode 100644 index 00000000..6ebdeba0 Binary files /dev/null and b/chalk/data/patterns/leaves.pat differ diff --git a/chalk/data/patterns/leopard.pat b/chalk/data/patterns/leopard.pat new file mode 100644 index 00000000..62f780b6 Binary files /dev/null and b/chalk/data/patterns/leopard.pat differ diff --git a/chalk/data/patterns/lightning.pat b/chalk/data/patterns/lightning.pat new file mode 100644 index 00000000..1e022676 Binary files /dev/null and b/chalk/data/patterns/lightning.pat differ diff --git a/chalk/data/patterns/marble1.pat b/chalk/data/patterns/marble1.pat new file mode 100644 index 00000000..7be031b1 Binary files /dev/null and b/chalk/data/patterns/marble1.pat differ diff --git a/chalk/data/patterns/marble2.pat b/chalk/data/patterns/marble2.pat new file mode 100644 index 00000000..447c32df Binary files /dev/null and b/chalk/data/patterns/marble2.pat differ diff --git a/chalk/data/patterns/marble3.pat b/chalk/data/patterns/marble3.pat new file mode 100644 index 00000000..c3b57e97 Binary files /dev/null and b/chalk/data/patterns/marble3.pat differ diff --git a/chalk/data/patterns/nops.pat b/chalk/data/patterns/nops.pat new file mode 100644 index 00000000..52d49fba Binary files /dev/null and b/chalk/data/patterns/nops.pat differ diff --git a/chalk/data/patterns/paper.pat b/chalk/data/patterns/paper.pat new file mode 100644 index 00000000..26fa0263 Binary files /dev/null and b/chalk/data/patterns/paper.pat differ diff --git a/chalk/data/patterns/parque1.pat b/chalk/data/patterns/parque1.pat new file mode 100644 index 00000000..d647761b Binary files /dev/null and b/chalk/data/patterns/parque1.pat differ diff --git a/chalk/data/patterns/parque2.pat b/chalk/data/patterns/parque2.pat new file mode 100644 index 00000000..0d493c6a Binary files /dev/null and b/chalk/data/patterns/parque2.pat differ diff --git a/chalk/data/patterns/parque3.pat b/chalk/data/patterns/parque3.pat new file mode 100644 index 00000000..aa43ec0d Binary files /dev/null and b/chalk/data/patterns/parque3.pat differ diff --git a/chalk/data/patterns/pastel.pat b/chalk/data/patterns/pastel.pat new file mode 100644 index 00000000..09b3efb1 Binary files /dev/null and b/chalk/data/patterns/pastel.pat differ diff --git a/chalk/data/patterns/pine.pat b/chalk/data/patterns/pine.pat new file mode 100644 index 00000000..284d7b4e Binary files /dev/null and b/chalk/data/patterns/pine.pat differ diff --git a/chalk/data/patterns/pink_marble.pat b/chalk/data/patterns/pink_marble.pat new file mode 100644 index 00000000..03b4060c Binary files /dev/null and b/chalk/data/patterns/pink_marble.pat differ diff --git a/chalk/data/patterns/pool.pat b/chalk/data/patterns/pool.pat new file mode 100644 index 00000000..748f9fa1 Binary files /dev/null and b/chalk/data/patterns/pool.pat differ diff --git a/chalk/data/patterns/qube1.pat b/chalk/data/patterns/qube1.pat new file mode 100644 index 00000000..de49fb2a Binary files /dev/null and b/chalk/data/patterns/qube1.pat differ diff --git a/chalk/data/patterns/rain.pat b/chalk/data/patterns/rain.pat new file mode 100644 index 00000000..d00aadb2 Binary files /dev/null and b/chalk/data/patterns/rain.pat differ diff --git a/chalk/data/patterns/recessed.pat b/chalk/data/patterns/recessed.pat new file mode 100644 index 00000000..04d86f37 Binary files /dev/null and b/chalk/data/patterns/recessed.pat differ diff --git a/chalk/data/patterns/redcube.pat b/chalk/data/patterns/redcube.pat new file mode 100644 index 00000000..7411b558 Binary files /dev/null and b/chalk/data/patterns/redcube.pat differ diff --git a/chalk/data/patterns/rock.pat b/chalk/data/patterns/rock.pat new file mode 100644 index 00000000..8c545fd2 Binary files /dev/null and b/chalk/data/patterns/rock.pat differ diff --git a/chalk/data/patterns/sky.pat b/chalk/data/patterns/sky.pat new file mode 100644 index 00000000..0add1646 Binary files /dev/null and b/chalk/data/patterns/sky.pat differ diff --git a/chalk/data/patterns/slate.pat b/chalk/data/patterns/slate.pat new file mode 100644 index 00000000..152da130 Binary files /dev/null and b/chalk/data/patterns/slate.pat differ diff --git a/chalk/data/patterns/sm_squares.pat b/chalk/data/patterns/sm_squares.pat new file mode 100644 index 00000000..93ddc976 Binary files /dev/null and b/chalk/data/patterns/sm_squares.pat differ diff --git a/chalk/data/patterns/starfield.pat b/chalk/data/patterns/starfield.pat new file mode 100644 index 00000000..f53ba402 Binary files /dev/null and b/chalk/data/patterns/starfield.pat differ diff --git a/chalk/data/patterns/stone33.pat b/chalk/data/patterns/stone33.pat new file mode 100644 index 00000000..08646912 Binary files /dev/null and b/chalk/data/patterns/stone33.pat differ diff --git a/chalk/data/patterns/terra.pat b/chalk/data/patterns/terra.pat new file mode 100644 index 00000000..79bc2ec4 Binary files /dev/null and b/chalk/data/patterns/terra.pat differ diff --git a/chalk/data/patterns/walnut.pat b/chalk/data/patterns/walnut.pat new file mode 100644 index 00000000..7007dd81 Binary files /dev/null and b/chalk/data/patterns/walnut.pat differ diff --git a/chalk/data/patterns/warning.pat b/chalk/data/patterns/warning.pat new file mode 100644 index 00000000..a62d98ad Binary files /dev/null and b/chalk/data/patterns/warning.pat differ diff --git a/chalk/data/patterns/wood1.pat b/chalk/data/patterns/wood1.pat new file mode 100644 index 00000000..07fa24ca Binary files /dev/null and b/chalk/data/patterns/wood1.pat differ diff --git a/chalk/data/patterns/wood2.pat b/chalk/data/patterns/wood2.pat new file mode 100644 index 00000000..7da760e6 Binary files /dev/null and b/chalk/data/patterns/wood2.pat differ diff --git a/chalk/data/patterns/wood3.pat b/chalk/data/patterns/wood3.pat new file mode 100644 index 00000000..0712c2de Binary files /dev/null and b/chalk/data/patterns/wood3.pat differ diff --git a/chalk/data/patterns/wood4.pat b/chalk/data/patterns/wood4.pat new file mode 100644 index 00000000..1fc27822 Binary files /dev/null and b/chalk/data/patterns/wood4.pat differ diff --git a/chalk/data/patterns/wood5.pat b/chalk/data/patterns/wood5.pat new file mode 100644 index 00000000..5f415ce6 Binary files /dev/null and b/chalk/data/patterns/wood5.pat differ diff --git a/chalk/data/profiles/Adobe.icm b/chalk/data/profiles/Adobe.icm new file mode 100644 index 00000000..ae368c6d Binary files /dev/null and b/chalk/data/profiles/Adobe.icm differ diff --git a/chalk/data/profiles/Apple.icm b/chalk/data/profiles/Apple.icm new file mode 100644 index 00000000..6113a226 Binary files /dev/null and b/chalk/data/profiles/Apple.icm differ diff --git a/chalk/data/profiles/CIE.icm b/chalk/data/profiles/CIE.icm new file mode 100644 index 00000000..bd5e20a8 Binary files /dev/null and b/chalk/data/profiles/CIE.icm differ diff --git a/chalk/data/profiles/CMY.icm b/chalk/data/profiles/CMY.icm new file mode 100644 index 00000000..acc71ddd Binary files /dev/null and b/chalk/data/profiles/CMY.icm differ diff --git a/chalk/data/profiles/ColorMatch.icm b/chalk/data/profiles/ColorMatch.icm new file mode 100644 index 00000000..d1c1a1f8 Binary files /dev/null and b/chalk/data/profiles/ColorMatch.icm differ diff --git a/chalk/data/profiles/Makefile.am b/chalk/data/profiles/Makefile.am new file mode 100644 index 00000000..22269dc5 --- /dev/null +++ b/chalk/data/profiles/Makefile.am @@ -0,0 +1,4 @@ + +chalkprofilesdir = $(prefix)/share/apps/chalk/profiles + +chalkprofiles_DATA = Adobe.icm Apple.icm CIE.icm CMY.icm cmyk.icm ColorMatch.icm fogra27l.icm lcmslabi.icm lcmsxyzi.icm monoscnr.icm NTSC.icm PAL.icm SMPTE-C.icm srgb_color_space_profile.icm sRGB.icm srgbspac.icm tifflab8spac.icm WideGamut.icm ycc601.icm ycc709.icm diff --git a/chalk/data/profiles/NTSC.icm b/chalk/data/profiles/NTSC.icm new file mode 100644 index 00000000..abe4dcfb Binary files /dev/null and b/chalk/data/profiles/NTSC.icm differ diff --git a/chalk/data/profiles/PAL.icm b/chalk/data/profiles/PAL.icm new file mode 100644 index 00000000..173a0d2b Binary files /dev/null and b/chalk/data/profiles/PAL.icm differ diff --git a/chalk/data/profiles/README b/chalk/data/profiles/README new file mode 100644 index 00000000..f0a75798 --- /dev/null +++ b/chalk/data/profiles/README @@ -0,0 +1,5 @@ +The icm profile files have been downloaded from the littlecms +(http://www.littlecms.com) and from the Scarse website +(http://www.scarse.org). The Scarse profiles have been available under +the GPL; the littlecms profiles appear to be public domain. +The cmyk.icm profile is taken from the GPL version jpedal. diff --git a/chalk/data/profiles/SMPTE-C.icm b/chalk/data/profiles/SMPTE-C.icm new file mode 100644 index 00000000..7f4ef578 Binary files /dev/null and b/chalk/data/profiles/SMPTE-C.icm differ diff --git a/chalk/data/profiles/WideGamut.icm b/chalk/data/profiles/WideGamut.icm new file mode 100644 index 00000000..120a99a1 Binary files /dev/null and b/chalk/data/profiles/WideGamut.icm differ diff --git a/chalk/data/profiles/cmyk.icm b/chalk/data/profiles/cmyk.icm new file mode 100644 index 00000000..65bc4e85 Binary files /dev/null and b/chalk/data/profiles/cmyk.icm differ diff --git a/chalk/data/profiles/fogra27l.icm b/chalk/data/profiles/fogra27l.icm new file mode 100644 index 00000000..1cf03c3a Binary files /dev/null and b/chalk/data/profiles/fogra27l.icm differ diff --git a/chalk/data/profiles/lcmslabi.icm b/chalk/data/profiles/lcmslabi.icm new file mode 100644 index 00000000..f86821b5 Binary files /dev/null and b/chalk/data/profiles/lcmslabi.icm differ diff --git a/chalk/data/profiles/lcmsxyzi.icm b/chalk/data/profiles/lcmsxyzi.icm new file mode 100644 index 00000000..099006aa Binary files /dev/null and b/chalk/data/profiles/lcmsxyzi.icm differ diff --git a/chalk/data/profiles/monoscnr.icm b/chalk/data/profiles/monoscnr.icm new file mode 100644 index 00000000..411a9728 Binary files /dev/null and b/chalk/data/profiles/monoscnr.icm differ diff --git a/chalk/data/profiles/sRGB.icm b/chalk/data/profiles/sRGB.icm new file mode 100644 index 00000000..878fdf12 Binary files /dev/null and b/chalk/data/profiles/sRGB.icm differ diff --git a/chalk/data/profiles/srgb_color_space_profile.icm b/chalk/data/profiles/srgb_color_space_profile.icm new file mode 100644 index 00000000..7f9d18d0 Binary files /dev/null and b/chalk/data/profiles/srgb_color_space_profile.icm differ diff --git a/chalk/data/profiles/srgbspac.icm b/chalk/data/profiles/srgbspac.icm new file mode 100644 index 00000000..83563ef9 Binary files /dev/null and b/chalk/data/profiles/srgbspac.icm differ diff --git a/chalk/data/profiles/tifflab8spac.icm b/chalk/data/profiles/tifflab8spac.icm new file mode 100644 index 00000000..0b6543cc Binary files /dev/null and b/chalk/data/profiles/tifflab8spac.icm differ diff --git a/chalk/data/profiles/ycc601.icm b/chalk/data/profiles/ycc601.icm new file mode 100644 index 00000000..7ee086db Binary files /dev/null and b/chalk/data/profiles/ycc601.icm differ diff --git a/chalk/data/profiles/ycc709.icm b/chalk/data/profiles/ycc709.icm new file mode 100644 index 00000000..d9f5a5a5 Binary files /dev/null and b/chalk/data/profiles/ycc709.icm differ diff --git a/chalk/data/templates/.directory b/chalk/data/templates/.directory new file mode 100644 index 00000000..66f4bc3c --- /dev/null +++ b/chalk/data/templates/.directory @@ -0,0 +1,56 @@ +[Desktop Entry] +Name=Empty +Name[bg]=Празен документ +Name[br]=Goullonderiñ +Name[ca]=Buit +Name[cs]=Prázdné +Name[cy]=Gwag +Name[da]=Tom +Name[de]=Leer +Name[el]=Κενό +Name[eo]=Malplena +Name[es]=Vacío +Name[et]=Tühi +Name[eu]=Hutsa +Name[fa]=خالی +Name[fi]=Tyhjä +Name[fr]=Neutre +Name[fy]=Leech +Name[ga]=Folamh +Name[gl]=Valeira +Name[he]=ריק +Name[hi]=खाली +Name[hr]=Prazno +Name[hu]=Üres +Name[is]=Tómt +Name[it]=Vuoto +Name[ja]=空 +Name[km]=ទទេ +Name[lt]=Tuščias +Name[lv]=Tukšs +Name[ms]=Kosong +Name[nb]=Tom +Name[nds]=Leddig +Name[ne]=खाली +Name[nl]=Leeg +Name[nn]=Tomt +Name[pl]=Pusta +Name[pt]=Vazio +Name[pt_BR]=Vazio +Name[ru]=Чистый лист +Name[se]=Guorus +Name[sk]=Prázdna +Name[sl]=Prazno +Name[sr]=Празно +Name[sr@Latn]=Prazno +Name[sv]=Tom +Name[ta]= வெற்று +Name[tg]=Ҳолӣ +Name[tr]=Boş +Name[uk]=Порожня +Name[uz]=Boʻsh +Name[uz@cyrillic]=Бўш +Name[wa]=Vude +Name[zh_CN]=空 +Name[zh_TW]=空白 +X-KDE-DefaultTab=true diff --git a/chalk/design.h b/chalk/design.h new file mode 100644 index 00000000..e4317fd8 --- /dev/null +++ b/chalk/design.h @@ -0,0 +1,27 @@ +/** + @mainpage Chalk Image manipulation and paint application + + Chalk is an advanced and modular paint and image manipulation + application. + + Chalk is built around two core libraries: chalkcolor and chalkimage. + + The chalkcolor library abstracts colorspaces and color + transformations. Colorspaces provide functions to manipulate pixels. The + kritcolor library loads colorspace plugins to extend the range of + available colorspaces. + + The chalkimage library abstracts the storage, creation, inspection + and manipulation of pixels stored in a rectangular area. It provides + layers, filters, iterators and painters. Filters and paint operations + are provided as service plugins loaded through the appropriate trader + queries. + + Both libraries are used by the user interface, which is a KOffice + part. the user interface loads tools and other plugins. + + */ +#ifndef DESIGN +#define DESIGN +// Let's keep icefox.net/kde/tests.headerincluded_koffice.html happy +#endif \ No newline at end of file diff --git a/chalk/doc/DESIGN.obsolete b/chalk/doc/DESIGN.obsolete new file mode 100644 index 00000000..51cadc58 --- /dev/null +++ b/chalk/doc/DESIGN.obsolete @@ -0,0 +1,179 @@ +A Perspective on Chalk's Design + + Chalk's codebase has been through as many changes as the app's name + itself. It started with KImageShop (hence the 'kis' prefix one finds + everwhere, and which would have been unnessary had Chalk used + namespaces, one fancies), then became Krayon to end up as Chalk. The + stated design goal was to create a application geared towards the + more artistic user; the kind of user who settles down with his + tablet to create a spot of Art. It ended up as a Gimp-clone, a Kimp, + so to say. + + This document was the basis for a discussion on the chalk mailinglist: + http://lists.kde.org/?l=kde-kimageshop&m=106530035202770&w=2. See the + answer for some answers to the questions at the end. + +Design Patterns + + Patrick Julien restructured Chalk to use a lot design patterns. Chalk + appears to have a very solid base for blasting pixels to the screen, + zooming, selecting and moving. These are what I recognize as his + changes: + + * Change brushes handling to a generic Mediator pattern + (kis_resource_mediator). Resources are brush tqshapes, + patterns (and colours, too?) Patrick intended a Flyweight + here. + + * The composite pattern is used in paint devices, layers, channels, + etc. (What about tqmasks?) + + * Change colourspace handling to a Strategy pattern + (strategy/kis_strategy_color) + + * Change moving chunks of painting to a Strategy pattern + (strategy/kis_strategy_move) + + * kis_factory points towards a Factory pattern Creates the + pluginserver and resourceserver. + + * Tools are created by a Factory pattern (but it isn't + dynamic yet): kis_tool_factory. Tools are intended to + become kparts. + + * There's the start of a Memento pattern for tools, but it + doesn't seem to be used (kis_tool_memento). It was an + experiment that didn't pan out. + + * The Builder pattern is used to do conversion to and/or + from ImageMagick. I guess this is used for importing + images in other file-formats than .chalk. An idea at one + was to use Koffice filters, but that didn't work because + images are rather different from other office documents. + + * Flyweight pattern used for background tiles. + kis_background. + + * Nameserver. Perhaps not a pattern -- at least not one + with an obvious GOF name. Appears to be computing a + number for new layers and new documents. + + * kis_render. Interface implemented by kis_paint_device + and kis_image. + + * Rename kisTool to kisToolInterface -- but the file is + still called kis_tool. (This is intentional, and should + be kept in the style guide.) + + * Addition of kis_types. Defines shared pointer pointers + to core chalk objects: image, paintdevice, channel, + tqmask, layer etc. + + * Tile architecture. There's Mediator and a Singleton + pattern here at least. This stuff seems to work, doesn't + need hacking at the moment. + + * Visitor pattern used to flatten an image or merge + layers. Merging exposes a funny bug where the tiles + are re-arranged in an interesting mosaic pattern. + + +User interface + + Chalk uses a fairly ugly side-panel to collect what are palettes + in other applications. I would prefer dockable, attachable + palettes myself. Doesn't KDE have a lib for that already? + + + ui/labels + + These classes are used in the statusbar. + + ui + + The dialogs appear to be created by hand, not with Qt + Designer. Besides, many are inoperational. + + other + + The canvas, rules and sidebar panels are defined here, too, + nicely separated. + +Tools + + Working: select_rectangular, test, zoom, colorpicker, paste, move + + Not working: airbrush, brush, colorchanger (no idea what it should + do), ellipse, eraser, fill, line, pen, polygon, polyline, + rectangle, select_contiguous, select_elliptical, select_freehand, + select_polygonal, stamp + + Missing tools: convolve, smear, smudge, whirl, charcoal, chalk, + oils, clone, select_by_colour + +Plugins + + The single plugin example has been present in chalk since about day + one, as far as I can see. It doesn't show anything about what one + can do with plugins. + + To judge from the code in kis_plugin_server, it never got beyond + an idea. (kdDebug() << "hallo\n"...) + + (This code should be removed.) + +ImageMagick + + There still appear to be some dependencies upon ImageMagick (builder + subdir). What are these for, and should they stay? Is it for + importing/exporting foreign file formats? + +Undo/Redo + + Undo and Redo make use of the standard KDE mechanism, which I don't + really understand either. + + +Obsolete files + + The following files appear to be unused: + + core/helper/kis_timer + core/helper/kis_scopedlock (Replaced with QMutexlocker) + core/kis_krayon (was predecessor of kis_resource) + core/kis_tqmask + core/kis_util + ui/kis_krayon_widget + +Random head-scratchings + + + - Why the QUANTUM redefinition: the number of bits per channel, + 8 for 32-bit colour, 16 for 64-bit colour. + + - is_tqmask unimplemented? What was it meant to do, or is it an + interface? + + - nameserver presents unique numbers for new layers and images. + + - what does 'upscale' do? in 8 bit/channel color mode, upscale + doesn't do anything. However, downscale and upscale in > 8 bit, + this is needed to covert the color for the actual display + rendering, i.e. X, etc, only do 8 bit color. Using this + everywhere you work on color will keep chalk color channel + bit depth independent. + + + - Is KisVector only used in obsolete tools? + + - I take it that the two tests that are present in chalk/test + are obsolete? + + - what with the dummmmmy.cc? + + - which bits of the chalk/ui files are still relevant? + + - kis_selection.h needs to be included to compile code that + uses kis_paint_device, and I wonder why. + + - what is paint-offset? diff --git a/chalk/doc/Developing Chalk Plugins.odt b/chalk/doc/Developing Chalk Plugins.odt new file mode 100644 index 00000000..1e74bff8 Binary files /dev/null and b/chalk/doc/Developing Chalk Plugins.odt differ diff --git a/chalk/doc/autoextending paintdevices b/chalk/doc/autoextending paintdevices new file mode 100644 index 00000000..a42dc683 --- /dev/null +++ b/chalk/doc/autoextending paintdevices @@ -0,0 +1,54 @@ + +This is an attempt to explain how autosizing paintdevices work + +The tileddatamanager which is the underlying object that organizes the pixel +storage is autoextending. So it starts with zero tiles, and as writing is +being done new tiles are added as needed. + +There is also a default tile that is only readable (in theory). Whenever +access is only readaccess you get this tile for areas that don't have their +own tile yet. The idea is that the default tile is filled with transparent +pixels. (Or, with special layers like the background pattern or the selection, +with something else relevant. bsar) + + +So imagine a new image of size 640x640. The layer has no tiles, but when the +layer is being read (for viewing) we probe all over the image (640x640) and +read from the default tile wherever we probe. + +The extent of the layer (paintdevice) is 0x0 because nothing has been +written yet. + +Then some drawing is done in one corner and a tile is created automatically. +Now the extent is 64x64 (tilesize defined at compilation) because a single +tile exists. + +If some drawing is done in the opposite corner another tile is created. The +extent is now 640x640, but only two tiles exist (one in each opposite +corner). When probing for viewing the default tile is what you get except +for the two tiles. + +If we now apply a filer that lightens the colors (or something else) we +could iterate over the extent. That way we are sure to get all the real +tiles that have been created. + +As there is no way for us to know which pixel have true tiles and which have +the default, we would write to all the pixels within the extent, which would +automatically create ALL the tiles inside the extent. +(XXX: Of course, the tile manager could decide that the written value +is the same as the default value, and if that's true for all pixels in a tile, +not create a tile at all) (bsar)) + +In other cases like a gradient fill we would probably want to fill the +current image area, so we we would just write to the paintdevice, and tiles +would be automatically created for us. + +So in short: if you read - data will be available (either real tiles or a +default) - and if you write to the paintdevice - tiles will be created as +needed. So simply don't worry. + +But in some cases, when you want to modify already written pixels, as in +some filters you want to know where true data have been written. Otherwise +we would have to modify an infinite number of pixels to be sure everything is +changed. This is where the extent comes in handy. If you have absolutely +no leeway, use exactBounds which is slow, but sure. diff --git a/chalk/doc/background_paper.txt b/chalk/doc/background_paper.txt new file mode 100644 index 00000000..96226fe2 --- /dev/null +++ b/chalk/doc/background_paper.txt @@ -0,0 +1,84 @@ +Background, paper, layers, blobs + +An image in Chalk is imposed upon a plane. Perhaps, using OpenGL, +we'll be able to rotate and elevate that plane at the users' whim. +If we can elevate the plane, there will be a direction of gravity +that naturalistic media can play with. Note: Wet & Sticky make it +possible to "paint" gravity. This looks like a fun feature, but +that needs to be done per-layer, and not for the whole image. + +The plane is represented by the checkered background. Ideally, +we'd be able to set the color of the checks & the size, and the +size shouldn't change with the zoomlevel. The checks are one +pattern, repeated for the whole image: + +O# +#O + +Placed on the plane is optionally the substrate -- a naturalistic +representation of canvas, linen, paper, board, wood, levkas. Or +something weird, kopper, rock, sand... There is one substrate +per image. The substrate can be a small texture repeated for the +whole image, or as big as the image -- the latter is important +if we want to make it possible to perturb the substrate (think scoring +lines into levkas or erasing through the paper). + +Provisionally, the substrate has the following properties: + +height +smoothness +absorbency +reflectiveness + +(Of course, layers below the current layer can influence these values +for layers on top of them.) + +I have a hunch that the effect of these properties are really easy to +render using OpenGL, but not so easy using plain QPainter. In any case, +media layers will need to know these values at every pixel. We need +a really easy & fast way to acquire them. + +We need to avoid the Corel Painter feature where you can use a naturalistic +paper and then paint away the paper structure, mixing the color of the paper +with your paint as if the paper were paint. So, we need to separate paper +and paint thoroughly. + +On top of the substrate and background are the layers themselves. +Some layers are just color; others contain media. Media means color, +but possibly in a kubelka-munk colorspace, and properties like: + +height +graininess +viscosity +wetness +smoothness +absorbency +stickiness (i.e, charcoal isn't sticky at all, acryl paints very +sticky) + +Note: Impasto models thick, 3-d paint, where tufts of thick oipaint can +cast shadows... + +Ordinary color layers (Shoup layers in the terminology of Cockshott) can +make use of the substrate parameters using special paint ops, and ordinary +color can be painted on a media layer, but the ordinary color paintops +do not deposit the above properties. Media paint just leaves color on the +color layers. We need to avoid at all costs the Corel Painter effect where +trying to use a pencil on a watercolor layer causes a nasty flow-impeding +useless error box to popup. + +Media and ordinary layers can be grouped and mixed at will, together with adjustment +layers. Adjustment layers can also be attached to selection tqmasks, per layer. + +The composited layers is either scaled and color corrected, or color corrected and +then scaled, depending on whether the zoom > 100% or < 100%. + +Note: do we need a visualisation layer on top of the layers for things +like wetness, reflectiveness, height? Perhaps this is the right place for that. +We need perhaps to add a light source or two, in OpenGL mode... I think +we do. + +On top of the layers are what Xara calls blobs: the temporary droppings of +tools, like rubber bands, vector paths, brush tqshape cursors. + + diff --git a/chalk/doc/brush.txt b/chalk/doc/brush.txt new file mode 100644 index 00000000..bb932eee --- /dev/null +++ b/chalk/doc/brush.txt @@ -0,0 +1,36 @@ +Painting with brushes + +:.,I don't know anything, nada, zilch, noppes about writing paint applications. So +when I started working on Chalk, I felt I needed examples. I used the following +sources: + +* The old Chalk brush code (http://webcvs.kde.org/cgi-bin/cvsweb.cgi/koffice/chalk/tools/kis_tool_brush.cc?rev=1.58&content-type=text/x-cvsweb-markup) +* Peter Jodda's Perico (http://software.jodda.de/perico.html) +* The source of the Gimp (both current and 0.99.11 -- the oldest version I could tqfind) (http://www.gimp.org) +* David Hodson's article on Gimp brushes (http://members.ozemail.com.au/~hodsond/gimpbrush.html) +* Raph Levien's article on Gimp brushes (http://www.levien.com/gimp/brush-arch.html) + +Chalk uses the gimp's brush file formats: .gbr and .gih, for singe +and pipeline brushes, respectively. These brushes contain one or more +grayscale or rgba images. If the image is grayscale, the gray image is +intended to be used as an alpha tqmask: each gray level corresponds to +a certain alpha level, and when painting the current painting colour +is composited in the image with this level as its alpha component. The +image brushes should be tqmasked -- i.e., these are coloured images placed +on a white background. The white background should be made transparent, +and then the brush image can be composited onto our image. + +This is currently only half supported: I make tqmasks of everything, +partly because I like that better, partly because until very recently +there was no way of making out the difference between gray and rgb +brushes because KisBrush didn't remember that bit of data. + +Making the initial tqmask of a brush is however by now pretty well done; the next +problem is painting with those tqmasks. + +Here we have two situations, one easy, one difficult. The easy one is the single +mouse click. If the user clicks or taps with his stylus, we can composite the +tqmask or the image at the pixel position of the mouse click. + +The difficult situation is drawing a line. This line needs to be antialiased. + diff --git a/chalk/doc/chalk-features b/chalk/doc/chalk-features new file mode 100644 index 00000000..77f79dcb --- /dev/null +++ b/chalk/doc/chalk-features @@ -0,0 +1,215 @@ +Chalk Features + +The following is a comprehensive list of all Chalk's features +that are or will be implemented for version 1.5. + +* Plugins + +Chalk is extensible through plugins. There are tools, colorspaces, +paint operations, filters and kpart-based user interface plugins. +It is intended to make layer types plugins, too. + +* Scriptable + +Chalk is scriptable in Python and Ruby. The scripting is +compatible with using the PyQt/KDE and Korundum for adding +GUI items. + +* File + +Import: png, tiff, jpeg, dicom, xcf, psd (up to version 6, +from version 7 on, the photoshop file format is closed and it +is impossible to get the spec to implement support in a +free software application), gif, raw, bmp, xpm, targa, rgb, ico, +openEXR. + +Export: png, tiff, jpeg, dicom, xcf, psd (up to version 6, +from version 7 on, the photoshop file format is closed and it +is impossible to get the spec to implement support in a +free software application), gif, bmp, xpm, targa, rgb, openEXR. + +Embedded icc profiles and exif information are preserved on +export to supporting file formats. + +Chalk's native file format stores icc and exif information. + +* Color models + +Chalk uses lcms for a dependable color workflow using icc profiles +for importing, exporting, selecting paint colors, printing, +cutting and pasting. + +** 8 bit/channel rgb, cmyk, grayscale, wet watercolors +** 16 bit/channel rgb, cmyk, grayscale, l*a*b, xyz (xyz may be removed) +** "half" rgb +** 32 bit float rgb (HDR), lms +** Colors can be selected from a color wheel, rgb or grayscale sliders + or with a palette + +* Editing + +** Unlimited undo and redo +** Cut, copy and paste with conversion through icc profiles if necessary +** paste into a new image + +** Viewing + +** Use OpenGL for display when possible +** View fullscreen +** Multiple views on one image +** Rulers +** zooming +** show or hide all palette windows in one go +** palette windows position is kept between sessions +** When maximized, Chalk is usable on a 1024x768 screen with all + palettes open. +** Permanently accurate histogram palette +** Exposure slider for HDR images +** Optional "greening-out" of inactive layers to assist with artistic + workflow. +** Bird's eyeview of image and zooming (not sure this will be done in time) + +* Images + +** mirror, shear, rotate and scale images +** change the size of the canvas +** change the resolution of the image +** convert images between colorspaces +** set image properties (name, comments, profile, resolution) +** Combine layers in different colorspaces. The bottom-most + layer determines the image colorspace. +** Separate the channels of an image into grayscale (8 or 16 bits) + layers or images. + +* Layers + +** Embed KOffice documents as layers into an image +** Group layers +** Adjustment layers (not sure whether this'll make it) +** Lock layers (tools and filters cannot change the layer, but not all + destructive operations are disabled yet) +** Make layers invisible +** Add and remove layers +** Change the position of layers in the layer stack +** Mirror, shear, rotate and scale layers +** Save layer as image +** Composite layers with supported composite options, like + over, in, out, atop, xor, plus, minus, add, subtract, diff, + mult, divide, dodge, burn, bumpmap, copy, copy one channel, + clear, dissolve, displace, darken, lighten, hue, saturation, value, + color, colorize, luminize, screen, overlay, erase. (Not all colorspaces + support all composite operations). +** Change layer properties like name, position, colorspace +** Create a drop shadow behind the layer +** View the histogram of a layer; 16 bits or wider images have zoomable + histograms +** Insert screenshot as layer + + +* Selections + +** Select by colorrange +** Feather selection +** Invert selection + +* Tools + +Throught the innovative paintOp plugin system, all painting tools +(brush, ellipse, line, etc.) can paint aliased, anti-aliased, +erase, airbrush and more. + +** paintbrush +** colorpicker +** duplicate +** ellipse +** anti-aliased bucket fill and selection fill with color, patterns + or gradients. +** gradient +** line +** layer or selection move +** canvas pan +** rectangle +** text +** zoom +** crop +** paint with filters (to be integrated in the paintop system) +** polygons +** polylines +** stars +** transform selection/layer +** select similar colors +** select by painting +** select contiguous areas +** select ellipse +** deselect by erasing +** select by painting outline +** select polygonal +** select rectangular + +* Filters + +Chalk can multithread the operation of some filters. Chalk's +filters can be previewed in the filter gallery. + +** Apply previous filter again +** bumpmap +** image restoration with cimg +** brightness/contrast +** color adjustment per channel +** autocontrast +** desaturate +** gaussian blur +** sharpen +** remove mean +** emboss (laplacian, all directions, horizontal, vertical, horizontal and +vertical) +** edge detection (top, right, bottom, left) +** custom convolution +** cubism (converts to 8 bit rgba and back) +** invert +** reduce noise (simple and with wavelets) +** oilpaint (converts to 8 bit rgba and back) +** pixelize (converts to 8 bit rgba and back) +** raindrops (converts to 8 bit rgba and back) +** round corners +** small tiles (converts to 8 bit rgba and back) +** sobel (converts to 8 bit rgba and back) + +* Paint operations + +Chalk's paint operations are usable with all painting tools. + +PaintOps can support composite options, like +over, in, out, atop, xor, plus, minus, add, subtract, diff, +mult, divide, dodge, burn, bumpmap, copy, copy one channel, +clear, dissolve, displace, darken, lighten, hue, saturation, value, +color, colorize, luminize, screen, overlay, erase. (Not all colorspaces +support all composite operations). + +PaintOps can support opacity settings and use the pressure value +of a tablet. Tilt and rotation is not yet supported. + +** airbrush +** eraser +** anti-aliased brush +** convolve +** duplicate +** aliased brush (pen tool) +** smeary brush (not sure whether this will get finished in time) +** paint with a tablet stylus. The pressure sensitivity + characteristics can be set. + +* Brushes + +** gimp brush tqshapes. Support for colored and grayscale brushes and + pipe brushes. Support from Gimp parasites in brushes. +** custom brush tqshapes +** text brush tqshapes +** brushes created from layers or images. These brushes can be saved +** colored brushes can also be used as tqmasks + +* Fills + +** gimp-style patterns +** gimp-style gradients +** custom gradients \ No newline at end of file diff --git a/chalk/doc/chalk.kpr b/chalk/doc/chalk.kpr new file mode 100644 index 00000000..b1fe023e Binary files /dev/null and b/chalk/doc/chalk.kpr differ diff --git a/chalk/doc/chalk.pdf b/chalk/doc/chalk.pdf new file mode 100644 index 00000000..1073941b Binary files /dev/null and b/chalk/doc/chalk.pdf differ diff --git a/chalk/doc/chalk.xmi b/chalk/doc/chalk.xmi new file mode 100644 index 00000000..913db577 --- /dev/null +++ b/chalk/doc/chalk.xmi @@ -0,0 +1,56432 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.2.0 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + +
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
diff --git a/chalk/doc/channels_masks_selections b/chalk/doc/channels_masks_selections new file mode 100644 index 00000000..4ce65414 --- /dev/null +++ b/chalk/doc/channels_masks_selections @@ -0,0 +1,12 @@ +We did a rethink on channels, selections and tqmasks last summer. + +Traditionally, a tqmask is seen as an extra channel for an image, analogous +to the alpha channel. We want to do away with that idea. + +A layer can have a number of permanent selections associated with it. +Such a selection can handle a composite method (determining the composition method +for the selected pixels) or a filter (making it an adjustment layer). + +Of course, a selection is just an 8-bit per pixel single channel layer that +belongs to a layer, so all filters can work automatically on a selection, +except that we don't have the ui for that yet. diff --git a/chalk/doc/colordiff b/chalk/doc/colordiff new file mode 100644 index 00000000..b84a98fa --- /dev/null +++ b/chalk/doc/colordiff @@ -0,0 +1,68 @@ +From: Mathew Brennesholtz +Subject: Re: contrast of color +Date: 01 Oct 1999 00:00:00 GMT +Message-ID: <37F4DD62.3AABA5D2@philabs.research.philips.com> +Content-Transfer-Encoding: 7bit +References: <37F3395E.484C921A@netvision.net.il> +Content-Type: text/plain; charset=us-ascii +X-Complaints-To: usenet@philabs.research.philips.com +X-Trace: news.philabs.research.philips.com 938783269 3770 130.140.53.137 (1 Oct 1999 13:07:49 GMT) +Organization: Philips Research, Briarcliff Manor, NY +Mime-Version: 1.0 +NNTP-Posting-Date: 1 Oct 1999 13:07:49 GMT +Newsgroups: sci.engr.color + +One intention of the L*a*b* formulation is that when you calculate: + + delta-E = sqrt((delta-L*)^2 + (delta-a*)^2 + (delta-b*)^2), + +a delta-E = 1 should be just barely percievable to some viewers. If you +want most people to be able to distinguish between two colors most of the +time, a delta-E = 3 is needed. Delta-E = 3 is called a MPCD (minimum +perceptible color difference) or a JND (just noticable difference) by +some authors. Keep in mind that the L*a*b* space is not a perfectly +uniform space, so the delta-E value that is percievable depends on +location in x-y space and the direction between the two colors. + +Using a delta-E = 1 threshold, M. R. Pointer (The Number of Discernible +Colours, Color Research and Application, 23:1 February 1998) calculated +that there are 2.28 million discernable color/luminance combinations. +Other studies (see references in Pointer) show that printing inks give +1.6 million colors and EBU phosphors give 1.35 million colors. These are +far less than the 16 million colors claimed by 8 bit/color video cards, +never mind 10 or 12 bit video systems. Obviously, some of these +color/luminance combinations are indistiguishable from each other. + +Hope that helps. + +IPLAB wrote: + +> Hallow !! +> I understand that to measure contrast between two objects in color +> picture, I can calculate the vector distance on L a b space (between +> the two objects). +> Does anyone can tell me what is the minimum of the Vector distance +> ,that eye can see ?? +> +> Thanks +> +> from sally + +http://www.compuphase.com/cmetric.htm: + + +typedef struct { + unsigned char r, g, b; +} RGB; + +long ColourDistance(RGB e1, RGB e2) +{ + long r,g,b; + long rmean; + + rmean = ( (int)e1.r + (int)e2.r ) / 2; + r = (int)e1.r - (int)e2.r; + g = (int)e1.g - (int)e2.g; + b = (int)e1.b - (int)e2.b; + return (((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8); +} diff --git a/chalk/doc/colorspaces.xmi b/chalk/doc/colorspaces.xmi new file mode 100644 index 00000000..cd874de8 --- /dev/null +++ b/chalk/doc/colorspaces.xmi @@ -0,0 +1,41965 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4.2 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+ + + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + +
+ +
+
+ + + +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
diff --git a/chalk/doc/colorstrategyAPI b/chalk/doc/colorstrategyAPI new file mode 100644 index 00000000..07c95ae9 --- /dev/null +++ b/chalk/doc/colorstrategyAPI @@ -0,0 +1,58 @@ +This is a working document. It list the places where pixels are mangled and requested functions to do it in an colorstrategy independent way + +The purpose is to find out which functions an API in colorstrategy must have to support pixelmangling in a colorstretegy independent manner. + + +Requested function: apply an alpha tqmask to pixels +Problem: alpha is hard-coded 8-bit in KisPixel, when it should be free + +void KisPaintDevice::clearSelection() +{ + if (!hasSelection()) return; + + QRect r = m_selection -> selectedRect(); + r = r.normalize(); + + for (Q_INT32 y = 0; y < r.height(); y++) { + KisHLineIterator devIt = createHLineIterator(r.x(), r.y() + y, r.width(), true); + KisHLineIterator selectionIt = m_selection -> createHLineIterator(r.x(), r.y() + y, r.width(), false); + + while (!devIt.isDone()) { + KisPixel p = toPixel(devIt.rawData()); + KisPixel s = m_selection -> toPixel(selectionIt.rawData()); + // XXX: Why Q_UIN16 here? Doesn't that clash with UINT8_MULT later on? + Q_UINT16 p_alpha, s_alpha; + p_alpha = p.alpha(); + s_alpha = MAX_SELECTED - s.alpha(); + + p.alpha() = UINT8_MULT(p_alpha, s_alpha); + + ++devIt; + ++selectionIt; + } + } +} + +void KisPaintDevice::applySelectionMask(KisSelectionSP tqmask) +{ + QRect r = tqmask -> extent(); + crop(r); + + for (Q_INT32 y = r.top(); y <= r.bottom(); ++y) { + + KisHLineIterator pixelIt = createHLineIterator(r.x(), y, r.width(), true); + KisHLineIterator tqmaskIt = tqmask -> createHLineIterator(r.x(), y, r.width(), false); + + while (!pixelIt.isDone()) { + + KisPixel pixel = toPixel(pixelIt.rawData()); + KisPixel tqmaskValue = tqmask -> toPixel(tqmaskIt.rawData()); + + pixel.alpha() = (pixel.alpha() * tqmaskValue.alpha()) / MAX_SELECTED; + + ++pixelIt; + ++tqmaskIt; + } + } +} + diff --git a/chalk/doc/controller.xmi b/chalk/doc/controller.xmi new file mode 100644 index 00000000..3281c344 --- /dev/null +++ b/chalk/doc/controller.xmi @@ -0,0 +1,39776 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ +
+ +
+
+
+ +
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+ + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ +
+ + +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
+
+
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+
+ +
+ +
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+
+
+
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
diff --git a/chalk/doc/coordinates.txt b/chalk/doc/coordinates.txt new file mode 100644 index 00000000..3d7e20dc --- /dev/null +++ b/chalk/doc/coordinates.txt @@ -0,0 +1,9 @@ +Coordinates in Chalk + +As with any paint app, finding out what you mean when you say (x,y) is difficult. +There are the screen coordinates, the coordinates of the canvas inside the view, +the zoomed coordinates -- and the image coordinates, paint device coordinates and the +coordinates of the data inside the paint device. + +Iterators are created in terms of the image coordinates. + diff --git a/chalk/doc/dirty.txt b/chalk/doc/dirty.txt new file mode 100644 index 00000000..ddb32279 --- /dev/null +++ b/chalk/doc/dirty.txt @@ -0,0 +1,53 @@ +Dirty marking and rendering + +Chalk organizes layers in the form of a tree, with a grouplayer at the root: + +group1 == image->rootLayer() + layer2 + layer3 + layer4 + group2 + layer6 + layer7 + adjustmentlayer 1 + layer9 + group3 + adjustmentlayer 2 + layer10 + layer11 + group4 + layer12 + layer13 + + +In this example, group1 is the rootlayer; layer13 is group3 is shown topmost +in the layerbox, with group4 right under that, and layer13 is the "highest" +paint layer in the complete tree. + +Compositing + +At every group level, a projection layer caches the result of compositing +the layerstack in a projection paint device. The cached projection is then +composited with the layers of that level, etc, until everything is composited +onto the projection or the root layer. The image does _not_ have a projection +anymore. + +We composite from layer2 downwards onto the projection of rootLayer, group1. + + +Dirty marking + +In order to do the least possible amount of work (which is very important, +especially with large amounts of layers and adjustment layers), we keep track +of which layer is dirty. Groups without dirty layers are not recomposited; this +dirtiness of course travels upwards, meaning that the rootlayer will always be +dirty. + +XXX: Should we keep a structure with dirty rects for every layer, so we +can determine whether the changed rect in a layer is actually in the area +we are recompositing? I don't think so, since we should always try to keep + +Adjustment layers also keep a copy of the result of their work; if in group 2, +layer 9 is adjusted, we do not want to composite layer 6 and 7 and filter the +result through adjustmentlayer 1; we want to composite the changes in layer 9 +directly onto the cached result of the adjustment layer. \ No newline at end of file diff --git a/chalk/doc/doc-outline b/chalk/doc/doc-outline new file mode 100644 index 00000000..373370b5 --- /dev/null +++ b/chalk/doc/doc-outline @@ -0,0 +1,187 @@ +Chalk documentation outline + +Last edited 2006-09-08 (Sander Koning) + + +Changelog (of major updates) + +2006-09-08: ASK: add section separators, update for 1.6 +2006-05-28: ASK: split into 1.5 and 1.6 parts +2006-01-31: ASK: elaborate on parts to be written; consistent spelling +2006-01-26: ASK: split the "Using Chalk" chapter +2006-01-21: ASK: update and make consistent +2006-01-12: ASK: add status, and put in SVN for others to enjoy ;) +2005-08-31: ASK: adhere to KDE style +2005-08-30: ASK: initial version + +---------------------------------------------------------------------- + +This document tries to give a suitable outline for Chalk's documentation. It +is based on the Chalk manual in SVN (koffice/chalk/doc/manual/chalk.kwd) as of +2005-07-08, the KDE documentation template, and furthermore contains my own +thoughts about what the documentation for a graphics application such as this +should look like. Comments, suggestions, ideas etc. are more than welcome. +Especially the real content still needs a lot of polishing. + +---------------------------------------------------------------------- + +The current outline (working towards 1.6): + +- Introduction + - What is Chalk + - Key features + - Color management + - File formats + - About this manual + - About the application author + +- Tutorial + - Starting to know Chalk (up to a new document) + - A small selections and layers tutorial + - Quick start guides + - Crop an area and save it as a new image + - Draw a rectangle on your picture + - Using tablets + - [TODO] Fills (colors, patterns and gradients) + - [TODO] Using tool options (the "Tool" palette) + - [TODO] Editing image properties (resize, rotate, ...) + +- [TODO] Painting + - [TODO] Introduction to Chalk's painting model + - [TODO] Detailed description of tools and options, colors, ... + - [TODO] Brushes, adding/customising, ... + - [TODO] ... + +- Viewing + - Zooming and full screen mode + - Working with views (multiple and split views) + - Miscellaneous view options (rulers and grid) + +- Layers + - General information + - Layer box + - Working with layers ([TODO] expand) + - Adjustment layers ([TODO] expand) + - [TODO] Layer tqmasks + - Compositing modes ([TODO] expand) + - [TODO] Create, transform, combine, histograms, ... + +- Selections + - Making a selection + - Painting your selection + - Unselecting + - Making a new selection + - Selecting a contiguous area (magic wand) + - Selecting similar colors + - Inverting the selection + - [TODO] elaborate and extend hugely + +- Filters + - (all filters) + +- Colorspaces + - Introduction to colorspaces + - Available colorspaces + - [TODO] properties, usage, converting, ... + +- Commands + - General tqlayout + - Menus + - Toolbars + - Palettes + - Dialogs + +- Settings + +- Developers' information + - Scripting + - Plugins + +- FAQ + +- Credits + +- Installation + +---------------------------------------------------------------------- + +Outline for the 1.5 manual (final as of 2006-05-31): + +- Introduction + - What is Chalk + - Key features + - Color management + - File formats + - About this manual + - About the application author + +- Tutorial + - Starting to know Chalk (up to a new document) + - A small selections and layers tutorial + - Quick start guides + - Crop an area and save it as a new image + - Draw a rectangle on you picture + +- Layers + - General information + - Adjustment layers ([TODO] elaborate) + +- Selections + - Making a selection + - Painting your selection + - Unselecting + - Making a new selection + - Selecting a contiguous area (magic wand) + - Selecting similar colors + - Inverting the selection + +- Filters + +- Colorspaces + - Introduction to colorspaces + - Available colorspaces + +- Commands ([TODO] make up-to-date) + - General tqlayout + - Menus + - Toolbars + - Palettes + - Dialogs + +- Settings + +- Scripting + +- FAQ + +- Credits + +- Installation + +---------------------------------------------------------------------- + +An outline of the manual content as in chalk.kwd: + +- Introduction + - About the manual + - About the author +- Showing Off + - Intro tutorial +- On the face of it + - Layout + - Menus +- Files +- Serious about color + - Colour theory +- Selections + - Creating selections (select, unselect, wand) +- Messing with images +- Painting +- Layers +- Filters +- Hacking Chalk +- Configuring Chalk +- Help! + - Help contact info + + diff --git a/chalk/doc/histograms.xmi b/chalk/doc/histograms.xmi new file mode 100644 index 00000000..209a795d --- /dev/null +++ b/chalk/doc/histograms.xmi @@ -0,0 +1,4145 @@ + + + + + umbrello uml modeller http://uml.sf.net + 1.4.2 + UnicodeUTF8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/doc/hooks b/chalk/doc/hooks new file mode 100644 index 00000000..83959a96 --- /dev/null +++ b/chalk/doc/hooks @@ -0,0 +1,33 @@ +Some color models support more tools, filters and other things like +colour selectors than other color models. Some support far less of +those things, in fact. + +Among these things are: + +* tools +* palettes +* filters +* paint ops + +Thus, if a paint device is of a certain color model, certain GUI things +must be activated and deactived when that paint device becomes active. + +A paint op may need to knwo something about the layer it is going to paint +on: it is not sufficient to generate a tqmask and have that composited by +the color strategy because the footprint may be determined by the deposit +and height field that is already present. + +For some color models, pixels in a paint device must be +initialized using more or less complex algorithms. It is not enough to +initialize a single default pixel (which we cannot do yet), we must +additionally initialize the whole default tile; and since nothing in +Chalk outside the tilemanager code should know about the very existence +of tiles, we must find a generic solution of the canvas initialisation. + +Additionally, some color models need permanently running filters to model +physical pocesses, like drying and flowing of paint or ink, or adsorbtion into +lower layers. + +Finally, some color models (like the selection, or wetdreams) want a way to +efficiently add some kind of visualisation at the paintView level, instead +of the rendering level. \ No newline at end of file diff --git a/chalk/doc/howtofilters.txt b/chalk/doc/howtofilters.txt new file mode 100644 index 00000000..09deabf6 --- /dev/null +++ b/chalk/doc/howtofilters.txt @@ -0,0 +1,30 @@ +The goal of this howto is to explain how to create a filter for chalk + + +2) using Qt/Designer for the ConfigurationWidget + +Just copy the following in a file named (for instance) myfiltercw.ui : + +Form1 + + + kisFilterConfigurationWidget1 + + + + 0 + 0 + 359 + 251 + + + + kisFilterConfigurationWidget1 + + + + + +And then open Qt/Designer + +NOTE: it would be nicer if I knew how to copy (using autoconf/automake) this file in $(QTDIR)/tools/designer/templates \ No newline at end of file diff --git a/chalk/doc/impexp.txt b/chalk/doc/impexp.txt new file mode 100644 index 00000000..123807dc --- /dev/null +++ b/chalk/doc/impexp.txt @@ -0,0 +1,41 @@ +THIS IS OBSOLETE + +Import/Export & ImageMagick + +Import/Export is currently hardcoded to use ImageMagick and the RGB colormodel. +Additionally, export is broken and even when working, only supported exporting +to images with one layer. + +Kimgio is not suitable for Chalk since it only supports importing images as one +QImage. + +The new design should support plugins instead of hardcoded filters, so we can +add an ImageMagick plugin, an openExr plugin or any other kind of image readers. + +Issues: + + * conflicts -- more than one plugin might want to support JPEG, for instance. + * configuration -- compression settings, optional flattening, adding + profiles, colorspace conversion + * identification -- no sane way to distinguish a particular type of tiff from + another type, for instance. + * colormodel integration -- basically, there are cmyk, rgb and grayscale + images in a variety of bit depths (e.g., openexr supports 16 bit and half). + Colorspaces must interpret the file data to build Chalk pixels and must + unpack chalk pixels to a format a file exporter (e.g, ImageMagick pixel + packets) can work with. This means that plugins can depend on the presence + of other plugins. + * Import/export should be lossless -- i.e., all extra information any file + format may attach to the image should be kept around and used on export. + Examples are Exif data and profiles, but also Gimp comments. + + +KisAnnotation contains metadata about an image that is grabbed from +a file, such as exif data or TIFF tags and that we should be able to save. + +KisAnnotation + + KisAnnotation(QString type, QString annotation); + KisAnnotation(QString type, QByteArray annotation);; + + diff --git a/chalk/doc/large_files b/chalk/doc/large_files new file mode 100644 index 00000000..9270bca0 --- /dev/null +++ b/chalk/doc/large_files @@ -0,0 +1,36 @@ +One think Chalk can not handle are really big files. A 125MB tif file is +loading into memory in one go, making Chalk take about 289MB of memory +-- with no image loaded, Chalk takes a more reasonable 41MB. And during +loading, Chalk needs 800MB, and that's a bit much. + +Since my employer has paid to upgrade my laptop to 1GB of memory, that's +not a problem for me :-). But it's the principle of the thing. Besides, +loading the file does take a few minutes to convert. And you don't want +to do a quick sharpen on a file of this size. + +Now it has never been a design goal to handle really enormous images, vips +does that a lot better than any general purpose paint app can ever aspire +to, but we should give some thought to our way of handling big images. + +The problem is layered: it's not enough to have lazy loading of chalk +files (although we should store, when an image gets above a certain +size, an .png file of the rendered image that we can quickly load and +display, and then we should only load the tiles we actually need for +editing/rerendering from the file), but we should also be able to do the +same with tiled tiffs and exr images that support random access loading. + +This must be done somewhere in the datamanager code. If an image reader +(whether it's a filter or Chalk's own file format reader) indicates that +it supports random access, then a file handle and a the reader object +is passed to the tile manager. + +The tile manager either does nothing until it gets a request for a +certain chunk of data (through one of the read functions or the creation +of an read/write iterator), and only then it starts reading and decoding +image data. Or, the tile manager starts a background thread and begins +converting the alien image data to Chalk tiles, carefully caching them +in a temp file. + +Maybe we could even devise an algorithm to delete unused tiles from +memory and cache them on disk; same with undo information. + diff --git a/chalk/doc/layersupdatesignals.flw b/chalk/doc/layersupdatesignals.flw new file mode 100644 index 00000000..7f7a66c5 Binary files /dev/null and b/chalk/doc/layersupdatesignals.flw differ diff --git a/chalk/doc/manual/chalk.kwd b/chalk/doc/manual/chalk.kwd new file mode 100644 index 00000000..9dd7bdb3 Binary files /dev/null and b/chalk/doc/manual/chalk.kwd differ diff --git a/chalk/doc/oasis b/chalk/doc/oasis new file mode 100644 index 00000000..d533f8bb --- /dev/null +++ b/chalk/doc/oasis @@ -0,0 +1,5 @@ +Chalk won't do OASIS. There is no suitable file format definition in +OASIS and it would take too much time from development to define +one and implement it. Besides, it would be boring work, and I'm +not paid for that. + diff --git a/chalk/doc/paint_device.txt b/chalk/doc/paint_device.txt new file mode 100644 index 00000000..a3c34a35 --- /dev/null +++ b/chalk/doc/paint_device.txt @@ -0,0 +1,98 @@ +THIS DOCUMENT IS OBSOLETED BY THE AUTOLAYERS MERGE + +* Paint devices and painters + +Chalk's core consists of paint devices and painters: + +KisPaintDevice +KisPainter + +These classes are (very) loosely modelled on QPaintDevice and +QPainter. KisPaintDevice also takes up some of the roles of QImage, +but isn't all that efficient at it. + +This is a write-up of my (Boudewijn's) understanding at this point; + +* Getting pixel data in and out of a KisPaintDevice. + +Chalk stores all image data in tiles; the tiles are managed by the +aptly named KisTileMgr. Inside the tiles, we have a KisPixelData +structure, which is basically a wrapper that packs together a pointer +to a memory area that contains the pixel data (QUANTUM's) and some +more information. + +Ordinarily, you will change the data inside a KisPaintDevice through +the KisPainter. Using KisPainter has the advantage that your changes +will be undoable and that the tile manager is hidden. That's +especially nice, since you generally don't want to work directly with +tiles, not before having bought shares in an aspirin producer. + +The other way of messing with the pixels inside a KisPaintDevice is +through the pixel() and and setPixel() methods in KisPaintDevice. +These methods retrieve and set the specified pixel data using the +tiles, but are not undoable. They are also rather ineffcient and slow. + +KisPainter and KisPaintDevice do the job of hiding the actual image +data from the chalk hacker, but sometimes it's not enough, sometimes +you need to loop over all the pixels in an image, do +something, and write the pixels back to this or another image (or +sections of images). + +In the near future, we will offer an iterator over the pixels, for now +you will have to ask the tile manager to copy all the bytes of the +image data in a buffer for you to read. Likewise, in the future we +will hopefully have something clever to feed pixel data to the tile +manager. For now, you will have to fill a memory buffer with the +desired data and feed that to the tile manager. + +** Getting pixel data into your buffer + +Define a pointer to a memory buffer with QUANTUMS + + QUANTUM *buf; + +Create the buffer. Note that you cannot assume that there is one byte +per channel; QUANTUM can be bigger. + + buf = new QUANTUM[width * heigth * depth * sizeof(QUANTUM)]; + +Fill the buf with the data. x1, y1, x2, y2 are the top left and bottom +right corner of the section you want. stride is the width of the +section in bytes, i.e. (x2 - x1 + 1) * depth. Note that stride does +not need to be pre-multiplied with sizeof(QUANTUM), aptqparently. + + tilemgr -> readPixelData(x1, y1, x2, y2, buf, stride); + +Now all the pixels in the tile manager are copied into 'buf' -- the +operative word is 'copy', which means slow, and takes a lot of memory +is the section is big. + +If you can stand computing with tiles, you can copy each tile into the +buffer, which takes a lot less memory, but you have to take care when +the image isn't exactly a multiple of the tilesize. See +kis_image_magick_converter.cpp for an example. + +** Getting your data into a KisPaintDevice without using KisPainter + +Although in the future we might offer a bitBlt that takes a simple +memory buffer and blits that onto the paint device, for now, you will +have to access the tile manager directly, using writePixelData. + + +First create a buffer, just as above: + + QUANTUM * newData = new QUANTUM[width * height * depth * sizeof(QUANTUM)]; + +But unless you are sure you are going to fill absolutely every pixel, +you might want to initialize the buffer with memset. Chalk, in +contrast with ImageMagick, uses 0 as the value for transparent +opacity, so that's nice: + + memset(newData, width * height * depth * sizeof(QUANTUM), 0); + +Then create a new tilemanager, or reuse the old one if the size is +still correct. Stride is again width * depth, not width * depth * +sizeof(QUANTUM) + + KisTileMgrSP tm = new KisTileMgr(depth, width, height); + tm -> writePixelData(x1, y1, x2, y2, newData, stride); diff --git a/chalk/doc/palettedesign.txt b/chalk/doc/palettedesign.txt new file mode 100644 index 00000000..9dc2cfab --- /dev/null +++ b/chalk/doc/palettedesign.txt @@ -0,0 +1,34 @@ +Requirements + +* Flexible: plugins should be able to add palettes or palette tabs +* Connected: palette tabs should be able to connect to the main application + using Q_SIGNALS and Q_SLOTS +* Configurable: palette widgets should be drag & droppable from palette + to palette, and from palette to void to create a new palette. +* Persistent: the palette configuration of a view should be persisted + on application end and reconfigured on application start. +* Pretty: the palettes should be small, but perfectly formed. There + should be the possibility to use either tabbars or toolboxes for + a palette. +* introspective: the application and plugins should be able to + query for existing palettes and tabs and retrieve a list and + pertinent data on existing palettes and tabs (so a plugin can + decide to place itself initially in a palette with other color + tabs, for instance. + +Classes: + +PaletteManager, Palette, PaletteContainer PaletteWidget + +The palettemanager keeps track of palettes and saves & restores sessions. + +Palettes can shade and unshade themselves with a double-click on the +titlebar or using the shade button + +Palettes contain a container, either tab-type or toolbox type. +The containers accept drops, in which case a widget is plugged into +the container. The tabs or separators accept drag events, in which +case a widget is unplugged and a drag operation is started. + +The drag operation can end in the void, or above another palette. +If above a palette, see above. Into the void: create a new palette diff --git a/chalk/doc/plugins.txt b/chalk/doc/plugins.txt new file mode 100644 index 00000000..2902adb8 --- /dev/null +++ b/chalk/doc/plugins.txt @@ -0,0 +1,32 @@ +There are several kinds of plugins in Chalk: CoreModules and Plugins. Core modules +add functionality to Chalk but do not directly add to the user interface (menus and +toolbars). Plugins create actions. + +All plugins register themselves with the appropriate registry: + +KisToolRegistry -- tools like brush, crop etc. Tools are added to the menu and the tools + box, but are special in that every view has a different instantiation of a tool for every + pointer X11 presents to Chalk (mouse, stylus, eraser, other styluses for fancy wacom + tablets). + +KisColorSpaceRegistry -- color models like cmyk or rgb are core modules. These add the capability + to load and save and edit images in a particular color model and bit depth. + +KisFilterRegistry -- Filters are a little mode complicated in that these are operations that + should be available from many places in the application -- i.e, some tools build on + the availablity of filters, and filters can be building blocks in scripts -- but are + also directly available from the filter menu. + +KisPaintOpRegistry -- Paintops are plugins that define the way tools actually make + marks on the canvas. Paintops have no independent life in the gui but can be shown + in the toolbox. + +KisPluginRegistry -- Plugins that do not fall into any of the previous categories. Examples + are the GUI for scaling/resizing an image, select-by-colour etc. + + +Chalk automatically adds filters to the items menu and tools to the tools menu; paintops +are managed in the paintop toolbox and the tool plugins add themselves to the tools toolbar. +This is done without referring to the XML gui buider. General plugins, like select-by-colour, +that are often gui wrappers around core functionality, are loaded using the ordinary +KDE plugin framework. diff --git a/chalk/doc/profiles.txt b/chalk/doc/profiles.txt new file mode 100644 index 00000000..c1841d52 --- /dev/null +++ b/chalk/doc/profiles.txt @@ -0,0 +1,125 @@ +* Using littlecms for professional colourmanagement. + + +Profiles are applied to image data on import, paste, copy, display and +printing to calibrate for particular ways in which image data can +be presented or created. Profiles are associated with a certain +color space and with a device class. + +* The following profiles are available in Chalk: + +Image profile The image profile is the default profile + for the default color space for the layers + in Chalk + +Layer profile Chalk images can have layers of different + color spaces, so each layer can have a + different profile, too. + +Display profile When converting the visible part of + an image for displaying on the users monitor, + a monitor calibration profile can be applied + to adjust for display idiosyncrasies. + +Import profile On importing an image from disk that does + not have a profile embedded (XXX: embedded + profiles aren't recoginized yet), a screenshot + or a scan, the import profile is attached + to the image. + +Output profile On printing, a profile can be applied to the + image to compensate for the printer + idiosyncrasies. XXX: Printing doesn't work + yet at all, and printing is big task that + should be part of KDE. We should simply + convert an image to a tiff file with embedded + profile, and send that to a system printer. + + +* At the following points we need to handle profiles: + + +File import Chalk uses ImageMagick to import files. + ImageMagick knows about embedded profiles and + makes them available in memory. We need to + hack our IM builder to convert the in-memory + profile blob to a profile handle. + + +File export Chalk uses ImageMagick to export files. + Here we need to do the reverse trick; take + a profile handle and get IM to save it with + the file. + +Paste from clipboard Two cases: Chalk has placed a clip on the + clipboard, or another application has placed + a clip on the clipboard. Clips are wrapped + in the KisClip class that can be created with + a profile. That can be the profile of the + image Chalk copied the clip from, or the + copy profile set in the Settings, or none. + + An external clip is always RGB8 (for now, no + doubt Qt will extend its clipboard once RGB16 + images or RGB half images become widespread), + so in those cases we always need an RGB + profile. + + Paste from external applications is handled by + the constructor from KisPaintDevice, + internally it might entail a mode conversion. + +Copy to clipboard If another application consumes a clip Chalk + has put on the clipboard it can receive the + data as-is, or with a profile applied. + + Paste is handled by KisPaintDevice::convertToQImage. + +Display on monitor For calibrated displays. This is handled + by KisPaintDevice::convertToQImage() + +Image mode conversion A user can either choose to convert an + existing layer or image to another color + model/profile/bit depth or the conversion can + happen automatically, for instance when + painting when the color of a pixel is + converted from KoColor to the color in the + color model. + + This is handled by + KisStrategyColorSpace:convertTo(). + +File loading Chalk's own file format now has a field for + the product name of a profile. We need also to + be able to embed the entire profile into a + Chalk file. That should be easy, since a Chalk + file is just a zipfile. + +File saving When loading a Chalk file format image we + should also be able to load embedded profiles. + + +* Chalk should have a few extra features that are easy to implement + once I a) know what they mean, technically and b) the foregoing is + completed. These are: + +Softproofing Showing the image on the monitor with profiles + for printing applied, too. + +Out-of-gamut warnign Colours that cannot be printed are shown in + some hideous colour. + +Blackpoint compenstion No idea about this... + +8-bit image dither No idea. + +... lcms offers more stuff that I don't know + anything about but which might be interesting. + + +* External factors play a role. We need a free display calibration + tool for X11, a printing system that takes this stuff into account + and all the rest. That's not part of Chalk, but it needs to be done + some time. XXX: Ask the KGamma developers about this? + + diff --git a/chalk/doc/resolution.txt b/chalk/doc/resolution.txt new file mode 100644 index 00000000..ac4ced7f --- /dev/null +++ b/chalk/doc/resolution.txt @@ -0,0 +1,40 @@ +Ranjan Ghosh on resolution: + +The resolution dialog needs a bit of fine-tuning IMO. + +1) It's not only the print size that changes but the size on any media. +Therefore I propose adding a single option"physical size" to +the zoom menu (like 100%,200%, Fit in Window, Physical Size) and +changing the text a bit: + + + +Physical Size +---------------- +Width: [---------] (cm, mm,...) +Height: [---------] (cm, mm,...) + +The physical size of an image is determined by the +size in pixels, the image resolution shown above +and the physical resolution of the target media +(screen, printer, etc). Most images do not... + + + +Now you can enter some value here and when you later select +"Zoom to physical size" you will size the image on your screen +just like it is on your printer. Requirements for this to work: +A proper screen resolution setting in Properties (I would not +repeat it here though as it is confusing) and proper printer +resolution setting. Can this determined automatically? Otherwise +there is a need to enter a printer resolution to (perhaps +in the print dialogue itself or under properties) + +The metric system is not needed IMO. The resolution is never +given in dots per centimeter but always in dots per inch. Nobody +- even in Europe - will need that. It's just not used. Even more: +Most people certainly will want to enter some values in centimeter +but read the resolution in dpi. So I propose setting all resolution +values to dpi. + + diff --git a/chalk/doc/scripts/dcop.py b/chalk/doc/scripts/dcop.py new file mode 100644 index 00000000..cc703930 --- /dev/null +++ b/chalk/doc/scripts/dcop.py @@ -0,0 +1,14 @@ +from pydcop import * + +app = "" +for a in apps(): + if (a.startswith("chalk")): + app = anyAppCalled(a) + +doc = app.KoApplicationIface.getDocuments()[0] +img=doc.currentImage() +dev=img.activeDevice() +dev.setName("A new name") +print dev.pixelSize() +print dev.nChannels() +print dev.readBytes(10, 10, 1, 1) diff --git a/chalk/doc/sdk b/chalk/doc/sdk new file mode 100644 index 00000000..b811d80a --- /dev/null +++ b/chalk/doc/sdk @@ -0,0 +1,10 @@ +Chalk SDK + +The Chalk SDK is in development. Basically, plugins and extensions should +not include anything from chalk/core, but only the headers from chalk/sdk. + +Problem: creating new paint devices, layers and images. You cannot, obviously, +instantiate an interface, and we should not, equally obvious, code against +implementations. The solution is a factory class that is made available to +the plugin when it is created -- i.e, the tqparent class of a plugin should +implement the various factory interfaces for paint devices, images and layers. diff --git a/chalk/doc/selections b/chalk/doc/selections new file mode 100644 index 00000000..bdcdaa03 --- /dev/null +++ b/chalk/doc/selections @@ -0,0 +1,127 @@ +Selections in Chalk + +Please disregard any lingering presence of the KisFloatingSelection +class and the associated rectangular marque rendering code. If you +find anything connected with that after I finish coding the new +selections scheme, it's something I forgot. + +Selections in Chalk are special paint devices as big as their tqparent +layer. The selection has the alpha colour strategy. The alpha channel +contains the selectedness of a pixel. It is not a binary value, but a scale, +hardcoded to 8 bits unsigned + +TODO: * implement heterogenous compositing. (Needs knowledge by the + target layer of the color strategy of the source layer). + +Selections can be changed using tools that are clones of the usual +painting tools: brush, eraser, polygon, etc. + +TODO: * implement most of these, the polygon, circle, rectangle tools + should fill by default. XXX: make it easier to leverage the + code for the standard tools: after all, the only difference + is which layer they should paint on. + +XXX: Fill-by-default should be an option for the polygon, circle, + rectangle painting tools, too. + +Selections can also changed by procedures like select-by-color etc. + +TODO: * finish dialog for select by color + * implement select-by-color (depends on usable iterators) + +Selections are represented as 0== unselected and 255 == fully +selected. Values in between are semi selected + +Other representations of selections are possible: the selection for a +particular rect is rendered as a separate step in +KisImage::renderToProjection. I like the tqmask type rendering, but +someone else might want to provide an optional marque-rendering. + +TODO: * enable kconfig option to select between renderings. + +Selected pixels can be mangled -- for instance, filled with a +gradient, moved, made brighter, lighter or sprightlier, cut and +pasted. These manglings fall into two groups: the kind that demands +that the selected pixels are removed from their native layer, and the +kind that merely changes their value. + + +A) Moving, cutting, copying, pasting. + +Each of these operations moves pixels to a new KisLayer that is not +part of the regular stack of layers. The operations are defined as +follows: + +Moving: create new layer, copy selected pixels to this layer, set +pixels in old layer to transparent background colour, set new layer +visible. + +Cutting: create new layer, copy selected pixels to this layer, set +pixels in old layer to transparent background colour, add new layer to +the cut scrapbook (if we're going to have such a thing). + +XXX: Discuss desirability of cut scrapbook. + +Copying: create new layer, copy selected pixels to this layer, add new +layer to the cut scrapbook (if we're going to have such a thing). + +Pasting: check if cut or copy layer exists in scrapbook, copy pixels +from this layer to the target layer. + +B) Changing the value of selected pixels + +Use cases: fills (gradient, pattern, color), filtering. + +Fills are easiest implemented by creating a filled paint device for +the rect covered by the selection, and then, while composting the fill +with the target layer, pass the tqmask to the compositing loop, and skip +un-selected pixels. + +XXX: Discuss whether this is true + +Filtering needs looping over all pixels of a layer, and, if selection +is present, only apply filter to the selected pixel. + +XXX: What about convolving, which takes a matrix of pixels. If only +the middle pixel of a matrix is selected, should we take the input of +the surrounding unselected pixels, or should the operation then assume +edge conditions? Or should this be an option? + +TODO: infrastructure for all these operations, actual implementation. + +Actions to a selection need to be undoable. + +TODO: Make it so. + +I am not sure whether selections need to be saved and loaded: +Photoshop offers this, but our selection mechanism works differently. +The Gimp offers selection adding/subtracting, but that's also not +really necessary. A good idea is perhaps to add a combobox to the +selection tool properties widget to choose between 'select' and +'deselect', where the brush is initially set to 'select' and the +eraser to 'deselect'. + +From a thread in the mailing list Boudewijn wrote: +----------------------------------------------------------------------- +This is the behaviour I expect from a paint app: + +If there's a selection on the current layer, only the selected pixels in the +current layer should be transformed, rotated, scaled or sheared. This happens +within the layer. If the new pixels overlap untransformed pixels, they are +composed with the giving composite op and opacity. + +If there's no selection, a transform on a layer should transform all pixels in +a layer, i.e., act as if the layer was completely selected. No new layer is +created. There is no composition, because the old layer data is completely +discarded. + +If a transform is applied to a image, all layers are transformed. The +selection is transformed, too: in the new situation, the layer that has a +selection active still has a selection, but the tqshape of the selection is +transformed. + +If a layer is moved, the selection moves with the layer (this is not +implemented yet). + +A transform never creates a new layer (expect perhaps temporarily and it +wouldn't be visible to the user). diff --git a/chalk/doc/the preview widget b/chalk/doc/the preview widget new file mode 100644 index 00000000..cc06b9de --- /dev/null +++ b/chalk/doc/the preview widget @@ -0,0 +1,81 @@ + +On Tuesday 21 June 2005 14:16, Casper Boemann wrote: +> Hi +> +> As you might have noticed I have changed the tqlayout of the preview, to lo= +ok +> more like digikam. +> +> Now the preview widget itself also needs some updating: +> - zoom doesn't exist in the digikam preview - the image is zoomed all out +> - that doesn't mean we shouldn't keep the abillity to zoom, but I think +> default should be zoomed out as in digikam. + +Agreed. We should show all of the image in our preview. + +> - the update of the preview seems slow. Is the algorithm as effective as +> it can be? + +No, definitely not. In fact, if I remember correctly, preview copies & rend= +ers=20 +the complete image. Options are: + +* Just preview the active layer, out of context +* Copy the image, scale it down, and then render it. Cache the scaled-down= +=20 +thumbnail. +* Work on the QImage of the rendered image, and apply all filters on that -= +=2D=20 +for preview, that may be accurate enough. + +Note that we want a fast thumbnail preview for in the bird's eye box, too, = +and=20 +in the variations dialog we need a whole bunch of previews. So I guess the= +=20 +requirements are: + +* Frugal with memory +* Fast +* Filters should work on the preview image +* Zoomable, but initially the complete image/layer is shown +* Selectable: preview layer/preview image + +I have a feeling that this may be hard to achieve... + +> This is not something I'm going to do, but I think we should discuss it a= +nd +> put it in the TODO. + +Definitely.=20 + +=2D-=20 +Boudewijn Rempt=20 +http://www.valdyas.org/fading/index.cgi + +--nextPart43061363.Bp4Ilo6nOP +Content-Type: application/pgp-signature + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.2.5 (GNU/Linux) + +iD8DBQBCuAdpdaCcgCmN5d8RAp2hAKDfwdjOxB6EoYaJUuYYJlrculR3yACfcYMJ +KjDOPxiFJdTsLAU00lJNOGE= +=1wDD +-----END PGP SIGNATURE----- + +--nextPart43061363.Bp4Ilo6nOP-- + +--===============1891010795== +Content-Type: text/plain; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Content-Disposition: inline + +_______________________________________________ +kimageshop mailing list +kimageshop@kde.org +https://mail.kde.org/mailman/listinfo/kimageshop + +--===============1891010795==-- + + diff --git a/chalk/doc/transform_undo.txt b/chalk/doc/transform_undo.txt new file mode 100644 index 00000000..fa960655 --- /dev/null +++ b/chalk/doc/transform_undo.txt @@ -0,0 +1,38 @@ +Problem: + +When working with the transform tool, the user performs many adjustments. +These adjustments should be aggregated into one transform, and always +performed from the original state of the image, as it was before the +first transformation adjustment was applied -- because otherwise +the quality degradation becomes too bad. + +That means that all work with the transform tool should eventually +result in one transform command. However, when working with the transform +tool, the user expects to be able to undo various stages of his transform +actions. And undo should not undo to the original state, but to the previous +state. + +When the user selects another tool, the definitive transform is applied. +This happens because selecting another tool calls the clear function of +the transform tool. One transform command should end up on the undo +stack. + +When the user selects an action from the menu, like a filter, +the definitive transform should also be applied, and only +then the action from the menu. + +Thus, we have two problems: + +* Transforms should always be done from the original image, but undoing +the transform command should unto to the previous state. + +* Pending transforms should be committed before a menu action is taken. + +These problems can be solved in one go, without any of the complications +I created yesterday by always committing the transform to the undo history +in the transform() method, but by performing the transform from the original +paint device, as it was when the tool got activated. + +Menu actions should reset the tool: for this we will need my complicated hack, +I propose resetting the transform tool after a command is added. + diff --git a/chalk/dtd/Makefile.am b/chalk/dtd/Makefile.am new file mode 100644 index 00000000..525277c4 --- /dev/null +++ b/chalk/dtd/Makefile.am @@ -0,0 +1,4 @@ +dtd_DATA = chalk.dtd + +dtddir = $(kde_datadir)/chalk/dtd + diff --git a/chalk/dtd/chalk.dtd b/chalk/dtd/chalk.dtd new file mode 100644 index 00000000..1e690f0b --- /dev/null +++ b/chalk/dtd/chalk.dtd @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/extracti18n.pl b/chalk/extracti18n.pl new file mode 100755 index 00000000..0e0fcf78 --- /dev/null +++ b/chalk/extracti18n.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl -w + +# This file is part of Chalk +# +# Copyright (c) 2005 Sven Langkamp +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +use strict; +use warnings; + +sub printi18n { + print "i18n(\"".$_[0]."\");\n"; +} + +my @filenames = glob("./data/gradients/*.ggr"); +push( @filenames, glob("./data/palettes/*.gpl")); +push( @filenames, glob("./data/brushes/*.gih")); +push( @filenames, glob("./data/brushes/*.gbr")); +push( @filenames, glob("./data/patterns/*.pat")); +foreach my $filename (@filenames) +{ + unless ( open(FILE, '<'.$filename) ) + { + next; + } + if( $filename =~ /ggr/ || $filename =~ /gpl/ || $filename =~ /gih/ ) + { + my @lines = ; + close(FILE); + if( $filename =~ /ggr/ || $filename =~ /gpl/ ) + { + my @splited = split(/: /, $lines[1]); + my $name = $splited[1]; + chomp($name); + printi18n $name; + } + else + { + my $name = $lines[0]; + chomp($name); + printi18n $name; + } + } + else + { + if( $filename =~ /gbr/ ) + { + read(FILE, my $bytes, 4); + my $size = unpack("N", $bytes); + read(FILE, $bytes, 4); + my $version = unpack("N", $bytes); + if( $version == 1 ) + { + read(FILE, $bytes, 12); + read(FILE, my $name, $size - 21); + printi18n $name; + } + else + { + read(FILE, $bytes, 20); + read(FILE, my $name, $size - 29); + printi18n $name; + } + } + else + { + read(FILE, my $bytes, 4); + my $size = unpack("N", $bytes); + read(FILE, $bytes, 20); + read(FILE, my $name, $size - 25); + printi18n $name; + } + } +} + + diff --git a/chalk/main.cc b/chalk/main.cc new file mode 100644 index 00000000..52ffc2fd --- /dev/null +++ b/chalk/main.cc @@ -0,0 +1,43 @@ +/* + * main.cc - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + */ +#include +#include +#include + +#include "ui/kis_aboutdata.h" + +static const KCmdLineOptions options[] = { + { "+[file(s)]", I18N_NOOP("File(s) or URL(s) to open"), 0 }, + KCmdLineLastOption +}; + +extern "C" KRITA_EXPORT int kdemain(int argc, char **argv) +{ + KCmdLineArgs::init(argc, argv, newChalkAboutData()); + KCmdLineArgs::addCmdLineOptions(options); + + KoApplication app; + + if (!app.start()) + return 1; + + return app.exec(); +} + diff --git a/chalk/pics/Makefile.am b/chalk/pics/Makefile.am new file mode 100644 index 00000000..8ce558d1 --- /dev/null +++ b/chalk/pics/Makefile.am @@ -0,0 +1,22 @@ + +chalkpics_DATA = deletelayer.png \ + lowerlayer.png \ + newlayer.png \ + raiselayer.png \ + visible.png \ + novisible.png \ + linked.png \ + unlinked.png \ + tool_screenshot.png \ + tablet.png \ + locked.png \ + unlocked.png + +# directory for pixmaps +chalkpicsdir = $(kde_datadir)/chalk/pics + +KDE_ICON = chalk + + + + diff --git a/chalk/pics/chalk.svg b/chalk/pics/chalk.svg new file mode 100644 index 00000000..8f43024e --- /dev/null +++ b/chalk/pics/chalk.svg @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/pics/deletelayer.png b/chalk/pics/deletelayer.png new file mode 100644 index 00000000..21395643 Binary files /dev/null and b/chalk/pics/deletelayer.png differ diff --git a/chalk/pics/height.png b/chalk/pics/height.png new file mode 100644 index 00000000..2458a882 Binary files /dev/null and b/chalk/pics/height.png differ diff --git a/chalk/pics/hi128-app-chalk.png b/chalk/pics/hi128-app-chalk.png new file mode 100644 index 00000000..da32794a Binary files /dev/null and b/chalk/pics/hi128-app-chalk.png differ diff --git a/chalk/pics/hi16-app-chalk.png b/chalk/pics/hi16-app-chalk.png new file mode 100644 index 00000000..061a063d Binary files /dev/null and b/chalk/pics/hi16-app-chalk.png differ diff --git a/chalk/pics/hi22-app-chalk.png b/chalk/pics/hi22-app-chalk.png new file mode 100644 index 00000000..304ce244 Binary files /dev/null and b/chalk/pics/hi22-app-chalk.png differ diff --git a/chalk/pics/hi32-app-chalk.png b/chalk/pics/hi32-app-chalk.png new file mode 100644 index 00000000..4762440d Binary files /dev/null and b/chalk/pics/hi32-app-chalk.png differ diff --git a/chalk/pics/hi48-app-chalk.png b/chalk/pics/hi48-app-chalk.png new file mode 100644 index 00000000..346c3b38 Binary files /dev/null and b/chalk/pics/hi48-app-chalk.png differ diff --git a/chalk/pics/hi64-app-chalk.png b/chalk/pics/hi64-app-chalk.png new file mode 100644 index 00000000..a89dbdb1 Binary files /dev/null and b/chalk/pics/hi64-app-chalk.png differ diff --git a/chalk/pics/linked.png b/chalk/pics/linked.png new file mode 100644 index 00000000..5c6b59c8 Binary files /dev/null and b/chalk/pics/linked.png differ diff --git a/chalk/pics/locked.png b/chalk/pics/locked.png new file mode 100644 index 00000000..dbd0a50d Binary files /dev/null and b/chalk/pics/locked.png differ diff --git a/chalk/pics/lowerlayer.png b/chalk/pics/lowerlayer.png new file mode 100644 index 00000000..4cdd6c69 Binary files /dev/null and b/chalk/pics/lowerlayer.png differ diff --git a/chalk/pics/newlayer.png b/chalk/pics/newlayer.png new file mode 100644 index 00000000..321381bb Binary files /dev/null and b/chalk/pics/newlayer.png differ diff --git a/chalk/pics/novisible.png b/chalk/pics/novisible.png new file mode 100644 index 00000000..d4f992f2 Binary files /dev/null and b/chalk/pics/novisible.png differ diff --git a/chalk/pics/raiselayer.png b/chalk/pics/raiselayer.png new file mode 100644 index 00000000..ed816bf5 Binary files /dev/null and b/chalk/pics/raiselayer.png differ diff --git a/chalk/pics/shade.png b/chalk/pics/shade.png new file mode 100644 index 00000000..84726dbc Binary files /dev/null and b/chalk/pics/shade.png differ diff --git a/chalk/pics/tablet.png b/chalk/pics/tablet.png new file mode 100644 index 00000000..229c4699 Binary files /dev/null and b/chalk/pics/tablet.png differ diff --git a/chalk/pics/tool_screenshot.png b/chalk/pics/tool_screenshot.png new file mode 100644 index 00000000..79743e82 Binary files /dev/null and b/chalk/pics/tool_screenshot.png differ diff --git a/chalk/pics/unlinked.png b/chalk/pics/unlinked.png new file mode 100644 index 00000000..ac74b836 Binary files /dev/null and b/chalk/pics/unlinked.png differ diff --git a/chalk/pics/unlocked.png b/chalk/pics/unlocked.png new file mode 100644 index 00000000..189ba8f8 Binary files /dev/null and b/chalk/pics/unlocked.png differ diff --git a/chalk/pics/visible.png b/chalk/pics/visible.png new file mode 100644 index 00000000..740efc8c Binary files /dev/null and b/chalk/pics/visible.png differ diff --git a/chalk/pics/width.png b/chalk/pics/width.png new file mode 100644 index 00000000..ad71ccc5 Binary files /dev/null and b/chalk/pics/width.png differ diff --git a/chalk/plugins/Makefile.am b/chalk/plugins/Makefile.am new file mode 100644 index 00000000..468df77e --- /dev/null +++ b/chalk/plugins/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = \ + filters \ + paintops \ + tools \ + viewplugins diff --git a/chalk/plugins/README b/chalk/plugins/README new file mode 100644 index 00000000..33af951e --- /dev/null +++ b/chalk/plugins/README @@ -0,0 +1,42 @@ +About plugins + +Plugins are components with a GUI that perform some action for Chalk. +Note that plugins are only loaded when a KisView is constructed; note +also that every plugin is reloaded when a new KisView is created. + +Plugins are _not_ allowed to depend on each other. You may _not_ +#include a header file from a plugin anywhere but in that same plugin. +You can however choose to group a cluster of related functions in +one plugin, like with the selection tools. + +There are several kinds of plugins for Chalk: + +* Tools + + Tools have the Chalk/Tool servicetype. A tool plugin registers + the tool factories it provides with the tool registry. A tool must descend + from the KisTool interface. There are several base classes for + specialized tools, like painting and non painting tools. + +* Paintops + + Paintops implement methods for changing pixels that can be used + by painting tools. Examples are brush, pen, airbrush. Paintop plugins + have the Chalk/Paintop servicetype, register paintop factories they + provide the paintop registry. Paintops inherit KisPaintOp. + +* Filters + + Filters implement methods of changin a rectangular area of pixels. Filter + plugins have the Chalk/Filter servicetype and are registered with + the filter registry. A filter inherits the KisFilter class and may + provide a configuration widget and a configuration object. + +* Extensions + + Extensions are loaded by every view instance. They provide user interface + elements such as dialog boxes and wizards. Their parent is KisView and + they provide an .rc file to merge their gui with the view gui. Extensions + have the servicetype Chalk/Plugin. They are not loaded automatically by + the KParts mechanism; please do not create ordinary kparts that are to + be loaded by the Chalk view since KParts are not versioned. diff --git a/chalk/plugins/configure.in.in b/chalk/plugins/configure.in.in new file mode 100644 index 00000000..c1845fdc --- /dev/null +++ b/chalk/plugins/configure.in.in @@ -0,0 +1,2 @@ +KDE_CHECK_HEADER(kjsembed/jsproxy_imp.h, have_kjsembed=yes, have_kjsembed=no) +AM_CONDITIONAL(use_kjsembed, test x$have_kjsembed = xyes) diff --git a/chalk/plugins/filters/Makefile.am b/chalk/plugins/filters/Makefile.am new file mode 100644 index 00000000..19ff6736 --- /dev/null +++ b/chalk/plugins/filters/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = bumpmap cimg convolutionfilters embossfilter example imageenhancement \ + oilpaintfilter pixelizefilter raindropsfilter roundcorners smalltilesfilter \ + sobelfilter colorsfilters noisefilter wavefilter randompickfilter \ + lenscorrectionfilter blur colors fastcolortransfer unsharp levelfilter colorify diff --git a/chalk/plugins/filters/blur/Makefile.am b/chalk/plugins/filters/blur/Makefile.am new file mode 100644 index 00000000..8ccfbe5f --- /dev/null +++ b/chalk/plugins/filters/blur/Makefile.am @@ -0,0 +1,22 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkblurfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkblurfilter_la_SOURCES = wdgblur.ui blur.cc kis_blur_filter.cc kis_wdg_blur.cc + +kde_module_LTLIBRARIES = chalkblurfilter.la +noinst_HEADERS = blur.h kis_blur_filter.h + +chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkblurfilter_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO + diff --git a/chalk/plugins/filters/blur/blur.cc b/chalk/plugins/filters/blur/blur.cc new file mode 100644 index 00000000..bcf798b9 --- /dev/null +++ b/chalk/plugins/filters/blur/blur.cc @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "blur.h" + +#include + +#include "kis_blur_filter.h" + +typedef KGenericFactory BlurFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkblurfilter, BlurFilterPluginFactory( "chalk" ) ) + +BlurFilterPlugin::BlurFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(BlurFilterPluginFactory::instance()); + + + kdDebug(41006) << "Extensions Convolution Filters plugin. Class: " + << className() + << ", Parent: " + << tqparent -> className() + << "\n"; + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisBlurFilter()); + } +} + +BlurFilterPlugin::~BlurFilterPlugin() +{ +} diff --git a/chalk/plugins/filters/blur/blur.h b/chalk/plugins/filters/blur/blur.h new file mode 100644 index 00000000..8ce31706 --- /dev/null +++ b/chalk/plugins/filters/blur/blur.h @@ -0,0 +1,37 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BLURPLUGIN_H +#define BLURPLUGIN_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class BlurFilterPlugin : public KParts::Plugin +{ +public: + BlurFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~BlurFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/blur/chalkblurfilter.desktop b/chalk/plugins/filters/blur/chalkblurfilter.desktop new file mode 100644 index 00000000..5adb437b --- /dev/null +++ b/chalk/plugins/filters/blur/chalkblurfilter.desktop @@ -0,0 +1,38 @@ +[Desktop Entry] +Icon= +Name=Convolution Filters (Extension) +Name[bg]=Изкривяващи филтри (разширения) +Name[ca]=Filtres d'enrotllament (Extensió) +Name[da]=Foldningsfiltre (Udvidelse) +Name[de]=Faltungsfilter (Erweiterung) +Name[el]=Φίλτρα περιέλιξης (Επέκταση) +Name[es]=Filtros de convolución (Extensión) +Name[et]=Konvolutsioonifiltrid (laiendus) +Name[fa]=پالایه‌های هم‌پیچش )پسوند( +Name[fr]=Filtres de convolution (extension) +Name[fy]=Ferdraaiïngsfilters (útwreiding) +Name[ga]=Scagairí Conbhlóide (Eisínteacht) +Name[gl]=Filtros de Convolución (Extensións) +Name[hu]=Konvolúciószűrők (kiterjesztés) +Name[it]=Filtri di convoluzione (estensione) +Name[ja]=コンボリューションフィルタ (拡張) +Name[km]=តម្រង​អង្កាញ់ (ផ្នែក​បន្ថែម) +Name[nb]=Konvolusjonsfiltre (Utvidelse) +Name[nds]=Fooldenfilters (Verwiedern) +Name[ne]=कुण्डलीकरण फिल्टरहरू (अपवाद) +Name[nl]=Verdraaiïngsfilters (uitbreiding) +Name[pl]=Filtry splotowe (rozszerzenie) +Name[pt]=Filtros de Convolução (Extensão) +Name[pt_BR]=Filtros de Convolução (Extensão) +Name[ru]=Свёртка (расширение) +Name[sk]=Filtre zatočenia (rozšírenie) +Name[sl]=Konvolucijski filtri (razširitev) +Name[sr]=Конволуциони филтери (проширење) +Name[sr@Latn]=Konvolucioni filteri (proširenje) +Name[sv]=Faltningsfilter (utökning) +Name[uk]=Фільтри згортки (розширення) +Name[zh_TW]=皺褶過濾器(延伸) +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkblurfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/blur/kis_blur_filter.cc b/chalk/plugins/filters/blur/kis_blur_filter.cc new file mode 100644 index 00000000..8709c073 --- /dev/null +++ b/chalk/plugins/filters/blur/kis_blur_filter.cc @@ -0,0 +1,143 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_blur_filter.h" + +#include +#include + +#include +#include +#include +#include +#include + + +#include "kis_wdg_blur.h" +#include "wdgblur.h" + +KisKernelSP kernelFromTQImage(const TQImage& img) +{ + KisKernelSP k = new KisKernel; + k->width = img.width(); + k->height = img.height(); + k->offset = 0; + uint count = k->width * k->height; + k->data = new TQ_INT32[count]; + TQ_INT32* itData = k->data; + TQ_UINT8* itImg = (TQ_UINT8*)img.bits(); + k->factor = 0; + for(uint i = 0; i < count; ++i , ++itData, itImg+=4) + { + *itData = 255 - ( *itImg + *(itImg+1) + *(itImg+2) ) / 3; + k->factor += *itData; + } + return k; +} + +KisBlurFilter::KisBlurFilter() : KisFilter(id(), "blur", i18n("&Blur...")) +{ +} + +KisFilterConfigWidget * KisBlurFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + return new KisWdgBlur(this, tqparent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisBlurFilter::configuration(TQWidget* w) +{ + KisWdgBlur * wCTA = dynamic_cast(w); + if(!wCTA) return 0; + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wCTA) + { + config->setProperty("halfWidth", wCTA->widget()->intHalfWidth->value() ); + config->setProperty("halfHeight", wCTA->widget()->intHalfWidth->value() ); + config->setProperty("rotate", wCTA->widget()->intAngle->value() ); + config->setProperty("strength", wCTA->widget()->intStrength->value() ); + config->setProperty("tqshape", wCTA->widget()->cbShape->currentItem()); + } + return config; +} + +void KisBlurFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + if(!config) config = new KisFilterConfiguration(id().id(), 1); + + TQVariant value; + int tqshape = (config->getProperty("tqshape", value)) ? value.toInt() : 0; + uint halfWidth = (config->getProperty("halfWidth", value)) ? value.toUInt() : 5; + uint width = 2 * halfWidth + 1; + uint halfHeight = (config->getProperty("halfHeight", value)) ? value.toUInt() : 5; + uint height = 2 * halfHeight + 1; + int rotate = (config->getProperty("rotate", value)) ? value.toInt() : 0; + int strength = 100 - (config->getProperty("strength", value)) ? value.toUInt() : 0; + + int hFade = (halfWidth * strength) / 100; + int vFade = (halfHeight * strength) / 100; + + KisAutobrushShape* kas; + kdDebug() << width << " " << height << " " << hFade << " " << vFade << endl; + switch(tqshape) + { + case 1: + kas = new KisAutobrushRectShape(width, height , hFade, vFade); + break; + case 0: + default: + kas = new KisAutobrushCircleShape(width, height, hFade, vFade); + break; + } + TQImage tqmask; + kas->createBrush(&tqmask); + + tqmask.convertDepth(1); + + if( rotate != 0) + { + TQWMatrix m; + m.rotate( rotate ); + tqmask = tqmask.xForm( m ); + if( (tqmask.height() & 1) || tqmask.width() & 1) + { + tqmask.smoothScale( tqmask.width() + !(tqmask.width() & 1), tqmask.height() + !(tqmask.height() & 1) ); + } + } + + KisConvolutionPainter painter( dst ); + if (m_progressDisplay) + m_progressDisplay->setSubject( &painter, true, true ); + + KisKernelSP kernel = kernelFromTQImage(tqmask); // TODO: for 1.6 reuse the chalk's core function for creating kernel : KisKernel::fromTQImage + + painter.applyMatrix(kernel, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_REPEAT, KisChannelInfo::FLAG_COLOR_AND_ALPHA); + + if (painter.cancelRequested()) { + cancel(); + } + + setProgressDone(); // Must be called even if you don't really support progression +} + diff --git a/chalk/plugins/filters/blur/kis_blur_filter.h b/chalk/plugins/filters/blur/kis_blur_filter.h new file mode 100644 index 00000000..88655186 --- /dev/null +++ b/chalk/plugins/filters/blur/kis_blur_filter.h @@ -0,0 +1,49 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_BLUR_FILTER_H +#define KIS_BLUR_FILTER_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include "kis_filter.h" + +class KisBlurFilter : public KisFilter +{ + public: + KisBlurFilter(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("blur", i18n("Blur")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual bool supportsThreading() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/blur/kis_wdg_blur.cc b/chalk/plugins/filters/blur/kis_wdg_blur.cc new file mode 100644 index 00000000..bfed7474 --- /dev/null +++ b/chalk/plugins/filters/blur/kis_wdg_blur.cc @@ -0,0 +1,116 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_blur.h" + +#include +#include + +#include +#include + +#include + +#include + +#include "wdgblur.h" + +KisWdgBlur::KisWdgBlur( KisFilter* nfilter, TQWidget * tqparent, const char * name) : KisFilterConfigWidget ( tqparent, name ) +{ + Q_UNUSED( nfilter ); + + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgBlur(this); + widgetLayout -> addWidget(m_widget,0,0); + + linkSpacingToggled(true); + + connect( widget()->bnLinkSize, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(linkSpacingToggled( bool ))); + connect( widget()->intHalfWidth, TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxHalfWidthChanged(int))); + connect( widget()->intHalfHeight, TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxHalfHeightChanged(int))); + + connect( widget()->intStrength, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intAngle, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbShape, TQT_SIGNAL( activated(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + + +void KisWdgBlur::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("tqshape", value)) + { + widget()->cbShape->setCurrentItem( value.toUInt() ); + } + if (config->getProperty("halfWidth", value)) + { + widget()->intHalfWidth->setValue( value.toUInt() ); + } + if (config->getProperty("halfHeight", value)) + { + widget()->intHalfHeight->setValue( value.toUInt() ); + } + if (config->getProperty("rotate", value)) + { + widget()->intAngle->setValue( value.toUInt() ); + } + if (config->getProperty("strength", value)) + { + widget()->intStrength->setValue( value.toUInt() ); + } +} + +void KisWdgBlur::linkSpacingToggled(bool b) +{ + m_halfSizeLink = b; + KoImageResource kir; + if (b) { + widget()->bnLinkSize->setPixmap(kir.chain()); + } + else { + widget()->bnLinkSize->setPixmap(kir.chainBroken()); + } +} + +void KisWdgBlur::spinBoxHalfWidthChanged(int v) +{ + if(m_halfSizeLink) { + widget()->intHalfHeight->setValue(v); + } +/* if( widget()->intHalfHeight->value() == v && widget()->cbShape->currentItem() != 1) + widget()->intAngle->setEnabled(false); + else + widget()->intAngle->setEnabled(true);*/ + emit sigPleaseUpdatePreview(); +} + +void KisWdgBlur::spinBoxHalfHeightChanged(int v) +{ + if(m_halfSizeLink) { + widget()->intHalfWidth->setValue(v); + } +/* if( widget()->intHalfWidth->value() == v && widget()->cbShape->currentItem() != 1) + widget()->intAngle->setEnabled(false); + else + widget()->intAngle->setEnabled(true);*/ + emit sigPleaseUpdatePreview(); +} + +#include "kis_wdg_blur.moc" diff --git a/chalk/plugins/filters/blur/kis_wdg_blur.h b/chalk/plugins/filters/blur/kis_wdg_blur.h new file mode 100644 index 00000000..c0cc4834 --- /dev/null +++ b/chalk/plugins/filters/blur/kis_wdg_blur.h @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_WDG_BLUR_H_ +#define _KIS_WDG_BLUR_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class KisFilter; +class WdgBlur; + +class KisWdgBlur : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgBlur( KisFilter* nfilter, TQWidget * tqparent, const char * name); + inline WdgBlur* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private slots: + void linkSpacingToggled(bool); + void spinBoxHalfWidthChanged(int ); + void spinBoxHalfHeightChanged(int ); + private: + bool m_halfSizeLink; + WdgBlur* m_widget; +}; + +#endif diff --git a/chalk/plugins/filters/blur/wdgblur.ui b/chalk/plugins/filters/blur/wdgblur.ui new file mode 100644 index 00000000..06119596 --- /dev/null +++ b/chalk/plugins/filters/blur/wdgblur.ui @@ -0,0 +1,227 @@ + +WdgBlur + + + WdgBlur + + + + 0 + 0 + 430 + 218 + + + + + unnamed + + + 0 + + + 0 + + + + spacer5_2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + tqlayout17 + + + + unnamed + + + + bnLinkSize + + + + 1 + 0 + 0 + 0 + + + + + 16 + 0 + + + + + 16 + 32767 + + + + + + + true + + + true + + + + + + Circle + + + + + Rectangle + + + + cbShape + + + + + textLabel5 + + + Angle: + + + + + + + + textLabel3 + + + Strength: + + + + + intHalfWidth + + + 10 + + + 1 + + + 1000 + + + + + intHalfHeight + + + 10 + + + 1 + + + 1000 + + + + + textLabel1 + + + Half-width: + + + + + textLabel4 + + + Shape: + + + + + intStrength + + + 0 + + + 100 + + + + + textLabel2 + + + Half-height: + + + + + intAngle + + + -180 + + + 180 + + + + + + + + + + + kcombobox.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/bumpmap/Makefile.am b/chalk/plugins/filters/bumpmap/Makefile.am new file mode 100644 index 00000000..ae6530ae --- /dev/null +++ b/chalk/plugins/filters/bumpmap/Makefile.am @@ -0,0 +1,19 @@ +kde_services_DATA = chalkbumpmapfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +chalkbumpmap_la_SOURCES = bumpmap.cc wdgbumpmap.ui + +kde_module_LTLIBRARIES = chalkbumpmap.la +noinst_HEADERS = bumpmap.h + +chalkbumpmap_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkbumpmap_la_LIBADD = ../../../libchalkcommon.la + +chalkbumpmap_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/bumpmap/bumpmap.cc b/chalk/plugins/filters/bumpmap/bumpmap.cc new file mode 100644 index 00000000..455889d5 --- /dev/null +++ b/chalk/plugins/filters/bumpmap/bumpmap.cc @@ -0,0 +1,533 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * This implementation completely and utterly based on the gimp's bumpmap.c, + * copyright: + * Copyright (C) 1997 Federico Mena Quintero + * Copyright (C) 1997-2000 Jens Lautenbacher + * Copyright (C) 2000 Sven Neumann + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wdgbumpmap.h" +#include "bumpmap.h" + +#define MOD(x, y) \ + ((x) < 0 ? ((y) - 1 - ((y) - 1 - (x)) % (y)) : (x) % (y)) + +typedef KGenericFactory ChalkBumpmapFactory; +K_EXPORT_COMPONENT_FACTORY( chalkbumpmap, ChalkBumpmapFactory( "chalk" ) ) + +ChalkBumpmap::ChalkBumpmap(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkBumpmapFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterBumpmap()); + } +} + +ChalkBumpmap::~ChalkBumpmap() +{ +} + +KisFilterBumpmap::KisFilterBumpmap() : KisFilter(id(), "map", i18n("&Bumpmap...")) +{ +} + +namespace { + void convertRow(KisPaintDevice * orig, TQ_UINT8 * row, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_UINT8 * lut, TQ_INT32 waterlevel) + { + KisColorSpace * csOrig = orig->colorSpace(); + + KisHLineIteratorPixel origIt = orig->createHLineIterator(x, y, w, false); + for (int i = 0; i < w; ++i) { + row[0] = csOrig->intensity8(origIt.rawData()); + row[0] = lut[waterlevel + ((row[0] - waterlevel) * csOrig->getAlpha(origIt.rawData())) / 255]; + + ++row; + ++origIt; + } + } + +} + +void KisFilterBumpmap::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* cfg, const TQRect& rect) +{ + if (!src) return; + if (!dst) return; + if (!cfg) return; + if (!rect.isValid()) return; + if (rect.isNull()) return; + if (rect.isEmpty()) return; + + KisBumpmapConfiguration * config = (KisBumpmapConfiguration*)cfg; + + TQ_INT32 xofs, yofs; /// The x,y offset values + TQ_INT32 lx, ly; /* X and Y components of light vector */ + TQ_INT32 nz2, nzlz; /* nz^2, nz*lz */ + TQ_INT32 background; /* Shade for vertical normals */ + double compensation; /* Background compensation */ + TQ_UINT8 lut[256]; /* Look-up table for modes */ + + double azimuth; + double elevation; + TQ_INT32 lz, nz; + TQ_INT32 i; + double n; + + // ------------------ Prepare parameters + + /* Convert the offsets */ + xofs = -config->xofs; + yofs = -config->yofs; + + /* Convert to radians */ + azimuth = M_PI * config->azimuth / 180.0; + elevation = M_PI * config->elevation / 180.0; + + /* Calculate the light vector */ + lx = (TQ_INT32)(cos(azimuth) * cos(elevation) * 255.0); + ly = (TQ_INT32)(sin(azimuth) * cos(elevation) * 255.0); + + lz = (TQ_INT32)(sin(elevation) * 255.0); + + /* Calculate constant Z component of surface normal */ + nz = (TQ_INT32)((6 * 255) / config->depth); + nz2 = nz * nz; + nzlz = nz * lz; + + /* Optimize for vertical normals */ + background = lz; + + /* Calculate darkness compensation factor */ + compensation = sin(elevation); + + /* Create look-up table for map type */ + for (i = 0; i < 256; i++) + { + switch (config->type) + { + case SPHERICAL: + n = i / 255.0 - 1.0; + lut[i] = (int) (255.0 * sqrt(1.0 - n * n) + 0.5); + break; + + case SINUSOIDAL: + n = i / 255.0; + lut[i] = (int) (255.0 * + (sin((-M_PI / 2.0) + M_PI * n) + 1.0) / + 2.0 + 0.5); + break; + + case LINEAR: + default: + lut[i] = i; + } + + if (config->invert) + lut[i] = 255 - lut[i]; + } + + + // Crate a grayscale layer from the bumpmap layer. + TQRect bmRect; + KisPaintDevice * bumpmap; + + if (!config->bumpmap.isNull() && src->image()) { + KisLayerSP l = src->image()->findLayer(config->bumpmap); + KisPaintDeviceSP bumplayer = 0; + + KisPaintLayer * pl = dynamic_cast(l.data()); + if (pl) { + bumplayer = pl->paintDevice(); + } + else { + KisGroupLayer * gl = dynamic_cast(l.data()); + if (gl) { + bumplayer = gl->projection(gl->extent()); + } + else { + KisAdjustmentLayer * al = dynamic_cast(l.data()); + if (al) { + bumplayer = al->cachedPaintDevice(); + } + } + } + + + if (bumplayer) { + bmRect = bumplayer->exactBounds(); + bumpmap = bumplayer.data(); + } + else { + bmRect = rect; + bumpmap = src; + } + } + + if(!bmRect.isValid()) { + bmRect = rect; + bumpmap = src; + } + + kdDebug(12345) << "KisFilterBumpmap::process: rect=" << rect << ", bumpmap rect=" << bmRect << "\n"; + + setProgressTotalSteps(rect.height()); + + // ---------------------- Load initial three bumpmap scanlines + + KisColorSpace * srcCs = src->colorSpace(); + TQValueVector channels = srcCs->channels(); + + // One byte per pixel, converted from the bumpmap layer. + TQ_UINT8 * bm_row1 = new TQ_UINT8[bmRect.width()]; + TQ_UINT8 * bm_row2 = new TQ_UINT8[bmRect.width()]; + TQ_UINT8 * bm_row3 = new TQ_UINT8[bmRect.width()]; + TQ_UINT8 * tmp_row; + + // ------------------- Map the bumps + TQ_INT32 yofs1, yofs2, yofs3; + + // ------------------- Initialize offsets + if (config->tiled) { + yofs2 = MOD (yofs, bmRect.height()); + yofs1 = MOD (yofs2 - 1, bmRect.height()); + yofs3 = MOD (yofs2 + 1, bmRect.height()); + } + else { + yofs2 = 0; + yofs1 = yofs2 - 1; + yofs3 = yofs2 + 1; + } + convertRow(bumpmap, bm_row1, bmRect.x(), yofs1+bmRect.top(), bmRect.width(), lut, config->waterlevel); + convertRow(bumpmap, bm_row2, bmRect.x(), yofs2+bmRect.top(), bmRect.width(), lut, config->waterlevel); + convertRow(bumpmap, bm_row3, bmRect.x(), yofs3+bmRect.top(), bmRect.width(), lut, config->waterlevel); + + for (int y = rect.top(); y<=rect.bottom(); y++) { + const TQ_INT32 yBump = y+yofs; + if(config->tiled || (bmRect.top()<=yBump && yBump<=bmRect.bottom()) ) { + // Get the iterators + KisHLineIteratorPixel dstIt = dst->createHLineIterator(rect.x(), y, rect.width(), true); + KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), y, rect.width(), false); + + //while (x < sel_w || cancelRequested()) { + while (!srcIt.isDone() && !cancelRequested()) { + if (srcIt.isSelected()) { + + const TQ_INT32 xBump = srcIt.x()+xofs; + TQ_INT32 nx, ny; + // Calculate surface normal from bumpmap + if (config->tiled || bmRect.left() <= xBump && xBump <= bmRect.right()) { + + TQ_INT32 xofs1, xofs2, xofs3; + if (config->tiled) { + xofs2 = MOD (xBump-bmRect.left(), bmRect.width()); + xofs1 = MOD (xofs2 - 1, bmRect.width()); + xofs3 = MOD (xofs2 + 1, bmRect.width()); + } else { + xofs2 = MOD (xBump-bmRect.left(), bmRect.width()); + xofs1 = ::max (xofs2 - 1, 0); + xofs3 = ::min (xofs2 + 1, bmRect.width()); + } + + nx = (bm_row1[xofs1] + bm_row2[xofs1] + bm_row3[xofs1] - + bm_row1[xofs3] - bm_row2[xofs3] - bm_row3[xofs3]); + ny = (bm_row3[xofs1] + bm_row3[xofs2] + bm_row3[xofs3] - + bm_row1[xofs1] - bm_row1[xofs2] - bm_row1[xofs3]); + } else { + nx = 0; + ny = 0; + } + + // Shade + TQ_INT32 shade; + if ((nx == 0) && (ny == 0)) { + shade = background; + } else { + TQ_INT32 ndotl = (nx * lx) + (ny * ly) + nzlz; + + if (ndotl < 0) { + shade = (TQ_INT32)(compensation * config->ambient); + } else { + shade = (TQ_INT32)(ndotl / sqrt(nx * nx + ny * ny + nz2)); + shade = (TQ_INT32)(shade + TQMAX(0, (255 * compensation - shade)) * config->ambient / 255); + } + } + + // Paint + srcCs->darken(srcIt.rawData(), dstIt.rawData(), shade, config->compensate, compensation, 1); + } + + ++srcIt; + ++dstIt; + } + + // Go to the next row + tmp_row = bm_row1; + bm_row1 = bm_row2; + bm_row2 = bm_row3; + bm_row3 = tmp_row; + + yofs2++; + if (yofs2 >= bmRect.height()) { yofs2 = 0; } + + if (config->tiled) { + yofs3 = MOD (yofs2 + 1, bmRect.height()); + } else { + yofs3 = yofs2 + 1; + } + convertRow(bumpmap, bm_row3, bmRect.x(), yofs3+bmRect.top(), bmRect.width(), lut, config->waterlevel); + } + + incProgress(); + } + + delete [] bm_row1; + delete [] bm_row2; + delete [] bm_row3; + setProgressDone(); + +} + +KisFilterConfigWidget * KisFilterBumpmap::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev) +{ + KisBumpmapConfigWidget * w = new KisBumpmapConfigWidget(this, dev, tqparent); + + + return w; +} + +KisFilterConfiguration * KisFilterBumpmap::configuration(TQWidget * w) +{ + + KisBumpmapConfigWidget * widget = dynamic_cast(w); + if (widget == 0) { + return new KisBumpmapConfiguration(); + } + else { + return widget->config(); + } +} + +KisFilterConfiguration * KisFilterBumpmap::configuration() +{ + return new KisBumpmapConfiguration(); +} + + +KisBumpmapConfiguration::KisBumpmapConfiguration() + : KisFilterConfiguration( "bumpmap", 1 ) +{ + bumpmap = TQString(); + azimuth = 135.0; + elevation = 45.0; + depth = 3; + xofs = 0; + yofs = 0; + waterlevel = 0; + ambient = 0; + compensate = true; + invert = false; + tiled = true; + type = chalk::LINEAR; +} +void KisBumpmapConfiguration::fromXML(const TQString & s) +{ + KisFilterConfiguration::fromXML( s ); + + bumpmap = TQString(); + azimuth = 135.0; + elevation = 45.0; + depth = 3; + xofs = 0; + yofs = 0; + waterlevel = 0; + ambient = 0; + compensate = true; + invert = false; + tiled = true; + type = chalk::LINEAR; + + TQVariant v; + + v = getProperty("bumpmap"); + if (v.isValid()) { bumpmap = v.asString(); } + v = getProperty("azimuth"); + if (v.isValid()) { azimuth = v.asDouble(); } + v = getProperty("elevation"); + if (v.isValid()) { elevation = v.asDouble();} + v = getProperty("depth"); + if (v.isValid()) { depth = v.asDouble(); } + v = getProperty("xofs"); + if (v.isValid()) { xofs = v.asInt(); } + v = getProperty("yofs"); + if (v.isValid()) { yofs = v.asInt();} + v = getProperty("waterlevel"); + if (v.isValid()) { waterlevel = v.asInt();} + v = getProperty("ambient"); + if (v.isValid()) { ambient = v.asInt();} + v = getProperty("compensate"); + if (v.isValid()) { compensate = v.asBool(); } + v = getProperty("invert"); + if (v.isValid()) { invert = v.asBool(); } + v = getProperty("tiled"); + if (v.isValid()) { tiled = v.asBool();} + v = getProperty("type"); + if (v.isValid()) { type = (enumBumpmapType)v.asInt(); } + +} + + +TQString KisBumpmapConfiguration::toString() +{ + m_properties.clear(); + + //setProperty("bumpmap", TQVariant(bumpmap)); + setProperty("azimuth", TQVariant(azimuth)); + setProperty("elevation", TQVariant(elevation)); + setProperty("depth", TQVariant(depth)); + setProperty("xofs", TQVariant(xofs)); + setProperty("yofs", TQVariant(yofs)); + setProperty("waterlevel", TQVariant(waterlevel)); + setProperty("ambient", TQVariant(ambient)); + setProperty("compensate", TQVariant(compensate)); + setProperty("invert", TQVariant(invert)); + setProperty("tiled", TQVariant(tiled)); + setProperty("type", TQVariant(type)); + + return KisFilterConfiguration::toString(); +} + +KisBumpmapConfigWidget::KisBumpmapConfigWidget(KisFilter *, KisPaintDeviceSP dev, TQWidget * tqparent, const char * name, WFlags f) + : KisFilterConfigWidget(tqparent, name, f) +{ + m_page = new WdgBumpmap(this); + TQHBoxLayout * l = new TQHBoxLayout(this); + Q_CHECK_PTR(l); + + l->add(m_page); + + // Find all of the layers in the group + if(dev->image() ) { + KisGroupLayerSP root = dev->image()->rootLayer(); + for(KisLayerSP layer = root->firstChild(); layer; layer = layer->nextSibling()) + { + m_page->cboxSourceLayer->insertItem(layer->name()); + } + } + + // Connect all of the widgets to update signal + connect( m_page->radioLinear, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->radioSpherical, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->radioSinusoidal, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkCompensate, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkInvert, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkTiled, TQT_SIGNAL( toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblAzimuth, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblElevation, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->dblDepth, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intXOffset, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intYOffset, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intWaterLevel, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->intAmbient, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +KisBumpmapConfiguration * KisBumpmapConfigWidget::config() +{ + KisBumpmapConfiguration * cfg = new KisBumpmapConfiguration(); + cfg->bumpmap = m_page->cboxSourceLayer->currentText(); + cfg->azimuth = m_page->dblAzimuth->value(); + cfg->elevation = m_page->dblElevation->value(); + cfg->depth = m_page->dblDepth->value(); + cfg->xofs = m_page->intXOffset->value(); + cfg->yofs = m_page->intYOffset->value(); + cfg->waterlevel = m_page->intWaterLevel->value(); + cfg->ambient = m_page->intAmbient->value(); + cfg->compensate = m_page->chkCompensate->isChecked(); + cfg->invert = m_page->chkInvert->isChecked(); + cfg->tiled = m_page->chkTiled->isChecked(); + cfg->type = (enumBumpmapType)m_page->grpType->selectedId(); + + return cfg; +} + +void KisBumpmapConfigWidget::setConfiguration(KisFilterConfiguration * config) +{ + KisBumpmapConfiguration * cfg = dynamic_cast(config); + if (!cfg) return; + + // NOTE: maybe we should find the item instead? + m_page->cboxSourceLayer->setCurrentText( cfg->bumpmap ); + m_page->dblAzimuth->setValue(cfg->azimuth); + m_page->dblElevation->setValue(cfg->elevation); + m_page->dblDepth->setValue(cfg->depth); + m_page->intXOffset->setValue(cfg->xofs); + m_page->intYOffset->setValue(cfg->yofs); + m_page->intWaterLevel->setValue(cfg->waterlevel); + m_page->intAmbient->setValue(cfg->ambient); + m_page->chkCompensate->setChecked(cfg->compensate); + m_page->chkInvert->setChecked(cfg->invert); + m_page->chkTiled->setChecked(cfg->tiled); + m_page->grpType->setButton(cfg->type); + +} + +#include "bumpmap.moc" diff --git a/chalk/plugins/filters/bumpmap/bumpmap.h b/chalk/plugins/filters/bumpmap/bumpmap.h new file mode 100644 index 00000000..b1c16b1a --- /dev/null +++ b/chalk/plugins/filters/bumpmap/bumpmap.h @@ -0,0 +1,130 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef BUMPMAP_H +#define BUMPMAP_H + +#include + +#include + +#include +#include +#include "kis_filter_config_widget.h" + +class WdgBumpMap; + +namespace chalk { + + enum enumBumpmapType { + LINEAR = 0, + SPHERICAL = 1, + SINUSOIDAL = 2 + }; + +} + +using namespace chalk; + + + +class ChalkBumpmap : public KParts::Plugin +{ +public: + ChalkBumpmap(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkBumpmap(); +}; + + +/** + * First stab at a bumpmapping filter. For now, this is taken both + * from the Gimp source and the code from emboss.c: + * ANSI C code from the article + * "Fast Embossing Effects on Raster Image Data" + * by John Schlag, jfs@kerner.com + * in "Graphics Gems IV", Academic Press, 1994 + */ +class KisFilterBumpmap : public KisFilter +{ +public: + KisFilterBumpmap(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; + static inline KisID id() { return KisID("bumpmap", i18n("Bumpmap")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return true; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual bool supportsThreading() { return false; } + + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration(); + +}; + + + +class KisBumpmapConfiguration : public KisFilterConfiguration { + +public: + + KisBumpmapConfiguration(); + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + + TQString bumpmap; + double azimuth; + double elevation; + double depth; + TQ_INT32 xofs; + TQ_INT32 yofs; + TQ_INT32 waterlevel; + TQ_INT32 ambient; + bool compensate; + bool invert; + bool tiled; + enumBumpmapType type; + +}; + + +class KisBumpmapConfigWidget : public KisFilterConfigWidget { + + Q_OBJECT + TQ_OBJECT + +public: + KisBumpmapConfigWidget(KisFilter * filter, KisPaintDeviceSP dev, TQWidget * tqparent, const char * name = 0, WFlags f = 0 ); + virtual ~KisBumpmapConfigWidget() {}; + + KisBumpmapConfiguration * config(); + void setConfiguration(KisFilterConfiguration * config); + +private: + + WdgBumpmap * m_page; +}; + +#endif diff --git a/chalk/plugins/filters/bumpmap/chalkbumpmapfilter.desktop b/chalk/plugins/filters/bumpmap/chalkbumpmapfilter.desktop new file mode 100644 index 00000000..727810df --- /dev/null +++ b/chalk/plugins/filters/bumpmap/chalkbumpmapfilter.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Name=Bumpmap Filter +Name[bg]=Филтър Bumpmap +Name[ca]=Filtre Bumpmap +Name[cy]=Hidlen chwyddfap +Name[da]=Bumpkortfilter +Name[de]=Bumpmap-Filter +Name[el]=Φίλτρο ανάγλυφου χάρτη +Name[es]=Filtro de mapa de colisiones +Name[et]=Kühmukaardi filter +Name[fa]=پالایۀ Bumpmap +Name[fr]=Filtre bumpmap +Name[fy]=Bumpmapfilter +Name[ga]=Scagaire Bumpmap +Name[gl]=Filtro de Bumpmaps +Name[hu]=Bumpmap szűrő +Name[is]=Bumpmap sía +Name[it]=Filtro bumpmap +Name[ja]=Bumpmap フィルタ +Name[km]=តម្រង​ផែនទី​រដិបរដុប +Name[nb]=Dumpkart-filter +Name[nds]=Bumpmap-Filter +Name[ne]=बम्पम्याप फिल्टर +Name[nl]=Bumpmapfilter +Name[pl]=Filtr odwzorowania nierówności +Name[pt]=Filtro de 'Bumpmaps' +Name[pt_BR]=Filtro de 'Bumpmaps' +Name[ru]=Рельеф +Name[sl]=Filter nagubanosti +Name[sr]=Филтер мапе рељефа +Name[sr@Latn]=Filter mape reljefa +Name[sv]=Bulkartefilter +Name[uk]=Рельєф +Name[zh_TW]=Bumpmap 過濾器 +Comment=Bumpmap filter +Comment[bg]=Филтър Bumpmap +Comment[ca]=Filtre de Bumpmap +Comment[cy]=Hidlen chwyddfap +Comment[da]=Bumpkortfilter +Comment[de]=Bumpmap-Filter +Comment[el]=Φίλτρο ανάγλυφου χάρτη +Comment[es]=Filtro de mapa de colisiones +Comment[et]=Kühmukaardi filter +Comment[fa]=پالایۀ Bumpmap +Comment[fr]=Filtre bumpmap +Comment[fy]=Bumpmapfilter +Comment[ga]=Scagaire Bumpmap +Comment[gl]=Filtro de bumpmaps +Comment[hu]=Bumpmap szűrő +Comment[is]=Bumpmap sía +Comment[it]=Filtro bumpmap +Comment[ja]=Bumpmap フィルタ +Comment[km]=តម្រង​ផែនទី​រដិបរដុប +Comment[nb]=Dumpkart-filter +Comment[nds]=Bumpmap-Filter +Comment[ne]=बम्पम्याप फिल्टर +Comment[nl]=Bumpmapfilter +Comment[pl]=Filtr odwzorowania nierówności (ang. bumpmap) +Comment[pt]=Filtro de 'bumpmaps' +Comment[pt_BR]=Filtro de 'bumpmaps' +Comment[ru]=Рельеф +Comment[sl]=Filter za nagubanost +Comment[sr]=Филтер мапе рељефа +Comment[sr@Latn]=Filter mape reljefa +Comment[sv]=Bulkartefilter +Comment[uk]=Фільтр рельєфу +Comment[zh_TW]=Bumpmap 的過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkbumpmap +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/bumpmap/wdgbumpmap.ui b/chalk/plugins/filters/bumpmap/wdgbumpmap.ui new file mode 100644 index 00000000..a783dd85 --- /dev/null +++ b/chalk/plugins/filters/bumpmap/wdgbumpmap.ui @@ -0,0 +1,374 @@ + +WdgBumpmap + + + WdgBumpmap + + + + 0 + 0 + 520 + 603 + + + + + unnamed + + + + frame3 + + + StyledPanel + + + Raised + + + + unnamed + + + + textLabel2 + + + + 5 + 3 + 0 + 0 + + + + <b>Bumpmapping</b> is a process where two layers are +combined to give one layer the illusion of <i>depth</i>. One layer +will contain your image, the other a grayscale or black-and-white +representation of height, which is the bumpmap. If you do not specify a bumpmap +layer, the current layer will be used. + + + RichText + + + WordBreak|AlignVCenter + + + + + spacer9 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + + grpSettings + + + Settings + + + AlignAuto + + + + unnamed + + + + dblElevation + + + 90 + + + 0.5 + + + 45 + + + + + textLabel4 + + + &Elevation: + + + dblElevation + + + + + textLabel5 + + + &Depth: + + + dblDepth + + + + + dblDepth + + + 65 + + + 1 + + + 3 + + + + + textLabel3 + + + &Azimuth: + + + dblAzimuth + + + + + intWaterLevel + + + 255 + + + + + intYOffset + + + -99 + + + + + intAmbient + + + 255 + + + + + textLabel8 + + + &Water level: + + + intWaterLevel + + + + + textLabel9 + + + &Ambient light: + + + intAmbient + + + + + intXOffset + + + -99 + + + + + textLabel7 + + + &Y offset: + + + intYOffset + + + + + textLabel6 + + + &X offset: + + + intXOffset + + + + + dblAzimuth + + + 360 + + + 135 + + + + + + + grpType + + + &Type + + + + unnamed + + + + radioLinear + + + &Linear + + + true + + + + + radioSpherical + + + &Spherical + + + + + radioSinusoidal + + + S&inusoidal + + + + + + + grpOptions + + + Options + + + + unnamed + + + + chkCompensate + + + &Compensate for darkening + + + true + + + + + chkTiled + + + &Tile bumpmap + + + + + chkInvert + + + I&nvert bumpmap + + + + + + + lblLayer + + + + 5 + 5 + 0 + 0 + + + + Bumpmap layer: + + + txtSourceLayer + + + + + cboxSourceLayer + + + + + + + + radioLinear + chkCompensate + chkInvert + chkTiled + dblAzimuth + dblElevation + dblDepth + intXOffset + intYOffset + intWaterLevel + intAmbient + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + kcombobox.h + + diff --git a/chalk/plugins/filters/cimg/.kdev_ignore b/chalk/plugins/filters/cimg/.kdev_ignore new file mode 100644 index 00000000..e69de29b diff --git a/chalk/plugins/filters/cimg/CImg.h b/chalk/plugins/filters/cimg/CImg.h new file mode 100644 index 00000000..871cb496 --- /dev/null +++ b/chalk/plugins/filters/cimg/CImg.h @@ -0,0 +1,19174 @@ +/* + # + # File : CImg.h + # + # Description : The C++ Template Image Processing Library + # ( http://cimg.sourceforge.net ) + # + # Copyright : David Tschumperle + # ( http://www.greyc.ensicaen.fr/~dtschump/ ) + # + # This software is governed by the CeCILL license under French law and + # abiding by the rules of distribution of free software. You can use, + # modify and or redistribute the software under the terms of the CeCILL + # license as circulated by CEA, CNRS and INRIA at the following URL + # "http://www.cecill.info". + # + # As a counterpart to the access to the source code and rights to copy, + # modify and redistribute granted by the license, users are provided only + # with a limited warranty and the software's author, the holder of the + # economic rights, and the successive licensors have only limited + # liability. + # + # In this respect, the user's attention is drawn to the risks associated + # with loading, using, modifying and/or developing or reproducing the + # software by the user in light of its specific status of free software, + # that may mean that it is complicated to manipulate, and that also + # therefore means that it is reserved for developers and experienced + # professionals having in-depth computer knowledge. Users are therefore + # encouraged to load and test the software's suitability as regards their + # requirements in conditions enabling the security of their systems and/or + # data to be ensured and, more generally, to use and operate it in the + # same conditions as regards security. + # + # The fact that you are presently reading this means that you have had + # knowledge of the CeCILL license and that you accept its terms. + # + */ + +#ifndef cimg_version +#define cimg_version 1.14 + +// Avoid strange warning messages on Visual C++ express 2005. +#if ( defined(_MSC_VER) && _MSC_VER>=1400 ) +#define _CRT_SECURE_NO_DEPRECATE 1 +#define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + +// Standard C++ includes +#include +#include +#include +#include +#include +#include + +// Overcome VisualC++ 6.0 and DMC compilers namespace 'std::' bug +#if ( defined(_MSC_VER) && _MSC_VER<=1200 ) || defined(__DMC__) +#define std +#endif + +/* + # + # Set CImg configuration flags. + # + # If compilation flags are not adapted to your system, + # you may override their values, before including + # the header file "CImg.h" (use the #define directive). + # + */ + +// Try to detect the current system and set value of 'cimg_OS'. +#ifndef cimg_OS +#if defined(sun) || defined(__sun) || defined(linux) || defined(__linux) \ + || defined(__linux__) || defined(__CYGWIN__) || defined(BSD) || defined(__FreeBSD__) \ + || defined(__OPENBSD__) || defined(__MACOSX__) || defined(__APPLE__) || defined(sgi) \ + || defined(__sgi) +// Unix-like (Linux, Solaris, BSD, Irix,...) +#define cimg_OS 1 +#ifndef cimg_display_type +#define cimg_display_type 1 +#endif +#ifndef cimg_color_terminal +#define cimg_color_terminal +#endif +#elif defined(_WIN32) || defined(__WIN32__) +// Windows +#define cimg_OS 2 +#ifndef cimg_display_type +#define cimg_display_type 2 +#endif +#else +// Unknown configuration : will compile with minimal dependencies. +#define cimg_OS 0 +#ifndef cimg_display_type +#define cimg_display_type 0 +#endif +#endif +#endif + +// Debug configuration. +// +// Define 'cimg_debug' to : 0 to remove dynamic debug messages (exceptions are still thrown) +// 1 to display dynamic debug messages (default behavior). +// 2 to add memory access controls (may slow down the code, but display extra warning messages) +#ifndef cimg_debug +#define cimg_debug 1 +#endif + +// Architecture-dependent includes. +#if cimg_OS==1 +#include +#include +#elif cimg_OS==2 +#include +// Discard unuseful macros in windows.h +// to allow compilation with VC++ 6.0. +#ifdef min +#undef min +#undef max +#undef abs +#endif +#endif +#if cimg_display_type==1 +#include +#include +#include +#include +#ifdef cimg_use_xshm +#include +#include +#include +#endif +#endif + +// Configuration for native PNG and JPEG support +// Define 'cimg_use_png' or 'cimg_use_jpeg' to enable native PNG or JPEG files support. +// This requires you link your code with the zlib/png or jpeg libraries. +// Without these libraries, PNG and JPEG support will be done by the Image Magick's 'convert' tool, if installed +// (this is the case on most unix plateforms). +#ifdef cimg_use_png +extern "C" { +#include "png.h" +} +#endif +#ifdef cimg_use_jpeg +extern "C" { +#include "jpeglib.h" +} +#endif + +/* + # + # + # Define some useful macros. Macros of the CImg Library are prefixed by 'cimg_' + # Documented macros below may be safely used in your own code + # (particularly useful for option parsing, image loops and neighborhoods). + # + # + */ + +// Macros used to describe the program usage, and retrieve command line arguments +// (See corresponding module 'Retrieving command line arguments' in the generated documentation). +#define cimg_usage(usage) cimg_library::cimg::option((const char*)0,argc,argv,(const char*)0,usage) +#define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage) + +// Macros used for neighborhood definitions and manipulations. +// (see module 'Using Image Loops' in the generated documentation). +#define CImg_2x2x1(I,T) T I##cc,I##nc=0,I##cn,I##nn=0 +#define CImg_3x1x1(I,T) T I##pp,I##cp,I##np=0 +#define CImg_3x3x1(I,T) T I##pp,I##cp,I##np=0,I##pc,I##cc,I##nc=0,I##pn,I##cn,I##nn=0 +#define CImg_4x1x1(I,T) T I##pp,I##cp,I##np=0,I##ap=0 +#define CImg_4x4x1(I,T) T I##pp,I##cp,I##np=0,I##ap=0, \ + I##pc,I##cc,I##nc=0,I##ac=0, \ + I##pn,I##cn,I##nn=0,I##an=0, \ + I##pa,I##ca,I##na=0,I##aa=0 +#define CImg_5x1x1(I,T) T I##bb,I##pb,I##cb,I##nb=0,I##ab=0 +#define CImg_5x5x1(I,T) T I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \ + I##bp,I##pp,I##cp,I##np=0,I##ap=0, \ + I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \ + I##bn,I##pn,I##cn,I##nn=0,I##an=0, \ + I##ba,I##pa,I##ca,I##na=0,I##aa=0 +#define CImg_2x2x2(I,T) T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \ + I##ccn,I##ncn=0,I##cnn,I##nnn=0 +#define CImg_3x3x3(I,T) T I##ppp,I##cpp,I##npp=0,I##pcp,I##ccp,I##ncp=0,I##pnp,I##cnp,I##nnp=0, \ + I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \ + I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0 + +#define CImg_2x2x1_ref(I,T,tab) T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3] +#define CImg_3x3x1_ref(I,T,tab) T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \ + &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \ + &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8] +#define CImg_4x4x1_ref(I,T,tab) T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2],&I##ap=(tab)[3], \ + &I##pc=(tab)[4],&I##cc=(tab)[5],&I##nc=(tab)[6],&I##ap=(tab)[7], \ + &I##pn=(tab)[8],&I##cn=(tab)[9],&I##nn=(tab)[10],&I##aa=(tab)[11], \ + &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15] +#define CImg_5x5x1_ref(I,T,tab) T &I##bb=(tab)[0],&I##pb=(tab)[1],&I##cb=(tab)[2],&I##nb=(tab)[3],&I##ab=(tab)[4], \ + &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \ + &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \ + &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \ + &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24] +#define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \ + &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7] +#define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \ + &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \ + &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \ + &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \ + &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \ + &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \ + &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \ + &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \ + &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26] + +#define cimg_copy2x2x1(J,I) I##cc=J##cc, I##nc=J##nc, I##cn=J##cn, I##nn=J##nn +#define cimg_copy3x3x1(J,I) I##pp=J##pp, I##cp=J##cp, I##np=J##np, \ + I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, \ + I##pn=J##pn, I##cn=J##cn, I##nn=J##nn +#define cimg_copy5x5x1(J,I) I##bb=J##bb, I##pb=J##pb, I##cb=J##cb, I##nb=J##nb, I##ab=J##ab, \ + I##bp=J##bp, I##pp=J##pp, I##cp=J##cp, I##np=J##np, I##ap=J##ap, \ + I##bc=J##bc, I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, I##ac=J##ac, \ + I##bn=J##bn, I##pn=J##pn, I##cn=J##cn, I##nn=J##nn, I##an=J##an, \ + I##ba=J##ba, I##pa=J##pa, I##ca=J##ca, I##na=J##na, I##aa=J##aa + +#define cimg_squaresum2x2x1(I) ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn ) +#define cimg_squaresum3x3x1(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \ + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \ + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn ) +#define cimg_squaresum4x4x1(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \ + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \ + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \ + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa ) +#define cimg_squaresum5x5x1(I) ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \ + I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \ + I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \ + I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \ + I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa ) +#define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \ + I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn ) +#define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \ + I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \ + I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \ + I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \ + I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \ + I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \ + I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \ + I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \ + I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn ) + +#define cimg_corr2x2x1(I,m) ( I##cc*(m)(0,0)+I##nc*(m)(1,0)+I##cn*(m)(0,1)+I##nn*(m)(1,1) ) +#define cimg_corr3x3x1(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \ + I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \ + I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) ) +#define cimg_corr4x4x1(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0)+I##ap*(m)(3,0) + \ + I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \ + I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \ + I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) ) +#define cimg_corr5x5x1(I,m) ( I##bb*(m)(0,0)+I##pb*(m)(1,0)+I##cb*(m)(2,0)+I##nb*(m)(3,0)+I##ab*(m)(4,0) + \ + I##bp*(m)(0,1)+I##pp*(m)(1,1)+I##cp*(m)(2,1)+I##np*(m)(3,1)+I##ap*(m)(4,1) + \ + I##bc*(m)(0,2)+I##pc*(m)(1,2)+I##cc*(m)(2,2)+I##nc*(m)(3,2)+I##ac*(m)(4,2) + \ + I##bn*(m)(0,3)+I##pn*(m)(1,3)+I##cn*(m)(2,3)+I##nn*(m)(3,3)+I##an*(m)(4,3) + \ + I##ba*(m)(0,4)+I##pa*(m)(1,4)+I##ca*(m)(2,4)+I##na*(m)(3,4)+I##aa*(m)(4,4) ) +#define cimg_corr2x2x2(I,m) ( I##ccc*(m)(0,0,0)+I##ncc*(m)(1,0,0)+I##cnc*(m)(0,1,0)+I##nnc*(m)(1,1,0) + \ + I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) ) +#define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \ + I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \ + I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \ + I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \ + I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \ + I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \ + I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \ + I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \ + I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) ) + +#define cimg_conv2x2x1(I,m) ( I##cc*(m)(1,1)+I##nc*(m)(0,1)+I##cn*(m)(1,0)+I##nn*(m)(0,0) ) +#define cimg_conv3x3x1(I,m) ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \ + I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \ + I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) ) +#define cimg_conv4x4x1(I,m) ( I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \ + I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \ + I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \ + I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) ) +#define cimg_conv5x5x1(I,m) ( I##bb*(m)(4,4)+I##pb*(m)(3,4)+I##cb*(m)(2,4)+I##nb*(m)(1,4)+I##ab*(m)(0,4) + \ + I##bp*(m)(4,3)+I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \ + I##bc*(m)(4,2)+I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \ + I##bn*(m)(4,1)+I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \ + I##ba*(m)(4,0)+I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) ) +#define cimg_conv2x2x2(I,m) ( I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \ + I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) ) +#define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \ + I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \ + I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \ + I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \ + I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \ + I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \ + I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \ + I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \ + I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) ) + +#define cimg_get2x2x1(img,x,y,z,v,I) \ + I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), \ + I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v) +#define cimg_get3x3x1(img,x,y,z,v,I) \ + I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), \ + I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), \ + I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v) +#define cimg_get4x4x1(img,x,y,z,v,I) \ + I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \ + I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), I##ac=(img)(_a##x, y,z,v), \ + I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \ + I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v) +#define cimg_get5x5x1(img,x,y,z,v,I) \ + I##bb=(img)(_b##x,_b##y,z,v), I##pb=(img)(_p##x,_b##y,z,v), I##cb=(img)(x,_b##y,z,v), I##nb=(img)(_n##x,_b##y,z,v), I##ab=(img)(_a##x,_b##y,z,v), \ + I##bp=(img)(_b##x,_p##y,z,v), I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \ + I##bc=(img)(_b##x, y,z,v), I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), I##ac=(img)(_a##x, y,z,v), \ + I##bn=(img)(_b##x,_n##y,z,v), I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \ + I##ba=(img)(_b##x,_a##y,z,v), I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v) +#define cimg_get2x2x2(img,x,y,z,v,I) \ + I##ccc=(img)(x,y, z,v), I##ncc=(img)(_n##x,y, z,v), I##cnc=(img)(x,_n##y, z,v), I##nnc=(img)(_n##x,_n##y, z,v), \ + I##ccc=(img)(x,y,_n##z,v), I##ncc=(img)(_n##x,y,_n##z,v), I##cnc=(img)(x,_n##y,_n##z,v), I##nnc=(img)(_n##x,_n##y,_n##z,v) +#define cimg_get3x3x3(img,x,y,z,v,I) \ + I##ppp=(img)(_p##x,_p##y,_p##z,v), I##cpp=(img)(x,_p##y,_p##z,v), I##npp=(img)(_n##x,_p##y,_p##z,v), \ + I##pcp=(img)(_p##x, y,_p##z,v), I##ccp=(img)(x, y,_p##z,v), I##ncp=(img)(_n##x, y,_p##z,v), \ + I##pnp=(img)(_p##x,_n##y,_p##z,v), I##cnp=(img)(x,_n##y,_p##z,v), I##nnp=(img)(_n##x,_n##y,_p##z,v), \ + I##ppc=(img)(_p##x,_p##y, z,v), I##cpc=(img)(x,_p##y, z,v), I##npc=(img)(_n##x,_p##y, z,v), \ + I##pcc=(img)(_p##x, y, z,v), I##ccc=(img)(x, y, z,v), I##ncc=(img)(_n##x, y, z,v), \ + I##pnc=(img)(_p##x,_n##y, z,v), I##cnc=(img)(x,_n##y, z,v), I##nnc=(img)(_n##x,_n##y, z,v), \ + I##ppn=(img)(_p##x,_p##y,_n##z,v), I##cpn=(img)(x,_p##y,_n##z,v), I##npn=(img)(_n##x,_p##y,_n##z,v), \ + I##pcn=(img)(_p##x, y,_n##z,v), I##ccn=(img)(x, y,_n##z,v), I##ncn=(img)(_n##x, y,_n##z,v), \ + I##pnn=(img)(_p##x,_n##y,_n##z,v), I##cnn=(img)(x,_n##y,_n##z,v), I##nnn=(img)(_n##x,_n##y,_n##z,v) + +#define CImg_2x2(I,T) CImg_2x2x1(I,T) +#define CImg_3x3(I,T) CImg_3x3x1(I,T) +#define CImg_4x4(I,T) CImg_4x4x1(I,T) +#define CImg_5x5(I,T) CImg_5x5x1(I,T) +#define CImg_2x2_ref(I,T,tab) CImg_2x2x1_ref(I,T,tab) +#define CImg_3x3_ref(I,T,tab) CImg_3x3x1_ref(I,T,tab) +#define CImg_4x4_ref(I,T,tab) CImg_4x4x1_ref(I,T,tab) +#define CImg_5x5_ref(I,T,tab) CImg_5x5x1_ref(I,T,tab) +#define cimg_copy2x2(J,I) cimg_copy2x2x1(J,I) +#define cimg_copy3x3(J,I) cimg_copy3x3x1(J,I) +#define cimg_copy5x5(J,I) cimg_copy5x5x1(J,I) +#define cimg_squaresum2x2(I) cimg_squaresum2x2x1(I) +#define cimg_squaresum3x3(I) cimg_squaresum3x3x1(I) +#define cimg_squaresum4x4(I) cimg_squaresum4x4x1(I) +#define cimg_squaresum5x5(I) cimg_squaresum5x5x1(I) +#define cimg_corr2x2(I) cimg_corr2x2x1(I) +#define cimg_corr3x3(I) cimg_corr3x3x1(I) +#define cimg_corr4x4(I) cimg_corr4x4x1(I) +#define cimg_corr5x5(I) cimg_corr5x5x1(I) +#define cimg_conv2x2(I) cimg_conv2x2x1(I) +#define cimg_conv3x3(I) cimg_conv3x3x1(I) +#define cimg_conv4x4(I) cimg_conv4x4x1(I) +#define cimg_conv5x5(I) cimg_conv5x5x1(I) +#define cimg_get2x2(img,x,y,z,k,I) cimg_get2x2x1(img,x,y,z,k,I) +#define cimg_get3x3(img,x,y,z,k,I) cimg_get3x3x1(img,x,y,z,k,I) +#define cimg_get4x4(img,x,y,z,k,I) cimg_get4x4x1(img,x,y,z,k,I) +#define cimg_get5x5(img,x,y,z,k,I) cimg_get5x5x1(img,x,y,z,k,I) +#define cimg_map2x2(img,x,y,z,k,I) cimg_map2x2x1(img,x,y,z,k,I) +#define cimg_map3x3(img,x,y,z,k,I) cimg_map3x3x1(img,x,y,z,k,I) +#define cimg_map4x4(img,x,y,z,k,I) cimg_map4x4x1(img,x,y,z,k,I) +#define cimg_map5x5(img,x,y,z,k,I) cimg_map5x5x1(img,x,y,z,k,I) + +// Macros used to define special image loops. +// (see module 'Using Image Loops' in the generated documentation). +#define cimg_map(img,ptr,T_ptr) for (T_ptr *ptr=(img).data+(img).size(); (ptr--)>(img).data; ) +#define cimgl_map(list,l) for (unsigned int l=0; l<(list).size; l++) +#define cimg_mapoff(img,off) for (unsigned int off=0; off<(img).size(); off++) +#define cimg_mapX(img,x) for (int x=0; x<(int)((img).width); x++) +#define cimg_mapY(img,y) for (int y=0; y<(int)((img).height);y++) +#define cimg_mapZ(img,z) for (int z=0; z<(int)((img).depth); z++) +#define cimg_mapV(img,v) for (int v=0; v<(int)((img).dim); v++) +#define cimg_mapXY(img,x,y) cimg_mapY(img,y) cimg_mapX(img,x) +#define cimg_mapXZ(img,x,z) cimg_mapZ(img,z) cimg_mapX(img,x) +#define cimg_mapYZ(img,y,z) cimg_mapZ(img,z) cimg_mapY(img,y) +#define cimg_mapXV(img,x,v) cimg_mapV(img,v) cimg_mapX(img,x) +#define cimg_mapYV(img,y,v) cimg_mapV(img,v) cimg_mapY(img,y) +#define cimg_mapZV(img,z,v) cimg_mapV(img,v) cimg_mapZ(img,z) +#define cimg_mapXYZ(img,x,y,z) cimg_mapZ(img,z) cimg_mapXY(img,x,y) +#define cimg_mapXYV(img,x,y,v) cimg_mapV(img,v) cimg_mapXY(img,x,y) +#define cimg_mapXZV(img,x,z,v) cimg_mapV(img,v) cimg_mapXZ(img,x,z) +#define cimg_mapYZV(img,y,z,v) cimg_mapV(img,v) cimg_mapYZ(img,y,z) +#define cimg_mapXYZV(img,x,y,z,v) cimg_mapV(img,v) cimg_mapXYZ(img,x,y,z) +#define cimg_imapX(img,x,n) for (int x=(n); x<(int)((img).width-(n)); x++) +#define cimg_imapY(img,y,n) for (int y=(n); y<(int)((img).height-(n)); y++) +#define cimg_imapZ(img,z,n) for (int z=(n); z<(int)((img).depth-(n)); z++) +#define cimg_imapV(img,v,n) for (int v=(n); v<(int)((img).dim-(n)); v++) +#define cimg_imapXY(img,x,y,n) cimg_imapY(img,y,n) cimg_imapX(img,x,n) +#define cimg_imapXYZ(img,x,y,z,n) cimg_imapZ(img,z,n) cimg_imapXY(img,x,y,n) +#define cimg_bmapX(img,x,n) for (int x=0; x<(int)((img).width); x==(n)-1?(x=(img).width-(n)): x++) +#define cimg_bmapY(img,y,n) for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++) +#define cimg_bmapZ(img,z,n) for (int z=0; z<(int)((img).depth); z==(n)-1?(x=(img).depth-(n)): z++) +#define cimg_bmapV(img,v,n) for (int v=0; v<(int)((img).dim); v==(n)-1?(x=(img).dim-(n)): v++) +#define cimg_bmapXY(img,x,y,n) cimg_mapY(img,y) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n))?x++: \ + ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n)))) +#define cimg_bmapXYZ(img,x,y,z,n) cimg_mapYZ(img,y,z) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n) || z<(n) || z>=(int)((img).depth)-(n))?x++: \ + ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n)))) +#define cimg_2mapX(img,x) for (int x=0,_n##x=1; _n##x<(int)((img).width) || x==--_n##x; x++, _n##x++) +#define cimg_2mapY(img,y) for (int y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y; y++, _n##y++) +#define cimg_2mapZ(img,z) for (int z=0,_n##z=1; _n##z<(int)((img).depth) || z==--_n##z; z++, _n##z++) +#define cimg_2mapXY(img,x,y) cimg_2mapY(img,y) cimg_2mapX(img,x) +#define cimg_2mapXZ(img,x,z) cimg_2mapZ(img,z) cimg_2mapX(img,x) +#define cimg_2mapYZ(img,y,z) cimg_2mapZ(img,z) cimg_2mapY(img,y) +#define cimg_2mapXYZ(img,x,y,z) cimg_2mapZ(img,z) cimg_2mapXY(img,x,y) +#define cimg_3mapX(img,x) for (int x=0,_p##x=0,_n##x=1; _n##x<(int)((img).width) || x==--_n##x; _p##x=x++,_n##x++) +#define cimg_3mapY(img,y) for (int y=0,_p##y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y; _p##y=y++,_n##y++) +#define cimg_3mapZ(img,z) for (int z=0,_p##z=0,_n##z=1; _n##z<(int)((img).depth) || z==--_n##z; _p##z=z++,_n##z++) +#define cimg_3mapXY(img,x,y) cimg_3mapY(img,y) cimg_3mapX(img,x) +#define cimg_3mapXZ(img,x,z) cimg_3mapZ(img,z) cimg_3mapX(img,x) +#define cimg_3mapYZ(img,y,z) cimg_3mapZ(img,z) cimg_3mapY(img,y) +#define cimg_3mapXYZ(img,x,y,z) cimg_3mapZ(img,z) cimg_3mapXY(img,x,y) +#define cimg_4mapX(img,x) for (int _p##x=0,x=0,_n##x=1,_a##x=2; \ + _a##x<(int)((img).width) || _n##x==--_a##x || x==(_a##x=--_n##x); \ + _p##x=x++,_n##x++,_a##x++) +#define cimg_4mapY(img,y) for (int _p##y=0,y=0,_n##y=1,_a##y=2; \ + _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \ + _p##y=y++,_n##y++,_a##y++) +#define cimg_4mapZ(img,z) for (int _p##z=0,z=0,_n##z=1,_a##z=2; \ + _a##z<(int)((img).depth) || _n##z==--_a##z || z==(_a##z=--_n##z); \ + _p##z=z++,_n##z++,_a##z++) +#define cimg_4mapXY(img,x,y) cimg_4mapY(img,y) cimg_4mapX(img,x) +#define cimg_4mapXZ(img,x,z) cimg_4mapZ(img,z) cimg_4mapX(img,x) +#define cimg_4mapYZ(img,y,z) cimg_4mapZ(img,z) cimg_4mapY(img,y) +#define cimg_4mapXYZ(img,x,y,z) cimg_4mapZ(img,z) cimg_4mapXY(img,x,y) +#define cimg_5mapX(img,x) for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \ + _a##x<(int)((img).width) || _n##x==--_a##x || x==(_a##x=--_n##x); \ + _b##x=_p##x,_p##x=x++,_n##x++,_a##x++) +#define cimg_5mapY(img,y) for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \ + _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \ + _b##y=_p##y,_p##y=y++,_n##y++,_a##y++) +#define cimg_5mapZ(img,z) for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \ + _a##z<(int)((img).depth) || _n##z==--_a##z || z==(_a##z=--_n##z); \ + _b##z=_p##z,_p##z=z++,_n##z++,_a##z++) +#define cimg_5mapXY(img,x,y) cimg_5mapY(img,y) cimg_5mapX(img,x) +#define cimg_5mapXZ(img,x,z) cimg_5mapZ(img,z) cimg_5mapX(img,x) +#define cimg_5mapYZ(img,y,z) cimg_5mapZ(img,z) cimg_5mapY(img,y) +#define cimg_5mapXYZ(img,x,y,z) cimg_5mapZ(img,z) cimg_5mapXY(img,x,y) + +#define cimg_map2x2x1(img,x,y,z,v,I) cimg_2mapY(img,y) \ + for (int _n##x=1, x=(int)((I##cc=(img)(0, y,z,v)), \ + (I##cn=(img)(0,_n##y,z,v)), \ + 0); \ + (_n##x<(int)((img).width) && ((I##nc=(img)(_n##x, y,z,v)), \ + (I##nn=(img)(_n##x,_n##y,z,v)), \ + 1)) || x==--_n##x; \ + I##cc=I##nc, I##cn=I##nn, \ + x++,_n##x++ ) + +#define cimg_map3x3x1(img,x,y,z,v,I) cimg_3mapY(img,y) \ + for (int _n##x=1, _p##x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \ + (I##cc=I##pc=(img)(0, y,z,v)), \ + (I##cn=I##pn=(img)(0,_n##y,z,v))), \ + x=_p##x=0; \ + (_n##x<(int)((img).width) && ((I##np=(img)(_n##x,_p##y,z,v)), \ + (I##nc=(img)(_n##x, y,z,v)), \ + (I##nn=(img)(_n##x,_n##y,z,v)), \ + 1)) || x==--_n##x; \ + I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, \ + I##cp=I##np, I##cc=I##nc, I##cn=I##nn, \ + _p##x=x++,_n##x++ ) + + +#define cimg_map4x4x1(img,x,y,z,v,I) cimg_4mapY(img,y) \ + for (int _a##x=2, _n##x=1, x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \ + (I##cc=I##pc=(img)(0, y,z,v)), \ + (I##cn=I##pn=(img)(0,_n##y,z,v)), \ + (I##ca=I##pa=(img)(0,_a##y,z,v)), \ + (I##np=(img)(_n##x,_p##y,z,v)), \ + (I##nc=(img)(_n##x, y,z,v)), \ + (I##nn=(img)(_n##x,_n##y,z,v)), \ + (I##na=(img)(_n##x,_a##y,z,v)), \ + 0), _p##x=0; \ + (_a##x<(int)((img).width) && ((I##ap=(img)(_a##x,_p##y,z,v)), \ + (I##ac=(img)(_a##x, y,z,v)), \ + (I##an=(img)(_a##x,_n##y,z,v)), \ + (I##aa=(img)(_a##x,_a##y,z,v)), \ + 1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \ + I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \ + I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \ + I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \ + _p##x=x++, _n##x++, _a##x++ ) + +#define cimg_map5x5x1(img,x,y,z,v,I) cimg_5mapY(img,y) \ + for (int _a##x=2, _n##x=1, _b##x=(int)((I##cb=I##pb=I##bb=(img)(0,_b##y,z,v)), \ + (I##cp=I##pp=I##bp=(img)(0,_p##y,z,v)), \ + (I##cc=I##pc=I##bc=(img)(0, y,z,v)), \ + (I##cn=I##pn=I##bn=(img)(0,_n##y,z,v)), \ + (I##ca=I##pa=I##ba=(img)(0,_a##y,z,v)), \ + (I##nb=(img)(_n##x,_b##y,z,v)), \ + (I##np=(img)(_n##x,_p##y,z,v)), \ + (I##nc=(img)(_n##x, y,z,v)), \ + (I##nn=(img)(_n##x,_n##y,z,v)), \ + (I##na=(img)(_n##x,_a##y,z,v))), \ + x=0, _p##x=_b##x=0; \ + (_a##x<(int)((img).width) && ((I##ab=(img)(_a##x,_b##y,z,v)), \ + (I##ap=(img)(_a##x,_p##y,z,v)), \ + (I##ac=(img)(_a##x, y,z,v)), \ + (I##an=(img)(_a##x,_n##y,z,v)), \ + (I##aa=(img)(_a##x,_a##y,z,v)), \ + 1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \ + I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \ + I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \ + I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \ + I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \ + _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ ) + +#define cimg_map2x2x2(img,x,y,z,v,I) cimg_2mapYZ(img,y,z) \ + for (int _n##x=1, x=(int)((I##ccc=(img)(0, y, z,v)), \ + (I##cnc=(img)(0,_n##y, z,v)), \ + (I##ccn=(img)(0, y,_n##z,v)), \ + (I##cnn=(img)(0,_n##y,_n##z,v)), \ + 0); \ + (_n##x<(int)((img).width) && ((I##ncc=(img)(_n##x, y, z,v)), \ + (I##nnc=(img)(_n##x,_n##y, z,v)), \ + (I##ncn=(img)(_n##x, y,_n##z,v)), \ + (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \ + 1)) || x==--_n##x; \ + I##ccc=I##ncc, I##cnc=I##nnc, \ + I##ccn=I##ncn, I##cnn=I##nnn, \ + x++, _n##x++ ) + +#define cimg_map3x3x3(img,x,y,z,v,I) cimg_3mapYZ(img,y,z) \ + for (int _n##x=1, _p##x=(int)((I##cpp=I##ppp=(img)(0,_p##y,_p##z,v)), \ + (I##ccp=I##pcp=(img)(0, y,_p##z,v)), \ + (I##cnp=I##pnp=(img)(0,_n##y,_p##z,v)), \ + (I##cpc=I##ppc=(img)(0,_p##y, z,v)), \ + (I##ccc=I##pcc=(img)(0, y, z,v)), \ + (I##cnc=I##pnc=(img)(0,_n##y, z,v)), \ + (I##cpn=I##ppn=(img)(0,_p##y,_n##z,v)), \ + (I##ccn=I##pcn=(img)(0, y,_n##z,v)), \ + (I##cnn=I##pnn=(img)(0,_n##y,_n##z,v))),\ + x=_p##x=0; \ + (_n##x<(int)((img).width) && ((I##npp=(img)(_n##x,_p##y,_p##z,v)), \ + (I##ncp=(img)(_n##x, y,_p##z,v)), \ + (I##nnp=(img)(_n##x,_n##y,_p##z,v)), \ + (I##npc=(img)(_n##x,_p##y, z,v)), \ + (I##ncc=(img)(_n##x, y, z,v)), \ + (I##nnc=(img)(_n##x,_n##y, z,v)), \ + (I##npn=(img)(_n##x,_p##y,_n##z,v)), \ + (I##ncn=(img)(_n##x, y,_n##z,v)), \ + (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \ + 1)) || x==--_n##x; \ + I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp, \ + I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp, \ + I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc, \ + I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc, \ + I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn, \ + I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn, \ + _p##x=x++, _n##x++ ) + +/* + #------------------------------------------------ + # + # + # Definition of the cimg_library:: namespace + # + # + #------------------------------------------------ + */ + +//! Namespace that encompasses all classes and functions of the %CImg library. +/** + This namespace is defined to avoid class names collisions that could happen + with the include of other C++ header files. Anyway, it should not happen + very often and you may start most of your programs with + \code + #include "CImg.h" + using namespace cimg_library; + \endcode + to simplify the declaration of %CImg Library objects variables afterward. +**/ + +namespace cimg_library { + + // Define the CImg classes. + template struct CImg; + template struct CImgl; + struct CImgStats; + struct CImgDisplay; + struct CImgException; + + namespace cimg { + + // The bodies of the functions below are defined at the end of the file + inline int dialog(const char *title,const char *msg,const char *button1_txt="OK", + const char *button2_txt=NULL,const char *button3_txt=NULL, + const char *button4_txt=NULL,const char *button5_txt=NULL, + const char *button6_txt=NULL,const bool centering = false); + + template + inline void marching_cubes(const tfunc& func, const float isovalue, + const float x0,const float y0,const float z0, + const float x1,const float y1,const float z1, + const float resx,const float resy,const float resz, + CImgl& points, CImgl& primitives, + const bool invert_faces = false); + + template + inline void marching_squares(const tfunc& func, const float isovalue, + const float x0,const float y0, + const float x1,const float y1, + const float resx,const float resy, + CImgl& points, CImgl& primitives); + } + + /* + #---------------------------------------------- + # + # + # Definition of the CImgException structures + # + # + #---------------------------------------------- + */ + + // Never use the following macro in your own code ! +#define cimg_exception_err(etype,disp_flag) \ + if (cimg_debug>=1) { \ + std::va_list ap; \ + va_start(ap,format); \ + std::vsprintf(message,format,ap); \ + va_end(ap); \ + if (disp_flag) { \ + try { cimg::dialog(etype,message,"Abort"); } \ + catch (CImgException&) { std::fprintf(stderr,"# %s :\n%s\n\n",etype,message); } \ + } else std::fprintf(stderr,"# %s :\n%s\n\n",etype,message); \ + } + + //! Class which is thrown when an error occured during a %CImg library function call. + /** + + \section ex1 Overview + + CImgException is the base class of %CImg exceptions. + Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call. + CImgException is seldom thrown itself. Children classes that specify the kind of error encountered + are generally used instead. These sub-classes are : + + - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not + correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example + below will throw a \a CImgInstanceException. + \code + CImg img; // Construct an empty image. + img.blur(10); // Try to blur the image. + \endcode + + - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct. + Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values. + The example below will throw a \a CImgArgumentException. + \code + CImg img(100,100,1,3); // Define a 100x100 color image with float pixels. + img = NULL; // Try to fill pixels from the NULL pointer (invalid argument to operator=() ). + \endcode + + - \b CImgIOException : Thrown when an error occured when trying to load or save image files. + The example below will throw a \a CImgIOException. + \code + CImg img("file_doesnt_exist.jpg"); // Try to load a file that doesn't exist. + \endcode + + - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window. + This exception is thrown when image display request cannot be satisfied. + + The tqparent class CImgException may be thrown itself when errors that cannot be classified in one of + the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally + reserved to %CImg Library functions. + \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple + subclasses of CImgException and are thus not detailled more in this reference documentation. + + \section ex2 Exception handling + + When an error occurs, the %CImg Library first displays the error in a modal window. + Then, it throws an instance of the corresponding exception class, generally leading the program to stop + (this is the default behavior). + You can bypass this default behavior by handling the exceptions yourself, + using a code block try { ... } catch() { ... }. + In this case, you can avoid the apparition of the modal window, by + defining the environment variable cimg_debug to 0 before including the %CImg header file. + The example below shows how to cleanly handle %CImg Library exceptions : + \code + #define cimg_debug 0 // Disable modal window in CImg exceptions. + #define "CImg.h" + int main() { + try { + ...; // Here, do what you want. + } + catch (CImgInstanceException &e) { + std::fprintf(stderr,"CImg Library Error : %s",e.message); // Display your own error message + ... // Do what you want now. + } + } + \endcode + **/ + struct CImgException { + char message[1024]; //!< Message associated with the error that thrown the exception. + CImgException() { message[0]='\0'; } + CImgException(const char *format,...) { cimg_exception_err("CImgException",true); } + }; + + // The \ref CImgInstanceException class is used to throw an exception related + // to a non suitable instance encountered in a library function call. + struct CImgInstanceException : CImgException { + CImgInstanceException(const char *format,...) { cimg_exception_err("CImgInstanceException",true); } + }; + + // The \ref CImgArgumentException class is used to throw an exception related + // to invalid arguments encountered in a library function call. + struct CImgArgumentException : CImgException { + CImgArgumentException(const char *format,...) { cimg_exception_err("CImgArgumentException",true); } + }; + + // The \ref CImgIOException class is used to throw an exception related + // to Input/Output file problems encountered in a library function call. + struct CImgIOException : CImgException { + CImgIOException(const char *format,...) { cimg_exception_err("CImgIOException",true); } + }; + + // The CImgDisplayException class is used to throw an exception related to display problems + // encountered in a library function call. + struct CImgDisplayException : CImgException { + CImgDisplayException(const char *format,...) { cimg_exception_err("CImgDisplayException",false); } + }; + + /* + #------------------------------------- + # + # + # Definition of the namespace 'cimg' + # + # + #------------------------------------- + */ + + //! Namespace that encompasses \a low-level functions and variables of the %CImg Library. + /** + Most of the functions and variables within this namespace are used by the library for low-level processing. + Nevertheless, documented variables and functions of this namespace may be used safely in your own source code. + + \warning Never write using namespace cimg_library::cimg; in your source code, since a lot of functions of the + cimg:: namespace have prototypes similar to standard C functions defined in the global namespace ::. + **/ + namespace cimg { + + // Define the trait that will be used to determine the best data type to work with. + template struct largest { typedef t type; }; + template<> struct largest { typedef unsigned char type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef char type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef unsigned short type; }; + template<> struct largest { typedef unsigned short type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef short type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef unsigned int type; }; + template<> struct largest { typedef unsigned int type; }; + template<> struct largest { typedef unsigned int type; }; + template<> struct largest { typedef unsigned int type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef int type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef float type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + template<> struct largest { typedef double type; }; + + // Define internal library variables. +#if cimg_display_type==1 + struct X11info { + pthread_mutex_t* mutex; + pthread_t* event_thread; + CImgDisplay* wins[1024]; + Display* display; + unsigned int nb_wins; + bool thread_finished; + unsigned int nb_bits; + GC* gc; + bool blue_first; + bool byte_order; + bool shm_enabled; + X11info():mutex(NULL),event_thread(NULL),display(NULL),nb_wins(0), + thread_finished(false),nb_bits(0),gc(NULL),blue_first(false),byte_order(false),shm_enabled(false) {}; + }; +#if defined(cimg_module) + X11info& X11attr(); +#elif defined(cimg_main) + X11info& X11attr() { static X11info val; return val; } +#else + inline X11info& X11attr() { static X11info val; return val; } +#endif +#endif +#ifdef cimg_color_terminal + const char t_normal[9] = {0x1b,'[','0',';','0',';','0','m','\0'}; + const char t_red[11] = {0x1b,'[','4',';','3','1',';','5','9','m','\0'}; + const char t_bold[5] = {0x1b,'[','1','m','\0'}; + const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'}; +#else + const char t_normal[1] = {'\0'}; + const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal, *const t_purple = cimg::t_normal; +#endif + +#if cimg_display_type==1 + // Keycodes for X11-based graphical systems + const unsigned int keyESC = XK_Escape; + const unsigned int keyF1 = XK_F1; + const unsigned int keyF2 = XK_F2; + const unsigned int keyF3 = XK_F3; + const unsigned int keyF4 = XK_F4; + const unsigned int keyF5 = XK_F5; + const unsigned int keyF6 = XK_F6; + const unsigned int keyF7 = XK_F7; + const unsigned int keyF8 = XK_F8; + const unsigned int keyF9 = XK_F9; + const unsigned int keyF10 = XK_F10; + const unsigned int keyF11 = XK_F11; + const unsigned int keyF12 = XK_F12; + const unsigned int keyPAUSE = XK_Pause; + const unsigned int key1 = XK_1; + const unsigned int key2 = XK_2; + const unsigned int key3 = XK_3; + const unsigned int key4 = XK_4; + const unsigned int key5 = XK_5; + const unsigned int key6 = XK_6; + const unsigned int key7 = XK_7; + const unsigned int key8 = XK_8; + const unsigned int key9 = XK_9; + const unsigned int key0 = XK_0; + const unsigned int keyBACKSPACE = XK_BackSpace; + const unsigned int keyINSERT = XK_Insert; + const unsigned int keyHOME = XK_Home; + const unsigned int keyPAGEUP = XK_Page_Up; + const unsigned int keyTAB = XK_Tab; + const unsigned int keyQ = XK_q; + const unsigned int keyW = XK_w; + const unsigned int keyE = XK_e; + const unsigned int keyR = XK_r; + const unsigned int keyT = XK_t; + const unsigned int keyY = XK_y; + const unsigned int keyU = XK_u; + const unsigned int keyI = XK_i; + const unsigned int keyO = XK_o; + const unsigned int keyP = XK_p; + const unsigned int keyDELETE = XK_Delete; + const unsigned int keyEND = XK_End; + const unsigned int keyPAGEDOWN = XK_Page_Down; + const unsigned int keyCAPSLOCK = XK_Caps_Lock; + const unsigned int keyA = XK_a; + const unsigned int keyS = XK_s; + const unsigned int keyD = XK_d; + const unsigned int keyF = XK_f; + const unsigned int keyG = XK_g; + const unsigned int keyH = XK_h; + const unsigned int keyJ = XK_j; + const unsigned int keyK = XK_k; + const unsigned int keyL = XK_l; + const unsigned int keyENTER = XK_Return; + const unsigned int keySHIFTLEFT = XK_Shift_L; + const unsigned int keyZ = XK_z; + const unsigned int keyX = XK_x; + const unsigned int keyC = XK_c; + const unsigned int keyV = XK_v; + const unsigned int keyB = XK_b; + const unsigned int keyN = XK_n; + const unsigned int keyM = XK_m; + const unsigned int keySHIFTRIGHT = XK_Shift_R; + const unsigned int keyARROWUP = XK_Up; + const unsigned int keyCTRLLEFT = XK_Control_L; + const unsigned int keyAPPLEFT = XK_Super_L; + const unsigned int keySPACE = XK_space; + const unsigned int keyALTGR = XK_Alt_R; + const unsigned int keyAPPRIGHT = XK_Super_R; + const unsigned int keyMENU = XK_Menu; + const unsigned int keyCTRLRIGHT = XK_Control_R; + const unsigned int keyARROWLEFT = XK_Left; + const unsigned int keyARROWDOWN = XK_Down; + const unsigned int keyARROWRIGHT = XK_Right; +#endif + +#if cimg_display_type==0 || (cimg_display_type==2 && cimg_OS==2) + // Keycodes for Windows-OS + const unsigned int keyESC = 27; + const unsigned int keyF1 = 112; + const unsigned int keyF2 = 113; + const unsigned int keyF3 = 114; + const unsigned int keyF4 = 115; + const unsigned int keyF5 = 116; + const unsigned int keyF6 = 117; + const unsigned int keyF7 = 118; + const unsigned int keyF8 = 119; + const unsigned int keyF9 = 120; + const unsigned int keyF10 = 121; + const unsigned int keyF11 = 122; + const unsigned int keyF12 = 123; + const unsigned int keyPAUSE = 19; + const unsigned int key1 = 49; + const unsigned int key2 = 50; + const unsigned int key3 = 51; + const unsigned int key4 = 52; + const unsigned int key5 = 53; + const unsigned int key6 = 54; + const unsigned int key7 = 55; + const unsigned int key8 = 56; + const unsigned int key9 = 57; + const unsigned int key0 = 48; + const unsigned int keyBACKSPACE = 8; + const unsigned int keyINSERT = 45; + const unsigned int keyHOME = 36; + const unsigned int keyPAGEUP = 33; + const unsigned int keyTAB = 9; + const unsigned int keyQ = 81; + const unsigned int keyW = 87; + const unsigned int keyE = 69; + const unsigned int keyR = 82; + const unsigned int keyT = 84; + const unsigned int keyY = 89; + const unsigned int keyU = 85; + const unsigned int keyI = 73; + const unsigned int keyO = 79; + const unsigned int keyP = 80; + const unsigned int keyDELETE = 8; + const unsigned int keyEND = 35; + const unsigned int keyPAGEDOWN = 34; + const unsigned int keyCAPSLOCK = 20; + const unsigned int keyA = 65; + const unsigned int keyS = 83; + const unsigned int keyD = 68; + const unsigned int keyF = 70; + const unsigned int keyG = 71; + const unsigned int keyH = 72; + const unsigned int keyJ = 74; + const unsigned int keyK = 75; + const unsigned int keyL = 76; + const unsigned int keyENTER = 13; + const unsigned int keySHIFTLEFT = 16; + const unsigned int keyZ = 90; + const unsigned int keyX = 88; + const unsigned int keyC = 67; + const unsigned int keyV = 86; + const unsigned int keyB = 66; + const unsigned int keyN = 78; + const unsigned int keyM = 77; + const unsigned int keySHIFTRIGHT = 16; + const unsigned int keyARROWUP = 38; + const unsigned int keyCTRLLEFT = 17; + const unsigned int keyAPPLEFT = 91; + const unsigned int keySPACE = 32; + const unsigned int keyALTGR = 17; + const unsigned int keyAPPRIGHT = 92; + const unsigned int keyMENU = 93; + const unsigned int keyCTRLRIGHT = 17; + const unsigned int keyARROWLEFT = 37; + const unsigned int keyARROWDOWN = 40; + const unsigned int keyARROWRIGHT = 39; +#endif + +#ifdef PI +#undef PI +#endif + const double PI = 3.14159265358979323846; //!< Definition of the mathematical constant PI + const int infinity_int = 0x7f800000; + const double infinity = (double)*(float*)&cimg::infinity_int; + + // Definition of a 7x11 font, used to return a default font for drawing text. + const unsigned int font7x11[7*11*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000, + 0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020, + 0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e, + 0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0, + 0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081, + 0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111, + 0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1, + 0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111, + 0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1, + 0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111, + 0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1, + 0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a, + 0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1, + 0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282, + 0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104, + 0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801, + 0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448, + 0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00, + 0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7, + 0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0, + 0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204, + 0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18, + 0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a, + 0x400000,0x44,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x62018,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x80000800, + 0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070 + }; + + // Definition of a 10x13 font (used in dialog boxes). + const unsigned int font10x13[256*10*13/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0, + 0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120, + 0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001, + 0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801, + 0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0, + 0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010, + 0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480, + 0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140, + 0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010, + 0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008, + 0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006, + 0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088, + 0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000, + 0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220, + 0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208, + 0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040, + 0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508, + 0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018, + 0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220, + 0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484, + 0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808, + 0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264, + 0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010, + 0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100, + 0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800, + 0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044, + 0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822, + 0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200, + 0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000, + 0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8, + 0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008, + 0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000, + 0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220, + 0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402, + 0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980, + 0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421, + 0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020, + 0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701, + 0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0, + 0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c, + 0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0, + 0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000, + 0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000, + 0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000, + 0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0, + 0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040 + }; + + // Definition of a 8x17 font + const unsigned int font8x17[8*17*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008, + 0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0, + 0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400, + 0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4, + 0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0, + 0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812, + 0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181, + 0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00, + 0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808, + 0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810, + 0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000, + 0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040, + 0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040, + 0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141, + 0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101, + 0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c, + 0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024, + 0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840, + 0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c, + 0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04, + 0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066, + 0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000, + 0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040, + 0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600, + 0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000, + 0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850, + 0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008, + 0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f, + 0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242, + 0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710, + 0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242, + 0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020, + 0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118, + 0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444, + 0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010, + 0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200, + 0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042, + 0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048, + 0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143, + 0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010, + 0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44, + 0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262, + 0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820, + 0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000, + 0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10, + 0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f, + 0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00, + 0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0, + 0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0, + 0x0,0x0,0x0,0x1000,0x1078,0x0,0x0,0x0,0x400500,0x0,0x1e081e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0, + 0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0, + 0x0,0x0,0x400000,0x8000000,0x41e0400,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x104010,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x1c,0x7000,0x0,0x40020000,0x0,0x300000, + 0x0,0xe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x0,0x0,0x0,0x400000,0x38000000,0x0,0x0,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x1c,0x0,0x0,0x0,0x0,0x0,0x304030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + // Definition of a 10x19 font + const unsigned int font10x19[10*19*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3600000,0x36000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x1c000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0, + 0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x2200000, + 0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000, + 0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c, + 0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0, + 0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000, + 0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0, + 0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10, + 0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000, + 0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000, + 0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000, + 0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301, + 0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c, + 0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202, + 0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409, + 0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000, + 0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020, + 0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190, + 0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202, + 0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902, + 0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024, + 0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888, + 0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482, + 0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838, + 0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41, + 0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902, + 0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108, + 0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850, + 0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482, + 0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408, + 0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182, + 0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040, + 0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022, + 0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048, + 0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120, + 0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090, + 0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000, + 0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040, + 0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101, + 0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048, + 0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210, + 0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090, + 0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000, + 0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040, + 0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100, + 0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000, + 0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210, + 0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f, + 0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224, + 0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902, + 0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021, + 0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020, + 0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010, + 0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020, + 0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000, + 0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021, + 0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008, + 0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200, + 0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020, + 0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024, + 0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301, + 0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102, + 0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000, + 0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007, + 0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842, + 0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661, + 0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07, + 0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000, + 0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360, + 0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0, + 0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e, + 0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0xc06,0xc,0x100,0x0,0x0,0x0,0x3000,0x0,0x20000000,0x0,0x0,0x0,0x0,0xc000, + 0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1040010,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x60c,0x18,0x0, + 0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000, + 0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400, + 0x2,0x1e02000,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x2040020,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x4000,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000, + 0x0,0x0,0x0,0x1000,0x1c00,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0xe0400e0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + + // Definition of a 12x24 font + const unsigned int font12x24[12*24*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0, + 0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c, + 0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003, + 0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019, + 0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000, + 0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000, + 0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6, + 0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f, + 0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603, + 0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8, + 0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3, + 0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00, + 0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019, + 0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc, + 0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003, + 0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f, + 0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006, + 0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009, + 0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018, + 0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00, + 0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000, + 0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000, + 0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3, + 0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980, + 0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000, + 0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60, + 0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600, + 0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f, + 0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600, + 0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0, + 0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000, + 0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606, + 0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6, + 0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f, + 0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001, + 0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061, + 0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6, + 0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000, + 0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660, + 0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d, + 0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180, + 0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020, + 0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660, + 0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060, + 0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000, + 0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006, + 0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06, + 0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090, + 0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006, + 0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066, + 0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183, + 0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044, + 0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001, + 0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003, + 0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1, + 0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f, + 0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660, + 0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60, + 0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000, + 0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001, + 0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003, + 0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603, + 0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00, + 0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066, + 0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, + 0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004, + 0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006, + 0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06, + 0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de, + 0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6, + 0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066, + 0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, + 0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000, + 0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006, + 0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06, + 0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc, + 0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000, + 0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8, + 0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000, + 0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000, + 0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e, + 0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c, + 0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000, + 0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140, + 0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060, + 0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0, + 0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030, + 0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60, + 0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c, + 0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000, + 0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240, + 0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0, + 0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71, + 0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300, + 0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8, + 0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8, + 0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0, + 0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000, + 0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000, + 0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83, + 0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000, + 0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6, + 0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6, + 0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0, + 0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0, + 0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f, + 0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c, + 0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0, + 0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0, + 0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6, + 0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000, + 0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000, + 0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000, + 0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0, + 0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000, + 0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0, + 0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0, + 0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + // Definition of a 16x32 + const unsigned int font16x32[16*32*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730, + 0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180, + 0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000, + 0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380, + 0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380, + 0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000, + 0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070, + 0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c, + 0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000, + 0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700, + 0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180, + 0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0, + 0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000, + 0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000, + 0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f, + 0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0, + 0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038, + 0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0, + 0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0, + 0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0, + 0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007, + 0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0, + 0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0, + 0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000, + 0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc, + 0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0, + 0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0, + 0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0, + 0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000, + 0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0, + 0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e, + 0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0, + 0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038, + 0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0, + 0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300, + 0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08, + 0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380, + 0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0, + 0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c, + 0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00, + 0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838, + 0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0, + 0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000, + 0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0, + 0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0, + 0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0, + 0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000, + 0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000, + 0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180, + 0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000, + 0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000, + 0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007, + 0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70, + 0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180, + 0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000, + 0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0, + 0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838, + 0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180, + 0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770, + 0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770, + 0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc, + 0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380, + 0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12, + 0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770, + 0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038, + 0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0, + 0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380, + 0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00, + 0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c, + 0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400, + 0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe, + 0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770, + 0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038, + 0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78, + 0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0, + 0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c, + 0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0, + 0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8, + 0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0, + 0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0, + 0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c, + 0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c, + 0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0, + 0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0, + 0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800, + 0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380, + 0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0, + 0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860, + 0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0, + 0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c, + 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70, + 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe, + 0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc, + 0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc, + 0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70, + 0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180, + 0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0, + 0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0, + 0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc, + 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70, + 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe, + 0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000, + 0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0, + 0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc, + 0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0, + 0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000, + 0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000, + 0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc, + 0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838, + 0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0, + 0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000, + 0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0, + 0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc, + 0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0, + 0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838, + 0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, + 0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c, + 0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0, + 0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180, + 0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000, + 0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0, + 0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c, + 0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0, + 0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838, + 0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, + 0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c, + 0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0, + 0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180, + 0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c, + 0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c, + 0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0, + 0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0, + 0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0, + 0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8, + 0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800, + 0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000, + 0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000, + 0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0, + 0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78, + 0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000, + 0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838, + 0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0, + 0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c, + 0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0, + 0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180, + 0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18, + 0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380, + 0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78, + 0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0, + 0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000, + 0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000, + 0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c, + 0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78, + 0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000, + 0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8, + 0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380, + 0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8, + 0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380, + 0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe, + 0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc, + 0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc, + 0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8, + 0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180, + 0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8, + 0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0, + 0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38, + 0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000, + 0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000, + 0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078, + 0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0, + 0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0, + 0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000, + 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0, + 0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000, + 0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000, + 0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0, + 0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000, + 0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000, + 0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0, + 0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000, + 0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000, + 0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000, + 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + // Definition of a 19x38 font + const unsigned int font19x38[19*38*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c380000,0x0,0x1c380,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800007,0x3c003,0x86000000, + 0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe700000,0x0,0xe700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000, + 0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x7e00000,0x0,0x7e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000, + 0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000, + 0x0,0x3c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000, + 0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60000000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c38,0x0,0x1,0xc3800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000003,0x80018000,0x0,0xc180000, + 0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78c00,0xc30, + 0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0, + 0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700, + 0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x3800000,0x700000,0x38, + 0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1, + 0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000, + 0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e, + 0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800, + 0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01, + 0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000, + 0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000, + 0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c, + 0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0, + 0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0, + 0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000, + 0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007, + 0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61800600,0x7f8001ff,0x70000, + 0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e, + 0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007, + 0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000, + 0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00, + 0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000, + 0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00, + 0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67, + 0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc, + 0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff, + 0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0, + 0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000, + 0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000, + 0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c, + 0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38, + 0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc, + 0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0, + 0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00, + 0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07, + 0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380, + 0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000, + 0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3, + 0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0, + 0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001, + 0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xff0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380, + 0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e, + 0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000, + 0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0, + 0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078, + 0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60, + 0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078, + 0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878, + 0x0,0x0,0x0,0x7,0x80000080,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c, + 0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707, + 0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01, + 0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff, + 0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc, + 0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000, + 0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606, + 0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c, + 0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07, + 0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007, + 0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07, + 0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700, + 0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038, + 0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe, + 0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000, + 0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0, + 0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000, + 0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001, + 0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff, + 0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8, + 0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800, + 0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00, + 0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000, + 0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03, + 0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000, + 0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c, + 0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060, + 0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0, + 0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff, + 0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c, + 0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f, + 0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07, + 0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1, + 0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8, + 0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03, + 0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0, + 0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c, + 0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3, + 0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003, + 0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0, + 0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07, + 0xc1e0e03c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1,0x8701c600,0x1e0f01e0,0x1, + 0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81, + 0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0, + 0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e, + 0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e, + 0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000, + 0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0, + 0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f, + 0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e, + 0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800, + 0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3, + 0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038, + 0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000, + 0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03, + 0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000, + 0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800, + 0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e, + 0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0, + 0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007, + 0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3, + 0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000, + 0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f, + 0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c, + 0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000, + 0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700, + 0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f, + 0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000, + 0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001, + 0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000, + 0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007, + 0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80, + 0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00, + 0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0, + 0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e, + 0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180, + 0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000, + 0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f, + 0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0, + 0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff, + 0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c, + 0xe0381c0,0x700e1c07,0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0xc000ff0, + 0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700, + 0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1, + 0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038, + 0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0, + 0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef, + 0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800, + 0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0, + 0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003, + 0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0, + 0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07, + 0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x7f,0xffc00678,0x707f9c1e,0x38000001, + 0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700, + 0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0, + 0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc, + 0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb, + 0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000, + 0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000, + 0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00, + 0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c, + 0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3, + 0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3, + 0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00, + 0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0, + 0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e, + 0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001, + 0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18, + 0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f, + 0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d, + 0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00, + 0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0061c,0xc0dc07,0xf0000001,0xc0000700, + 0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e, + 0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00, + 0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1, + 0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000, + 0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c, + 0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001, + 0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807, + 0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038, + 0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c, + 0xe0381c0,0x70077807,0x701de0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x1c00061c, + 0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87, + 0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0, + 0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c, + 0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000, + 0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c, + 0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0, + 0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00, + 0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700, + 0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f, + 0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e, + 0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07, + 0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700, + 0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e, + 0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f, + 0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0, + 0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c, + 0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787, + 0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001, + 0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00, + 0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700, + 0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e, + 0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703, + 0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077, + 0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003, + 0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0, + 0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800, + 0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e, + 0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007, + 0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c, + 0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0, + 0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03, + 0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0, + 0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0, + 0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0, + 0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f, + 0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff, + 0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe, + 0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc, + 0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700, + 0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff, + 0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe, + 0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000, + 0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000, + 0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc, + 0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000, + 0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff, + 0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x30007fc0,0x1e00f8,0x78000000,0x70001c00, + 0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000, + 0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0, + 0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0, + 0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010, + 0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f, + 0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00, + 0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0, + 0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00, + 0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007, + 0x1f000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x70001c00,0x0, + 0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0, + 0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000, + 0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, + 0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000, + 0x0,0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x30001800, + 0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000, + 0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000, + 0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, + 0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x38003800, + 0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000, + 0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000, + 0x78000e,0x3c000,0x0,0x0,0x180001,0xc0018300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0, + 0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x38007,0xe00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x18003000, + 0x0,0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0, + 0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000, + 0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, + 0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78007, + 0x1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000, + 0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0, + 0x0,0x10007f,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x38,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x3800,0x0,0x1f800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f8007,0xfe00,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x7fe000,0x0, + 0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1f000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x3f0007,0xfc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0, + 0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0007,0xf000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + // Definition of a 29x57 font + const unsigned int font29x57[29*57*256/32] = { + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7, + 0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000, + 0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000, + 0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000, + 0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0, + 0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f, + 0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00, + 0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800, + 0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3, + 0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e, + 0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0, + 0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003, + 0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0, + 0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0, + 0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00, + 0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0, + 0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000, + 0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0, + 0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0, + 0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0, + 0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0, + 0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000, + 0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000, + 0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000, + 0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800, + 0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3, + 0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0, + 0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000, + 0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80, + 0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0, + 0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000, + 0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000, + 0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000, + 0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f, + 0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000, + 0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc, + 0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00, + 0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e, + 0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000, + 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe, + 0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000, + 0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff, + 0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00, + 0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80, + 0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000, + 0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0, + 0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff, + 0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0, + 0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003, + 0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d, + 0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, + 0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc, + 0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff, + 0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff, + 0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000, + 0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0, + 0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f, + 0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000, + 0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0, + 0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff, + 0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8, + 0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003, + 0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380, + 0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000, + 0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80, + 0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff, + 0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c, + 0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000, + 0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80, + 0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00, + 0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000, + 0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe, + 0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800, + 0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f, + 0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700, + 0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f, + 0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007, + 0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007, + 0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f, + 0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0, + 0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000, + 0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000, + 0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000, + 0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000, + 0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, + 0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007, + 0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003, + 0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000, + 0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007, + 0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00, + 0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1, + 0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0, + 0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c, + 0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000, + 0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000, + 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00, + 0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000, + 0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007, + 0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80, + 0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0, + 0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f, + 0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800, + 0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000, + 0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000, + 0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000, + 0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0, + 0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000, + 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00, + 0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803, + 0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f, + 0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780, + 0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e, + 0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0, + 0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0, + 0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078, + 0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007, + 0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780, + 0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e, + 0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003, + 0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800, + 0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001, + 0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc, + 0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000, + 0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03, + 0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0, + 0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000, + 0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, + 0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc, + 0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0, + 0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000, + 0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780, + 0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0, + 0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000, + 0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f, + 0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff, + 0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000, + 0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0, + 0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c, + 0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0, + 0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000, + 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00, + 0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f, + 0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f, + 0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, + 0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f, + 0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e, + 0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001, + 0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001, + 0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f, + 0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780, + 0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007, + 0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000, + 0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0, + 0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787, + 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f, + 0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001, + 0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f, + 0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001, + 0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00, + 0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0, + 0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079, + 0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c, + 0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00, + 0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f, + 0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000, + 0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000, + 0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780, + 0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00, + 0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000, + 0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e, + 0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff, + 0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff, + 0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000, + 0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e, + 0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c, + 0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001, + 0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801, + 0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc, + 0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780, + 0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f, + 0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000, + 0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078, + 0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001, + 0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, + 0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8, + 0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0, + 0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007, + 0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00, + 0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0, + 0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007, + 0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807, + 0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c, + 0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000, + 0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18, + 0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0, + 0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe, + 0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078, + 0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000, + 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, + 0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008, + 0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0, + 0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003, + 0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00, + 0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80, + 0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e, + 0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000, + 0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000, + 0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c, + 0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00, + 0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00, + 0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000, + 0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00, + 0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000, + 0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00, + 0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c, + 0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00, + 0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0, + 0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078, + 0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000, + 0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0, + 0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c, + 0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000, + 0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0, + 0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e, + 0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c, + 0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0, + 0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e, + 0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0, + 0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007, + 0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000, + 0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800, + 0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1, + 0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff, + 0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000, + 0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000, + 0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000, + 0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000, + 0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003, + 0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce, + 0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00, + 0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f, + 0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0, + 0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e, + 0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800, + 0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0, + 0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007, + 0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00, + 0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff, + 0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0, + 0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0, + 0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00, + 0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000, + 0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000, + 0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f, + 0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0, + 0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007, + 0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8, + 0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0, + 0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000, + 0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00, + 0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80, + 0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0, + 0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e, + 0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c, + 0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f, + 0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c, + 0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003, + 0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000, + 0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303, + 0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc, + 0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000, + 0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780, + 0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000, + 0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078, + 0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007, + 0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00, + 0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f, + 0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0, + 0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c, + 0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000, + 0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000, + 0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000, + 0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800, + 0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0, + 0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000, + 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, + 0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003, + 0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00, + 0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f, + 0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3, + 0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070, + 0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0, + 0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0, + 0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e, + 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0, + 0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000, + 0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80, + 0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303, + 0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00, + 0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, + 0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000, + 0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe, + 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07, + 0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f, + 0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f, + 0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007, + 0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800, + 0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007, + 0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003, + 0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0, + 0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00, + 0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00, + 0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000, + 0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000, + 0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c, + 0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01, + 0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000, + 0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800, + 0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000, + 0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070, + 0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0, + 0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0, + 0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e, + 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0, + 0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff, + 0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001, + 0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000, + 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801, + 0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, + 0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000, + 0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe, + 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, + 0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000, + 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000, + 0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800, + 0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000, + 0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, + 0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800, + 0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0, + 0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078, + 0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000, + 0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0, + 0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000, + 0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0, + 0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000, + 0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078, + 0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001, + 0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e, + 0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007, + 0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001, + 0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007, + 0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000, + 0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003, + 0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff, + 0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00, + 0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80, + 0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000, + 0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00, + 0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000, + 0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, + 0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000, + 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000, + 0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800, + 0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001, + 0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, + 0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003, + 0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001, + 0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800, + 0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000, + 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03, + 0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, + 0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000, + 0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000, + 0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c, + 0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00, + 0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff, + 0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e, + 0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c, + 0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f, + 0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e, + 0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f, + 0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000, + 0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0, + 0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807, + 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f, + 0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80, + 0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000, + 0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800, + 0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00, + 0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03, + 0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800, + 0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, + 0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, + 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000, + 0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff, + 0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c, + 0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81, + 0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000, + 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0, + 0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c, + 0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00, + 0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f, + 0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e, + 0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03, + 0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780, + 0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, + 0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, + 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000, + 0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f, + 0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000, + 0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00, + 0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, + 0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f, + 0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07, + 0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00, + 0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0, + 0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, + 0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000, + 0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e, + 0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf, + 0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f, + 0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e, + 0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000, + 0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000, + 0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0, + 0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, + 0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e, + 0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80, + 0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000, + 0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00, + 0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, + 0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000, + 0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e, + 0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf, + 0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f, + 0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e, + 0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000, + 0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0, + 0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0, + 0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00, + 0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007, + 0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c, + 0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000, + 0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0, + 0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0, + 0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007, + 0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0, + 0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f, + 0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007, + 0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000, + 0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018, + 0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0, + 0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00, + 0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070, + 0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003, + 0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8, + 0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80, + 0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0, + 0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f, + 0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780, + 0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff, + 0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000, + 0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000, + 0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff, + 0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000, + 0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f, + 0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000, + 0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1, + 0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0, + 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f, + 0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff, + 0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8, + 0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f, + 0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780, + 0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff, + 0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000, + 0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000, + 0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff, + 0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000, + 0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7, + 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381, + 0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0, + 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f, + 0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3, + 0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0, + 0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003, + 0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780, + 0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff, + 0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000, + 0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000, + 0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff, + 0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000, + 0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7, + 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff, + 0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0, + 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007, + 0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1, + 0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0, + 0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000, + 0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000, + 0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000, + 0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000, + 0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e, + 0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0, + 0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f, + 0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800, + 0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0, + 0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000, + 0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000, + 0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000, + 0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000, + 0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0, + 0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000, + 0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0, + 0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0, + 0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000, + 0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff, + 0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000, + 0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0, + 0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f, + 0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, + 0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0, + 0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0, + 0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0, + 0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, + 0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0, + 0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000, + 0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; + + // Definition of a 40x38 'danger' color logo + const unsigned char logo40x38[4576] = { + 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200, + 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0, + 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200, + 1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0, + 2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255, + 255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189, + 189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189, + 189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123, + 22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200, + 1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0, + 0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1, + 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189, + 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255, + 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189, + 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255, + 0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123, + 123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189, + 189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255, + 0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189, + 189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1, + 0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255, + 255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123, + 123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86, + 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0}; + + // Return a 'stringification' of standard integral types. + const char* const bool_st = "bool"; + const char* const uchar_st = "unsigned char"; + const char* const char_st = "char"; + const char* const ushort_st = "unsigned short"; + const char* const short_st = "short"; + const char* const uint_st = "unsigned int"; + const char* const int_st = "int"; + const char* const ulong_st = "unsigned long"; + const char* const long_st = "long"; + const char* const float_st = "float"; + const char* const double_st = "double"; + const char* const unknown_st = "unknown"; + template inline const char* get_type(const t&) { return cimg::unknown_st; } + inline const char* get_type(const bool& ) { return cimg::bool_st; } + inline const char* get_type(const unsigned char& ) { return cimg::uchar_st; } + inline const char* get_type(const char& ) { return cimg::char_st; } + inline const char* get_type(const unsigned short&) { return cimg::ushort_st; } + inline const char* get_type(const short& ) { return cimg::short_st; } + inline const char* get_type(const unsigned int& ) { return cimg::uint_st; } + inline const char* get_type(const int& ) { return cimg::int_st; } + inline const char* get_type(const unsigned long& ) { return cimg::ulong_st; } + inline const char* get_type(const long& ) { return cimg::long_st; } + inline const char* get_type(const float& ) { return cimg::float_st; } + inline const char* get_type(const double& ) { return cimg::double_st; } + + // Return an approximation of the minimum value of a type. + // (Necessary because of buggy on VC++ 6.0) + template inline t get_type_min(const t&) { + static const double p = std::pow(2.0,8.0*sizeof(t)-1.0); + static const t res = (t)(((t)-1)>=0?0:(-p)); + return res; + } + inline float get_type_min(const float&) { return -(float)cimg::infinity; } + inline double get_type_min(const double&) { return -cimg::infinity; } + + // Return an approximation of the maximum value of a type. + // (Necessary because of buggy on VC++ 6.0) + template inline t get_type_max(const t&) { + static const double p = std::pow(2.0,8.0*sizeof(t)-1.0); + static const t res = (t)(((t)-1)>=0?(2*p-1):(p-1)); + return res; + } + inline float get_type_max(const float&) { return (float)cimg::infinity; } + inline double get_type_max(const double&) { return cimg::infinity; } + + // Display a warning message if parameter 'cond' is true. +#if cimg_debug>=1 + inline void warn(const bool cond,const char *format,...) { + if (cond) { + std::va_list ap; + va_start(ap,format); + std::fprintf(stderr," "); + std::vfprintf(stderr,format,ap); + std::fputc('\n',stderr); + va_end(ap); + } + } +#else + inline void warn(const bool cond,const char *format,...) {} +#endif + + inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; } + inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); } + inline float atof(const char *str) { + float x=0,y=1; + if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; } + } + inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; } + inline int strncmp(const char *s1,const char *s2,const int l) { + if (s1 && s2) { int n=0; for (int k=0; k=0 && s[l]!=c; l--) ; + return l; + } + return -1; + } + inline const char* basename(const char *s) { + return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):NULL):(s?s+1+cimg::strfind(s,'\\'):NULL); + } + inline void system(const char *command) { +#if cimg_OS==2 + PROCESS_INFORMATION pi; + STARTUPINFO si; + GetStartupInfo(&si); + si.wShowWindow = SW_HIDE; + si.dwFlags |= SW_HIDE; + BOOL res = CreateProcess(NULL,(LPTSTR)command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi); + if (res) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } +#else + std::system(command); +#endif + } + + //! Return path of the ImageMagick's \c convert tool. + /** + If you have installed the ImageMagick package + in a standard directory, this function should return the correct path of the \c convert tool + used by the %CImg Library to load and save compressed image formats. + Conversely, if the \c convert executable is not auto-detected by the function, + you can define the macro \c cimg_convert_path with the correct path + of the \c convert executable, before including CImg.h in your program : + \code + #define cimg_convert_path "/users/thatsme/local/bin/convert" + #include "CImg.h" + + int main() { + CImg<> img("my_image.jpg"); // Read a JPEG image file. + return 0; + } + \endcode + + Note that non compressed image formats can be read without installing ImageMagick. + + \sa temporary_path(), get_load_convert(), load_convert(), save_convert(). + **/ + inline const char* convert_path() { + static char *st_convert_path = NULL; + if (!st_convert_path) { + st_convert_path = new char[1024]; + bool path_found = false; +#ifdef cimg_convert_path + { + std::FILE *file = NULL; + std::strcpy(st_convert_path,cimg_convert_path); + if ((file=std::fopen(st_convert_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + } +#endif +#if cimg_OS==2 + { + std::FILE *file = NULL; + for (unsigned int k=0; k<=9 && !path_found; k++) { + std::sprintf(st_convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u-Q\\convert.exe",k); + if ((file=std::fopen(st_convert_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + } + { for (unsigned int k=0; k<=9 && !path_found; k++) { + std::sprintf(st_convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u\\convert.exe",k); + if ((file=std::fopen(st_convert_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + }} + { for (unsigned int k=0; k<=9 && !path_found; k++) { + std::sprintf(st_convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(st_convert_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + }} + { for (unsigned int k=0; k<=9 && !path_found; k++) { + std::sprintf(st_convert_path,"C:\\PROGRA~1\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",k); + if ((file=std::fopen(st_convert_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + }} + if (!path_found) std::strcpy(st_convert_path,"convert.exe"); + } +#else + { + if (!path_found) std::strcpy(st_convert_path,"convert"); + } +#endif + } + return st_convert_path; + } + + //! Return path of the \c XMedcon tool. + /** + If you have installed the XMedcon package + in a standard directory, this function should return the correct path of the \c medcon tool + used by the %CIg Library to load DICOM image formats. + Conversely, if the \c medcon executable is not auto-detected by the function, + you can define the macro \c cimg_medcon_path with the correct path + of the \c medcon executable, before including CImg.h in your program : + \code + #define cimg_medcon_path "/users/thatsme/local/bin/medcon" + #include "CImg.h" + + int main() { + CImg<> img("my_image.dcm"); // Read a DICOM image file. + return 0; + } + \endcode + + Note that \c medcon is only needed if you want to read DICOM image formats. + + \sa temporary_path(), get_load_dicom(), load_dicom(). + **/ + inline const char* medcon_path() { + static char *st_medcon_path = NULL; + if (!st_medcon_path) { + st_medcon_path = new char[1024]; + bool path_found = false; +#ifdef cimg_medcon_path + { + std::FILE *file = NULL; + std::strcpy(st_medcon_path,cimg_medcon_path); + if ((file=std::fopen(st_medcon_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + } +#endif +#if cimg_OS==2 + { + std::FILE *file = NULL; + if (!path_found) { + std::sprintf(st_medcon_path,"C:\\PROGRA~1\\XMedCon\\bin\\medcon.bat"); + if ((file=std::fopen(st_medcon_path,"r"))!=NULL) { std::fclose(file); path_found = true; } + } + if (!path_found) std::strcpy(st_medcon_path,"medcon.bat"); + } +#else + { + if (!path_found) std::strcpy(st_medcon_path,"medcon"); + } +#endif + } + return st_medcon_path; + } + + //! Return path to store temporary files. + /** + If you are running on a standard Unix or Windows system, this function should return a correct path + where temporary files can be stored. If such a path is not auto-detected by this function, + you can define the macro \c cimg_temporary_path with a correct path, before including CImg.h + in your program : + \code + #define cimg_temporary_path "/users/thatsme/tmp" + #include "CImg.h" + + int main() { + CImg<> img("my_image.jpg"); // Read a JPEG image file (using the defined temporay path). + return 0; + } + \endcode + + A temporary path is necessary to load and save compressed image formats, using \c convert + or \c medcon. + + \sa convert_path(), get_load_convert(), load_convert(), save_convert(), get_load_dicom(), load_dicom(). + **/ + inline const char* temporary_path() { + static char *st_temporary_path = NULL; + if (!st_temporary_path) { + st_temporary_path = new char[1024]; +#ifdef cimg_temporary_path + std::strcpy(st_temporary_path,cimg_temporary_path); + const char* testing_path[7] = { st_temporary_path, "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL }; +#else + const char* testing_path[6] = { "/tmp","C:\\WINNT\\Temp", "C:\\WINDOWS\\Temp","","C:",NULL }; +#endif + char filetmp[1024]; + std::FILE *file=NULL; + int i=-1; + while (!file && testing_path[++i]) { + std::sprintf(filetmp,"%s/CImg%.4d.ppm",testing_path[i],std::rand()%10000); + if ((file=std::fopen(filetmp,"w"))!=NULL) { std::fclose(file); std::remove(filetmp); } + } + if (!file) + throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n" + "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n" + "#define cimg_temporary_path \"path\" (before including 'CImg.h')"); + std::strcpy(st_temporary_path,testing_path[i]); + } + return st_temporary_path; + } + + inline const char *filename_split(const char *const filename, char *const body=NULL) { + if (!filename) { if (body) body[0]='\0'; return NULL; } + int l = cimg::strfind(filename,'.'); + if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }} + else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; } + return filename+l+1; + } + + inline char* filename_number(const char *filename,const int number,const unsigned int n,char *const string) { + if (!filename) { if (string) string[0]='\0'; return NULL; } + char format[1024],body[1024]; + const char *ext = cimg::filename_split(filename,body); + if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext); + else std::sprintf(format,"%s_%%d.%s",body,ext); + std::sprintf(string,format,number); + return string; + } + + inline std::FILE *fopen(const char *const path,const char *const mode) { + if(!path || !mode) throw CImgArgumentException("cimg::fopen() : Can't open file '%s' with mode '%s'",path,mode); + if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; + else { + std::FILE *dest = std::fopen(path,mode); + if(!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened %s", + path,mode[0]=='r'?"for reading":(mode[0]=='w'?"for writing":""),path); + return dest; + } + } + + inline int fclose(std::FILE *file) { + warn(!file,"cimg::fclose() : Can't close (null) file"); + if (!file || file==stdin || file==stdout) return 0; + const int errn=std::fclose(file); + warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn); + return errn; + } + template inline int fread(T *ptr,const unsigned int nmemb,std::FILE *stream) { + if (!ptr || nmemb<=0 || !stream) + throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'", + nmemb,sizeof(T),stream,ptr); + const unsigned int errn = (unsigned int)std::fread((void*)ptr,sizeof(T),nmemb,stream); + cimg::warn(errn!=nmemb,"cimg::fread() : File reading problems, only %u/%u elements read",errn,nmemb); + return errn; + } + template inline int fwrite(const T *ptr,const unsigned int nmemb,std::FILE *stream) { + if (!ptr || nmemb<=0 || !stream) + throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'", + nmemb,sizeof(T),stream,ptr); + const unsigned int errn = (unsigned int)std::fwrite(ptr,sizeof(T),nmemb,stream); + if(errn!=nmemb) + throw CImgIOException("cimg::fwrite() : File writing problems, only %u/%u elements written",errn,nmemb); + return errn; + } + + // Exchange the values of variables \p a and \p b + template inline void swap(T& a,T& b) { T t=a; a=b; b=t; } + template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2) { + cimg::swap(a1,b1); cimg::swap(a2,b2); + } + template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3) { + cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); + } + template + inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4) { + cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); + } + template + inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4,T5& a5,T5& b5) { + cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); + } + template + inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4,T5& a5,T5& b5,T6& a6,T6& b6) { + cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6); + } + + template inline void endian_swap(T* const buffer, const unsigned int size) { + switch (sizeof(T)) { + case 1: break; + case 2: { + for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer;) { + const register unsigned short val = *(--ptr); + *ptr = (val>>8)|((val<<8)); + } + } break; + case 4: { + for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer;) { + const register unsigned int val = *(--ptr); + *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24); + } + } break; + default: { + for (T* ptr = buffer+size; ptr>buffer; --ptr) { + register unsigned char *pb=(unsigned char*)(--ptr), *pe=pb+sizeof(T); + for (int i=0; i<(int)sizeof(T)/2; i++) cimg::swap(*(pb++),*(--pe)); + } break; + } + } + } + template inline T& endian_swap(T& a) { endian_swap(&a,1); return a; } + + inline const char* option(const char *const name, const int argc, char **argv, + const char *defaut, const char *const usage=NULL) { + static bool first=true, visu=false; + const char *res = NULL; + if (first) { + first=false; + visu = (cimg::option("-h",argc,argv,(const char*)NULL)!=NULL); + visu |= (cimg::option("-help",argc,argv,(const char*)NULL)!=NULL); + visu |= (cimg::option("--help",argc,argv,(const char*)NULL)!=NULL); + } + if (!name && visu) { + std::fprintf(stderr,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal); + if (usage) std::fprintf(stderr," : %s",usage); + std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__); + } + if (name) { + if (argc>0) { + int k=0,i; + while (k Architecture : %s%-12s%s %s(cimg_OS=%d)\n%s", + cimg::t_bold, + cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknown"), + cimg::t_normal,cimg::t_purple,cimg_OS,cimg::t_normal); + std::fprintf(stderr," > Display type : %s%-12s%s %s(cimg_display_type=%d)%s\n", + cimg::t_bold,cimg_display_type==0?"No": + (cimg_display_type==1?"X11": + (cimg_display_type==2?"WindowsGDI": + "Unknown")), + cimg::t_normal,cimg::t_purple,cimg_display_type,cimg::t_normal); +#ifdef cimg_color_terminal + std::fprintf(stderr," > Color terminal : %s%-12s%s %s(cimg_color_terminal defined)%s\n", + cimg::t_bold,"Yes",cimg::t_normal,cimg::t_purple,cimg::t_normal); +#else + std::fprintf(stderr," > Color terminal : %-12s (cimg_color_terminal undefined)\n","No"); +#endif + std::fprintf(stderr," > Debug messages : %s%-12s%s %s(cimg_debug=%d)%s\n",cimg::t_bold, + cimg_debug==2?"High":(cimg_debug==1?"Yes":"No"), + cimg::t_normal,cimg::t_purple,cimg_debug,cimg::t_normal); + std::fprintf(stderr,"\n"); + } + + //! Get the value of a system timer with a millisecond precision. + inline long time() { +#if cimg_OS==1 + struct timeval st_time; + gettimeofday(&st_time,NULL); + return (long)(st_time.tv_usec/1000 + st_time.tv_sec*1000); +#elif cimg_OS==2 + static SYSTEMTIME st_time; + GetSystemTime(&st_time); + return (long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour))); +#else + return 0; +#endif + } + + //! Sleep for a certain numbers of milliseconds. + /** + This function frees the CPU ressources during the sleeping time. + It may be used to temporize your program properly, without wasting CPU time. + \sa wait(), time(). + **/ + inline void sleep(const int milliseconds) { +#if cimg_OS==1 + struct timespec tv; + tv.tv_sec = milliseconds/1000; + tv.tv_nsec = (milliseconds%1000)*1000000; + nanosleep(&tv,NULL); +#elif cimg_OS==2 + Sleep(milliseconds); +#endif + } + + //! Wait for a certain number of milliseconds since the last call. + /** + This function is equivalent to sleep() but the waiting time is computed with regard to the last call + of wait(). It may be used to temporize your program properly. + \sa sleep(), time(). + **/ + inline long wait(const int milliseconds=20,long reference_time=-1) { + static long latest_time = cimg::time(); + if (reference_time>=0) latest_time = reference_time; + const long current_time = cimg::time(), time_diff = milliseconds + latest_time - current_time; + if (time_diff>0) { cimg::sleep(time_diff); return (latest_time = current_time + time_diff); } + else return (latest_time = current_time); + } + + template inline const T rol(const T& a,const unsigned int n=1) { return (T)((a<>((sizeof(T)<<3)-n))); } + template inline const T ror(const T& a,const unsigned int n=1) { return (T)((a>>n)|(a<<((sizeof(T)<<3)-n))); } + +#if ( !defined(_MSC_VER) || _MSC_VER>1200 ) + //! Return the absolute value of \p a + template inline T abs(const T& a) { return a>=0?a:-a; } + inline bool abs(const bool a) { return a; } + inline unsigned char abs(const unsigned char a) { return a; } + inline unsigned short abs(const unsigned short a) { return a; } + inline unsigned int abs(const unsigned int a) { return a; } + inline unsigned long abs(const unsigned long a) { return a; } + inline double abs(const double a) { return std::fabs(a); } + inline float abs(const float a) { return (float)std::fabs((double)a); } + inline int abs(const int a) { return std::abs(a); } + + //! Return the minimum between \p a and \p b. + template inline const T& min(const T& a,const T& b) { return a<=b?a:b; } + + //! Return the minimum between \p a,\p b and \a c. + template inline const T& min(const T& a,const T& b,const T& c) { return cimg::min(cimg::min(a,b),c); } + + //! Return the minimum between \p a,\p b,\p c and \p d. + template inline const T& min(const T& a,const T& b,const T& c,const T& d) { return cimg::min(cimg::min(a,b,c),d); } + + //! Return the maximum between \p a and \p b. + template inline const T& max(const T& a,const T& b) { return a>=b?a:b; } + + //! Return the maximum between \p a,\p b and \p c. + template inline const T& max(const T& a,const T& b,const T& c) { return cimg::max(cimg::max(a,b),c); } + + //! Return the maximum between \p a,\p b,\p c and \p d. + template inline const T& max(const T& a,const T& b,const T& c,const T& d) { return cimg::max(cimg::max(a,b,c),d); } + + //! Return the sign of \p x. + template inline T sign(const T& x) { return (x<0)?(T)(-1):(x==0?(T)0:(T)1); } +#else + + // Special versions due to object reference bug in VisualC++ 6.0. + template inline const T abs(const T a) { return a>=0?a:-a; } + template inline const T min(const T a,const T b) { return a<=b?a:b; } + template inline const T min(const T a,const T b,const T c) { return cimg::min(cimg::min(a,b),c); } + template inline const T min(const T a,const T b,const T c,const T& d) { return cimg::min(cimg::min(a,b,c),d); } + template inline const T max(const T a,const T b) { return a>=b?a:b; } + template inline const T max(const T a,const T b,const T c) { return cimg::max(cimg::max(a,b),c); } + template inline const T max(const T a,const T b,const T c,const T& d) { return cimg::max(cimg::max(a,b,c),d); } + template inline char sign(const T x) { return (x<0)?-1:(x==0?0:1); } +#endif + + //! Return the nearest power of 2 higher than \p x. + template inline unsigned long nearest_pow2(const T& x) { + unsigned long i=1; + while (x>i) i<<=1; + return i; + } + + //! Return \p x modulo \p m (generic modulo). + /** + This modulo function accepts negative and floating-points modulo numbers \p m. + **/ + inline double mod(const double& x,const double& m) { return x-m*std::floor(x/m); } + inline float mod(const float& x,const float& m) { return (float)(x-m*std::floor((double)x/m)); } + inline int mod(const int x,const int m) { return x>=0?x%m:(x%m?m+x%m:0); } + + //! Return minmod(\p a,\p b). + /** + The operator minmod(\p a,\p b) is defined to be : + - minmod(\p a,\p b) = min(\p a,\p b), if (\p a * \p b)>0. + - minmod(\p a,\p b) = 0, if (\p a * \p b)<=0 + **/ + template inline T minmod(const T& a,const T& b) { return a*b<=0?0:(a>0?(aabsb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); } + else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); } + } + + // End of the 'cimg' namespace + } + + /* + #---------------------------------------- + # + # + # + # Definition of the CImgStats structure + # + # + # + #---------------------------------------- + */ + //! Class used to compute basic statistics on pixel values of a \ref CImg image. + /** + Constructing a CImgStats instance from an image CImg or a list CImgl + will compute the minimum, maximum and average pixel values of the input object. + Optionally, the variance of the pixel values can be computed. + Coordinates of the pixels whose values are minimum and maximum are also stored. + The example below shows how to use CImgStats objects to retrieve simple statistics of an image : + \code + const CImg img("my_image.jpg"); // Read JPEG image file. + const CImgStats stats(img); // Compute basic statistics on the image. + stats.print("My statistics"); // Display statistics. + std::printf("Max-Min = %lf",stats.max-stats.min); // Compute the difference between extremum values. + \endcode + + Note that statistics are computed by considering the set of \a scalar values of the image pixels. + No vector-valued statistics are computed. + **/ + struct CImgStats { + double min; //!< Minimum of the pixel values. + double max; //!< Maximum of the pixel values. + double mean; //!< Mean of the pixel values. + double variance; //!< Variance of the pixel values. + int xmin; //!< X-coordinate of the pixel with minimum value. + int ymin; //!< Y-coordinate of the pixel with minimum value. + int zmin; //!< Z-coordinate of the pixel with minimum value. + int vmin; //!< V-coordinate of the pixel with minimum value. + int lmin; //!< Image number (for a list) containing the minimum pixel. + int xmax; //!< X-coordinate of the pixel with maximum value. + int ymax; //!< Y-coordinate of the pixel with maximum value. + int zmax; //!< Z-coordinate of the pixel with maximum value. + int vmax; //!< V-coordinate of the pixel with maximum value. + int lmax; //!< Image number (for a list) containing the maximum pixel. + + //! Empty constructor. + /** + Field values of a CImgStats constructed with the empty constructor have no meaning. + **/ + CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1), + xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {} + //! Copy constructor. + CImgStats(const CImgStats& stats):min(stats.min),max(stats.max),mean(stats.mean),variance(stats.variance), + xmin(stats.xmin),ymin(stats.ymin),zmin(stats.zmin),vmin(stats.vmin),lmin(stats.lmin), + xmax(stats.xmax),ymax(stats.ymax),zmax(stats.zmax),vmax(stats.vmax),lmax(stats.lmax) {}; + + //! In-place version of the copy constructor. + CImgStats& assign(const CImgStats& stats) { + return (*this)=stats; + } + + //! Constructor that computes statistics of an input image \p img. + /** + \param img The input image. + \param compute_variance If true, the \c variance field is computed, else it is set to 0. + **/ + template CImgStats(const CImg& img,const bool compute_variance=true):mean(0),variance(0),lmin(-1),lmax(-1) { + if (img.is_empty()) + throw CImgArgumentException("CImgStats::CImgStats() : Specified input image (%u,%u,%u,%u,%p) is empty.", + img.width,img.height,img.depth,img.dim,img.data); + T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin; + cimg_map(img,ptr,T) { + const T& a=*ptr; + mean+=(double)a; + if (apmax) { pmax=a; ptrmax = ptr; } + } + mean/=img.size(); + min=(double)pmin; + max=(double)pmax; + unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data); + const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height; + vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.width; xmin = offmin%img.width; + vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.width; xmax = offmax%img.width; + if (compute_variance) { + cimg_map(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; } + const unsigned int siz = img.size(); + if (siz>1) variance/=(siz-1); else variance=0; + } + } + + //! In-place version of the copy constructor. + template CImgStats& assign(const CImg& img, const bool compute_variance=true) { + return (*this) = CImgStats(img,compute_variance); + } + + //! Constructor that computes statistics of an input image list \p list. + /** + \param list The input list of images. + \param compute_variance If true, the \c variance field is computed, else it is set to 0. + **/ + template CImgStats(const CImgl& list,const bool compute_variance=true):mean(0),variance(0),lmin(0),lmax(0) { + if (list.is_empty()) + throw CImgArgumentException("CImgStats::CImgStats() : Specified input list (%u,%p) is empty.", + list.size,list.data); + T pmin=list[0][0], pmax=pmin, *ptrmin=list[0].data, *ptrmax=ptrmin; + int psize=0; + cimgl_map(list,l) { + cimg_map(list[l],ptr,T) { + const T& a=*ptr; + mean+=(double)a; + if (apmax) { pmax=a; ptrmax = ptr; lmax = l; } + } + psize+=list[l].size(); + } + mean/=psize; + min=(double)pmin; + max=(double)pmax; + const CImg &imin = list[lmin], &imax = list[lmax]; + unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data); + const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height; + vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.width; xmin = offmin%imin.width; + const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height; + vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.width; xmax = offmax%imax.width; + if (compute_variance) { + cimgl_map(list,l) cimg_map(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; } + if (psize>1) variance/=(psize-1); else variance=0; + } + } + + //! In-place version of the copy constructor + template CImgStats& assign(const CImgl& list, const bool compute_variance=true) { + return (*this) = CImgStats(list,compute_variance); + } + + //! Assignement operator. + CImgStats& operator=(const CImgStats& stats) { + min = stats.min; + max = stats.max; + mean = stats.mean; + variance = stats.variance; + xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin; + xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax; + return *this; + } + + //! Print the current statistics. + /** + Printing is done on the standart error output. + **/ + const CImgStats& print(const char* title=NULL) const { + if (lmin>=0 && lmax>=0) + std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, " + "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n", + title?title:"CImgStats",(void*)this,min,mean,variance,max, + lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax); + else + std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, " + "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n", + title?title:"CImgStats",(void*)this,min,mean,variance,max, + xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax); + return *this; + } + + // Swap fields between two CImgStats + CImgStats& swap(CImgStats& stats) { + cimg::swap(min,stats.min); + cimg::swap(max,stats.max); + cimg::swap(mean,stats.mean); + cimg::swap(variance,stats.variance); + cimg::swap(xmin,stats.xmin); cimg::swap(ymin,stats.ymin); cimg::swap(zmin,stats.zmin); cimg::swap(vmin,stats.vmin); + cimg::swap(lmin,stats.lmin); + cimg::swap(xmax,stats.xmax); cimg::swap(ymax,stats.ymax); cimg::swap(zmax,stats.zmax); cimg::swap(vmax,stats.vmax); + cimg::swap(lmax,stats.lmax); + return *this; + } + +#ifdef cimgstats_plugin +#include cimgstats_plugin +#endif + + }; + + /* + #------------------------------------------- + # + # + # + # Definition of the CImgDisplay structure + # + # + # + #------------------------------------------- + */ + + //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events. + /** + Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg image + of a \c CImgl image list inside. When a display is created, associated window events + (such as mouse motion, keyboard and window size changes) are handled and can be easily + detected by testing specific \c CImgDisplay data fields. + See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class. + **/ + + struct CImgDisplay { + + //! Width of the display. + /** + Prefer using CImgDisplay::dimx() to get the width of the display. + + \note Using CImgDisplay::dimx() instead of \p width is more safe when doing arithmetics + involving the value of \p width, since it returns a \e signed int. Arithmetics with + \e unsigned types needs a lot of attention. + + \note The variable \c width should be considered as read-only. + Setting a new value for \p CImgDisplay::width is done through CImgDisplay::resize(). + Modifying directly \p width would probably result in a crash. + + \see CImgDisplay::height, CImgDisplay::resize() + **/ + unsigned int width; + + //! Height of the display. + /** + Prefer using CImgDisplay::dimy() to get the height of the display. + + \note Using CImgDisplay::dimy() instead of \p height is more safe when doing arithmetics + involving the value of \p height, since it returns a \e signed int. Artihmetics with + \e unsigned types needs a lot of attention. + + \note The variable \c height should be considered as read-only. + Setting a new value for \p CImgDisplay::height is done through CImgDisplay::resize(). + Modifying directly \p height would probably result in a crash. + + \see CImgDisplay::width, CImgDisplay::resize() + **/ + unsigned int height; + + //! Width of the window containing the display. + /** + \note This is not the width of the display, but the width of the underlying system window. + This variable is updated when an user resized the window associated to the display. + When it occurs, \c width and \c window_width will be probably different. + \see CImgDisplay::window_height, CImgDisplay::resized, CImgDisplay::resize(). + **/ + volatile unsigned int window_width; + + //! Height of the window containing the display. + /** + \note This is not the height of the display, but the height of the underlying system window. + This variable is updated when an user resized the window associated to the display. + When it occurs, \c height and \c window_height will be probably different. + \see CImgDisplay::window_width, CImgDisplay::resized, CImgDisplay::resize(). + **/ + volatile unsigned int window_height; + + //! X-coordinate of the display, relative to screen coordinates. + volatile int window_x; + + //! Y-coordinate of the display, relative to screen coordinates. + volatile int window_y; + + //! Type of pixel normalization done by the display. + /** + It represents the way the pixel values are normalized for display purposes. + Its value can be set to : + - \c 0 : No pixel value normalization are performed (fastest). Be sure your image data are bounded in [0,255]. + - \c 1 : Pixel value renormalization between [0,255] is done at each display request (default). + - \c 2 : Pixel value renormalization between [0,255] is done at the first display request. Then the + normalization parameters are kept and used for the next image display requests. + \note \c normalization is preferably set by invoking constructors CImgDisplay::CImgDisplay(). + \see CImgDisplay::CImgDisplay(), CImgDisplay::display(). + **/ + unsigned int normalization; + + //! Type of events handled by the display. + /** + It represents what events are handled by the display. Its value can be set to : + - \c 0 : No events are handled by the display. + - \c 1 : Display closing and resizing are handled by the display. + - \c 2 : Display closing, resizing, mouse motion and buttons press, as well as key press are handled by the display. + - \c 3 : Display closing, resizing, mouse motion and buttons press/release, as well as key press/release + are handled by the display. + \note \c events if preferably set by invoking constructors CImgDisplay::CImgDisplay(). + \see CImgDisplay::CImgDisplay(), CImgDisplay::mouse_x, CImgDisplay::mouse_y, CImgDisplay::key, + CImgDisplay::button, CImgDisplay::resized, CImgDisplay::closed. + **/ + unsigned int events; + + //! Flag indicating fullscreen mode. + /** + If the display has been specified to be fullscreen at the construction, this variable is set to \c true. + **/ + const bool fullscreen; + + //! X-coordinate of the mouse pointer over the display. + /** + If CImgDisplay::events>=2, \p mouse_x represents the current x-coordinate of the mouse pointer. + - If the mouse pointer is outside the display window, \p mouse_x is equal to \p -1. + - If the mouse pointer is over the display window, \p mouse_x falls in the range [0,CImgDisplay::width-1], + where \p 0 corresponds to the far left coordinate and \p CImgDisplay::width-1 to the far right coordinate. + \note \p mouse_x is updated every 25 milliseconds, through an internal thread. + \see CImgDisplay::mouse_y, CImgDisplay::button + **/ + volatile int mouse_x; + + //! Y-coordinate of the mouse pointer over the display. + /** + If CImgDisplay::events>=2, \p mouse_y represents the current y-coordinate of the mouse pointer. + - If the mouse pointer is outside the display window, \p mouse_y is equal to \p -1. + - If the mouse pointer is over the display window, \p mouse_y falls in the range [0,CImgDisplay::height-1], + where \p 0 corresponds to the far top coordinate and \p CImgDisplay::height-1 to the far bottom coordinate. + \note \p mouse_y is updated every 25 milliseconds, through an internal thread. + \see CImgDisplay::mouse_x, CImgDisplay::button + **/ + volatile int mouse_y; + + //! Variable representing the state of the mouse buttons when the mouse pointer is over the display window. + //! (should be considered as read only) + /** + If CImgDisplay::events>=2, \c button represents the current state of the mouse buttons. + - If the mouse pointer is outside the display window, \c button is equal to \c 0. + - If the mouse pointer is over the display window, \c button is a combination of the following bits : + - bit 0 : State of the left mouse button. + - bit 1 : State of the right mouse button. + - bit 2 : State of the middle mouse button. + - Other bits are unused. + \note + - \c button is updated every 25 milliseconds, through an internal thread. + - If CImgDisplay::events==2, you should re-init \p button to \p 0 after catching the + mouse button events, since it will NOT be done automatically (\p Mouse \p button \p Release event is + not handled in this case). + \see CImgDisplay::mouse_x, CImgDisplay::mouse_y + **/ + volatile unsigned int button; + + //! Variable representing the key pressed when mouse pointer is over the display window. + /** + If CImgDisplay::events>=2, \c key represents a raw integer value corresponding + to the current pressed key. + - If no keys are pressed, \c key is equal to \p 0. + - If a key is pressed, \p key is a value representing the key. This raw value is \e OS-dependent. + Testing the \p key value directly with a raw integer will mostly result in incompabilities + between different plateforms. + To bypass this problem, \b OS-independent \b keycodes are defined in the \p cimg:: namespace. + They are named as \p cimg::key*, where * stands for the key name : + \p cimg::keyESC, \p cimg::keyF1, \p cimg::key0, \p cimg::keyA, \p cimg::keySPACE, \p cimg::keySHIFTLEFT, etc... + \code + CImgDisplay disp(320,200,"Display"); // Create a display window with full events handling + ... + if (disp.key==cimg::keyESC) std::exit(0); // Exit when pressing the ESC key. + ... + \endcode + + \note + - \p key is updated every 25 milliseconds, through an internal thread. + - If CImgDisplay::events==2, You should re-init the \c key variable to \c 0 after catching + the \p Key \p Pressed event, since it will NOT be done automatically (Key Release event is handled + only when \c CImgDisplay::events>=3). + + \see CImgDisplay::button, CImgDisplay::mouse_x, CImgDisplay::mouse_y + **/ + volatile unsigned int key; + + //! Variable representing the visibility state of the display window (should be read only). + /** + \p closed can be either true or false : + - \p false : The window is visible. + - \p true : The window is hidden. + + If CImgDisplay::events>=1, \p closed is set to \p true when the user try to close the display window. + The way to set a value for \p closed is to use the functions : + - CImgDisplay::show(), to set \p closed to \p false. + - CImgDisplay::close(), to set \p closed to \p true. + + Closing a display window DO NOT destroy the instance object. It simply \e hides the display window + and set the variable \p closed to true. You are then free to decide what to do + when this event occurs. For instance, the following code will re-open the window indefinitely + when the user tries to close it : + \code + CImgDisplay disp(320,200,"Try to close me !"); + for (;; disp.wait()) if (disp.closed) disp.show(); + \endcode + + \note - \p closed is updated every 25 milliseconds, through an internal thread. + + \see CImgDisplay::show(), CImgDisplay::close(). + **/ + volatile bool closed; + + //! Event-variable + volatile bool resized; + volatile bool moved; + + // Not documented, internal use only. + double min,max; + + //! Return the width of the display window, as a signed integer. + /** \note When working with resizing window, \p dimx() does not necessarily return the width of the resized window, + but the width of the internal data structure that can be used to display image. + Resizing a display window can be done with the function CImgDisplay::resize(). + + \see CImgDisplay::width, CImgDisplay::dimy(), CImgDisplay::resize() + **/ + int dimx() const { return (int)width; } + + //! Return the height of the display window, as a signed integer. + /** \note When working with resizing window, \p dimy() does not necessarily return the height of the resized window, + but the height of the internal data structure that can be used to display image. + Resizing a display window can be done with the function CImgDisplay::resize(). + + \see CImgDisplay::height, CImgDisplay::dimx(), CImgDisplay::resize() + **/ + int dimy() const { return (int)height; } + + int window_dimx() const { return (int)window_width; } + int window_dimy() const { return (int)window_height; } + + // operator=(). It is actually defined to avoid its use, and throw a CImgDisplay exception. + private: + CImgDisplay& operator=(const CImgDisplay&) { + throw CImgDisplayException("CImgDisplay()::operator=() : Assignement of CImgDisplay is not allowed. Use pointers instead !"); + return *this; + } + public: + + //! Synchronized waiting function. Same as cimg::wait(). + /** \see cimg::wait() + **/ + const CImgDisplay& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; } + + //! Display an image list CImgl into a display window. + /** First, all images of the list are appended into a single image used for visualization, + then this image is displayed in the current display window. + \param list : The list of images to display. + \param axe : The axe used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'. + \param align : Defines the relative tqalignment of images when displaying images of different sizes. + Can be '\p c' (centered, which is the default), '\p p' (top tqalignment) and '\p n' (bottom aligment). + + \see CImg::get_append() + **/ + template CImgDisplay& display(const CImgl& list,const char axe='x',const char align='c') { + return display(list.get_append(axe,align)); + } + + //! Resize a display window with the size of an image. + /** \param img : Input image. \p image.width and \p image.height give the new dimensions of the display window. + \param redraw : If \p true (default), the current displayed image in the display window will + be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window. + \param force : If \p true, the window size is effectively set to the specified dimensions (default). + If \p false, only internal data buffer to display images is resized, not the window itself. + + \see CImgDisplay::resized, CImgDisplay::resizedimx(), CImgDisplay::resizedimy() + **/ + template CImgDisplay& resize(const CImg& img,const bool redraw=false,const bool force=true) { + return resize(img.width,img.height,redraw,force); + } + + //! Resize a display window using the size of the given display \p disp + CImgDisplay& resize(const CImgDisplay& disp,const bool redraw=false,const bool force=true) { + return resize(disp.width,disp.height,redraw,force); + } + + //! Force to resize a display window in its current size. + CImgDisplay& resize(const bool redraw=false,const bool force=false) { + resize(window_width,window_height,redraw,force); + return *this; + } + + //! Display a 3d object + template + CImgDisplay& display_object3d(const tp& points, const CImgl& primitives, + const CImgl& colors, const CImg& opacities, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes = true, const bool keep_pos = false) { + CImg(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this, + centering,render_static,render_motion, + double_sided,focale,ambiant_light,display_axes,keep_pos); + return *this; + } + + //! Display a 3d object + template + CImgDisplay& display_object3d(const tp& points, const CImgl& primitives, + const CImgl& colors, const CImgl& opacities, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes = true, const bool keep_pos = false) { + CImg(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this, + centering,render_static,render_motion, + double_sided,focale,ambiant_light,display_axes,keep_pos); + return *this; + } + + //! Display a 3D object. + template + CImgDisplay& display_object3d(const tp& points, const CImgl& primitives, + const CImgl& colors, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const float opacity=1.0f, const bool display_axes = true, const bool keep_pos = false) { + typedef typename cimg::largest::type to; + CImg(width,height,1,3,0).display_object3d(points,primitives,colors, + CImg(primitives.size)=(to)opacity,*this, + centering,render_static,render_motion, + double_sided,focale,ambiant_light,display_axes,keep_pos); + return *this; + } + + // Inner routine used for fast resizing of buffer to display size. + template static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, + T *ptrd, const unsigned int wd, const unsigned int hd) { + unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy; + float s, curr, old; + s = (float)ws/wd; + poffx = offx; curr=0; for (unsigned int x=0; x + CImgDisplay(const CImg& img,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + width(0),height(0),window_width(0),window_height(0),window_x(0),window_y(0),normalization(0), + events(0),fullscreen(false),mouse_x(0),mouse_y(0),button(0),key(0),closed(true),resized(false), + moved(false),min(0),max(0) { + nodisplay_available(); + } + + //! Create a display window from an image list. + /** \param list : The list of images to display. + \param title : Title of the display window + \param normalization_type : Normalization type of the display window. + \param events_type : Type of events handled by the display window. + \param fullscreen_flag : Fullscreen mode. + \param closed_flag : Initially visible mode. + **/ + template + CImgDisplay(const CImgl& list,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + width(0),height(0),window_width(0),window_height(0),window_x(0),window_y(0),normalization(0), + events(0),fullscreen(false),mouse_x(0),mouse_y(0),button(0),key(0),closed(true),resized(false), + moved(false),min(0),max(0) { + nodisplay_available(); + } + + //! Create a display window by copying another one. + /** \param win : Display window to copy. + \param title : Title of the new display window. + **/ + CImgDisplay(const CImgDisplay& win, char *title=NULL): + width(0),height(0),window_width(0),window_height(0),window_x(0),window_y(0),normalization(0), + events(0),fullscreen(false),mouse_x(0),mouse_y(0),button(0),key(0),closed(true),resized(false), + moved(false),min(0),max(0) { + nodisplay_available(); + } + + //! Resize a display window with new dimensions \p width and \p height. + CImgDisplay& resize(const int width, const int height,const bool redraw=false,const bool force=true) { + return *this; + } + //! Move a display window at a specific location \p posx, \p posy, and show it on screen. + CImgDisplay& move(const int posx,const int posy) { return *this; } + + //! Destructor. Close and destroy a display. + ~CImgDisplay() {} + + //! Fill the pixel data of the window buffer according to the image \p pimg. + template void render(const CImg& img) {} + + //! Display an image in a window. + template CImgDisplay& display(const CImg& img) { return *this; } + + //! Wait for a window event + CImgDisplay& wait() { return *this; } + + //! Show a closed display + CImgDisplay& show() { return *this; } + + //! Close a visible display + CImgDisplay& close() { return *this; } + + //! Return the width of the screen resolution. + static int screen_dimx() { return 0; } + + //! Return the height of the screen resolution. + static int screen_dimy() { return 0; } + + //! Set the window title + CImgDisplay& title(const char *title,...) { return *this; } + + // X11-based display + //------------------- +#elif cimg_display_type==1 + void *data; + Window window; + XImage *image; + Colormap colormap; + Atom wm_delete_window, wm_delete_protocol; +#ifdef cimg_use_xshm + XShmSegmentInfo *shminfo; +#else + void *shminfo; +#endif + + CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3), + fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(-1) { + if (!(dimw && dimh)) throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified window size (%u,%u) is not valid.", + dimw,dimh); + new_lowlevel(title); + std::memset(data,0, + (cimg::X11attr().nb_bits==8?sizeof(unsigned char): + (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height); + _XRefresh(); + } + + template + CImgDisplay(const CImg& img,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + normalization(normalization_type&3),events(events_type&3), + fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) { + if (img.is_empty()) + throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input image (%u,%u,%u,%u,%p) is empty.", + img.width,img.height,img.depth,img.dim,img.data); + CImg tmp; + const CImg& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); + width = nimg.width; + height = nimg.height; + if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; } + new_lowlevel(title); + render(img); + _XRefresh(); + } + + template + CImgDisplay(const CImgl& list,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag), + closed(closed_flag),min(0),max(0) { + if (list.is_empty()) + throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input list (%u,%p) is empty.", + list.size,list.data); + CImg tmp; + const CImg + img0 = list.get_append('x'), + &img = (img0.depth==1)?img0:(tmp=img0.get_projections2d(img0.width/2,img0.height/2,img0.depth/2)); + width = img.width; + height = img.height; + if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; } + new_lowlevel(title); + render(list.get_append('x','c')); + _XRefresh(); + } + + CImgDisplay(const CImgDisplay& win, char *title="[Copy]"): + width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3), + fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) { + new_lowlevel(title); + std::memcpy(data,win.data, + (cimg::X11attr().nb_bits==8?sizeof(unsigned char): + (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height); + _XRefresh(); + } + + void _XRefresh(const bool wait_expose = true) { + if (!closed) { + if (wait_expose) { + static XEvent event; + pthread_mutex_lock(cimg::X11attr().mutex); + event.xexpose.type = Expose; + event.xexpose.serial = 0; + event.xexpose.send_event = True; + event.xexpose.display = cimg::X11attr().display; + event.xexpose.window = window; + event.xexpose.x = 0; + event.xexpose.y = 0; + event.xexpose.width = (int)width; + event.xexpose.height = (int)height; + event.xexpose.count = 0; + XSendEvent(cimg::X11attr().display, window, False, 0, &event); + pthread_mutex_unlock(cimg::X11attr().mutex); + } else { +#if cimg_use_xshm + if (shminfo) + XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False); + else +#endif + XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height); + XSync(cimg::X11attr().display, False); + } + } + } + + template void _resize(const T& foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) { + if (shminfo) { +#ifdef cimg_use_xshm + XShmSegmentInfo *nshminfo = new XShmSegmentInfo; + XImage *nimage; + nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), + cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy); + nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777); + nshminfo->shmaddr = nimage->data = (char*)(data = shmat(nshminfo->shmid,0,0)); + nshminfo->readOnly = False; + XShmAttach(cimg::X11attr().display, nshminfo); + T *ndata = (T*)nimage->data; + if (redraw) for (unsigned int y=0; yshmaddr); + shmctl(shminfo->shmid,IPC_RMID,0); + image = nimage; + data = (void*)ndata; + delete shminfo; + shminfo = nshminfo; +#endif + } else { + T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T)); + if (redraw) for (unsigned int y=0; y0)?nwidth:(-nwidth*width/100), + tmpdimy=(nheight>0)?nheight:(-nheight*height/100), + dimx = tmpdimx?tmpdimx:1, + dimy = tmpdimy?tmpdimy:1; + pthread_mutex_lock(cimg::X11attr().mutex); + if (dimx!=width || dimy!=height) { + switch (cimg::X11attr().nb_bits) { + case 8: { unsigned char foo; _resize(foo,dimx,dimy,redraw); } break; + case 16: { unsigned short foo; _resize(foo,dimx,dimy,redraw); } break; + default: { unsigned int foo; _resize(foo,dimx,dimy,redraw); } break; + } + } + width = dimx; + height = dimy; + if (force && (window_width!=width || window_height!=height)) { + XResizeWindow(cimg::X11attr().display,window,width,height); + window_width = width; + window_height = height; + } + resized = false; + pthread_mutex_unlock(cimg::X11attr().mutex); + _XRefresh(); + return *this; + } + + CImgDisplay& move(const int posx,const int posy) { + show(); + pthread_mutex_lock(cimg::X11attr().mutex); + XMoveWindow(cimg::X11attr().display,window,posx,posy); + moved = false; + window_x = posx; + window_y = posy; + pthread_mutex_unlock(cimg::X11attr().mutex); + _XRefresh(); + return *this; + } + + ~CImgDisplay() { + unsigned int i; + pthread_mutex_lock(cimg::X11attr().mutex); + for (i=0; ishmaddr); + shmctl(shminfo->shmid,IPC_RMID,0); + delete shminfo; +#endif + } else XDestroyImage(image); + if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap); + pthread_mutex_unlock(cimg::X11attr().mutex); + if (!cimg::X11attr().nb_wins) { + pthread_cancel(*cimg::X11attr().event_thread); + pthread_join(*cimg::X11attr().event_thread,NULL); + pthread_mutex_lock(cimg::X11attr().mutex); + XCloseDisplay(cimg::X11attr().display); + cimg::X11attr().display=NULL; + pthread_mutex_unlock(cimg::X11attr().mutex); + pthread_mutex_destroy(cimg::X11attr().mutex); + delete cimg::X11attr().event_thread; + delete cimg::X11attr().mutex; + delete cimg::X11attr().gc; + } + } + + void set_colormap(Colormap& colormap, const unsigned int dim) { + XColor palette[256]; + switch (dim) { + case 1: // palette for greyscale images + for (unsigned int index=0; index<256; index++) { + palette[index].pixel = index; + palette[index].red = palette[index].green = palette[index].blue = index<<8; + palette[index].flags = DoRed | DoGreen | DoBlue; + } + break; + case 2: // palette for RG images + for (unsigned int index=0, r=8; r<256; r+=16) + for (unsigned int g=8; g<256; g+=16) { + palette[index].pixel = index; + palette[index].red = palette[index].blue = r<<8; + palette[index].green = g<<8; + palette[index++].flags = DoRed | DoGreen | DoBlue; + } + break; + default: // palette for RGB images + for (unsigned int index=0, r=16; r<256; r+=32) + for (unsigned int g=16; g<256; g+=32) + for (unsigned int b=32; b<256; b+=64) { + palette[index].pixel = index; + palette[index].red = r<<8; + palette[index].green = g<<8; + palette[index].blue = b<<8; + palette[index++].flags = DoRed | DoGreen | DoBlue; + } + break; + } + XStoreColors(cimg::X11attr().display,colormap,palette,256); + } + + + static int _new_lowlevel_shm(Display *dpy, XErrorEvent *error) { + cimg::X11attr().shm_enabled = false; + return 0; + } + + void new_lowlevel(const char *title=NULL) { + if (!cimg::X11attr().display) { // Open X11 Display if not already done. + cimg::X11attr().nb_wins = 0; + cimg::X11attr().thread_finished = false; + cimg::X11attr().mutex = new pthread_mutex_t; + pthread_mutex_init(cimg::X11attr().mutex,NULL); + pthread_mutex_lock(cimg::X11attr().mutex); + cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); + if (!cimg::X11attr().display) throw CImgDisplayException("CImgDisplay::new_lowlevel() : Can't open X11 display"); + cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display)); + if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24) + throw CImgDisplayException("CImgDisplay::new_lowlevel() : %u bits mode is not supported " + "(only 8, 16 and 24 bits modes are supported)",cimg::X11attr().nb_bits); + cimg::X11attr().gc = new GC; + *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); + Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); + XVisualInfo vtemplate; + vtemplate.visualid = XVisualIDFromVisual(visual); + int nb_visuals; + XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals); + if (vinfo && vinfo->red_maskblue_mask) cimg::X11attr().blue_first = true; + cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display); + cimg::X11attr().event_thread = new pthread_t; + pthread_create(cimg::X11attr().event_thread,NULL,thread_lowlevel,NULL); + } else pthread_mutex_lock(cimg::X11attr().mutex); + + // Create display window and image data. + if (fullscreen) { + const unsigned int sx = screen_dimx(), sy = screen_dimy(); + XSetWindowAttributes winattr; + winattr.override_redirect = True; + window = XCreateWindow(cimg::X11attr().display, + RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), + (sx-width)/2,(sy-height)/2,width,height,0,0,InputOutput,CopyFromParent, + CWOverrideRedirect, + &winattr); + } else + window = XCreateSimpleWindow(cimg::X11attr().display, + RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), + 0,0,width,height,2,0,0x0L); + + const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4)); +#ifdef cimg_use_xshm + if (XShmQueryExtension(cimg::X11attr().display)) shminfo = new XShmSegmentInfo; + else +#endif + shminfo = 0; + if (shminfo) { +#ifdef cimg_use_xshm + image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), + cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height); + if (!image) { delete shminfo; shminfo = 0; } + else { + shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777); + if (shminfo->shmid==-1) { XDestroyImage(image); delete shminfo; shminfo = 0; } + else { + shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0)); + if (shminfo->shmaddr==(char*)-1) { XDestroyImage(image); shmctl(shminfo->shmid,IPC_RMID,0); delete shminfo; shminfo = 0; } + shminfo->readOnly = False; + cimg::X11attr().shm_enabled = true; + XErrorHandler oldXErrorHandler = XSetErrorHandler(_new_lowlevel_shm); + XShmAttach(cimg::X11attr().display, shminfo); + XSync(cimg::X11attr().display, False); + XSetErrorHandler(oldXErrorHandler); + if (!cimg::X11attr().shm_enabled) { + XDestroyImage(image); + shmdt(shminfo->shmaddr); + shmctl(shminfo->shmid,IPC_RMID,0); + delete shminfo; shminfo = 0; + } + } + } +#endif + } + if (!shminfo) { + data = std::malloc(bufsize); + image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), + cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0); + } + + XStoreName(cimg::X11attr().display,window,title?title:" "); + if (cimg::X11attr().nb_bits==8) { + colormap = XCreateColormap(cimg::X11attr().display,window, + DefaultVisual(cimg::X11attr().display, + DefaultScreen(cimg::X11attr().display)),AllocAll); + set_colormap(colormap,3); + XSetWindowColormap(cimg::X11attr().display,window,colormap); + } + if (!closed) { + XEvent event; + XSelectInput(cimg::X11attr().display,window,StructureNotifyMask); + XMapRaised(cimg::X11attr().display,window); + do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event); + while (event.type!=MapNotify); + XWindowAttributes attr; + XGetWindowAttributes(cimg::X11attr().display, window, &attr); + while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False); + XGetWindowAttributes(cimg::X11attr().display,window,&attr); + window_x = attr.x; + window_y = attr.y; + } else { + const int foo=0; + window_x = window_y = cimg::get_type_min(foo); + } + if (events) { + wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False); + wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False); + XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1); + if (fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime); + } + window_width = width; + window_height = height; + mouse_x = mouse_y = -1; + button = key = 0; + resized = moved = false; + cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this; + pthread_mutex_unlock(cimg::X11attr().mutex); + } + + void proc_lowlevel(XEvent *pevent) { + const unsigned int buttoncode[3] = { 1,4,2 }; + XEvent event=*pevent; + switch (event.type) { + case ClientMessage: + if ((int)event.xclient.message_type==(int)wm_delete_protocol && + (int)event.xclient.data.l[0]==(int)wm_delete_window) { + XUnmapWindow(cimg::X11attr().display,window); + mouse_x=mouse_y=-1; + button=key=0; + closed=true; + } + break; + case ConfigureNotify: { + while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)); + const unsigned int + nw = event.xconfigure.width, + nh = event.xconfigure.height; + const int + nx = event.xconfigure.x, + ny = event.xconfigure.y; + if (nw && nh && (nw!=window_width || nh!=window_height)) { + window_width = nw; + window_height = nh; + mouse_x = mouse_y = -1; + XResizeWindow(cimg::X11attr().display,window,window_width,window_height); + resized = true; + } + if (nx!=window_x || ny!=window_y) { + window_x = nx; + window_y = ny; + moved = true; + } + } break; + case Expose: { + while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)); + _XRefresh(false); + if (fullscreen) { + XWindowAttributes attr; + XGetWindowAttributes(cimg::X11attr().display, window, &attr); + while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False); + XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime); + } + } break; + case ButtonPress: + while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event)); + button |= buttoncode[event.xbutton.button-1]; + break; + case ButtonRelease: + while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event)); + button &= ~buttoncode[event.xbutton.button-1]; + break; + case KeyPress: { + while (XCheckWindowEvent(cimg::X11attr().display,window,KeyPressMask,&event)); + char tmp; + KeySym ksym; + XLookupString(&event.xkey,&tmp,1,&ksym,NULL); + key = (unsigned int)ksym; + } + break; + case KeyRelease: + while (XCheckWindowEvent(cimg::X11attr().display,window,KeyReleaseMask,&event)); + key = 0; + break; + case LeaveNotify: + while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)); + mouse_x = mouse_y =-1; + break; + case MotionNotify: + while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)); + mouse_x = event.xmotion.x; + mouse_y = event.xmotion.y; + if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x=mouse_y=-1; + break; + } + } + + static void* thread_lowlevel(void *arg) { + XEvent event; + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); + for (;;) { + pthread_mutex_lock(cimg::X11attr().mutex); + for (unsigned int i=0; ievents)&3; + const unsigned int etqmask = + ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)| + ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)| + ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0); + XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,etqmask); + } + bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event); + if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display, + ExposureMask|StructureNotifyMask|ButtonPressMask| + KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask| + KeyReleaseMask,&event); + if (event_flag) { + for (unsigned int i=0; iclosed && event.xany.window==cimg::X11attr().wins[i]->window) + cimg::X11attr().wins[i]->proc_lowlevel(&event); + cimg::X11attr().thread_finished = true; + } + pthread_mutex_unlock(cimg::X11attr().mutex); + pthread_testcancel(); + cimg::wait(25); + } + return NULL; + } + + template XImage* render(const CImg& img, const bool flag8 = false) { + if (img.is_empty()) + throw CImgArgumentException("CImgDisplay::render() : Specified input image (%u,%u,%u,%u,%p) is empty.", + img.width,img.height,img.depth,img.dim,img.data); + if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2)); + if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1)); + if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true); + + const unsigned int xymax = img.width*img.height; + const T + *data1 = img.ptr(), + *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1, + *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1; + if (cimg::X11attr().blue_first) cimg::swap(data1,data3); + pthread_mutex_lock(cimg::X11attr().mutex); + + if (!normalization) { + switch (cimg::X11attr().nb_bits) { + case 8: { + set_colormap(colormap,img.dim); + unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + switch (img.dim) { + case 1: for (unsigned int xy=0; xy>4); + } break; + default: for (unsigned int xy=0; xy>5)<<2) | (B>>6); + } break; + } + if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; } + } break; + case 16: { + unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + const unsigned int M = 248; + if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy>2; + *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3); + *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); + } else for (unsigned int xy=0; xy>2; + *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); + *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3); + } + if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; } + } break; + default: { + unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + if (cimg::X11attr().byte_order) for (unsigned int xy=0; xymax) || normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; } + const T nmin = (T)min, delta = (T)max-nmin, mm=delta?delta:(T)1; + switch (cimg::X11attr().nb_bits) { + case 8: { + set_colormap(colormap,img.dim); + unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + switch (img.dim) { + case 1: for (unsigned int xy=0; xy>4); + } break; + default: + for (unsigned int xy=0; xy>5)<<2) | (B>>6); + } break; + } + if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; } + } break; + case 16: { + unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + const unsigned int M = 248; + if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy>2; + *(ptrd++) = (unsigned char)(255*(*(data1++)-nmin)/mm)&M | (G>>3); + *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-nmin)/mm)>>3); + } else for (unsigned int xy=0; xy>2; + *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-nmin)/mm)>>3); + *(ptrd++) = (unsigned char)(255*(*(data1++)-nmin)/mm)&M | (G>>3); + } + if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; } + } break; + default: { + unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height]; + unsigned char *ptrd = (unsigned char*)ndata; + if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy CImgDisplay& display(const CImg& img) { + render(img); + pthread_mutex_lock(cimg::X11attr().mutex); + _XRefresh(false); + pthread_mutex_unlock(cimg::X11attr().mutex); + return *this; + } + + CImgDisplay& wait() { + if (!closed && events) { + XEvent event; + do { + pthread_mutex_lock(cimg::X11attr().mutex); + const unsigned int + etqmask = ExposureMask|StructureNotifyMask| + ((events>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)| + ((events>=3)?ButtonReleaseMask|KeyReleaseMask:0); + XSelectInput(cimg::X11attr().display,window,etqmask); + XPeekEvent(cimg::X11attr().display,&event); + cimg::X11attr().thread_finished = false; + pthread_mutex_unlock(cimg::X11attr().mutex); + } while (event.xany.window!=window); + while (!cimg::X11attr().thread_finished) cimg::wait(25); + } + return *this; + } + + CImgDisplay& show() { + if (closed) { + closed = false; + const int foo=0, tmin = cimg::get_type_min(foo); + pthread_mutex_lock(cimg::X11attr().mutex); + XEvent event; + XSelectInput(cimg::X11attr().display,window,StructureNotifyMask); + XMapRaised(cimg::X11attr().display,window); + if (window_x!=tmin || window_y!=tmin) XMoveWindow(cimg::X11attr().display,window,window_x,window_y); + do XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event); + while (event.type!=MapNotify); + if (window_x==tmin && window_y==tmin) { + XWindowAttributes attr; + XGetWindowAttributes(cimg::X11attr().display,window,&attr); + window_x = attr.x; + window_y = attr.y; + } + pthread_mutex_unlock(cimg::X11attr().mutex); + } + _XRefresh(); + return *this; + } + + CImgDisplay& close() { + if (!closed) { + pthread_mutex_lock(cimg::X11attr().mutex); + XUnmapWindow(cimg::X11attr().display,window); + closed = true; + window_x = window_y = 0; + pthread_mutex_unlock(cimg::X11attr().mutex); + } + return *this; + } + + static int screen_dimx() { + int res = 0; + if (!cimg::X11attr().display) { + Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); + if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display"); + res = DisplayWidth(disp,DefaultScreen(disp)); + XCloseDisplay(disp); + } else res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); + return res; + } + + static int screen_dimy() { + int res = 0; + if (!cimg::X11attr().display) { + Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); + if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display"); + res = DisplayHeight(disp,DefaultScreen(disp)); + XCloseDisplay(disp); + } else res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); + return res; + } + + CImgDisplay& title(const char *title,...) { + char tmp[1024]={0}; + va_list ap; + va_start(ap, title); + std::vsprintf(tmp,title,ap); + va_end(ap); + pthread_mutex_lock(cimg::X11attr().mutex); + XStoreName(cimg::X11attr().display,window,tmp); + pthread_mutex_unlock(cimg::X11attr().mutex); + return *this; + } + + // Windows-based display + //----------------------- +#elif cimg_display_type==2 + CLIENTCREATESTRUCT ccs; + BITMAPINFO bmi; + unsigned int *data; + DEVMODE curr_mode; + HWND window; + HDC hdc; + HANDLE thread; + HANDLE wait_disp; + HANDLE created; + HANDLE mutex; + + CImgDisplay(const unsigned int dimw,const unsigned int dimh,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + width(dimw),height(dimh),normalization(normalization_type&3),events(events_type&3), + fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(-1) { + if (!(dimw && dimh)) throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified window size (%u,%u) is not valid.", + dimw,dimh); + new_lowlevel(title); + std::memset(data,0,sizeof(unsigned int)*width*height); + SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS); + } + + template + CImgDisplay(const CImg& img,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + normalization(normalization_type&3),events(events_type&3), + fullscreen(fullscreen_flag),closed(closed_flag),min(0),max(0) { + if (img.is_empty()) + throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input image (%u,%u,%u,%u,%p) is empty.", + img.width,img.height,img.depth,img.dim,img.data); + CImg tmp; + const CImg& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); + width = nimg.width; + height = nimg.height; + if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; } + new_lowlevel(title); + display(nimg); + } + + template + CImgDisplay(const CImgl& list,const char *title=NULL, + const unsigned int normalization_type=1,const unsigned int events_type=3, + const bool fullscreen_flag=false,const bool closed_flag=false): + normalization(normalization_type&3),events(events_type&3),fullscreen(fullscreen_flag), + closed(closed_flag),min(0),max(0) { + if (list.is_empty()) + throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input list (%u,%p) is empty", + list.size,list.data); + CImg tmp; + const CImg + img0 = list.get_append('x'), + &img = (img0.depth==1)?img0:(tmp=img0.get_projections2d(img0.width/2,img0.height/2,img0.depth/2)); + width = img.width; + height = img.height; + if (normalization==2) { CImgStats st(img,false); min=st.min; max=st.max; } + new_lowlevel(title); + display(img); + } + + CImgDisplay(const CImgDisplay& win, char *title="[Copy]"): + width(win.width),height(win.height),normalization(win.normalization&3),events(win.events&3), + fullscreen(win.fullscreen),closed(win.closed),min(win.min),max(win.max) { + new_lowlevel(title); + std::memcpy(data,win.data,sizeof(unsigned int)*width*height); + SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS); + } + + CImgDisplay& resize(const int nwidth, const int nheight,const bool redraw=false,const bool force=true) { + if (!(nwidth && nheight)) + throw CImgArgumentException("CImgDisplay::resize() : Specified window size (%d,%d) is not valid.", + nwidth,nheight); + const unsigned int + tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100), + tmpdimy=(nheight>0)?nheight:(-nheight*height/100), + dimx = tmpdimx?tmpdimx:1, + dimy = tmpdimy?tmpdimy:1; + if (dimx!=width || dimy!=height) { + unsigned int *ndata = new unsigned int[dimx*dimy]; + if (redraw) + for (unsigned int y=0; ybestbpp) { + bestbpp = mode.dmBitsPerPel; + ibest=imode; + } + //cimg::warn(!bestbpp,"CImgDisplay::new_lowlevel() : Could not initialize fullscreen mode %ux%u\n",width,height); + if (bestbpp) { + curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0; + EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&curr_mode); + EnumDisplaySettings(NULL,ibest,&mode); + ChangeDisplaySettings(&mode,0); + } + else curr_mode.dmSize = 0; + } + else curr_mode.dmSize = 0; + if (events) { + mutex = CreateMutex(NULL,FALSE,NULL); + created = CreateEvent(NULL,FALSE,FALSE,NULL); + wait_disp = CreateEvent(NULL,FALSE,FALSE,NULL); + thread = CreateThread(NULL,0,thread_lowlevel,arg,0,&ThreadID); + WaitForSingleObject(created,INFINITE); + } else thread_lowlevel(arg); + } + + static LRESULT APIENTRY proc_lowlevel(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) { + CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA); + MSG st_msg; + + switch(msg) { + case WM_CLOSE: + disp->mouse_x=disp->mouse_y=-1; + disp->key=disp->button=disp->window_x=disp->window_y=0; + disp->closed=true; + ReleaseMutex(disp->mutex); + ShowWindow(disp->window,SW_HIDE); + return 0; + case WM_SIZE: { + while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)); + WaitForSingleObject(disp->mutex,INFINITE); + const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam); + if (nw && nh && (nw!=disp->width || nh!=disp->height)) { + disp->window_width = nw; + disp->window_height = nh; + disp->mouse_x = disp->mouse_y = -1; + disp->resized = true; + } + ReleaseMutex(disp->mutex); + } break; + case WM_MOVE: { + while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)); + WaitForSingleObject(disp->mutex,INFINITE); + const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam)); + if (nx!=disp->window_x || ny!=disp->window_y) { + disp->window_x = nx; + disp->window_y = ny; + disp->moved = true; + } + ReleaseMutex(disp->mutex); + } break; + case WM_PAINT: + WaitForSingleObject(disp->mutex,INFINITE); + SetDIBitsToDevice(disp->hdc,0,0,disp->width,disp->height,0,0,0,disp->height,disp->data,&(disp->bmi),DIB_RGB_COLORS); + ReleaseMutex(disp->mutex); + break; + } + if (disp->events>=2) switch(msg) { + case WM_KEYDOWN: + while (PeekMessage(&st_msg,window,WM_KEYDOWN,WM_KEYDOWN,PM_REMOVE)); + disp->key=(int)wParam; + break; + case WM_MOUSEMOVE: { + while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)); + disp->mouse_x = LOWORD(lParam); + disp->mouse_y = HIWORD(lParam); + if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy()) + disp->mouse_x=disp->mouse_y=-1; + } + break; + case WM_LBUTTONDOWN: + while (PeekMessage(&st_msg,window,WM_LBUTTONDOWN,WM_LBUTTONDOWN,PM_REMOVE)); + disp->button |= 1; + break; + case WM_RBUTTONDOWN: + while (PeekMessage(&st_msg,window,WM_RBUTTONDOWN,WM_RBUTTONDOWN,PM_REMOVE)); + disp->button |= 2; + break; + case WM_MBUTTONDOWN: + while (PeekMessage(&st_msg,window,WM_MBUTTONDOWN,WM_MBUTTONDOWN,PM_REMOVE)); + disp->button |= 4; + break; + } + if (disp->events>=3) switch(msg) { + case WM_KEYUP: + while (PeekMessage(&st_msg,window,WM_KEYUP,WM_KEYUP,PM_REMOVE)); + disp->key=0; + break; + case WM_LBUTTONUP: + while (PeekMessage(&st_msg,window,WM_LBUTTONUP,WM_LBUTTONUP,PM_REMOVE)); + disp->button &= ~1; + break; + case WM_RBUTTONUP: + while (PeekMessage(&st_msg,window,WM_RBUTTONUP,WM_RBUTTONUP,PM_REMOVE)); + disp->button &= ~2; + break; + case WM_MBUTTONUP: + while (PeekMessage(&st_msg,window,WM_MBUTTONUP,WM_MBUTTONUP,PM_REMOVE)); + disp->button &= ~4; + break; + } + return DefWindowProc(window,msg,wParam,lParam); + } + + static DWORD WINAPI thread_lowlevel(void* arg) { + CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]); + const char *title = (const char*)(((void**)arg)[1]); + MSG msg; + delete[] (void**)arg; + disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + disp->bmi.bmiHeader.biWidth=disp->width; + disp->bmi.bmiHeader.biHeight=-(int)disp->height; + disp->bmi.bmiHeader.biPlanes=1; + disp->bmi.bmiHeader.biBitCount=32; + disp->bmi.bmiHeader.biCompression=BI_RGB; + disp->bmi.bmiHeader.biSizeImage=0; + disp->bmi.bmiHeader.biXPelsPerMeter=1; + disp->bmi.bmiHeader.biYPelsPerMeter=1; + disp->bmi.bmiHeader.biClrUsed=0; + disp->bmi.bmiHeader.biClrImportant=0; + disp->data = new unsigned int[disp->width*disp->height]; + if (!disp->fullscreen) { // Normal window + RECT rect; + rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1; + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); + const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1; + +#if defined(_MSC_VER) && _MSC_VER>1200 + disp->window = CreateWindowA("MDICLIENT",title?title:" ", + WS_OVERLAPPEDWINDOW | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT, + disp->width + 2*border1, disp->height + border1 + border2, + NULL,NULL,NULL,&(disp->ccs)); +#else + disp->window = CreateWindow("MDICLIENT",title?title:" ", + WS_OVERLAPPEDWINDOW | (disp->closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT, + disp->width + 2*border1, disp->height + border1 + border2, + NULL,NULL,NULL,&(disp->ccs)); +#endif + if (!disp->closed) { + GetWindowRect(disp->window,&rect); + disp->window_x = rect.left + border1; + disp->window_y = rect.top + border2; + } else disp->window_x = disp->window_y = 0; + } else { // Fullscreen window + const unsigned int sx = screen_dimx(), sy = screen_dimy(); +#if defined(_MSC_VER) && _MSC_VER>1200 + disp->window = CreateWindowA("MDICLIENT",title?title:" ", + WS_POPUP | (disp->closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2, + disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs)); +#else + disp->window = CreateWindow("MDICLIENT",title?title:" ", + WS_POPUP | (disp->closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2, + disp->width,disp->height,NULL,NULL,NULL,&(disp->ccs)); +#endif + disp->window_x = disp->window_y = 0; + } + SetForegroundWindow(disp->window); + disp->hdc = GetDC(disp->window); + disp->window_width = disp->width; + disp->window_height = disp->height; + disp->mouse_x = disp->mouse_y = -1; + disp->button = disp->key = 0; + disp->resized = disp->moved = false; + if (disp->events) { + SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp); + SetWindowLong(disp->window,GWL_WNDPROC,(LONG)proc_lowlevel); + SetEvent(disp->created); + while( GetMessage( &msg, NULL, 0, 0 ) ) { DispatchMessage( &msg ); SetEvent(disp->wait_disp); } + } + return 0; + } + + template BITMAPINFO* render(const CImg& img) { + if (img.is_empty()) + throw CImgArgumentException("CImgDisplay::render() : Specified input image (%u,%u,%u,%u,%p) is empty.", + img.width,img.height,img.depth,img.dim,img.data); + if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2)); + + const T + *data1 = img.ptr(), + *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1, + *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1; + + WaitForSingleObject(mutex,INFINITE); + unsigned int + *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height], + *ptrd = ndata; + + if (!normalization) for (unsigned int xy = img.width*img.height; xy>0; xy--) + *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); + else { + if ((min>max) || normalization==1) { CImgStats st(img,false); min=st.min; max=st.max; } + const T nmin = (T)min, delta = (T)max-nmin, mm = delta?delta:(T)1; + for (unsigned int xy = img.width*img.height; xy>0; xy--) { + const unsigned char + R = (unsigned char)(255*(*(data1++)-nmin)/mm), + G = (unsigned char)(255*(*(data2++)-nmin)/mm), + B = (unsigned char)(255*(*(data3++)-nmin)/mm); + *(ptrd++) = (R<<16) | (G<<8) | (B); + } + } + if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; } + ReleaseMutex(mutex); + return &bmi; + } + + template CImgDisplay& display(const CImg& img) { + render(img); + if (!closed) { + WaitForSingleObject(mutex,INFINITE); + SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS); + ReleaseMutex(mutex); + } + return *this; + } + + CImgDisplay& wait() { + if (!closed && events) WaitForSingleObject(wait_disp,INFINITE); + return *this; + } + + CImgDisplay& show() { + if (closed) { + ShowWindow(window,SW_SHOW); + SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS); + RECT rect; + rect.left=rect.top=0; rect.right=width-1; rect.bottom=height-1; + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); + const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1; + GetWindowRect(window,&rect); + window_x = rect.left + border1; + window_y = rect.top + border2; + closed = false; + } + return *this; + } + + CImgDisplay& close() { + if (!closed) { + ShowWindow(window,SW_HIDE); + closed = true; + window_x = window_y = 0; + } + return *this; + } + + static int screen_dimx() { + DEVMODE mode; + mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; + EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode); + return mode.dmPelsWidth; + } + + static int screen_dimy() { + DEVMODE mode; + mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; + EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&mode); + return mode.dmPelsHeight; + } + + CImgDisplay& title(const char *title,...) { + char tmp[1024]={0}; + va_list ap; + va_start(ap, title); + std::vsprintf(tmp,title,ap); + va_end(ap); +#if defined(_MSC_VER) && _MSC_VER>1200 + SetWindowTextA(window, tmp); +#else + SetWindowText(window, tmp); +#endif + return *this; + } + +#endif + +#ifdef cimgdisplay_plugin +#include cimgdisplay_plugin +#endif + + }; + + /* + #-------------------------------------- + # + # + # + # Definition of the CImg structure + # + # + # + #-------------------------------------- + */ + + //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T. + /** + This is the main structure of the %CImg Library. It allows the declaration and construction + of an image, the access to its pixel values, and the application of various operations on it. + + \par Image representation + + A %CImg image is defined as an instance of the container \ref CImg, which contains a regular grid of pixels, + each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth + and number of channels. + Usually, the three first dimensions are used to describe spatial coordinates (x,y,z), while the number of channels + is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance). + If you need a fifth dimension, you can use image lists \ref CImgl rather than simple images \ref CImg. + + Thus, the \ref CImg class is able to represent volumetric images of vector-valued pixels, + as well as images with less dimensions (1D scalar signal, 2D color images, ...). + Most member functions of the class CImg are designed to handle this maximum case of (3+1) dimensions. + + Concerning the pixel value type \c T : + fully supported template types are the basic C++ types : unsigned char, char, short, unsigned int, int, + unsigned long, long, float, double, ... . + Typically, fast image display can be done using CImg images, + while complex image processing algorithms may be rather coded using CImg or CImg + images that have floating-point pixel values. The default value for the template T is \c float. + Using your own template types may be possible. However, you will certainly have to define the complete set + of arithmetic and logical operators for your class. + + \par Image structure + + The \ref CImg<\c T> structure tqcontains \a five fields : + - \ref width defines the number of \a columns of the image (size along the X-axis). + - \ref height defines the number of \a rows of the image (size along the Y-axis). + - \ref depth defines the number of \a slices of the image (size along the Z-axis). + - \ref dim defines the number of \a channels of the image (size along the V-axis). + - \ref data defines a \a pointer to the \a pixel \a data (of type \c T). + + You can access these fields publicly although it is recommended to use the dedicated functions + dimx(), dimy(), dimz(), dimv() and ptr() to do so. + Image dimensions are not limited to a specific range (as long as you got enough available memory). + A value of \e 1 usually means that the corresponding dimension is \a flat. + If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty. + Empty images should not contain any pixel data and thus, will not be processed by CImg member functions + (a CImgInstanceException will be thrown instead). + Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage). + + \par Image declaration and construction + + Declaring an image can be done by using one of the several available constructors. + Here is a list of the most used : + + - Construct images from arbitrary dimensions : + - CImg img; declares an empty image. + - CImg img(128,128); declares a 128x128 greyscale image with + \c unsigned \c char pixel values. + - CImg img(3,3); declares a 3x3 matrix with \c double coefficients. + - CImg img(256,256,1,3); declares a 256x256x1x3 (color) image + (colors are stored as an image with three channels). + - CImg img(128,128,128); declares a 128x128x128 volumetric and greyscale image + (with \c double pixel values). + - CImg<> img(128,128,128,3); declares a 128x128x128 volumetric color image + (with \c float pixels, which is the default value of the template parameter \c T). + - \b Note : images pixels are not automatically initialized to 0. You may use the function \ref fill() to + do it, or use the specific constructor taking 5 parameters like this : + CImg<> img(128,128,128,3,0); declares a 128x128x128 volumetric color image with all pixel values to 0. + + - Construct images from filenames : + - CImg img("image.jpg"); reads a JPEG color image from the file "image.jpg". + - CImg img("analyze.hdr"); reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr". + - \b Note : You need to install ImageMagick + to be able to read common compressed image formats (JPG,PNG,...) (See \ref cimg_files_io). + + - Construct images from C-style arrays : + - CImg img(data_buffer,256,256); constructs a 256x256 greyscale image from a \c int* buffer + \c data_buffer (of size 256x256=65536). + - CImg img(data_buffer,256,256,1,3,false); constructs a 256x256 color image + from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). + - CImg img(data_buffer,256,256,1,3,true); constructs a 256x256 color image + from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed). + + The complete list of constructors can be found here. + + \par Most useful functions + + The \ref CImg class contains a lot of functions that operates on images. + Some of the most useful are : + + - operator()(), operator[]() : allows to access or write pixel values. + - display() : displays the image in a new window. + + \sa CImgl, CImgStats, CImgDisplay, CImgException. + + **/ + template struct CImg { + + //! Number of columns in the instance image (size along the X-axis). + /** + - Prefer using dimx() to get the width of the instance image. + - Should be considered as \a read-only. Modifying directly \c width would probably result in a library crash. + - This value can be safely modified by resize(). + - If width==0, the image is \a empty and contains no pixel data. + **/ + unsigned int width; + + //! Number of rows in the instance image (size along the Y-axis). + /** + - Prefer using dimy() to get the height of the instance image. + - Should be considered as \a read-only. Modifying directly \c height would probably result in a library crash. + - This value can be safely modified by resize(). + - If height==0, the image is \a empty and contains no pixel data. + **/ + unsigned int height; + + //! Number of slices in the instance image (size along the Z-axis). + /** + - Prefer using dimz() to get the depth of the instance image. + - Should be considered as \a read-only. Modifying directly \c depth would probably result in a library crash. + - This value can be safely modified by resize(). + - If depth==0, the image is \a empty and contains no pixel data. + **/ + unsigned int depth; + + //! Number of vector channels in the instance image (size along the V-axis). + /** + - Prefer using dimv() to get the number of channels of the instance image. + - Should be considered as \a read-only. Modifying directly \c dim would probably result in a library crash. + - This value can be safely modified by resize(). + - If dim==0, the image is \a empty and contains no pixel data. + **/ + unsigned int dim; + + //! This variable defines if the instance image uses shared memory. + /** + \note shared images are retrieved by the functions CImg<>::get_shared_*() + **/ + const bool shared; + + //! Pointer to pixel values (array of elements \c T). + /** + - Prefer using ptr() to get a pointer to the pixel buffer. + - Should be considered as \a read-only. Modifying directly \c data would probably result in a library crash. + - If data==0, the image is \a empty and contains no pixel data. + **/ + T *data; + + //! Define the iterator type for any CImg. + /** + A CImg iterator is only a pointer to an array of T (the pixel buffer). + **/ + typedef T* iterator; + + //! Define the const iterator type for any CImg. + /** + A CImg const_iterator is only a pointer to an array of const T (the pixel buffer). + **/ + typedef const T* const_iterator; + + //-------------------------------------- + // + //! \name Constructors-Destructor-Copy + //@{ + //-------------------------------------- + + //! Create an image of size (\c dx,\c dy,\c dz,\c dv) with pixels of type \c T. + /** + \param dx Number of columns of the created image (size along the X-axis i.e image width). + \param dy Number of rows of the created image (size along the Y-axis, i.e image height). + \param dz Number of slices of the created image (size along the Z-axis, i.e image depth). + \param dv Number of channels of the created image (size along the V-axis). + + - Pixel values are \a not \a initialized by this constructor (this can be done afterwards by fill()). + - If invoked without parameters, this constructor creates an \a empty image (default constructor). + - The construction of an empty image does not allocate memory. + + \par example: + \code + CImg img1(100,100); // Define a 100x100 greyscale image of \c unsigned \c char pixels. + CImg img2(256,256,1,3); // Define a 256x256 color image of \c float pixels. + CImg img3(128,128,128); // Define a 128x128x128 volumetric image of \c short pixels. + CImg img4(10); // Define a 1D array of 10 double values. + CImg img5; // Define an empty image. + \endcode + **/ + explicit CImg(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1):shared(false) { + const unsigned int siz = dx*dy*dz*dv; + if (siz) { data = new T[siz]; width = dx; height = dy; depth = dz; dim = dv; } + else { width = height = depth = dim = 0; data = 0; } + } + + //! In-place version of the previous constructor. + CImg& assign(const unsigned int dx=0,const unsigned int dy=1,const unsigned int dz=1,const unsigned int dv=1) { + return CImg(dx,dy,dz,dv).swap(*this); + } + + //! Create an image of size (\c dx,\c dy,\c dz,\c dv) with pixels of type \c T, and set the value of image pixels to \c val. + /** + \param dx Number of columns of the created image (size along the X-axis, i.e image width). + \param dy Number of rows of the created image (size along the Y-axis, i.e image height). + \param dz Number of slices of the created image (size along the Z-axis, i.e image depth). + \param dv Number of channels of the created image (size along the V-axis). + \param val Initialization value set to all image pixels. + + - Same as previous constructor except that pixel values are now initialized to value \c val. + + \par example: + \code + CImg img(100,100,1,3,0); // Define a 100x100 color image with black pixels (all color channels equal to 0). + \endcode + **/ + explicit CImg(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val):shared(false) { + const unsigned int siz = dx*dy*dz*dv; + if (siz) { data = new T[siz]; width = dx; height = dy; depth = dz; dim = dv; fill(val); } + else { width = height = depth = dim = 0; data = 0; } + } + + //! In-place version of the previous constructor. + CImg& assign(const unsigned int dx,const unsigned int dy,const unsigned int dz,const unsigned int dv,const T& val) { + return CImg(dx,dy,dz,dv,val).swap(*this); + } + + //! Copy an image (copy constructor). + /** + \param img Image to copy. + + - The copy constructor is faster if input and output images have same template types. + - Otherwise, pixel values are casted as in C. + + \par example: + \code + CImg src(100,100,1,1,0); // Define a 100x100 greyscale image with black pixels. + CImg dest1(src); // Define a perfect copy of src (fast). + CImg dest2(src); // Define a copy with a cast float->int. + \endcode + + \sa operator=(). + **/ + template CImg(const CImg& img):shared(false) { + const unsigned int siz = img.size(); + if (img.data && siz) { + data = new T[siz]; + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + const t *ptrs = img.data + siz; + cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs); + } else { width = height = depth = dim = 0; data = 0; } + } + + //! Copy an image (copy constructor, fast version). + CImg(const CImg& img):shared(img.shared) { + const unsigned int siz = img.size(); + if (img.data && siz) { + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + if (shared) data = img.data; + else { + data = new T[siz]; + std::memcpy(data,img.data,siz*sizeof(T)); + } + } else { width = height = depth = dim = 0; data = 0; } + } + + //! In-place version of the previous constructor. + template CImg& assign(const CImg& img) { + return CImg(img).swap(*this); + } + + //! Copy an image, with or without copying the pixel buffer. + template CImg(const CImg& img, const bool pixel_copy):shared(false) { + const unsigned int siz = img.size(); + if (img.data && siz) { + data = new T[siz]; + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + if (pixel_copy) { + const t *ptrs = img.data + siz; + cimg_map(*this,ptrd,T) (*ptrd)=(T)*(--ptrs); + } + } else { data = 0; width = height = depth = dim = 0; } + } + + //! Copy an image, with or without copying the pixel buffer (fast version). + CImg(const CImg& img, const bool pixel_copy):shared(img.shared) { + const unsigned int siz = img.size(); + if (img.data && siz) { + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + if (shared) data = img.data; + else { + data = new T[siz]; + if (pixel_copy) std::memcpy(data,img.data,siz*sizeof(T)); + } + } else { width = height = depth = dim = 0; data = 0; } + } + + //! In-place version of the previous constructor. + template CImg& assign(const CImg& img, const bool pixel_copy) { + if (pixel_copy) return assign(img); + return assign(img.width,img.height,img.depth,img.dim); + } + + //! Create an image from a filename. + /** + \param filename Filename of the image file to load as an image. + + - The filename extension implicitely informs CImg about the image format. + - Image pixels of the loaded image will be converted as values of the image type \c T. + + \par example: + \code + CImg img1("foo.jpg"); // Load JPEG image "foo.jpg" and store RGB colors as three channels of unsigned char pixels. + CImg img2("foo.png"); // Load PNG image "foo.png" ans store RGB colors as three channels of float pixels. + \endcode + + \sa get_load(), load(), cimg_files_io. + **/ + CImg(const char *const filename):width(0),height(0),depth(0),dim(0),shared(false),data(0) { + load(filename); + } + + //! In-place version of the previous constructor. + CImg& assign(const char *const filename) { + return load(filename); + } + + //! Create an image from a one-dimensional data buffer. + /** + \param data_buffer Pointer \c t* to a buffer of pixel values t. + \param dx Number of columns of the created image (size along the X-axis, i.e image width). + \param dy Number of rows of the created image (size along the Y-axis, i.e image height). + \param dz Number of slices of the created image (size along the Z-axis, i.e image depth). + \param dv Number of vector channels of the created image (size along the V-axis). + **/ + template CImg(const t *const data_buffer, + const unsigned int dx,const unsigned int dy=1, + const unsigned int dz=1,const unsigned int dv=1):shared(false) { + const unsigned int siz = dx*dy*dz*dv; + if (data_buffer && siz) { + data = new T[siz]; + width = dx; height = dy; depth = dz; dim = dv; + const t *ptrs = data_buffer+siz; + cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)); + } else { width = height = depth = dim = 0; data=0; } + } + + //! In-place version of the previous constructor. + template CImg& assign(const t *const data_buffer, + const unsigned int dx,const unsigned int dy=1, + const unsigned int dz=1,const unsigned int dv=1) { + return CImg(data_buffer,dx,dy,dz,dv).swap(*this); + } + + //! Create an image from a one-dimensional data buffer. + /** + \param data_buffer Pointer \c T* to a buffer of pixel values t. + \param dx Number of columns of the created image (size along the X-axis, i.e image width). + \param dy Number of rows of the created image (size along the Y-axis, i.e image height). + \param dz Number of slices of the created image (size along the Z-axis, i.e image depth). + \param dv Number of vector channels of the created image (size along the V-axis). + \param shared_memory Tell if memory must be shared. + **/ + CImg(const T *const data_buffer, + const unsigned int dx, const unsigned int dy, + const unsigned int dz,const unsigned int dv, + const bool shared_memory):shared(shared_memory) { + const unsigned int siz = dx*dy*dz*dv; + if (data_buffer && siz) { + width=dx; height=dy; depth=dz; dim=dv; + if (shared) data=const_cast(data_buffer); + else { + data = new T[siz]; + std::memcpy(data,data_buffer,siz*sizeof(T)); + } + } else { width = height = depth = dim = 0; data=0; } + } + + //! In-place version of the previous constructor. + CImg& assign(const T *const data_buffer, + const unsigned int dx,const unsigned int dy, + const unsigned int dz,const unsigned int dv, const bool shared_memory=false) { + return CImg(data_buffer,dx,dy,dz,dv,shared_memory).swap(*this); + } + + //! Destructor. + /** + - The destructor frees the memory eventually allocated for the image pixels. + **/ + ~CImg() { + if (data && !shared) delete[] data; + } + + //! Replace the instance image by an empty image. + /** + This is the in-place version of the destructor. + \sa ~CImg() + **/ + CImg& empty() { + return CImg().swap(*this); + } + + //! Same as empty(). + /** + This function has been added since its name is 'STL-compliant'. + \sa empty() + **/ + CImg& clear() { + return empty(); + } + + //! Return an empty image + static CImg get_empty() { + return CImg(); + } + + // Swap fields of an image (use it carefully!) + // If an image is shared, its content is replaced by the non-shared image (which is unchanged). + CImg& swap(CImg& img) { + if (img.shared==shared) { + cimg::swap(width,img.width); + cimg::swap(height,img.height); + cimg::swap(depth,img.depth); + cimg::swap(dim,img.dim); + cimg::swap(data,img.data); + } else { + if (img.shared) img=*this; + if (shared) *this=img; + } + return img; + } + + //@} + //------------------------------------- + // + //! \name Access to image informations + //@{ + //------------------------------------- + + //! Return the type of the pixel values. + /** + \return a string describing the type of the image pixels (template parameter \p T). + - The string returned may contains spaces ("unsigned char"). + - If the template parameter T does not correspond to a registered type, the string "unknown" is returned. + **/ + static const char* pixel_type() { + T val; + return cimg::get_type(val); + } + + //! Return the total number of pixel values in an image. + /** + - Equivalent to : dimx() * dimy() * dimz() * dimv(). + + \par example: + \code + CImg<> img(100,100,1,3); + if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true"); + \endcode + \sa dimx(), dimy(), dimz(), dimv() + **/ + unsigned long size() const { + return width*height*depth*dim; + } + + //! Return the number of columns of the instance image (size along the X-axis, i.e image width). + /** + \sa width, dimy(), dimz(), dimv(), size(). + **/ + int dimx() const { + return (int)width; + } + + //! Return the number of rows of the instance image (size along the Y-axis, i.e image height). + /** + \sa height, dimx(), dimz(), dimv(), size(). + **/ + int dimy() const { + return (int)height; + } + + //! Return the number of slices of the instance image (size along the Z-axis). + /** + \sa depth, dimx(), dimy(), dimv(), size(). + **/ + int dimz() const { + return (int)depth; + } + + //! Return the number of vector channels of the instance image (size along the V-axis). + /** + \sa dim, dimx(), dimy(), dimz(), size(). + **/ + int dimv() const { + return (int)dim; + } + + //! Return \c true if images \c (*this) and \c img have same width. + template bool has_sameX(const CImg& img) const { + return (width==img.width); + } + + //! Return \c true if images \c (*this) and \c img have same height. + template bool has_sameY(const CImg& img) const { + return (height==img.height); + } + + //! Return \c true if images \c (*this) and \c img have same depth. + template bool has_sameZ(const CImg& img) const { + return (depth==img.depth); + } + + //! Return \c true if images \c (*this) and \c img have same dim. + template bool has_sameV(const CImg& img) const { + return (dim==img.dim); + } + + //! Return \c true if images have same width and same height. + template bool has_sameXY(const CImg& img) const { + return (has_sameX(img) && has_sameY(img)); + } + + //! Return \c true if images have same width, same height and same depth. + template bool has_sameXYZ(const CImg& img) const { + return (has_sameXY(img) && has_sameZ(img)); + } + + //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels. + template bool has_sameXYZV(const CImg& img) const { + return (has_sameXYZ(img) && has_sameV(img)); + } + + //! Return \c true if image is empty. + bool is_empty() const { + return !(data && width && height && depth && dim); + } + + //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data. + /** + \param x X-coordinate of the pixel. + \param y Y-coordinate of the pixel. + \param z Z-coordinate of the pixel. + \param v V-coordinate of the pixel. + + - No checking is done on the validity of the given coordinates. + + \par example: + \code + CImg img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. + long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10). + float val = img[off]; // Get the blue value of the pixel. + \endcode + \sa ptr(), operator()(), operator[](), cimg_storage. + **/ + long offset(const int x=0, const int y=0, const int z=0, const int v=0) const { + return x+width*(y+height*(z+depth*v)); + } + + //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v). + /** + \param x X-coordinate of the pixel. + \param y Y-coordinate of the pixel. + \param z Z-coordinate of the pixel. + \param v V-coordinate of the pixel. + + - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer. + - If the macro \c cimg_debug == 2, boundary checking is performed and warning messages may appear if + given coordinates are outside the image range (but function performances decrease). + + \par example: + \code + CImg img(100,100,1,1,0); // Define a 100x100 greyscale image with float-valued pixels. + float *ptr = ptr(10,10); // Get a pointer to the pixel located at (10,10). + float val = *ptr; // Get the pixel value. + \endcode + \sa data, offset(), operator()(), operator[](), cimg_storage, cimg_environment. + **/ + T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) { + const long off = offset(x,y,z,v); +#if cimg_debug>1 + if (off<0 || off>=(long)size()) { + cimg::warn(true,"CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%u), " + "outside image range (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return data; + } +#endif + return data+off; + } + + const T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const { + const long off = offset(x,y,z,v); +#if cimg_debug>1 + if (off<0 || off>=(long)size()) { + cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%d) which is" + "outside the data of the image (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return data; + } +#endif + return data+off; + } + + //! Return an iterator to the first image pixel + iterator begin() { return data; } + const_iterator begin() const { return data; } + + //! Return an iterator to the last image pixel + iterator end() { return data + size(); } + const_iterator end() const { return data + size(); } + + //! Fast access to pixel value for reading or writing. + /** + \param x X-coordinate of the pixel. + \param y Y-coordinate of the pixel. + \param z Z-coordinate of the pixel. + \param v V-coordinate of the pixel. + + - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below). + - If the macro \c cimg_debug == 2, boundary checking is performed and warning messages may appear + (but function performances decrease). + + \par example: + \code + CImg img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. + const float valR = img(10,10,0,0); // Read the red component at coordinates (10,10). + const float valG = img(10,10,0,1); // Read the green component at coordinates (10,10) + const float valB = img(10,10,2); // Read the blue component at coordinates (10,10) (Z-coordinate omitted here). + const float avg = (valR + valG + valB)/3; // Compute average pixel value. + img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the pixel (10,10) by the average grey value. + \endcode + + \sa operator[](), ptr(), offset(), cimg_storage, cimg_environment. + **/ + T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) { + const long off = offset(x,y,z,v); +#if cimg_debug>1 + if (!data || off>=(long)size()) { + cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) " + "outside the image range (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return *data; + } +#endif + return data[off]; + } + + const T& operator()(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const { + const long off = offset(x,y,z,v); +#if cimg_debug>1 + if (!data || off>=(long)size()) { + cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) " + "outside the image range (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return *data; + } +#endif + return data[off]; + } + + //! Return pixel value at a given position. Equivalent to operator(). + T& at(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) { + const long off = offset(x,y,z,v); + if (!data || off>=(long)size()) + throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) " + "outside the image range (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return data[off]; + } + + const T& at(const unsigned int x,const unsigned int y=0,const unsigned int z=0,const unsigned int v=0) const { + const long off = offset(x,y,z,v); + if (!data || off>=(long)size()) + throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%d) " + "outside the image range (%u,%u,%u,%u) (size=%u)", + pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); + return data[off]; + } + + //! Fast access to pixel value for reading or writing, using an offset to the image pixel. + /** + \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr(). + + - If the macro \c cimg_debug==2, boundary checking is performed and warning messages may appear + (but function performances decrease). + - As pixel values are aligned in memory, this operator can sometime useful to access values easier than + with operator()() (see example below). + + \par example: + \code + CImg vec(1,10); // Define a vector of float values (10 lines, 1 row). + const float val1 = vec(0,4); // Get the fifth element using operator()(). + const float val2 = vec[4]; // Get the fifth element using operator[]. Here, val2==val1. + \endcode + + \sa operator()(), ptr(), offset(), cimg_storage, cimg_environment. + **/ + T& operator[](const unsigned long off) { + return operator()(off); + } + + const T& operator[](const unsigned long off) const { + return operator()(off); + } + + //! Return a reference to the last image value + T& back() { + return operator()(size()-1); + } + + const T& back() const { + return operator()(size()-1); + } + + //! Return a reference to the first image value + T& front() { + return *data; + } + + const T& front() const { + return *data; + } + + //! Read a pixel value with Dirichlet or Neumann boundary conditions. + /** + \param x X-coordinate of the pixel. + \param y Y-coordinate of the pixel. + \param z Z-coordinate of the pixel. + \param v V-coordinate of the pixel. + \param out_val Desired value if pixel coordinates are outside the image range (optional parameter). + + - This function allows to read pixel values with boundary checking on all coordinates. + - If given coordinates are outside the image range and the parameter out_val is specified, the value \c out_val is returned. + - If given coordinates are outside the image range and the parameter out_val is not specified, the closest pixel value + is returned. + + \par example: + \code + CImg img(100,100,1,1,128); // Define a 100x100 images with all pixel values equal to 128. + const float val1 = img.pix4d(10,10,0,0,0); // Equivalent to val1=img(10,10) (but slower). + const float val2 = img.pix4d(-4,5,0,0,0); // Return 0, since coordinates are outside the image range. + const float val3 = img.pix4d(10,10,5,0,64); // Return 64, since coordinates are outside the image range. + \endcode + + \sa operator()(), linear_pix4d(), cubic_pix2d(). + **/ + T pix4d(const int x, const int y, const int z, const int v, const T& out_val) const { + return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v); + } + + T pix4d(const int x, const int y, const int z, const int v) const { + return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y), + z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v)); + } + + //! Read a pixel value with Dirichlet or Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z). + T pix3d(const int x, const int y, const int z, const int v, const T& out_val) const { + return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v); + } + + const T& pix3d(const int x, const int y, const int z, const int v=0) const { + return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y), + z<0?0:(z>=dimz()?dimz()-1:z),v); + } + + //! Read a pixel value with Dirichlet or Neumann boundary conditions for the two first coordinates (\c x,\c y). + T pix2d(const int x, const int y, const int z, const int v, const T& out_val) const { + return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v); + } + + const T& pix2d(const int x,const int y,const int z=0,const int v=0) const { + return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v); + } + + //! Read a pixel value with Dirichlet or Neumann boundary conditions for the first coordinate \c x. + T pix1d(const int x, const int y, const int z, const int v, const T& out_val) const { + return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v); + } + + const T& pix1d(const int x, const int y=0, const int z=0, const int v=0) const { + return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v); + } + + //! Read a pixel value using linear interpolation. + /** + \param ffx X-coordinate of the pixel (float-valued). + \param ffy Y-coordinate of the pixel (float-valued). + \param ffz Z-coordinate of the pixel (float-valued). + \param ffv V-coordinate of the pixel (float-valued). + \param out_val Out-of-border pixel value + + - This function allows to read pixel values with boundary checking on all coordinates. + - If given coordinates are outside the image range, the value of the nearest pixel inside the image is returned + (Neumann boundary conditions). + - If given coordinates are float-valued, a linear interpolation is performed in order to compute the returned value. + + \par example: + \code + CImg img(2,2); // Define a greyscale 2x2 image. + img(0,0) = 0; // Fill image with specified pixel values. + img(1,0) = 1; + img(0,1) = 2; + img(1,1) = 3; + const double val = img.linear_pix4d(0.5,0.5); // Return val=1.5, which is the average intensity of the four pixels values. + \endcode + + \sa operator()(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix2d(). + **/ + typename cimg::largest::type linear_pix4d(const float fx,const float fy,const float fz,const float fv, + const T& out_val) const { + const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), v = (int)fv-(fv>=0?0:1), + nx = x+1, ny = y+1, nz = z+1, nv = v+1; + const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v; + const T + Icccc = pix4d(x,y,z,v,out_val), Inccc = pix4d(nx,y,z,v,out_val), + Icncc = pix4d(x,ny,z,v,out_val), Inncc = pix4d(nx,ny,z,v,out_val), + Iccnc = pix4d(x,y,nz,v,out_val), Incnc = pix4d(nx,y,nz,v,out_val), + Icnnc = pix4d(x,ny,nz,v,out_val), Innnc = pix4d(nx,ny,nz,v,out_val), + Icccn = pix4d(x,y,z,nv,out_val), Inccn = pix4d(nx,y,z,nv,out_val), + Icncn = pix4d(x,ny,z,nv,out_val), Inncn = pix4d(nx,ny,z,nv,out_val), + Iccnn = pix4d(x,y,nz,nv,out_val), Incnn = pix4d(nx,y,nz,nv,out_val), + Icnnn = pix4d(x,ny,nz,nv,out_val), Innnn = pix4d(nx,ny,nz,nv,out_val); + return Icccc + + dx*(Inccc-Icccc + + dy*(Icccc+Inncc-Icncc-Inccc + + dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + + dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + + dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + + dz*(Icccc+Incnc-Iccnc-Inccc + + dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + + dv*(Icccc+Inccn-Inccc-Icccn)) + + dy*(Icncc-Icccc + + dz*(Icccc+Icnnc-Iccnc-Icncc + + dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + + dv*(Icccc+Icncn-Icncc-Icccn)) + + dz*(Iccnc-Icccc + + dv*(Icccc+Iccnn-Iccnc-Icccn)) + + dv*(Icccn-Icccc); + } + + typename cimg::largest::type linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const { + const float + fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), + fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv); + const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz, v = (unsigned int)fv; + const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v; + const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z, nv = dv>0?v+1:v; + const T + &Icccc = (*this)(x,y,z,v), &Inccc = (*this)(nx,y,z,v), &Icncc = (*this)(x,ny,z,v), &Inncc = (*this)(nx,ny,z,v), + &Iccnc = (*this)(x,y,nz,v), &Incnc = (*this)(nx,y,nz,v), &Icnnc = (*this)(x,ny,nz,v), &Innnc = (*this)(nx,ny,nz,v), + &Icccn = (*this)(x,y,z,nv), &Inccn = (*this)(nx,y,z,nv), &Icncn = (*this)(x,ny,z,nv), &Inncn = (*this)(nx,ny,z,nv), + &Iccnn = (*this)(x,y,nz,nv), &Incnn = (*this)(nx,y,nz,nv), &Icnnn = (*this)(x,ny,nz,nv), &Innnn = (*this)(nx,ny,nz,nv); + return Icccc + + dx*(Inccc-Icccc + + dy*(Icccc+Inncc-Icncc-Inccc + + dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + + dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + + dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + + dz*(Icccc+Incnc-Iccnc-Inccc + + dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + + dv*(Icccc+Inccn-Inccc-Icccn)) + + dy*(Icncc-Icccc + + dz*(Icccc+Icnnc-Iccnc-Icncc + + dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + + dv*(Icccc+Icncn-Icncc-Icccn)) + + dz*(Iccnc-Icccc + + dv*(Icccc+Iccnn-Iccnc-Icccn)) + + dv*(Icccn-Icccc); + } + + //! Read a pixel value using linear interpolation for the three first coordinates (\c cx,\c cy,\c cz). + /** + - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the three first coordinates. + + \sa operator()(), linear_pix4d(), linear_pix2d(), linear_pix1d(), linear_pix3d(), cubic_pix2d(). + **/ + typename cimg::largest::type linear_pix3d(const float fx,const float fy,const float fz,const int v, + const T& out_val) const { + const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), nx = x+1, ny = y+1, nz = z+1; + const float dx = fx-x, dy = fy-y, dz = fz-z; + const T + Iccc = pix3d(x,y,z,v,out_val), Incc = pix3d(nx,y,z,v,out_val), Icnc = pix3d(x,ny,z,v,out_val), Innc = pix3d(nx,ny,z,v,out_val), + Iccn = pix3d(x,y,nz,v,out_val), Incn = pix3d(nx,y,nz,v,out_val), Icnn = pix3d(x,ny,nz,v,out_val), Innn = pix3d(nx,ny,nz,v,out_val); + return Iccc + + dx*(Incc-Iccc + + dy*(Iccc+Innc-Icnc-Incc + + dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + + dz*(Iccc+Incn-Iccn-Incc)) + + dy*(Icnc-Iccc + + dz*(Iccc+Icnn-Iccn-Icnc)) + + dz*(Iccn-Iccc); + } + + typename cimg::largest::type linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const { + const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), fz = ffz<0?0:(ffz>depth-1?depth-1:ffz); + const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz; + const float dx = fx-x, dy = fy-y, dz = fz-z; + const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z; + const T + &Iccc = (*this)(x,y,z,v), &Incc = (*this)(nx,y,z,v), &Icnc = (*this)(x,ny,z,v), &Innc = (*this)(nx,ny,z,v), + &Iccn = (*this)(x,y,nz,v), &Incn = (*this)(nx,y,nz,v), &Icnn = (*this)(x,ny,nz,v), &Innn = (*this)(nx,ny,nz,v); + return Iccc + + dx*(Incc-Iccc + + dy*(Iccc+Innc-Icnc-Incc + + dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + + dz*(Iccc+Incn-Iccn-Incc)) + + dy*(Icnc-Iccc + + dz*(Iccc+Icnn-Iccn-Icnc)) + + dz*(Iccn-Iccc); + } + + //! Read a pixel value using linear interpolation for the two first coordinates (\c cx,\c cy). + /** + - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the two first coordinates. + + \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix1d(), linear_pix2d(), cubic_pix2d(). + **/ + typename cimg::largest::type linear_pix2d(const float fx, const float fy, const int z, const int v, + const T& out_val) const { + const int x = (int)fx-(fx>0?0:1), y = (int)fy-(fy>0?0:1), nx = x+1, ny = y+1; + const float dx = fx-x, dy = fy-y; + const T + Icc = pix2d(x,y,z,v,out_val), Inc = pix2d(nx,y,z,v,out_val), + Icn = pix2d(x,ny,z,v,out_val), Inn = pix2d(nx,ny,z,v,out_val); + return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); + } + + typename cimg::largest::type linear_pix2d(const float ffx, const float ffy=0, const int z=0, const int v=0) const { + const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy); + const unsigned int x = (unsigned int)fx, y = (unsigned int)fy; + const float dx = fx-x, dy = fy-y; + const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y; + const T &Icc = (*this)(x,y,z,v), &Inc = (*this)(nx,y,z,v), &Icn = (*this)(x,ny,z,v), &Inn = (*this)(nx,ny,z,v); + return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); + } + + //! Read a pixel value using linear interpolation for the first coordinate \c cx. + /** + - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the first coordinate. + + \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix1d(). + **/ + typename cimg::largest::type linear_pix1d(const float fx,const int y,const int z,const int v, + const T& out_val) const { + const int x = (int)fx-(fx>0?0:1), nx = x+1; + const float dx = fx-x; + const T Ic = pix1d(x,y,z,v,out_val), In = pix2d(nx,y,z,v,out_val); + return Ic + dx*(In-Ic); + } + + typename cimg::largest::type linear_pix1d(const float ffx,const int y=0,const int z=0,const int v=0) const { + const float fx = ffx<0?0:(ffx>width-1?width-1:ffx); + const unsigned int x = (unsigned int)fx; + const float dx = fx-x; + const unsigned int nx = dx>0?x+1:x; + const T &Ic = (*this)(x,y,z,v), &In = (*this)(nx,y,z,v); + return Ic + dx*(In-Ic); + } + + // This function is used as a subroutine for cubic interpolation + static float _cubic_R(const float x) { + const float xp2 = x+2, xp1 = x+1, xm1 = x-1, + nxp2 = xp2>0?xp2:0, nxp1 = xp1>0?xp1:0, nx = x>0?x:0, nxm1 = xm1>0?xm1:0; + return (nxp2*nxp2*nxp2 - 4*nxp1*nxp1*nxp1 + 6*nx*nx*nx - 4*nxm1*nxm1*nxm1)/6.0f; + } + + //! Read a pixel value using cubic interpolation for the first coordinate \c cx. + /** + - Same as cubic_pix2d(), except that cubic interpolation and boundary checking is performed only on the first coordinate. + + \sa operator()(), cubic_pix2d(), linear_pix1d(). + **/ + typename cimg::largest::type cubic_pix1d(const float fx,const int y,const int z,const int v, + const T& out_val) const { + const int x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = nx+1; + const float dx = fx-x; + const T a = pix2d(px,y,z,v,out_val), b = pix2d(x,y,z,v,out_val), c = pix2d(nx,y,z,v,out_val), d = pix2d(ax,y,z,v,out_val); + const float Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx); + return Rxp*a + Rxc*b + Rxn*c + Rxa*d; + } + + typename cimg::largest::type cubic_pix1d(const float pfx,const int y=0,const int z=0,const int v=0) const { + const float fx = pfx<0?0:(pfx>width-1?width-1:pfx); + const unsigned int x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1::type cubic_pix2d(const float fx,const float fy,const int z,const int v, + const T& out_val) const { + const int + x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), + px = x-1, nx = x+1, ax = nx+1, py = y-1, ny = y+1, ay = ny+1; + const float dx = fx-x, dy = fy-y; + const T + a = pix2d(px,py,z,v,out_val), b = pix2d(x,py,z,v,out_val), c = pix2d(nx,py,z,v,out_val), d = pix2d(ax,py,z,v,out_val), + e = pix2d(px, y,z,v,out_val), f = pix2d(x, y,z,v,out_val), g = pix2d(nx, y,z,v,out_val), h = pix2d(ax, y,z,v,out_val), + i = pix2d(px,ny,z,v,out_val), j = pix2d(x,ny,z,v,out_val), k = pix2d(nx,ny,z,v,out_val), l = pix2d(ax,ny,z,v,out_val), + m = pix2d(px,ay,z,v,out_val), n = pix2d(x,ay,z,v,out_val), o = pix2d(nx,ay,z,v,out_val), p = pix2d(ax,ay,z,v,out_val); + const float + Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx), + Ryp = _cubic_R(dy+1), Ryc = _cubic_R(dy), Ryn = _cubic_R(dy-1), Rya = _cubic_R(dy-2); + return + Rxp*Ryp*a + Rxc*Ryp*b + Rxn*Ryp*c + Rxa*Ryp*d + + Rxp*Ryc*e + Rxc*Ryc*f + Rxn*Ryc*g + Rxa*Ryc*h + + Rxp*Ryn*i + Rxc*Ryn*j + Rxn*Ryn*k + Rxa*Ryn*l + + Rxp*Rya*m + Rxc*Rya*n + Rxn*Rya*o + Rxa*Rya*p; + } + + typename cimg::largest::type cubic_pix2d(const float pfx,const float pfy=0,const int z=0,const int v=0) const { + const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy); + const unsigned int + x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1=0?y-1:0, ny = y+1 img("foo.jpg"); // Load image from a JPEG file. + img.print("Image : foo.jpg",1); // Print image informations and statistics. + \endcode + + \sa CImgStats + **/ + const CImg& print(const char *title=NULL,const unsigned int print_flag=1) const { + std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p (%s)", + title?title:"CImg",(void*)this, + width,height,depth,dim,pixel_type(),(void*)data, + shared?"shared":"not shared"); + if (is_empty()) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; } + if (print_flag>=1) { + CImgStats st(*this); + std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)", + st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax); + } + if (print_flag>=2 || size()<=16) { + std::fprintf(stderr," }\n%s = [ ",title?title:"data"); + cimg_mapXYZV(*this,x,y,z,k) + std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k), + ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]\n":(((x+1)%width==0)?" ; ":" "))); + } else std::fprintf(stderr," }\n"); + return *this; + } + + //! Display informations about the image on the standart output. + const CImg& print(const unsigned int print_flag) const { return print(NULL,print_flag); } + + //@} + //------------------------------------------ + // + //! \name Arithmetic and Boolean operators + //@{ + //------------------------------------------ + + //! Assign an image to the instance image. + /** + \param img Image to copy. + + - Replace the instance image by a copy of the image \c img. + - The assignement is faster if input and output images have same template types. + - Otherwise, pixel values are casted as in C. + + \par example: + \code + CImg img("foo.jpg"); // Load image from a JPEG file. + CImg dest1; // Define an empty image of unsigned char pixels. + CImg dest2; // Define an empty image of float pixels. + dest1 = img; // Fast copy of img to dest1. + dest2 = img; // Copy of img to dest2, with conversion of pixel to float values. + \endcode + **/ + template CImg& operator=(const CImg& img) { + const unsigned long siz = img.size(); + if (img.data && siz) { + if (shared) { + if (siz==size()) { + const t* ptrs = img.data + siz; + for (T *ptrd = data+siz; ptrd>data; ) *(--ptrd) = (T)*(--ptrs); + } else throw CImgArgumentException("CImg<%s>::operator=() : Given image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) " + "must have same dimensions, since instance image has shared memory.", + pixel_type(),img.width,img.height,img.depth,img.dim,img.data,width,height,depth,dim,data); + } else { + if (siz!=size()) { if (data) delete[] data; data = new T[siz]; } + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + const t* ptrs = img.data + siz; + for (T *ptrd = data+siz; ptrd>data; ) *(--ptrd) = (T)*(--ptrs); + } + } else { + if (data) delete[] data; + width = height = depth = dim = 0; data = 0; + } + return *this; + } + + // Assignment operator (fast version). + CImg& operator=(const CImg& img) { + if (&img!=this) { + const unsigned int siz = img.size(); + if (img.data && siz) { + if (shared) { + if (siz==size()) std::memcpy(data,img.data,siz*sizeof(T)); + else throw CImgArgumentException("CImg<%s>::operator=() : Given image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) " + "must have same dimensions, since instance image has shared memory.", + pixel_type(),img.width,img.height,img.depth,img.dim,img.data,width,height,depth,dim,data); + } else { + T* xdata = 0; + if (siz!=width*height*depth*dim) xdata = new T[siz]; + width = img.width; height = img.height; depth = img.depth; dim = img.dim; + std::memcpy(xdata?xdata:data,img.data,siz*sizeof(T)); + if (xdata) { delete[] data; data = xdata; } + } + } else { + if (data) delete[] data; + width = height = depth = dim = 0; data = 0; + } + } + return *this; + } + + //! Assign a value to each image pixel of the instance image. + /** + \param val Value to assign. + + - Replace all pixel values of the instance image by \c val. + - Can be used to easily initialize an image. + + \par example: + \code + CImg img(100,100); // Define a 100x100 greyscale image. + img = 3.14f; // Set all pixel values to 3.14. + \endcode + + \sa fill(). + **/ + CImg& operator=(const T& val) { + return fill(val); + } + + //! Assign values of a C-array to the instance image. + /** + \param buf Pointer to a C-style array having a size of (at least) this->size(). + + - Replace pixel values by the content of the array \c buf. + - Warning : the value types in the array and in the image must be the same. + + \par example: + \code + float tab[4*4] = { 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16 }; // Define a 4x4 matrix in C-style. + CImg matrice(4,4); // Define a 4x4 greyscale image. + matrice = tab; // Fill the image by the values in tab. + \endcode + **/ + CImg& operator=(const T *buf) { + if (buf) std::memcpy(data,buf,size()*sizeof(T)); + else empty(); + return *this; + } + + //! Addition. + /** + \param val Constant value added to each image pixel of the instance image. + **/ + CImg operator+(const T& val) const { + return CImg(*this)+=val; + } + + //! Addition. + /** + \param img Image added to the instance image. + **/ + template CImg::type> operator+(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this)+=img; + } + + //! Addition. + friend CImg operator+(const T& val, const CImg& img) { + return CImg(img)+=val; + } + + //! In-place addition. + /** This is the in-place version of operator+(). **/ + CImg& operator+=(const T& val) { + cimg_map(*this,ptr,T) (*ptr)+=val; + return *this; + } + + //! In-place addition. + /** This is the in-place version of operator+(). **/ + template CImg& operator+=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + t *ptrs = img.data+smin; + for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))); + return *this; + } + + //! In-place increment. + /** Equivalent to \c operator+=(1). **/ + CImg& operator++() { + return (*this)+=1; + } + + //! Substraction. + /** + \param val Constant value substracted to each image pixel of the instance image. + **/ + CImg operator-(const T& val) const { + return CImg(*this)-=val; + } + + //! Substraction. + /** + \param img Image substracted to the instance image. + **/ + template CImg::type> operator-(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this)-=img; + } + + //! Substraction. + friend CImg operator-(const T& val, const CImg& img) { + return CImg(img.width,img.height,img.depth,img.dim,val)-=img; + } + + //! In-place substraction. + /** This is the in-place version of operator-(). **/ + CImg& operator-=(const T& val) { + cimg_map(*this,ptr,T) (*ptr)-=val; + return *this; + } + + //! In-place substraction. + /** This is the in-place version of operator-(). **/ + template CImg& operator-=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + t *ptrs = img.data+smin; + for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs)))); + return *this; + } + + //! In-place decrement. + /** Equivalent to \c operator-=(1). **/ + CImg& operator--() { + return (*this)-=1; + } + + //! Multiplication. + /** + \param val Constant value multiplied to each image pixel of the instance image. + **/ + CImg operator*(const double val) const { + return CImg(*this)*=val; + } + + //! Multiplication. + /** + Matrix multiplication. + **/ + template CImg::type> operator*(const CImg& img) const { + typedef typename cimg::largest::type restype; + if (width!=img.height) + throw CImgArgumentException("CImg<%s>::operator*() : can't multiply a matrix *this = (%ux%u) by a matrix (%ux%u)", + pixel_type(),width,height,img.width,img.height); + CImg res(img.width,height); + restype val; + cimg_mapXY(res,i,j) { val=0; cimg_mapX(*this,k) val+=(*this)(k,j)*img(i,k); res(i,j) = val; } + return res; + } + + //! Multiplication. + friend CImg operator*(const double val,const CImg &img) { + return CImg(img)*=val; + } + + //! In-place multiplication. + /** This is the in-place version of operator*(). **/ + CImg& operator*=(const double val) { + cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)*val); + return *this; + } + + //! In-place multiplication. + /** This is the in-place version of operator*(). **/ + template CImg& operator*=(const CImg& img) { + return ((*this)*img).swap(*this); + } + + //! Division. + /** + \param val Constant value divided to each image pixel of the instance image. + **/ + CImg operator/(const double val) const { + return CImg(*this)/=val; + } + + //! In-place division. + /** This is the in-place version of operator/(). **/ + CImg& operator/=(const double val) { + cimg_map(*this,ptr,T) (*ptr)=(T)((*ptr)/val); + return *this; + } + + //! Modulo. + /** + \param val Constant valued used for a modulo on each image pixel. + **/ + CImg operator%(const T& val) const { + return CImg(*this)%=val; + } + + //! Modulo. + /** + \param img Image whose values are used for a modulo. + **/ + CImg operator%(const CImg& img) const { return CImg(*this)%=img; } + + //! In-place modulo. + /** This is the in-place version of operator%(). **/ + CImg& operator%=(const T& val) { cimg_map(*this,ptr,T) (*ptr)%=val; return *this; } + + //! In-place modulo. + /** This is the in-place version of operator%(). **/ + CImg& operator%=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)%=*(--ptrs)); + return *this; + } + + //! Bitwise AND. + /** + \param val Constant valued used for a bitwise AND on each image pixel. + **/ + CImg operator&(const T& val) const { return CImg(*this)&=val; } + + //! Bitwise AND. + /** + \param img Image whose value are used for the AND. + **/ + CImg operator&(const CImg& img) const { return CImg(*this)&=img; } + + //! In-place bitwise AND. + /** This is the in-place version of operator&(). **/ + CImg& operator&=(const T& val) { cimg_map(*this,ptr,T) (*ptr)&=val; return *this; } + + //! In-place bitwise AND. + /** This is the in-place version of operator&=(). **/ + CImg& operator&=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)&=*(--ptrs)); + return *this; + } + + //! Bitwise OR. + /** + \param val Constant valued used for a bitwise OR on each image pixel. + **/ + CImg operator|(const T& val) const { return CImg(*this)|=val; } + + //! Bitwise OR. + /** + \param img Image whose values are used for the OR. + **/ + CImg operator|(const CImg& img) const { return CImg(*this)|=img; } + + //! In-place bitwise OR. + /** This is the in-place version of operator|(). **/ + CImg& operator|=(const T& val) { cimg_map(*this,ptr,T) (*ptr)|=val; return *this; } + + //! In-place bitwise OR. + /** This is the in-place version of operator|(). **/ + CImg& operator|=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)|=*(--ptrs)); + return *this; + } + + //! Bitwise XOR. + /** + \param val Constant valued used for a bitwise XOR on each image pixel. + **/ + CImg operator^(const T& val) const { return CImg(*this)^=val; } + + //! Bitwise XOR. + /** + \param img Image whose values are used for the XOR. + **/ + CImg operator^(const CImg& img) const { return CImg(*this)^=img; } + + //! In-place bitwise XOR. + /** This is the in-place version of operator^(). **/ + CImg& operator^=(const T& val) { cimg_map(*this,ptr,T) (*ptr)^=val; return *this; } + + //! In-place bitwise XOR. + /** This is the in-place version of operator^(). **/ + CImg& operator^=(const CImg& img) { + const unsigned int smin = cimg::min(size(),img.size()); + for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; *(--ptrd)^=*(--ptrs)); + return *this; + } + + //! Boolean NOT. + CImg operator!() const { + CImg res(*this,false); + const T *ptrs = end(); + cimg_map(res,ptrd,T) *ptrd=!(*(--ptrs)); + return res; + } + + //! Bitwise NOT. + CImg operator~() const { + CImg res(*this,false); + const T *ptrs = end(); + cimg_map(res,ptrd,T) *ptrd=~(*(--ptrs)); + return res; + } + + //! Boolean equality. + template bool operator==(const CImg& img) const { + const unsigned int siz = size(); + bool vequal = true; + if (siz!=img.size()) return false; + t *ptrs=img.data+siz; + for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs)))); + return vequal; + } + + //! Boolean difference. + template bool operator!=(const CImg& img) const { return !((*this)==img); } + + //@} + //--------------------------------------- + // + //! \name Usual mathematical operations + //@{ + //--------------------------------------- + + //! In-place pointwise multiplication between \c *this and \c img. + /** + This is the in-place version of get_mul(). + \sa get_mul(). + **/ + template CImg& mul(const CImg& img) { + t *ptrs = img.data; + T *ptrf = data + cimg::min(size(),img.size()); + for (T* ptrd = data; ptrd CImg::type> get_mul(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this).mul(img); + } + + //! Replace the image by the pointwise division between \p *this and \p img. + /** + This is the in-place version of get_div(). + \see get_div(). + **/ + template CImg& div(const CImg& img) { + t *ptrs = img.data; + T *ptrf = data + cimg::min(size(),img.size()); + for (T* ptrd = data; ptrd CImg::type> get_div(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this).div(img); + } + + //! Replace the image by the pointwise max operator between \p *this and \p img + /** + This is the in-place version of get_max(). + \see get_max(). + **/ + template CImg& max(const CImg& img) { + t *ptrs = img.data; + T *ptrf = data + cimg::min(size(),img.size()); + for (T* ptrd = data; ptrd CImg::type> get_max(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this).max(img); + } + + //! Replace the image by the pointwise max operator between \p *this and \p val + /** + This is the in-place version of get_max(). + \see get_max(). + **/ + CImg& max(const T& val) { + cimg_map(*this,ptr,T) (*ptr)=cimg::max(*ptr,val); + return *this; + } + + //! Return the image corresponding to the max value for each pixel. + /** + \param val = second argument of the max operator (the first one is *this). + \see max(), min(), get_min() + **/ + CImg get_max(const T& val) const { + return CImg(*this).max(val); + } + + //! Replace the image by the pointwise min operator between \p *this and \p img + /** + This is the in-place version of get_min(). + \see get_min(). + **/ + template CImg& min(const CImg& img) { + t *ptrs = img.data; + T *ptrf = data + cimg::min(size(),img.size()); + for (T* ptrd = data; ptrd CImg::type> get_min(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this).min(img); + } + + //! Replace the image by the pointwise min operator between \p *this and \p val + /** + This is the in-place version of get_min(). + \see get_min(). + **/ + CImg& min(const T& val) { + cimg_map(*this,ptr,T) (*ptr)=cimg::min(*ptr,val); + return *this; + } + + //! Return the image corresponding to the min value for each pixel. + /** + \param val = second argument of the min operator (the first one is *this). + \see min(), max(), get_max() + **/ + CImg get_min(const T& val) const { + return CImg(*this).min(val); + } + + //! Replace each image pixel by its square root. + /** + \see get_sqrt() + **/ + CImg& sqrt() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr)); + return *this; + } + + //! Return the image of the square root of the pixel values. + /** + \see sqrt() + **/ + CImg::type> get_sqrt() const { + typedef typename cimg::largest::type restype; + return CImg(*this).sqrt(); + } + + //! Replace each image pixel by its log. + /** + \see get_log(), log10(), get_log10() + **/ + CImg& log() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr)); + return *this; + } + + //! Return the image of the log of the pixel values. + /** + \see log(), log10(), get_log10() + **/ + CImg::type> get_log() const { + typedef typename cimg::largest::type restype; + return CImg(*this).log(); + } + + //! Replace each image pixel by its log10. + /** + \see get_log10(), log(), get_log() + **/ + CImg& log10() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr)); + return *this; + } + + //! Return the image of the log10 of the pixel values. + /** + \see log10(), log(), get_log() + **/ + CImg::type> get_log10() const { + typedef typename cimg::largest::type restype; + return CImg(*this).log10(); + } + + //! Replace each image pixel by its power by \p p. + /** + \param p = power + \see get_pow(), sqrt(), get_sqrt() + **/ + CImg& pow(const double p) { + if (p==0) return fill(1); + if (p==1) return *this; + if (p==2) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val; } return *this; } + if (p==3) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val; } return *this; } + if (p==4) { cimg_map(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val*val; } return *this; } + cimg_map(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p); + return *this; + } + + //! Return the image of the square root of the pixel values. + /** + \param p = power + \see pow(), sqrt(), get_sqrt() + **/ + CImg::type> get_pow(const double p) const { + typedef typename cimg::largest::type restype; + return CImg(*this).pow(p); + } + + //! Return each image pixel (*this)(x,y,z,k) by its power by \p img(x,y,z,k) + /** + In-place version + **/ + template CImg& pow(const CImg& img) { + t *ptrs = img.data; + T *ptrf = data + cimg::min(size(),img.size()); + for (T* ptrd = data; ptrd CImg::type> get_pow(const CImg& img) const { + typedef typename cimg::largest::type restype; + return CImg(*this).pow(img); + } + + //! Replace each pixel value by its absolute value. + /** + \see get_abs() + **/ + CImg& abs() { + cimg_map(*this,ptr,T) (*ptr)=cimg::abs(*ptr); + return *this; + } + + //! Return the image of the absolute value of the pixel values. + /** + \see abs() + **/ + CImg::type> get_abs() const { + typedef typename cimg::largest::type restype; + return CImg(*this).abs(); + } + + //! Replace each image pixel by its cosinus. + /** + \see get_cos(), sin(), get_sin(), tan(), get_tan() + **/ + CImg& cos() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr)); + return *this; + } + + //! Return the image of the cosinus of the pixel values. + /** + \see cos(), sin(), get_sin(), tan(), get_tan() + **/ + CImg::type> get_cos() const { + typedef typename cimg::largest::type restype; + return CImg(*this).cos(); + } + + //! Replace each image pixel by its sinus. + /** + \see get_sin(), cos(), get_cos(), tan(), get_tan() + **/ + CImg& sin() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr)); + return *this; + } + + //! Return the image of the sinus of the pixel values. + /** + \see sin(), cos(), get_cos(), tan(), get_tan() + **/ + CImg::type> get_sin() const { + typedef typename cimg::largest::type restype; + return CImg(*this).sin(); + } + + //! Replace each image pixel by its tangent. + /** + \see get_tan(), cos(), get_cos(), sin(), get_sin() + **/ + CImg& tan() { + cimg_map(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr)); + return *this; + } + + //! Return the image of the tangent of the pixel values. + /** + \see tan(), cos(), get_cos(), sin(), get_sin() + **/ + CImg::type> get_tan() const { + typedef typename cimg::largest::type restype; + return CImg(*this).tan(); + } + + //! Return the MSE (Mean-Squared Error) between two images. + template double MSE(const CImg& img) const { + if (img.size()!=size()) + throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.", + pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim); + + double vMSE = 0; + const t* ptr2 = img.end(); + cimg_map(*this,ptr1,T) { + const double diff = (double)*ptr1 - (double)*(--ptr2); + vMSE += diff*diff; + } + vMSE/=img.size(); + return vMSE; + } + + //! Return the PSNR between two images. + template double PSNR(const CImg& img, const double valmax=255.0) const { + const double vMSE = std::sqrt(MSE(img)); + return (vMSE!=0)?(20*std::log10(valmax/vMSE)):(cimg::infinity); + } + + //@} + //----------------------------------- + // + //! \name Usual image transformation + //@{ + //----------------------------------- + + //! Fill an image by a value \p val. + /** + \param val = fill value + \note All pixel values of the instance image will be initialized by \p val. + \see operator=(). + **/ + CImg& fill(const T& val) { + if (!is_empty()) { + if (val!=0 && sizeof(T)!=1) cimg_map(*this,ptr,T) *ptr=val; + else std::memset(data,(int)val,size()*sizeof(T)); + } + return *this; + } + + //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively. + /** + \param val0 = fill value 1 + \param val1 = fill value 2 + **/ + CImg& fill(const T& val0,const T& val1) { + if (!is_empty()) { + T *ptr, *ptr_end = end()-1; + for (ptr=data; ptr(*this).normalize(a,b); } + + //! Cut pixel values between \a a and \a b. + /** + \param a = minimum pixel value after cut. + \param b = maximum pixel value after cut. + \see get_cut(), normalize(), get_normalize(). + **/ + CImg& cut(const T& a, const T& b) { + if (!is_empty()) + cimg_map(*this,ptr,T) *ptr = (*ptrb)?b:*ptr); + return *this; + } + + //! Return the image of cutted values. + /** + \param a = minimum pixel value after cut. + \param b = maximum pixel value after cut. + \see cut(), normalize(), get_normalize(). + **/ + CImg get_cut(const T& a, const T& b) const { return CImg(*this).cut(a,b); } + + //! Quantize pixel values into \n levels. + /** + \param n = number of quantification levels + \see get_quantize(). + **/ + CImg& quantize(const unsigned int n=256) { + if (!is_empty()) { + if (!n) throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.", + pixel_type()); + const CImgStats st(*this,false); + const double range = st.max-st.min; + if (range>0) cimg_map(*this,ptr,T) { + const unsigned int val = (unsigned int)((*ptr-st.min)*n/range); + *ptr = (T)(st.min + cimg::min(val,n-1)*range); + } + } + return *this; + } + + //! Return a quantified image, with \n levels. + /** + \param n = number of quantification levels + \see quantize(). + **/ + CImg get_quantize(const unsigned int n=256) const { return CImg(*this).quantize(n); } + + //! Threshold the image. + /** + \param thres = threshold + \see get_threshold(). + **/ + CImg& threshold(const T& thres) { + if (!is_empty()) + cimg_map(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1; + return *this; + } + + //! Return a thresholded image. + /** + \param thres = threshold. + \see threshold(). + **/ + CImg get_threshold(const T& thres) const { + return CImg(*this).threshold(thres); + } + + //! Return a rotated image. + /** + \param angle = rotation angle (in degrees). + \param cond = rotation type. can be : + - 0 = zero-value at borders + - 1 = repeat image at borders + - 2 = zero-value at borders and linear interpolation + \note Returned image will probably have a different size than the instance image *this. + \see rotate() + **/ + CImg get_rotate(const float angle, const unsigned int cond=3) const { + if (is_empty()) return CImg(); + CImg dest; + const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0), + ca=(float)std::cos(rad), sa=(float)std::sin(rad); + if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles + const int wm1 = dimx()-1, hm1 = dimy()-1; + const int iangle = (int)nangle/90; + switch (iangle) { + case 1: { + dest.assign(height,width,depth,dim); + cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v); + } break; + case 2: { + dest.assign(*this,false); + cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v); + } break; + case 3: { + dest.assign(height,width,depth,dim); + cimg_mapXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v); + } break; + default: + return *this; + } + } else { // generic version + const float + ux = (float)(cimg::abs(width*ca)), uy = (float)(cimg::abs(width*sa)), + vx = (float)(cimg::abs(height*sa)), vy = (float)(cimg::abs(height*ca)), + w2 = 0.5f*width, h2 = 0.5f*height, + dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy); + dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim); + switch (cond) { + case 0: { + cimg_mapXY(dest,x,y) + cimg_mapZV(*this,z,v) + dest(x,y,z,v) = pix2d((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0); + } break; + case 1: { + cimg_mapXY(dest,x,y) + cimg_mapZV(*this,z,v) + dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),width), + cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),height),z,v); + } break; + case 2: { + cimg_mapXY(dest,x,y) { + const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca; + cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v,0); + } + } break; + default: { + cimg_mapXY(dest,x,y) { + const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca; + cimg_mapZV(*this,z,v) dest(x,y,z,v) = (T)cubic_pix2d(X,Y,z,v,0); + } + } break; + } + } + return dest; + } + + //! Rotate the image + /** + \param angle = rotation angle (in degrees). + \param cond = rotation type. can be : + - 0 = zero-value at borders + - 1 = repeat image at borders + - 2 = zero-value at borders and linear interpolation + \see get_rotate() + **/ + CImg& rotate(const float angle,const unsigned int cond=3) { return get_rotate(angle,cond).swap(*this); } + + //! Return a rotated image around the point (\c cx,\c cy). + /** + \param angle = rotation angle (in degrees). + \param cx = X-coordinate of the rotation center. + \param cy = Y-coordinate of the rotation center. + \param zoom = zoom. + \param cond = rotation type. can be : + - 0 = zero-value at borders + - 1 = repeat image at borders + - 2 = zero-value at borders and linear interpolation + \see rotate() + **/ + CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=3) const { + if (is_empty()) return CImg(); + CImg dest(*this,false); + const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0), + ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom; + if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles + const int iangle = (int)nangle/90; + switch (iangle) { + case 1: { + dest.fill(0); + const unsigned int + xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height), + ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width), + xoff = xmin + cimg::min(0,(dimx()-dimy())/2), + yoff = ymin + cimg::min(0,(dimy()-dimx())/2); + cimg_mapZV(dest,z,v) for (unsigned int y=ymin; y(); + const unsigned int + dx = pdx<0?-pdx*width/100:pdx, + dy = pdy<0?-pdy*height/100:pdy, + dz = pdz<0?-pdz*depth/100:pdz, + dv = pdv<0?-pdv*dim/100:pdv; + CImg res(dx?dx:1,dy?dy:1,dz?dz:1,dv?dv:1); + if (is_empty()) return res.fill(0); + if (width==res.width && height==res.height && depth==res.depth && dim==res.dim) return *this; + switch (interp) { + case 0: // Zero filling + res.fill(0).draw_image(*this,0,0,0,0); + break; + case 1: { // Nearest-neighbor interpolation + unsigned int + *const offx = new unsigned int[res.width], + *const offy = new unsigned int[res.height+1], + *const offz = new unsigned int[res.depth+1], + *const offv = new unsigned int[res.dim+1], + *poffx, *poffy, *poffz, *poffv; + const unsigned int + wh = width*height, + whd = width*height*depth, + rwh = res.width*res.height, + rwhd = res.width*res.height*res.depth; + float s, curr, old; + s = (float)width/res.width; + poffx = offx; curr=0; { cimg_mapX(res,x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }} + s = (float)height/res.height; + poffy = offy; curr=0; { cimg_mapY(res,y) { old=curr; curr+=s; *(poffy++) = width*((unsigned int)curr-(unsigned int)old); }} *poffy=0; + s = (float)depth/res.depth; + poffz = offz; curr=0; { cimg_mapZ(res,z) { old=curr; curr+=s; *(poffz++) = wh*((unsigned int)curr-(unsigned int)old); }} *poffz=0; + s = (float)dim/res.dim; + poffv = offv; curr=0; { cimg_mapV(res,v) { old=curr; curr+=s; *(poffv++) = whd*((unsigned int)curr-(unsigned int)old); }} *poffv=0; + + T *ptrd = res.ptr(); + const T* ptrv = ptr(); + poffv = offv; + for (unsigned int k=0; k1?(width-1.0f)/(res.width-1):0), + sy = by?(height-1.0f)/(res.height+1):(res.height>1?(height-1.0f)/(res.height-1):0), + sz = bz?(depth-1.0f)/(res.depth+1):(res.depth>1?(depth-1.0f)/(res.depth-1):0), + sk = bk?(dim-1.0f)/(res.dim+1):(res.dim>1?(dim-1.0f)/(res.dim-1):0), + dx = bx?sx:0, dy = by?sy:0, dz = bz?sz:0, dk = bk?sk:0; + float cx,cy,cz,ck=dk; + cimg_mapV(res,k) { cz = dz; + cimg_mapZ(res,z) { cy = dy; + cimg_mapY(res,y) { cx = dx; + cimg_mapX(res,x) { res(x,y,z,k) = (T)linear_pix4d(cx,cy,cz,ck); cx+=sx; + } cy+=sy; + } cz+=sz; + } ck+=sk; + } + } break; + case 4: { // Grid filling + const float sx = (float)width/res.width, sy = (float)height/res.height, sz = (float)depth/res.depth, sk = (float)dim/res.dim; + res.fill(0); + cimg_mapXYZV(*this,x,y,z,k) res((int)(x/sx),(int)(y/sy),(int)(z/sz),(int)(k/sk)) = (*this)(x,y,z,k); + } break; + case 5: { // Cubic interpolation + const bool bx = (res.width1?(width-1.0f)/(res.width-1):0), + sy = by?(height-1.0f)/(res.height+1):(res.height>1?(height-1.0f)/(res.height-1):0), + sz = bz?(depth-1.0f)/(res.depth+1):(res.depth>1?(depth-1.0f)/(res.depth-1):0), + sk = bk?(dim-1.0f)/(res.dim+1):(res.dim>1?(dim-1.0f)/(res.dim-1):0), + dx = bx?sx:0, dy = by?sy:0, dz = bz?sz:0, dk = bk?sk:0; + float cx,cy,cz,ck=dk; + cimg_mapV(res,k) { cz = dz; + cimg_mapZ(res,z) { cy = dy; + cimg_mapY(res,y) { cx = dx; + cimg_mapX(res,x) { res(x,y,z,k) = (T)cubic_pix2d(cx,cy,(int)cz,(int)ck); cx+=sx; + } cy+=sy; + } cz+=sz; + } ck+=sk; + } + } break; + } + return res; + } + + //! Return a resized image. + /** + \param src = Image giving the tqgeometry of the resize. + \param interp = Resizing type : + - 0 = no interpolation : additionnal space is filled with 0. + - 1 = bloc interpolation (nearest point). + - 2 = mosaic : image is repeated if necessary. + - 3 = linear interpolation. + - 4 = grid interpolation. + - 5 = bi-cubic interpolation. + \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). + **/ + template CImg get_resize(const CImg& src,const unsigned int interp=1) const { + return get_resize(src.width,src.height,src.depth,src.dim,interp); + } + + //! Return a resized image. + /** + \param disp = Display giving the tqgeometry of the resize. + \param interp = Resizing type : + - 0 = no interpolation : additionnal space is filled with 0. + - 1 = bloc interpolation (nearest point). + - 2 = mosaic : image is repeated if necessary. + - 3 = linear interpolation. + - 4 = grid interpolation. + - 5 = bi-cubic interpolation. + \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). + **/ + CImg get_resize(const CImgDisplay& disp,const unsigned int interp=1) const { + return get_resize(disp.width,disp.height,depth,dim,interp); + } + + //! Resize the image. + /** + \param pdx = Number of columns (new size along the X-axis). + \param pdy = Number of rows (new size along the Y-axis). + \param pdz = Number of slices (new size along the Z-axis). + \param pdv = Number of vector-channels (new size along the V-axis). + \param interp = Resizing type : + - 0 = no interpolation : additionnal space is filled with 0. + - 1 = bloc interpolation (nearest point). + - 2 = mosaic : image is repeated if necessary. + - 3 = linear interpolation. + - 4 = grid interpolation. + - 5 = bi-cubic interpolation. + \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). + **/ + CImg& resize(const int pdx=-100,const int pdy=-100,const int pdz=-100,const int pdv=-100,const unsigned int interp=1) { + if (!pdx || !pdy || !pdz || !pdv) return empty(); + const unsigned int + dx = pdx<0?-pdx*width/100:pdx, + dy = pdy<0?-pdy*height/100:pdy, + dz = pdz<0?-pdz*depth/100:pdz, + dv = pdv<0?-pdv*dim/100:pdv; + if (width==dx && height==dy && depth==dz && dim==dv) return *this; + return get_resize(dx,dy,dz,dv,interp).swap(*this); + } + + //! Resize the image. + /** + \param src = Image giving the tqgeometry of the resize. + \param interp = Resizing type : + - 0 = no interpolation : additionnal space is filled with 0. + - 1 = bloc interpolation (nearest point). + - 2 = mosaic : image is repeated if necessary. + - 3 = linear interpolation. + - 4 = grid interpolation. + - 5 = bi-cubic interpolation. + \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). + **/ + template CImg& resize(const CImg& src,const unsigned int interp=1) { + return resize(src.width,src.height,src.depth,src.dim,interp); + } + + //! Resize the image + /** + \param disp = Display giving the tqgeometry of the resize. + \param interp = Resizing type : + - 0 = no interpolation : additionnal space is filled with 0. + - 1 = bloc interpolation (nearest point). + - 2 = mosaic : image is repeated if necessary. + - 3 = linear interpolation. + - 4 = grid interpolation. + - 5 = bi-cubic interpolation. + \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). + **/ + CImg& resize(const CImgDisplay& disp,const unsigned int interp=1) { + return resize(disp.width,disp.height,depth,dim,interp); + } + + //! Return an half-resized image, using a special filter. + /** + \see resize_halfXY(), resize(), get_resize(). + **/ + CImg get_resize_halfXY() const { + typedef typename cimg::largest::type ftype; + if (is_empty()) return CImg(); + CImg tqmask = CImg::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f, + 0.1231940459f, 0.1935127547f, 0.1231940459f, + 0.07842776544f, 0.1231940459f, 0.07842776544f); + CImg_3x3x1(I,ftype); + CImg dest(width/2,height/2,depth,dim); + cimg_mapZV(*this,z,k) cimg_map3x3x1(*this,x,y,z,k,I) + if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)cimg_conv3x3x1(I,tqmask); + return dest; + } + + //! Half-resize the image, using a special filter + /** + \see get_resize_halfXY(), resize(), get_resize(). + **/ + CImg& resize_halfXY() { + return get_resize_halfXY().swap(*this); + } + + //! Return a square region of the image, as a new image + /** + \param x0 = X-coordinate of the upper-left crop rectangle corner. + \param y0 = Y-coordinate of the upper-left crop rectangle corner. + \param z0 = Z-coordinate of the upper-left crop rectangle corner. + \param v0 = V-coordinate of the upper-left crop rectangle corner. + \param x1 = X-coordinate of the lower-right crop rectangle corner. + \param y1 = Y-coordinate of the lower-right crop rectangle corner. + \param z1 = Z-coordinate of the lower-right crop rectangle corner. + \param v1 = V-coordinate of the lower-right crop rectangle corner. + \param border_condition = Dirichlet (false) or Neumann border conditions. + \see crop() + **/ + CImg get_crop(const unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0, + const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1, + const bool border_condition = false) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::get_crop() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1; + CImg dest(dx,dy,dz,dv); + if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth || + v0>=dim || v1>=dim || x1end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim); + return CImg(data+beg,x1-x0+1,1,1,1,true); + } + + //! Get a shared-memory image referencing a set of points of the instance image (const version). + const CImg get_shared_points(const unsigned int x0, const unsigned int x1, + const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const { + const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim); + return CImg(data+beg,x1-x0+1,1,1,1,true); + } + + //! Get a copy of a set of points of the instance image. + CImg get_points(const unsigned int x0, const unsigned int x1, + const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const { + const CImg sh = get_shared_points(x0,x1,y0,z0,v0); + return CImg(sh.data,sh.width,sh.height,sh.depth,sh.dim); + } + + //! Return a shared-memory image referencing a set of lines of the instance image. + CImg get_shared_lines(const unsigned int y0, const unsigned int y1, + const unsigned int z0=0, const unsigned int v0=0) { + const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim); + return CImg(data+beg,width,y1-y0+1,1,1,true); + } + + //! Return a shared-memory image referencing a set of lines of the instance image (const version). + const CImg get_shared_lines(const unsigned int y0, const unsigned int y1, + const unsigned int z0=0, const unsigned int v0=0) const { + const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim); + return CImg(data+beg,width,y1-y0+1,1,1,true); + } + + //! Get a copy of a set of lines of the instance image. + CImg get_lines(const unsigned int y0, const unsigned int y1, + const unsigned int z0=0, const unsigned int v0=0) const { + const CImg sh = get_shared_lines(y0,y1,z0,v0); + return CImg(sh.data,sh.width,sh.height,sh.depth,sh.dim); + } + + //! Replace the instance image by a set of lines of the instance image. + CImg& lines(const unsigned int y0, const unsigned int y1, + const unsigned int z0=0, const unsigned int v0=0) const { + return get_lines(y0,y1,z0,v0).swap(*this); + } + + //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image. + CImg get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) { + return get_shared_lines(y0,y0,z0,v0); + } + + //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image (const version). + const CImg get_shared_line(const unsigned int y0,const unsigned int z0=0,const unsigned int v0=0) const { + return get_shared_lines(y0,y0,z0,v0); + } + + //! Get a copy of a line of the instance image. + CImg get_line(const unsigned int y0, + const unsigned int z0=0, const unsigned int v0=0) const { + return get_lines(y0,y0,z0,v0); + } + + //! Replace the instance image by one of its line. + CImg& line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) { + return get_line(y0,z0,v0).swap(*this); + } + + //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image. + CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) { + const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim); + return CImg(data+beg,width,height,z1-z0+1,1,true); + } + + //! Return a shared-memory image referencing a set of planes (z0->z1,v0) of the instance image (const version). + const CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const { + const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim); + return CImg(data+beg,width,height,z1-z0+1,1,true); + } + + //! Return a copy of a set of planes of the instance image. + CImg get_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const { + CImg sh = get_shared_planes(z0,z1,v0); + return CImg(sh.data,sh.width,sh.height,sh.depth,sh.dim); + } + + //! Replace the instance image by a set of planes of the instance image. + CImg& planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) { + return get_planes(z0,z1,v0).swap(*this); + } + + //! Return a shared-memory image referencing one plane (z0,v0) of the instance image. + CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) { + return get_shared_planes(z0,z0,v0); + } + + //! Return a shared-memory image referencing one plane (z0,v0) of the instance image (const version). + const CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) const { + return get_shared_planes(z0,z0,v0); + } + + //! Return a copy of a plane of the instance image. + CImg get_plane(const unsigned int z0, const unsigned int v0=0) const { + return get_planes(z0,z0,v0); + } + + //! Replace the instance image by one plane of the instance image. + CImg& plane(const unsigned int z0, const unsigned int v0=0) { + return get_plane(z0,v0).swap(*this); + } + + //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image. + CImg get_shared_channels(const unsigned int v0, const unsigned int v1) { + const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim); + return CImg(data+beg,width,height,depth,v1-v0+1,true); + } + + //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image (const version). + const CImg get_shared_channels(const unsigned int v0, const unsigned int v1) const { + const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1); + if (beg>end || beg>=size() || end>=size()) + throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from " + "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim); + return CImg(data+beg,width,height,depth,v1-v0+1,true); + } + + //! Return a copy of a set of channels of the instance image. + CImg get_channels(const unsigned int v0, const unsigned int v1) const { + CImg sh = get_shared_channels(v0,v1); + return CImg(sh.data,sh.width,sh.height,sh.depth,sh.dim); + } + + //! Replace the instance image by a set of channels of the instance image. + CImg& channels(const unsigned int v0, const unsigned int v1) { + return get_channels(v0,v1).swap(*this); + } + + //! Return a shared-memory image referencing one channel v0 of the instance image. + CImg get_shared_channel(const unsigned int v0) { + return get_shared_channels(v0,v0); + } + + //! Return a shared-memory image referencing one channel v0 of the instance image (const version). + const CImg get_shared_channel(const unsigned int v0) const { + return get_shared_channels(v0,v0); + } + + //! Return a copy of a channel of the instance image. + CImg get_channel(const unsigned int v0) const { + return get_channels(v0,v0); + } + + //! Replace the instance image by one of its channel. + CImg& channel(const unsigned int v0) { + return get_channel(v0).swap(*this); + } + + //! Return a shared version of the instance image. + CImg get_shared() { + return CImg(data,width,height,depth,dim,true); + } + + //! Return a shared version of the instance image (const version). + const CImg get_shared() const { + return CImg(data,width,height,depth,dim,true); + } + + //! Get the z-slice \a z of *this, as a new image. + /** + \param z0 = Z-slice to return. + \see slice(), get_channel(), channel(), get_plane(), plane(). + **/ + CImg get_slice(const unsigned int z0=0) const { + return get_crop(0,0,z0,0,width-1,height-1,z0,dim-1); + } + + //! Replace the image by one of its slice. + CImg& slice(const unsigned int z0) { return get_slice(z0).swap(*this); } + + //! Mirror an image along the specified axis. + /** + This is the in-place version of get_mirror(). + \sa get_mirror(). + **/ + CImg& mirror(const char axe='x') { + if (!is_empty()) { + T *pf,*pb,*buf=NULL; + switch (cimg::uncase(axe)) { + case 'x': { + pf = ptr(); pb = ptr(width-1); + for (unsigned int yzv=0; yzv::mirror() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); + } + if (buf) delete[] buf; + } + return *this; + } + + //! Get a mirrored version of the image, along the specified axis. + /** + \param axe Axe used to mirror the image. Can be \c 'x', \c 'y', \c 'z' or \c 'v'. + \sa mirror(). + **/ + CImg get_mirror(const char axe='x') { + return CImg(*this).mirror(axe); + } + + //! Scroll the image + /** + This is the in-place version of get_scroll(). + \sa get_scroll(). + **/ + CImg& scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0,const int border_condition=0) { + if (!is_empty()) { + + if (scrollx) // Scroll along X-axis + switch (border_condition) { + case 0: + if (cimg::abs(scrollx)>=(int)width) return fill(0); + if (scrollx>0) cimg_mapYZV(*this,y,z,k) { + std::memmove(ptr(0,y,z,k),ptr(scrollx,y,z,k),(width-scrollx)*sizeof(T)); + std::memset(ptr(width-scrollx,y,z,k),0,scrollx*sizeof(T)); + } else cimg_mapYZV(*this,y,z,k) { + std::memmove(ptr(-scrollx,y,z,k),ptr(0,y,z,k),(width+scrollx)*sizeof(T)); + std::memset(ptr(0,y,z,k),0,-scrollx*sizeof(T)); + } + break; + case 1: + if (scrollx>0) { + const int nscrollx = (scrollx>=(int)width)?width-1:scrollx; + if (!nscrollx) return *this; + cimg_mapYZV(*this,y,z,k) { + std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T)); + T *ptrd = ptr(width-1,y,z,k); + const T &val = *ptrd; + for (int l=0; l=(int)width)?width-1:-scrollx; + if (!nscrollx) return *this; + cimg_mapYZV(*this,y,z,k) { + std::memmove(ptr(nscrollx,y,z,k),ptr(0,y,z,k),(width-nscrollx)*sizeof(T)); + T *ptrd = ptr(0,y,z,k); + const T &val = *ptrd; + for (int l=0; l0) cimg_mapYZV(*this,y,z,k) { + std::memcpy(buf,ptr(0,y,z,k),nscrollx*sizeof(T)); + std::memmove(ptr(0,y,z,k),ptr(nscrollx,y,z,k),(width-nscrollx)*sizeof(T)); + std::memcpy(ptr(width-nscrollx,y,z,k),buf,nscrollx*sizeof(T)); + } else cimg_mapYZV(*this,y,z,k) { + std::memcpy(buf,ptr(width+nscrollx,y,z,k),-nscrollx*sizeof(T)); + std::memmove(ptr(-nscrollx,y,z,k),ptr(0,y,z,k),(width+nscrollx)*sizeof(T)); + std::memcpy(ptr(0,y,z,k),buf,-nscrollx*sizeof(T)); + } + delete[] buf; + } break; + } + + if (scrolly) // Scroll along Y-axis + switch (border_condition) { + case 0: + if (cimg::abs(scrolly)>=(int)height) return fill(0); + if (scrolly>0) cimg_mapZV(*this,z,k) { + std::memmove(ptr(0,0,z,k),ptr(0,scrolly,z,k),width*(height-scrolly)*sizeof(T)); + std::memset(ptr(0,height-scrolly,z,k),0,width*scrolly*sizeof(T)); + } else cimg_mapZV(*this,z,k) { + std::memmove(ptr(0,-scrolly,z,k),ptr(0,0,z,k),width*(height+scrolly)*sizeof(T)); + std::memset(ptr(0,0,z,k),0,-scrolly*width*sizeof(T)); + } + break; + case 1: + if (scrolly>0) { + const int nscrolly = (scrolly>=(int)height)?height-1:scrolly; + if (!nscrolly) return *this; + cimg_mapZV(*this,z,k) { + std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T)); + T *ptrd = ptr(0,height-nscrolly,z,k), *ptrs = ptr(0,height-1,z,k); + for (int l=0; l=(int)height)?height-1:-scrolly; + if (!nscrolly) return *this; + cimg_mapZV(*this,z,k) { + std::memmove(ptr(0,nscrolly,z,k),ptr(0,0,z,k),width*(height-nscrolly)*sizeof(T)); + T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k); + for (int l=0; l0) cimg_mapZV(*this,z,k) { + std::memcpy(buf,ptr(0,0,z,k),width*nscrolly*sizeof(T)); + std::memmove(ptr(0,0,z,k),ptr(0,nscrolly,z,k),width*(height-nscrolly)*sizeof(T)); + std::memcpy(ptr(0,height-nscrolly,z,k),buf,width*nscrolly*sizeof(T)); + } else cimg_mapZV(*this,z,k) { + std::memcpy(buf,ptr(0,height+nscrolly,z,k),-nscrolly*width*sizeof(T)); + std::memmove(ptr(0,-nscrolly,z,k),ptr(0,0,z,k),width*(height+nscrolly)*sizeof(T)); + std::memcpy(ptr(0,0,z,k),buf,-nscrolly*width*sizeof(T)); + } + delete[] buf; + } break; + } + + if (scrollz) // Scroll along Z-axis + switch (border_condition) { + case 0: + if (cimg::abs(scrollz)>=(int)depth) return fill(0); + if (scrollz>0) cimg_mapV(*this,k) { + std::memmove(ptr(0,0,0,k),ptr(0,0,scrollz,k),width*height*(depth-scrollz)*sizeof(T)); + std::memset(ptr(0,0,depth-scrollz,k),0,width*height*scrollz*sizeof(T)); + } else cimg_mapV(*this,k) { + std::memmove(ptr(0,0,-scrollz,k),ptr(0,0,0,k),width*height*(depth+scrollz)*sizeof(T)); + std::memset(ptr(0,0,0,k),0,-scrollz*width*height*sizeof(T)); + } + break; + case 1: + if (scrollz>0) { + const int nscrollz = (scrollz>=(int)depth)?depth-1:scrollz; + if (!nscrollz) return *this; + cimg_mapV(*this,k) { + std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T)); + T *ptrd = ptr(0,0,depth-nscrollz,k), *ptrs = ptr(0,0,depth-1,k); + for (int l=0; l=(int)depth)?depth-1:-scrollz; + if (!nscrollz) return *this; + cimg_mapV(*this,k) { + std::memmove(ptr(0,0,nscrollz,k),ptr(0,0,0,k),width*height*(depth-nscrollz)*sizeof(T)); + T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k); + for (int l=0; l0) cimg_mapV(*this,k) { + std::memcpy(buf,ptr(0,0,0,k),width*height*nscrollz*sizeof(T)); + std::memmove(ptr(0,0,0,k),ptr(0,0,nscrollz,k),width*height*(depth-nscrollz)*sizeof(T)); + std::memcpy(ptr(0,0,depth-nscrollz,k),buf,width*height*nscrollz*sizeof(T)); + } else cimg_mapV(*this,k) { + std::memcpy(buf,ptr(0,0,depth+nscrollz,k),-nscrollz*width*height*sizeof(T)); + std::memmove(ptr(0,0,-nscrollz,k),ptr(0,0,0,k),width*height*(depth+nscrollz)*sizeof(T)); + std::memcpy(ptr(0,0,0,k),buf,-nscrollz*width*height*sizeof(T)); + } + delete[] buf; + } break; + } + + if (scrollv) // Scroll along V-axis + switch (border_condition) { + case 0: + if (cimg::abs(scrollv)>=(int)dim) return fill(0); + if (scrollv>0) { + std::memmove(data,ptr(0,0,0,scrollv),width*height*depth*(dim-scrollv)*sizeof(T)); + std::memset(ptr(0,0,0,dim-scrollv),0,width*height*depth*scrollv*sizeof(T)); + } else cimg_mapV(*this,k) { + std::memmove(ptr(0,0,0,-scrollv),data,width*height*depth*(dim+scrollv)*sizeof(T)); + std::memset(data,0,-scrollv*width*height*depth*sizeof(T)); + } + break; + case 1: + if (scrollv>0) { + const int nscrollv = (scrollv>=(int)dim)?dim-1:scrollv; + if (!nscrollv) return *this; + std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T)); + T *ptrd = ptr(0,0,0,dim-nscrollv), *ptrs = ptr(0,0,0,dim-1); + for (int l=0; l=(int)dim)?dim-1:-scrollv; + if (!nscrollv) return *this; + std::memmove(ptr(0,0,0,nscrollv),data,width*height*depth*(dim-nscrollv)*sizeof(T)); + T *ptrd = ptr(0,0,0,1); + for (int l=0; l0) { + std::memcpy(buf,data,width*height*depth*nscrollv*sizeof(T)); + std::memmove(data,ptr(0,0,0,nscrollv),width*height*depth*(dim-nscrollv)*sizeof(T)); + std::memcpy(ptr(0,0,0,dim-nscrollv),buf,width*height*depth*nscrollv*sizeof(T)); + } else { + std::memcpy(buf,ptr(0,0,0,dim+nscrollv),-nscrollv*width*height*depth*sizeof(T)); + std::memmove(ptr(0,0,0,-nscrollv),data,width*height*depth*(dim+nscrollv)*sizeof(T)); + std::memcpy(data,buf,-nscrollv*width*height*depth*sizeof(T)); + } + delete[] buf; + } break; + } + } + return *this; + } + + //! Return a scrolled image. + /** + \param scrollx Amount of displacement along the X-axis. + \param scrolly Amount of displacement along the Y-axis. + \param scrollz Amount of displacement along the Z-axis. + \param scrollv Amount of displacement along the V-axis. + \param border_condition Border condition. + + - \c border_condition can be : + - 0 : Zero border condition (Dirichlet). + - 1 : Nearest neighbors (Neumann). + - 2 : Repeat Pattern (Fourier style). + **/ + CImg get_scroll(const int scrollx,const int scrolly=0,const int scrollz=0,const int scrollv=0, + const int border_condition=0) const { + return CImg(*this).scroll(scrollx,scrolly,scrollz,scrollv,border_condition); + } + + //! Return a 2D representation of a 3D image, with three slices. + CImg get_projections2d(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const { + if (is_empty()) return CImg(); + const unsigned int + x0=(px0>=width)?width-1:px0, + y0=(py0>=height)?height-1:py0, + z0=(pz0>=depth)?depth-1:pz0; + CImg res(width+depth,height+depth,1,dim); + res.fill((*this)[0]); + { cimg_mapXYV(*this,x,y,k) res(x,y,0,k) = (*this)(x,y,z0,k); } + { cimg_mapYZV(*this,y,z,k) res(width+z,y,0,k) = (*this)(x0,y,z,k); } + { cimg_mapXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); } + return res; + } + + //! Return the image histogram. + /** + The histogram H of an image I is a 1D-function where H(x) is the number of + occurences of the value x in I. + \param nblevels = Number of different levels of the computed histogram. + For classical images, this value is 256 (default value). You should specify more levels + if you are working with CImg or images with high range of pixel values. + \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min + won't be counted. + \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max + won't be counted. + \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum + pixel values of the current image, then uses these values for the histogram computation. + \result The histogram is returned as a 1D CImg image H, having a size of (nblevels,1,1,1) such that + H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I. + \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images + are not multi-dimensional. + \see get_equalize_histogram(), equalize_histogram() + **/ + CImg get_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const { + if (is_empty()) return CImg(); + if (nblevels<1) + throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %u levels", + pixel_type(),nblevels); + T vmin=val_min, vmax=val_max; + CImg res(nblevels,1,1,1,0); + if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; } + cimg_map(*this,ptr,T) { + const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); + if (pos>=0 && pos<(int)nblevels) res[pos]++; + } + return res; + } + + //! Equalize the image histogram + /** This is the in-place version of \ref get_equalize_histogram() **/ + CImg& equalize_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) { + if (!is_empty()) { + T vmin=val_min, vmax=val_max; + if (vmin==vmax && vmin==0) { CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; } + CImg hist = get_histogram(nblevels,vmin,vmax); + float cumul=0; + cimg_mapX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; } + cimg_map(*this,ptr,T) { + const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); + if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size()); + } + } + return *this; + } + + //! Return the histogram-equalized version of the current image. + /** + The histogram equalization is a classical image processing algorithm that enhances the image contrast + by expanding its histogram. + \param nblevels = Number of different levels of the computed histogram. + For classical images, this value is 256 (default value). You should specify more levels + if you are working with CImg or images with high range of pixel values. + \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min + won't be changed. + \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max + won't be changed. + \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image. + \return A new image with same size is returned, where pixels have been equalized. + \see get_histogram(), equalize_histogram() + **/ + CImg get_equalize_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const { + return CImg(*this).equalize_histogram(nblevels,val_min,val_max); + } + + //! Return the scalar image of vector norms. + /** + When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each + vector-valued pixel. + \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf). + \return A scalar-valued image CImg with size (dimx(),dimy(),dimz(),1), where each pixel is the norm + of the corresponding pixels in the original vector-valued image. + \see get_orientation_pointwise, orientation_pointwise, norm_pointwise. + **/ + CImg::type> get_norm_pointwise(int norm_type=2) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + CImg res(width,height,depth); + switch(norm_type) { + case -1: { // Linf norm + cimg_mapXYZ(*this,x,y,z) { + restype n=0; cimg_mapV(*this,v) { + const restype tmp = (restype)cimg::abs((*this)(x,y,z,v)); + if (tmp>n) n=tmp; res(x,y,z) = n; + } + } + } break; + case 1: { // L1 norm + cimg_mapXYZ(*this,x,y,z) { + restype n=0; cimg_mapV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n; + } + } break; + default: { // L2 norm + cimg_mapXYZ(*this,x,y,z) { + restype n=0; cimg_mapV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (restype)std::sqrt((double)n); + } + } break; + } + return res; + } + + //! Replace each pixel value with its vector norm. + /** + This is the in-place version of \ref get_norm_pointwise(). + \note Be careful when using this function on CImg with T=char, unsigned char,unsigned int or int. The vector norm + is usually a floating point value, and a rough cast will be done here. + **/ + CImg& norm_pointwise() { + return CImg(get_norm_pointwise()).swap(*this); + } + + //! Return the image of normalized vectors + /** + When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors + (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization. + \return A new vector-valued image with same size, where each vector-valued pixels have been normalized. + \see get_norm_pointwise, norm_pointwise, orientation_pointwise. + **/ + CImg::type> get_orientation_pointwise() const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + return CImg(*this).orientation_pointwise(); + } + + //! Replace each pixel value by its normalized vector + /** This is the in-place version of \ref get_orientation_pointwise() **/ + CImg& orientation_pointwise() { + cimg_mapXYZ(*this,x,y,z) { + float n = 0.0f; + cimg_mapV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v)); + n = (float)std::sqrt(n); + if (n>0) cimg_mapV(*this,v) (*this)(x,y,z,v)=(T)((*this)(x,y,z,v)/n); + else cimg_mapV(*this,v) (*this)(x,y,z,v)=0; + } + return *this; + } + + //! Split image into a list CImgl<>. + CImgl get_split(const char axe,const unsigned int nb=0) const { + if (is_empty()) return CImgl(); + CImgl res; + switch (cimg::uncase(axe)) { + case 'x': { + if (nb>width) + throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.", + pixel_type(),width,height,depth,dim,data,nb); + res.assign(nb?nb:width); + const unsigned int delta = width/res.size + ((width%res.size)?1:0); + unsigned int l,x; + for (l=0, x=0; lheight) + throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.", + pixel_type(),width,height,depth,dim,data,nb); + res.assign(nb?nb:height); + const unsigned int delta = height/res.size + ((height%res.size)?1:0); + unsigned int l,x; + for (l=0, x=0; ldepth) + throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.", + pixel_type(),width,height,depth,dim,data,nb); + res.assign(nb?nb:depth); + const unsigned int delta = depth/res.size + ((depth%res.size)?1:0); + unsigned int l,x; + for (l=0, x=0; ldim) + throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.", + pixel_type(),width,height,depth,dim,data,nb); + res.assign(nb?nb:dim); + const unsigned int delta = dim/res.size + ((dim%res.size)?1:0); + unsigned int l,x; + for (l=0, x=0; l::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); + break; + } + return res; + } + + //! Append an image to another one + CImg get_append(const CImg& img,const char axis='x',const char align='c') const { + if (img.is_empty()) return *this; + if (is_empty()) return img; + CImgl temp(2); + temp[0].width = width; temp[0].height = height; temp[0].depth = depth; + temp[0].dim = dim; temp[0].data = data; + temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth; + temp[1].dim = img.dim; temp[1].data = img.data; + const CImg res = temp.get_append(axis,align); + temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = NULL; + temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = NULL; + return res; + } + + //! Append an image to another one (in-place version) + CImg& append(const CImg& img,const char axis='x', const char align='c') { + if (img.is_empty()) return *this; + if (is_empty()) return (*this=img); + return get_append(img,axis,align).swap(*this); + } + + //! Append an image to another one (in-place operator<< version) + CImg& operator<<(const CImg& img) { + return append(img); + } + + //! Return a list of images, corresponding to the XY-gradients of an image. + /** + \param scheme = Numerical scheme used for the gradient computation : + - -1 = Backward finite differences + - 0 = Centered finite differences + - 1 = Forward finite differences + - 2 = Using Sobel tqmasks + - 3 = Using rotation invariant tqmasks + - 4 = Using Deriche recusrsive filter. + **/ + CImgl::type> get_gradientXY(const int scheme=0) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImgl(2); + CImgl res(2,width,height,depth,dim); + switch(scheme) { + case -1: { // backward finite differences + CImg_3x3x1(I,restype); + cimg_mapZV(*this,z,k) cimg_map3x3x1(*this,x,y,z,k,I) { res[0](x,y,z,k) = Icc-Ipc; res[1](x,y,z,k) = Icc-Icp; } + } break; + case 1: { // forward finite differences + CImg_2x2x1(I,restype); + cimg_mapZV(*this,z,k) cimg_map2x2x1(*this,x,y,z,k,I) { res[0](x,y,0,k) = Inc-Icc; res[1](x,y,z,k) = Icn-Icc; } + } break; + case 2: { // using Sobel tqmask + CImg_3x3x1(I,restype); + const float a = 1, b = 2; + cimg_mapZV(*this,z,k) cimg_map3x3x1(*this,x,y,z,k,I) { + res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn; + res[1](x,y,z,k) = -a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn; + } + } break; + case 3: { // using rotation invariant tqmask + CImg_3x3x1(I,restype); + const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1)); + cimg_mapZV(*this,z,k) cimg_map3x3x1(*this,x,y,z,k,I) { + res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn; + res[1](x,y,z,k) = -a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn; + } + } break; + case 4: { // using Deriche filter with low standard variation + res[0] = get_deriche(0,1,'x'); + res[1] = get_deriche(0,1,'y'); + } break; + default: { // central finite differences + CImg_3x3x1(I,restype); + cimg_mapZV(*this,z,k) cimg_map3x3x1(*this,x,y,z,k,I) { + res[0](x,y,z,k) = 0.5f*(Inc-Ipc); + res[1](x,y,z,k) = 0.5f*(Icn-Icp); + } + } break; + } + return res; + } + + //! Return a list of images, corresponding to the XYZ-gradients of an image. + /** + \see get_gradientXY(). + **/ + CImgl::type> get_gradientXYZ(const int scheme=0) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImgl(3); + CImgl res(3,width,height,depth,dim); + CImg_3x3x3(I,restype); + switch(scheme) { + case -1: { // backward finite differences + cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) { + res[0](x,y,z,k) = Iccc-Ipcc; + res[1](x,y,z,k) = Iccc-Icpc; + res[2](x,y,z,k) = Iccc-Iccp; + } + } break; + case 1: { // forward finite differences + cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) { + res[0](x,y,z,k) = Incc-Iccc; + res[1](x,y,z,k) = Icnc-Iccc; + res[2](x,y,z,k) = Iccn-Iccc; + } + } break; + case 4: { // using Deriche filter with low standard variation + res[0] = get_deriche(0,1,'x'); + res[1] = get_deriche(0,1,'y'); + res[2] = get_deriche(0,1,'z'); + } break; + default: { // central finite differences + cimg_mapV(*this,k) cimg_map3x3x3(*this,x,y,z,k,I) { + res[0](x,y,z,k) = 0.5f*(Incc-Ipcc); + res[1](x,y,z,k) = 0.5f*(Icnc-Icpc); + res[2](x,y,z,k) = 0.5f*(Iccn-Iccp); + } + } break; + } + return res; + } + + struct _marching_cubes_func { + const CImg& ref; + _marching_cubes_func(const CImg& pref):ref(pref) {} + float operator()(const float x, const float y, const float z) const { + return (float)ref((int)x,(int)y,(int)z); + } + }; + + //! Get a triangularization of an implicit function defined by the instance image + template + const CImg& marching_cubes(const float isovalue,CImgl& points, CImgl& primitives, + const bool invert_faces = false) const { + if (depth<=1 || dim>1) + throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.", + pixel_type(),width,height,depth,dim,data); + const _marching_cubes_func func(*this); + cimg::marching_cubes(func,isovalue,0.0f,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f, + 1.0f,1.0f,1.0f,points,primitives,invert_faces); + return *this; + } + + struct _marching_cubes_func_float { + const CImg& ref; + _marching_cubes_func_float(const CImg& pref):ref(pref) {} + float operator()(const float x, const float y, const float z) const { + return (float)ref.linear_pix3d(x,y,z); + } + }; + + //! Get a triangularization of an implicit function defined by the instance image + /** + This version allows to specify the marching cube resolution along x,y and z. + **/ + template + const CImg& marching_cubes(const float isovalue, + const float resx, const float resy, const float resz, + CImgl& points, CImgl& primitives, + const bool invert_faces = false) const { + if (depth<=1 || dim>1) + throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.", + pixel_type(),width,height,depth,dim,data); + const _marching_cubes_func_float func(*this); + cimg::marching_cubes(func,isovalue,0.0f,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f, + resx,resy,resz,points,primitives,invert_faces); + return *this; + } + + struct _marching_squares_func { + const CImg& ref; + _marching_squares_func(const CImg& pref):ref(pref) {} + float operator()(const float x, const float y) const { + return (float)ref((int)x,(int)y); + } + }; + + //! Get a vectorization of an implicit function defined by the instance image. + template + const CImg& marching_squares(const float isovalue,CImgl& points, CImgl& primitives) const { + if (height<=1 || depth>1 || dim>1) + throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.", + pixel_type(),width,height,depth,dim,data); + const _marching_squares_func func(*this); + cimg::marching_squares(func,isovalue,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,1.0f,1.0f,points,primitives); + return *this; + } + + struct _marching_squares_func_float { + const CImg& ref; + _marching_squares_func_float(const CImg& pref):ref(pref) {} + float operator()(const float x, const float y) const { + return (float)ref.linear_pix2d(x,y); + } + }; + + //! Get a vectorization of an implicit function defined by the instance image. + /** + This version allows to specify the marching squares resolution along x,y, and z. + **/ + template + const CImg& marching_squares(const float isovalue, + const float resx, const float resy, + CImgl& points, CImgl& primitives) const { + if (height<=1 || depth>1 || dim>1) + throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.", + pixel_type(),width,height,depth,dim,data); + const _marching_squares_func_float func(*this); + cimg::marching_squares(func,isovalue,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,resx,resy,points,primitives); + return *this; + } + + //@} + // + // + // + //! \name Color conversion functions + //@{ + // + // + + //! Return the default 256 colors palette. + /** + The default color palette is used by %CImg when displaying images on 256 colors displays. + It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding + (i.e 8 levels for the Red and Green and 4 levels for the Blue). + \return A 256x1x1x3 color image defining the palette entries. + **/ + static CImg get_default_LUT8() { + static CImg palette; + if (!palette.data) { + palette.assign(256,1,1,3); + for (unsigned int index=0, r=16; r<256; r+=32) + for (unsigned int g=16; g<256; g+=32) + for (unsigned int b=32; b<256; b+=64) { + palette(index,0) = r; + palette(index,1) = g; + palette(index++,2) = b; + } + } + return palette; + } + + //! Convert color pixels from (R,G,B) to match a specified palette. + /** + This function return a (R,G,B) image where colored pixels are constrained to match entries + of the specified color \c palette. + \param palette User-defined palette that will constraint the color conversion. + \param dithering Enable/Disable Floyd-Steinberg dithering. + \param indexing If \c true, each resulting image pixel is an index to the given color palette. + Otherwise, (R,G,B) values of the palette are copied instead. + **/ + template CImg get_RGBtoLUT(const CImg& palette, const bool dithering=true,const bool indexing=false) const { + if (is_empty()) return CImg(); + if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, " + "should be a (R,G,B) image.",pixel_type(),dim); + if (palette.data && palette.dim!=3) + throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, " + "should be a (R,G,B) palette",pixel_type(),palette.dim); + CImg res(width,height,depth,indexing?1:3), pal = palette.data?palette:CImg::get_default_LUT8(); + float *line1 = new float[3*width], *line2 = new float[3*width], *pline1 = line1, *pline2 = line2; + cimg_mapZ(*this,z) { + float *ptr=pline2; cimg_mapX(*this,x) { *(ptr++)=(*this)(x,0,z,0); *(ptr++)=(*this)(x,0,z,1); *(ptr++)=(*this)(x,0,z,2); } + cimg_mapY(*this,y) { + cimg::swap(pline1,pline2); + if (y255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B); + int best_index = 0; + t Rbest=0,Gbest=0,Bbest=0; + if (palette.data) { // find best match in given color palette + float min = (float)cimg::infinity; + cimg_mapX(palette,off) { + const t Rp = palette(off,0), Gp = palette(off,1), Bp = palette(off,2); + const float error = (float)((Rp-R)*(Rp-R) + (Gp-G)*(Gp-G) + (Bp-B)*(Bp-B)); + if (error>3) | ((unsigned char)Bbest>>6); + } + if (indexing) res(x,y,z) = best_index; + else { res(x,y,z,0) = Rbest; res(x,y,z,1) = Gbest; res(x,y,z,2) = Bbest; } + if (dithering) { // apply dithering to neighborhood pixels if needed + const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest); + if (x0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; } + if (x get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const { + CImg foo; + return get_RGBtoLUT(foo,dithering,indexing); + } + + //! Convert color pixels from (R,G,B) to match the specified color palette. + /** This is the in-place version of get_RGBtoLUT(). **/ + CImg& RGBtoLUT(const CImg& palette,const bool dithering=true,const bool indexing=false) { + return get_RGBtoLUT(palette,dithering,indexing).swap(*this); + } + + //! Convert color pixels from (R,G,B) to match the specified color palette. + /** This is the in-place version of get_RGBtoLUT(). **/ + CImg& RGBtoLUT(const bool dithering=true,const bool indexing=false) { + CImg foo; + return get_RGBtoLUT(foo,dithering,indexing).swap(*this); + } + + //! Convert an indexed image to a (R,G,B) image using the specified color palette. + template CImg get_LUTtoRGB(const CImg& palette) const { + if (is_empty()) return CImg(); + if (dim!=1) throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, " + "should be a LUT image",pixel_type(),dim); + if (palette.data && palette.dim!=3) + throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, " + "should be a (R,G,B) palette",pixel_type(),palette.dim); + CImg res(width,height,depth,3); + CImg pal = palette.data?palette:get_default_LUT8(); + cimg_mapXYZ(*this,x,y,z) { + const unsigned int index = (unsigned int)(*this)(x,y,z); + res(x,y,z,0) = pal(index,0); + res(x,y,z,1) = pal(index,1); + res(x,y,z,2) = pal(index,2); + } + return res; + } + + //! Convert an indexed image (with the default palette) to a (R,G,B) image. + CImg get_LUTtoRGB() const { + CImg foo; + return get_LUTtoRGB(foo); + } + + //! In-place version of get_LUTtoRGB(). + CImg& LUTtoRGB(const CImg& palette) { + return get_LUTtoRGB(palette).swap(*this); + } + + //! In-place version of get_LUTroRGB(). + CImg& LUTtoRGB() { + CImg foo; + return get_LUTtoRGB(foo).swap(*this); + } + + //! Convert color pixels from (R,G,B) to (H,S,V). + CImg& RGBtoHSV() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, " + "should be a (R,G,B) image.",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const float + R = (float)((*this)(x,y,z,0)/255.0f), + G = (float)((*this)(x,y,z,1)/255.0f), + B = (float)((*this)(x,y,z,2)/255.0f); + const float m = cimg::min(R,G,B), v = cimg::max(R,G,B); + float h,s; + if (v==m) { h=-1; s=0; } else { + const float + f = (R==m)?(G-B):((G==m)?(B-R):(R-G)), + i = (R==m)?3.0f:((G==m)?5.0f:1.0f); + h = (i-f/(v-m)); + s = (v-m)/v; + if (h>=6.0f) h-=6.0f; + h*=(float)cimg::PI/3.0f; + } + (*this)(x,y,z,0) = (T)h; + (*this)(x,y,z,1) = (T)s; + (*this)(x,y,z,2) = (T)v; + } + } + return *this; + } + + //! Convert color pixels from (H,S,V) to (R,G,B). + CImg& HSVtoRGB() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, " + "should be a (H,S,V) image",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + float + H = (float)((*this)(x,y,z,0)), + S = (float)((*this)(x,y,z,1)), + V = (float)((*this)(x,y,z,2)); + float R=0,G=0,B=0; + if (H<0) R=G=B=V; + else { + H/=(float)cimg::PI/3.0f; + const int i = (int)std::floor(H); + const float + f = (i&1)?(H-i):(1.0f-H+i), + m = V*(1.0f-S), + n = V*(1.0f-S*f); + switch(i) { + case 6: + case 0: R=V; G=n; B=m; break; + case 1: R=n; G=V; B=m; break; + case 2: R=m; G=V; B=n; break; + case 3: R=m; G=n; B=V; break; + case 4: R=n; G=m; B=V; break; + case 5: R=V; G=m; B=n; break; + } + } + (*this)(x,y,z,0) = (T)(R*255.0f); + (*this)(x,y,z,1) = (T)(G*255.0f); + (*this)(x,y,z,2) = (T)(B*255.0f); + } + } + return *this; + } + + //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8 (Thanks to Chen Wang). + CImg& RGBtoYCbCr() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, " + "should be a (R,G,B) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const int + R = (int)((*this)(x,y,z,0)), + G = (int)((*this)(x,y,z,1)), + B = (int)((*this)(x,y,z,2)); + const int + Y = ((66*R+129*G+25*B+128)>>8) + 16, + Cb = ((-38*R-74*G+112*B+128)>>8) + 128, + Cr = ((112*R-94*G-18*B+128)>>8) + 128; + (*this)(x,y,z,0) = (T)(Y<0?0:(Y>255?255:Y)); + (*this)(x,y,z,1) = (T)(Cb<0?0:(Cb>255?255:Cb)); + (*this)(x,y,z,2) = (T)(Cr<0?0:(Cr>255?255:Cr)); + } + } + return *this; + } + + //! Convert color pixels from (Y,Cb,Cr)_8 to (R,G,B). + CImg& YCbCrtoRGB() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, " + "should be a (Y,Cb,Cr)_8 image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const int + Y = (int)((*this)(x, y, z, 0)-16), + Cb = (int)((*this)(x, y, z, 1)-128), + Cr = (int)((*this)(x, y, z, 2)-128); + const int + R = ((298*Y + 409*Cr + 128) >> 8 ), + G = ((298*Y - 100*Cb - 208*Cr + 128) >> 8 ), + B = ((298*Y + 516*Cb + 128) >> 8 ); + (*this)(x,y,z,0) = (T)(R<0?0:(R>255?255:R)); + (*this)(x,y,z,1) = (T)(G<0?0:(G>255?255:G)); + (*this)(x,y,z,2) = (T)(B<0?0:(B>255?255:B)); + } + } + return *this; + } + + //! Convert color pixels from (R,G,B) to (Y,U,V). + CImg& RGBtoYUV() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, " + "should be a (R,G,B) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const float + R = (*this)(x,y,z,0)/255.0f, + G = (*this)(x,y,z,1)/255.0f, + B = (*this)(x,y,z,2)/255.0f, + Y = (T)(0.299*R + 0.587*G + 0.114*B); + (*this)(x,y,z,0) = Y; + (*this)(x,y,z,1) = (T)(0.492*(B-Y)); + (*this)(x,y,z,2) = (T)(0.877*(R-Y)); + } + } + return *this; + } + + //! Convert color pixels from (Y,U,V) to (R,G,B). + CImg& YUVtoRGB() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, " + "should be a (Y,U,V) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const T Y = (*this)(x,y,z,0), U = (*this)(x,y,z,1), V = (*this)(x,y,z,2); + (*this)(x,y,z,0) = (T)((Y + 1.140*V)*255.0f); + (*this)(x,y,z,1) = (T)((Y - 0.395*U - 0.581*V)*255.0f); + (*this)(x,y,z,2) = (T)((Y + 2.032*U)*255.0f); + } + } + return *this; + } + + //! Convert color pixels from (R,G,B) to (X,Y,Z)_709. + CImg& RGBtoXYZ() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, " + "should be a (R,G,B) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const float + R = (float)((*this)(x,y,z,0)/255.0f), + G = (float)((*this)(x,y,z,1)/255.0f), + B = (float)((*this)(x,y,z,2)/255.0f); + (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B); + (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B); + (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B); + } + } + return *this; + } + + //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space. + CImg& XYZtoRGB() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, " + "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const float + X = (float)(255.0f*(*this)(x,y,z,0)), + Y = (float)(255.0f*(*this)(x,y,z,1)), + Z = (float)(255.0f*(*this)(x,y,z,2)); + (*this)(x,y,z,0) = (T)(3.240479*X - 1.537150*Y - 0.498535*Z); + (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z); + (*this)(x,y,z,2) = (T)(0.055648*X - 0.204043*Y + 1.057311*Z); + } + } + return *this; + } + + //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space. +#define cimg_Labf(x) ((x)>=0.008856?(std::pow(x,1/3.0)):(7.787*(x)+16.0/116.0)) +#define cimg_Labfi(x) ((x)>=0.206893?((x)*(x)*(x)):(((x)-16.0/116.0)/7.787)) + + CImg& XYZtoLab() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, " + "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); + const double + Xn = 0.412453 + 0.357580 + 0.180423, + Yn = 0.212671 + 0.715160 + 0.072169, + Zn = 0.019334 + 0.119193 + 0.950227; + cimg_mapXYZ(*this,x,y,z) { + const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2); + const double + XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn, + fX = cimg_Labf(XXn), fY = cimg_Labf(YYn), fZ = cimg_Labf(ZZn); + (*this)(x,y,z,0) = (T)(116*fY-16); + (*this)(x,y,z,1) = (T)(500*(fX-fY)); + (*this)(x,y,z,2) = (T)(200*(fY-fZ)); + } + } + return *this; + } + + //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space. + CImg& LabtoXYZ() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, " + "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); + const double + Xn = 0.412453 + 0.357580 + 0.180423, + Yn = 0.212671 + 0.715160 + 0.072169, + Zn = 0.019334 + 0.119193 + 0.950227; + cimg_mapXYZ(*this,x,y,z) { + const T L = (*this)(x,y,z,0), a = (*this)(x,y,z,1), b = (*this)(x,y,z,2); + const double + cY = (L+16)/116.0, + Y = Yn*cimg_Labfi(cY), + pY = std::pow(Y/Yn,1.0/3), + cX = a/500+pY, + X = Xn*cX*cX*cX, + cZ = pY-b/200, + Z = Zn*cZ*cZ*cZ; + (*this)(x,y,z,0) = (T)(X); + (*this)(x,y,z,1) = (T)(Y); + (*this)(x,y,z,2) = (T)(Z); + } + } + return *this; + } + + //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space. + CImg& XYZtoxyY() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, " + "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2), sum = (X+Y+Z), nsum = sum>0?sum:1; + (*this)(x,y,z,0) = X/nsum; + (*this)(x,y,z,1) = Y/nsum; + (*this)(x,y,z,2) = Y; + } + } + return *this; + } + + //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space. + CImg& xyYtoXYZ() { + if (!is_empty()) { + if (dim!=3) throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, " + "should be a (x,y,Y) image (dim=3)",pixel_type(),dim); + cimg_mapXYZ(*this,x,y,z) { + const T px = (*this)(x,y,z,0), py = (*this)(x,y,z,1), Y = (*this)(x,y,z,2), ny = py>0?py:1; + (*this)(x,y,z,0) = (T)(px*Y/ny); + (*this)(x,y,z,1) = Y; + (*this)(x,y,z,2) = (T)((1-px-py)*Y/ny); + } + } + return *this; + } + + //! In-place version of get_RGBtoLab(). + CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); } + + //! In-place version of get_LabtoRGb(). + CImg& LabtoRGB() { return LabtoXYZ().XYZtoRGB(); } + + //! In-place version of get_RGBtoxyY(). + CImg& RGBtoxyY() { return RGBtoXYZ().XYZtoxyY(); } + + //! In-place version of get_xyYtoRGB(). + CImg& xyYtoRGB() { return xyYtoXYZ().XYZtoRGB(); } + + //! Convert a (R,G,B) image to a (H,S,V) one. + CImg get_RGBtoHSV() const { return CImg(*this).RGBtoHSV(); } + + //! Convert a (H,S,V) image to a (R,G,B) one. + CImg get_HSVtoRGB() const { return CImg(*this).HSVtoRGB(); } + + //! Convert a (R,G,B) image to a (Y,Cb,Cr) one. + CImg get_RGBtoYCbCr() const { return CImg(*this).RGBtoYCbCr(); } + + //! Convert a (Y,Cb,Cr) image to a (R,G,B) one. + CImg get_YCbCrtoRGB() const { return CImg(*this).YCbCrtoRGB(); } + + //! Convert a (R,G,B) image into a (Y,U,V) one. + CImg::type> get_RGBtoYUV() const { + typedef typename cimg::largest::type restype; + return CImg(*this).RGBtoYUV(); + } + + //! Convert a (Y,U,V) image into a (R,G,B) one. + CImg get_YUVtoRGB() const { return CImg(*this).YUVtoRGB(); } + + //! Convert a (R,G,B) image to a (X,Y,Z) one. + CImg::type> get_RGBtoXYZ() const { + typedef typename cimg::largest::type restype; + return CImg(*this).RGBtoXYZ(); + } + + //! Convert a (X,Y,Z) image to a (R,G,B) one. + CImg get_XYZtoRGB() const { return CImg(*this).XYZtoRGB(); } + + //! Convert a (X,Y,Z) image to a (L,a,b) one. + CImg get_XYZtoLab() const { return CImg(*this).XYZtoLab(); } + + //! Convert a (L,a,b) image to a (X,Y,Z) one. + CImg get_LabtoXYZ() const { return CImg(*this).LabtoXYZ(); } + + //! Convert a (X,Y,Z) image to a (x,y,Y) one. + CImg get_XYZtoxyY() const { return CImg(*this).XYZtoxyY(); } + + //! Convert a (x,y,Y) image to a (X,Y,Z) one. + CImg get_xyYtoXYZ() const { return CImg(*this).xyYtoXYZ(); } + + //! Convert a (R,G,B) image to a (L,a,b) one. + CImg get_RGBtoLab() const { return CImg(*this).RGBtoLab(); } + + //! Convert a (L,a,b) image to a (R,G,B) one. + CImg get_LabtoRGB() const { return CImg(*this).LabtoRGB(); } + + //! Convert a (R,G,B) image to a (x,y,Y) one. + CImg get_RGBtoxyY() const { return CImg(*this).RGBtoxyY(); } + + //! Convert a (x,y,Y) image to a (R,G,B) one. + CImg get_xyYtoRGB() const { return CImg(*this).xyYtoRGB(); } + + //@} + // + // + // + //! \name Drawing functions + //@{ + // + // + + // Should be used only by member functions. Not an user-friendly function. + // Pre-requisites : x0=0) { + if (opacity>=1) { + int off = whz-dx-1; + if (sizeof(T)!=1) cimg_mapV(*this,k) { + const T val = (T)(*(col++)*brightness); + for (int x=dx; x>=0; x--) *(ptrd++)=val; + ptrd+=off; + } else cimg_mapV(*this,k) { std::memset(ptrd,(int)(*(col++)*brightness),dx+1); ptrd+=whz; } + col-=dim; + } else { + int off = whz-dx-1; + cimg_mapV(*this,k) { + const T val = (T)(*(col++)*brightness); + for (int x=dx; x>=0; x--) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ptrd++; } + ptrd+=off; + } + col-=dim; + } + } + } + return *this; + } + + CImg& draw_scanline(const T *const color,const float opacity=1) { return draw_scanline(0,0,0,color,opacity,1.0f,true); } + + //! Draw a colored point in the instance image, at coordinates (\c x0,\c y0,\c z0). + /** + \param x0 = X-coordinate of the vector-valued pixel to plot. + \param y0 = Y-coordinate of the vector-valued pixel to plot. + \param z0 = Z-coordinate of the vector-valued pixel to plot. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_point(const int x0,const int y0,const int z0, + const T *const color,const float opacity=1) { + if (!is_empty()) { + if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",pixel_type()); + if (x0>=0 && y0>=0 && z0>=0 && x0=1) cimg_mapV(*this,k) { *ptrd = *(col++); ptrd+=whz; } + else cimg_mapV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } + } + } + return *this; + } + + //! Draw a colored point in the instance image, at coordinates (\c x0,\c y0). + /** + \param x0 = X-coordinate of the vector-valued pixel to plot. + \param y0 = Y-coordinate of the vector-valued pixel to plot. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_point(const int x0,const int y0,const T *const color,const float opacity=1) { + return draw_point(x0,y0,0,color,opacity); + } + + //! Draw a 2D colored line in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). + /** + \param x0 = X-coordinate of the starting point of the line. + \param y0 = Y-coordinate of the starting point of the line. + \param x1 = X-coordinate of the ending point of the line. + \param y1 = Y-coordinate of the ending point of the line. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param pattern = An integer whose bits describes the line pattern. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_line(const int x0,const int y0,const int x1,const int y1, + const T *const color,const unsigned int pattern=~0L,const float opacity=1) { + if (!is_empty()) { + if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",pixel_type()); + const T* col=color; + unsigned int hatch=1; + int nx0=x0, nx1=x1, ny0=y0, ny1=y1; + if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1); + if (nx1<0 || nx0>=dimx()) return *this; + if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; } + if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;} + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); + if (ny1<0 || ny0>=dimy()) return *this; + if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; } + if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;} + const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), whz = width*height*depth; + const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0; + float x = (float)nx0, y = (float)ny0; + if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) { + if (!(~pattern) || (~pattern && pattern&hatch)) { + T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); + cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; } + col-=dim; + } + x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); + } else { + const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f); + for (unsigned int t=0; t<=dmax; t++) { + if (!(~pattern) || (~pattern && pattern&hatch)) { + T* ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); + cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; } + col-=dim; + } + x+=px; y+=py; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); + } + } + } + return *this; + } + + //! Draw a 3D colored line in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1). + /** + \param x0 = X-coordinate of the starting point of the line. + \param y0 = Y-coordinate of the starting point of the line. + \param z0 = Z-coordinate of the starting point of the line. + \param x1 = X-coordinate of the ending point of the line. + \param y1 = Y-coordinate of the ending point of the line. + \param z1 = Z-coordinate of the ending point of the line. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param pattern = An integer whose bits describes the line pattern. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_line(const int x0,const int y0,const int z0,const int x1,const int y1,const int z1, + const T *const color,const unsigned int pattern=~0L,const float opacity=1) { + if (!is_empty()) { + if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",pixel_type()); + const T* col=color; + unsigned int hatch=1; + int nx0=x0, ny0=y0, nz0=z0, nx1=x1, ny1=y1, nz1=z1; + if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); + if (nx1<0 || nx0>=dimx()) return *this; + if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; nz0-=nx0*(nz1-nz0)/D; nx0=0; } + if (nx1>=dimx()) { const int d=nx1-dimx(), D=nx1-nx0; ny1+=d*(ny0-ny1)/D; nz1+=d*(nz0-nz1)/D; nx1=dimx()-1;} + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); + if (ny1<0 || ny0>=dimy()) return *this; + if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; nz0-=ny0*(nz1-nz0)/D; ny0=0; } + if (ny1>=dimy()) { const int d=ny1-dimy(), D=ny1-ny0; nx1+=d*(nx0-nx1)/D; nz1+=d*(nz0-nz1)/D; ny1=dimy()-1;} + if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); + if (nz1<0 || nz0>=dimz()) return *this; + if (nz0<0) { const int D=nz1-nz0; nx0-=nz0*(nx1-nx0)/D; ny0-=nz0*(ny1-ny0)/D; nz0=0; } + if (nz1>=dimz()) { const int d=nz1-dimz(), D=nz1-nz0; nx1+=d*(nx0-nx1)/D; ny1+=d*(ny0-ny1)/D; nz1=dimz()-1;} + const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),cimg::abs(ny1-ny0),nz1-nz0), whz = width*height*depth; + const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, pz = dmax?(nz1-nz0)/(float)dmax:0; + float x = (float)nx0, y = (float)ny0, z = (float)nz0; + if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) { + if (!(~pattern) || (~pattern && pattern&hatch)) { + T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0); + cimg_mapV(*this,k) { *ptrd=*(col++); ptrd+=whz; } + col-=dim; + } + x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); + } else { + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + for (unsigned int t=0; t<=dmax; t++) { + if (!(~pattern) || (~pattern && pattern&hatch)) { + T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0); + cimg_mapV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; } + col-=dim; + } + x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); + } + } + } + return *this; + } + + //! Draw a 2D textured line in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). + /** + \param x0 = X-coordinate of the starting point of the line. + \param y0 = Y-coordinate of the starting point of the line. + \param x1 = X-coordinate of the ending point of the line. + \param y1 = Y-coordinate of the ending point of the line. + \param texture = a colored texture image used to draw the line color. + \param tx0 = X-coordinate of the starting point of the texture. + \param ty0 = Y-coordinate of the starting point of the texture. + \param tx1 = X-coordinate of the ending point of the texture. + \param ty1 = Y-coordinate of the ending point of the texture. + \param opacity = opacity of the drawing. + \note Clipping is supported, but texture coordinates do not support clipping. + **/ + template CImg& draw_line(const int x0,const int y0,const int x1,const int y1, + const CImg& texture, + const int tx0,const int ty0,const int tx1,const int ty1, + const float opacity=1) { + if (!is_empty()) { + if (texture.is_empty() || texture.dim::draw_line() : specified texture (%u,%u,%u,%u,%p) has wrong dimensions.", + pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); + int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1; + if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); + if (nx1<0 || nx0>=dimx()) return *this; + if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; ntx0-=nx0*(ntx1-ntx0)/D; nty0-=nx0*(nty1-nty0)/D; nx0=0; } + if (nx1>=dimx()) { const int d=nx1-dimx(),D=nx1-nx0; ny1+=d*(ny0-ny1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; nx1=dimx()-1; } + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); + if (ny1<0 || ny0>=dimy()) return *this; + if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; ntx0-=ny0*(ntx1-ntx0)/D; nty0-=ny0*(nty1-nty0)/D; ny0=0; } + if (ny1>=dimy()) { const int d=ny1-dimy(),D=ny1-ny0; nx1+=d*(nx0-nx1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; ny1=dimy()-1; } + const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), + whz = width*height*depth, twhz = texture.width*texture.height*texture.depth; + const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, + tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0; + float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0; + if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) { + T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); + const t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0); + cimg_mapV(*this,k) { *ptrd = (T)(*ptrs); ptrd+=whz; ptrs+=twhz; } + x+=px; y+=py; tx+=tpx; ty+=tpy; + } else { + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + for (unsigned int tt=0; tt<=dmax; tt++) { + T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); + const t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0); + cimg_mapV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; } + x+=px; y+=py; tx+=tpx; ty+=tpy; + } + } + } + return *this; + } + + //! Draw a 2D colored arrow in the instance image, at coordinates (\c x0,\c y0)->(\c x1,\c y1). + /** + \param x0 = X-coordinate of the starting point of the arrow (tail). + \param y0 = Y-coordinate of the starting point of the arrow (tail). + \param x1 = X-coordinate of the ending point of the arrow (head). + \param y1 = Y-coordinate of the ending point of the arrow (head). + \param color = array of dimv() values of type \c T, defining the drawing color. + \param angle = aperture angle of the arrow head + \param length = length of the arrow head. If <0, described as a percentage of the arrow length. + \param pattern = An integer whose bits describes the line pattern. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1, + const T *const color, + const float angle=30,const float length=-10,const unsigned int pattern=~0L,const float opacity=1) { + if (!is_empty()) { + const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v, + deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f, + l = (length>=0)?length:-length*(float)std::sqrt(sq)/100; + if (sq>0) { + const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg); + const int + xl = x1+(int)(l*cl), yl = y1+(int)(l*sl), + xr = x1+(int)(l*cr), yr = y1+(int)(l*sr), + xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2; + draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); + } else draw_point(x0,y0,color,opacity); + } + return *this; + } + + //! Draw a sprite image in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0). + /** + \param sprite = sprite image. + \param x0 = X-coordinate of the sprite position in the instance image. + \param y0 = Y-coordinate of the sprite position in the instance image. + \param z0 = Z-coordinate of the sprite position in the instance image. + \param v0 = V-coordinate of the sprite position in the instance image. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + template CImg& draw_image(const CImg& sprite, + const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) { + if (!is_empty()) { + if (sprite.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); + const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); + const int + lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), + lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), + lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), + lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); + const t *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+ + (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0); + const unsigned int + offX = width-lX, soffX = sprite.width-lX, + offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), + offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ); + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); + if (lX>0 && lY>0 && lZ>0 && lV>0) + for (int v=0; v=1) for (int x=0; x=7.1 +#if ( !defined(_MSC_VER) || _MSC_VER>1300 ) + CImg& draw_image(const CImg& sprite,const int x0=0,const int y0=0,const int z0=0,const int v0=0,const float opacity=1) { + if (!is_empty()) { + if (sprite.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); + if (this==&sprite) return draw_image(CImg(sprite),x0,y0,z0,v0,opacity); + const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); + const int + lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), + lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), + lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), + lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); + const T *ptrs = sprite.ptr()-(bx?x0:0)-(by?y0*sprite.dimx():0)+(bz?z0*sprite.dimx()*sprite.dimy():0)+ + (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0); + const unsigned int + offX = width-lX, soffX = sprite.width-lX, + offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), + offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ), + slX = lX*sizeof(T); + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); + if (lX>0 && lY>0 && lZ>0 && lV>0) + for (int v=0; v=1) for (int y=0; y CImg& draw_image(const CImg& sprite,const CImg& tqmask, + const int x0=0,const int y0=0,const int z0=0,const int v0=0, + const tm tqmask_valmax=1,const float opacity=1) { + if (!is_empty()) { + if (sprite.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); + if (tqmask.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_image() : Specified tqmask image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,tqmask.data); + if ((void*)this==(void*)&sprite) return draw_image(CImg(sprite),tqmask,x0,y0,z0,v0); + if(tqmask.width!=sprite.width || tqmask.height!=sprite.height || tqmask.depth!=sprite.depth) + throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim); + const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); + const int + lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), + lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), + lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), + lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); + const int coff = -(bx?x0:0)-(by?y0*tqmask.dimx():0)-(bz?z0*tqmask.dimx()*tqmask.dimy():0)- + (bv?v0*tqmask.dimx()*tqmask.dimy()*tqmask.dimz():0), + ssize = tqmask.dimx()*tqmask.dimy()*tqmask.dimz(); + const ti *ptrs = sprite.ptr() + coff; + const tm *ptrm = tqmask.ptr() + coff; + const unsigned int + offX = width-lX, soffX = sprite.width-lX, + offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), + offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ); + T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); + if (lX>0 && lY>0 && lZ>0 && lV>0) + for (int v=0; v=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0), + lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0), + lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0), + lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0); + const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ); + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0); + if (lX>0 && lY>0 && lZ>0 && lV>0) + for (int v=0; v=1) { + if (sizeof(T)!=1) { for (int x=0; x::draw_rectangle : specified color is (null)",pixel_type()); + cimg_mapV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity); + return *this; + } + + //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). + /** + \param x0 = X-coordinate of the upper-left rectangle corner in the instance image. + \param y0 = Y-coordinate of the upper-left rectangle corner in the instance image. + \param x1 = X-coordinate of the lower-right rectangle corner in the instance image. + \param y1 = Y-coordinate of the lower-right rectangle corner in the instance image. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1, + const T *const color,const float opacity=1) { + draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity); + return *this; + } + + //! Draw a 2D filled colored triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing (<1) + \param brightness = brightness of the drawing (in [0,1]) + \note Clipping is supported. + **/ + CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const T *const color, + const float opacity=1, + const float brightness=1) { + draw_scanline(color,opacity); + int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1); + float xleft = (float)nx0, xright = xleft, pleft = (p1dimy()?height:ny1; + for (int y=ny0<0?0:ny0; y=dimy()?height-1:ny2; + for (int yy=ny1<0?0:ny1; yy<=yb; yy++) { + draw_scanline((int)xleft,(int)xright,yy,color,opacity,brightness); + xleft+=pleft; xright+=pright; + } + return *this; + } + + //! Draw a 2D Gouraud-filled triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param color = array of dimv() values of type \c T, defining the global drawing color. + \param c0 = brightness of the first corner. + \param c1 = brightness of the second corner. + \param c2 = brightness of the third corner. + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const T *const color, + const float c0,const float c1,const float c2, + const float opacity=1) { + if (!is_empty()) { + int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,whz=width*height*depth; + float nc0=c0,nc1=c1,nc2=c2; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), + cp1 = (ny1-ny0)?(nc1-nc0)/(float)(ny1-ny0):0, + cp2 = (ny2-ny0)?(nc2-nc0)/(float)(ny2-ny0):0, + cp3 = (ny2-ny1)?(nc2-nc1)/(float)(ny2-ny1):0; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + float pleft,pright,cpleft,cpright,xleft=(float)nx0,xright=xleft,cleft=nc0,cright=cleft; + if (p1=0)?cleft:(cleft-xleft*cp); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + const T col = color[k]; + float c=ci; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*col); c+=cp; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + const T col = color[k]; + float c=ci; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*col+copacity*(*ptrd)); ptrd++; c+=cp; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; cleft+=cpleft; cright+=cpright; + } + + if (p1=dimy()?(height-1):ny2; + for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { + const int dx = (int)xright-(int)xleft; + const float + cp = dx?(cright-cleft)/dx:0, + ci = (xleft>=0)?cleft:(cleft-xleft*cp); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + const T col = color[k]; + float c=ci; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*col); c+=cp; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + const T col = color[k]; + float c=ci; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*col+copacity*(*ptrd)); ptrd++; c+=cp; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; cleft+=cpleft; cright+=cpright; + } + } + return *this; + } + + //! Draw a 2D phong-shaded triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param color = array of dimv() values of type \c T, defining the global drawing color. + \param light = light image. + \param lx0 = X-coordinate of the first corner in the light image. + \param ly0 = Y-coordinate of the first corner in the light image. + \param lx1 = X-coordinate of the second corner in the light image. + \param ly1 = Y-coordinate of the second corner in the light image. + \param lx2 = X-coordinate of the third corner in the light image. + \param ly2 = Y-coordinate of the third corner in the light image. + \param opacity = opacity of the drawing. + \note Clipping is supported, but texture coordinates do not support clipping. + **/ + template CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const T *const color, + const CImg& light, + const int lx0,const int ly0, + const int lx1,const int ly1, + const int lx2,const int ly2, + const float opacity=1.0f) { + if (!is_empty()) { + if (light.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.", + pixel_type(),light.width,light.height,light.depth,light.dim,light.data); + int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,nlx0=lx0,nly0=ly0,nlx1=lx1,nly1=ly1,nlx2=lx2,nly2=ly2,whz=width*height*depth; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), + lpx1 = (ny1-ny0)?(nlx1-nlx0)/(float)(ny1-ny0):0, + lpy1 = (ny1-ny0)?(nly1-nly0)/(float)(ny1-ny0):0, + lpx2 = (ny2-ny0)?(nlx2-nlx0)/(float)(ny2-ny0):0, + lpy2 = (ny2-ny0)?(nly2-nly0)/(float)(ny2-ny0):0, + lpx3 = (ny2-ny1)?(nlx2-nlx1)/(float)(ny2-ny1):0, + lpy3 = (ny2-ny1)?(nly2-nly1)/(float)(ny2-ny1):0; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + float pleft,pright,lpxleft,lpyleft,lpxright,lpyright, + xleft=(float)nx0,xright=xleft,lxleft=(float)nlx0,lyleft=(float)nly0,lxright=lxleft,lyright=lyleft; + if (p1=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), + lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*color[k]); lx+=lpx; ly+=lpy; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*color[k]+copacity*(*ptrd)); ptrd++; lx+=lpx; ly+=lpy; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; + } + + if (p1=dimy()?(height-1):ny2; + for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { + const int dx = (int)xright-(int)xleft; + const float + lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, + lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, + lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), + lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*color[k]); lx+=lpx; ly+=lpy; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*color[k]+copacity*(*ptrd)); ptrd++; lx+=lpx; ly+=lpy; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; + } + } + return *this; + } + + //! Draw a 2D textured triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param texture = texture image used to fill the triangle. + \param tx0 = X-coordinate of the first corner in the texture image. + \param ty0 = Y-coordinate of the first corner in the texture image. + \param tx1 = X-coordinate of the second corner in the texture image. + \param ty1 = Y-coordinate of the second corner in the texture image. + \param tx2 = X-coordinate of the third corner in the texture image. + \param ty2 = Y-coordinate of the third corner in the texture image. + \param opacity = opacity of the drawing. + \param brightness = brightness of the drawing. + \note Clipping is supported, but texture coordinates do not support clipping. + **/ + template CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const CImg& texture, + const int tx0,const int ty0, + const int tx1,const int ty1, + const int tx2,const int ty2, + const float opacity=1.0f, const float brightness=1.0f) { + if (!is_empty()) { + if (texture.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", + pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); + int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2,whz=width*height*depth; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), + tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, + tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, + tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, + tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, + tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, + tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + float pleft,pright,tpxleft,tpyleft,tpxright,tpyright, + xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft; + if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; + } + + if (p1=dimy()?(height-1):ny2; + for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { + const int dx = (int)xright-(int)xleft; + const float + tpx = dx?((int)txright-(int)txleft)/(float)dx:0, + tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, + txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; + } + } + return *this; + } + + //! Draw a 2D textured triangle with Gouraud-Shading in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param texture = texture image used to fill the triangle. + \param tx0 = X-coordinate of the first corner in the texture image. + \param ty0 = Y-coordinate of the first corner in the texture image. + \param tx1 = X-coordinate of the second corner in the texture image. + \param ty1 = Y-coordinate of the second corner in the texture image. + \param tx2 = X-coordinate of the third corner in the texture image. + \param ty2 = Y-coordinate of the third corner in the texture image. + \param c0 = brightness value of the first corner. + \param c1 = brightness value of the second corner. + \param c2 = brightness value of the third corner. + \param opacity = opacity of the drawing. + \note Clipping is supported, but texture coordinates do not support clipping. + **/ + template CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const CImg& texture, + const int tx0,const int ty0, + const int tx1,const int ty1, + const int tx2,const int ty2, + const float c0,const float c1,const float c2, + const float opacity=1) { + if (!is_empty()) { + if (texture.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", + pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); + int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2,whz=width*height*depth; + float nc0=c0,nc1=c1,nc2=c2; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), + tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, + tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, + tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, + tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, + tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, + tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0, + cp1 = (ny1-ny0)?(nc1-nc0)/(float)(ny1-ny0):0, + cp2 = (ny2-ny0)?(nc2-nc0)/(float)(ny2-ny0):0, + cp3 = (ny2-ny1)?(nc2-nc1)/(float)(ny2-ny1):0; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,cpleft,cpright, + xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft,cleft=nc0,cright=cleft; + if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), + ci = (xleft>=0)?cleft:(cleft-xleft*cp); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi, c=ci; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; c+=cp; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi, c=ci; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; c+=cp; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; cleft+=cpleft; cright+=cpright; + } + + if (p1=dimy()?(height-1):ny2; + for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { + const int dx = (int)xright-(int)xleft; + const float + tpx = dx?((int)txright-(int)txleft)/(float)dx:0, + tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, + cp = dx?(cright-cleft)/dx:0, + txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), + ci = (xleft>=0)?cleft:(cleft-xleft*cp); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi, c=ci; + for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; c+=cp; } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi, c=ci; + for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; c+=ci; } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; cleft+=cpleft; cright+=cpright; + } + } + return *this; + } + + //! Draw a phong-shaded 2D textured triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). + /** + \param x0 = X-coordinate of the first corner in the instance image. + \param y0 = Y-coordinate of the first corner in the instance image. + \param x1 = X-coordinate of the second corner in the instance image. + \param y1 = Y-coordinate of the second corner in the instance image. + \param x2 = X-coordinate of the third corner in the instance image. + \param y2 = Y-coordinate of the third corner in the instance image. + \param texture = texture image used to fill the triangle. + \param tx0 = X-coordinate of the first corner in the texture image. + \param ty0 = Y-coordinate of the first corner in the texture image. + \param tx1 = X-coordinate of the second corner in the texture image. + \param ty1 = Y-coordinate of the second corner in the texture image. + \param tx2 = X-coordinate of the third corner in the texture image. + \param ty2 = Y-coordinate of the third corner in the texture image. + \param light = light image. + \param lx0 = X-coordinate of the first corner in the light image. + \param ly0 = Y-coordinate of the first corner in the light image. + \param lx1 = X-coordinate of the second corner in the light image. + \param ly1 = Y-coordinate of the second corner in the light image. + \param lx2 = X-coordinate of the third corner in the light image. + \param ly2 = Y-coordinate of the third corner in the light image. + \param opacity = opacity of the drawing. + \note Clipping is supported, but texture coordinates do not support clipping. + **/ + template CImg& draw_triangle(const int x0,const int y0, + const int x1,const int y1, + const int x2,const int y2, + const CImg& texture, + const int tx0,const int ty0, + const int tx1,const int ty1, + const int tx2,const int ty2, + const CImg& light, + const int lx0,const int ly0, + const int lx1,const int ly1, + const int lx2,const int ly2, + const float opacity=1.0f) { + if (!is_empty()) { + if (texture.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", + pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); + if (light.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light (%u,%u,%u,%u,%p) is empty.", + pixel_type(),light.width,light.height,light.depth,light.dim,light.data); + int + nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2, + ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2, + nlx0=lx0,nly0=ly0,nlx1=lx1,nly1=ly1,nlx2=lx2,nly2=ly2, + whz=width*height*depth; + if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1); + if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2); + if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2); + if (ny0>=dimy() || ny2<0) return *this; + const float + p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), + p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), + p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), + tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, + tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, + tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, + tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, + tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, + tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0, + lpx1 = (ny1-ny0)?(nlx1-nlx0)/(float)(ny1-ny0):0, + lpy1 = (ny1-ny0)?(nly1-nly0)/(float)(ny1-ny0):0, + lpx2 = (ny2-ny0)?(nlx2-nlx0)/(float)(ny2-ny0):0, + lpy2 = (ny2-ny0)?(nly2-nly0)/(float)(ny2-ny0):0, + lpx3 = (ny2-ny1)?(nlx2-nlx1)/(float)(ny2-ny1):0, + lpy3 = (ny2-ny1)?(nly2-nly1)/(float)(ny2-ny1):0; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,lpxleft,lpyleft,lpxright,lpyright, + xleft=(float)nx0,xright=xleft, + txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft, + lxleft=(float)nlx0,lyleft=(float)nly0,lxright=lxleft,lyright=lyleft; + if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), + lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, + lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, + lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), + lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi, lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { + *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)); + tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; + } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi, lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { + *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; + tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; + } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; + txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; + lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; + } + + if (p1=dimy()?(height-1):ny2; + for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { + const int dx = (int)xright-(int)xleft; + const float + tpx = dx?((int)txright-(int)txleft)/(float)dx:0, + tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, + txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), + tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), + lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, + lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, + lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), + lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); + const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_mapV(*this,k) { + float tx=txi, ty=tyi, lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { + *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)); + tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; + } + ptrd+=offx; + } else cimg_mapV(*this,k) { + float tx=txi, ty=tyi, lx=lxi, ly=lyi; + for (int x=xmin; x<=xmax; x++) { + *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; + tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; + } + ptrd+=offx; + } + } + xleft+=pleft; xright+=pright; + txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; + lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; + } + } + return *this; + } + + + //! Draw an ellipse on the instance image + /** + \param x0 = X-coordinate of the ellipse center. + \param y0 = Y-coordinate of the ellipse center. + \param r1 = First radius of the ellipse. + \param r2 = Second radius of the ellipse. + \param ru = X-coordinate of the orientation vector related to the first radius. + \param rv = Y-coordinate of the orientation vector related to the first radius. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. + \param opacity = opacity of the drawing. + **/ + CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv, + const T *const color,const unsigned int pattern=0L, const float opacity=1) { + if (!is_empty()) { + draw_scanline(color,opacity); + if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",pixel_type()); + unsigned int hatch=1; + const float + nr1 = cimg::abs(r1), nr2 = cimg::abs(r2), + norm = (float)std::sqrt(ru*ru+rv*rv), + u = norm>0?ru/norm:1, + v = norm>0?rv/norm:0, + rmax = cimg::max(nr1,nr2), + l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2), + l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2), + a = l1*u*u + l2*v*v, + b = u*v*(l1-l2), + c = l1*v*v + l2*u*u; + const int + yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)), + ymin = (y0-yb<0)?0:(y0-yb), + ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb); + int oxmin=0, oxmax=0; + bool first_line = true; + for (int y=ymin; y<=ymax; y++) { + const float + Y = (float)(y-y0), + delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax), + sdelta = (float)((delta>0?std::sqrt(delta):0)), + fxmin = x0-(b*Y+sdelta)/a, + fxmax = x0-(b*Y-sdelta)/a; + const int xmin = (int)fxmin, xmax = (int)fxmax; + if (!pattern) draw_scanline(xmin,xmax,y,color,opacity); + else { + if (!(~pattern) || (~pattern && pattern&hatch)) { + if (first_line) { draw_scanline(xmin,xmax,y,color,opacity); first_line = false; } + else { + if (xmin>(sizeof(unsigned int)*8-1)); + } + } + return *this; + } + + //! Draw an ellipse on the instance image + /** + \param x0 = X-coordinate of the ellipse center. + \param y0 = Y-coordinate of the ellipse center. + \param tensor = Diffusion tensor describing the ellipse. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. + \param opacity = opacity of the drawing. + **/ + template CImg& draw_ellipse(const int x0,const int y0,const CImg &tensor, + const T *color,const unsigned int pattern=0L,const float opacity=1) { + CImgl eig = tensor.get_symeigen(); + const CImg &val = eig[0], &vec = eig[1]; + return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,pattern,opacity); + } + + //! Draw a circle on the instance image + /** + \param x0 = X-coordinate of the circle center. + \param y0 = Y-coordinate of the circle center. + \param r = radius of the circle. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param pattern = If zero, the circle is filled, else pattern is an integer whose bits describe the outline pattern. + \param opacity = opacity of the drawing. + **/ + CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const unsigned int pattern=0L,const float opacity=1) { + return draw_ellipse(x0,y0,r,r,1,0,color,pattern,opacity); + } + + //! Draw a text into the instance image. + /** + \param text = a C-string containing the text to display. + \param x0 = X-coordinate of the text in the instance image. + \param y0 = Y-coordinate of the text in the instance image. + \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (NULL means 'transparent'). + \param bgcolor = an array of dimv() values of type \c T, defining the background color (NULL means 'transparent'). + \param font = List of font characters used for the drawing. + \param opacity = opacity of the drawing. + \note Clipping is supported. + \see get_font(). + **/ + template CImg& draw_text(const char *const text, + const int x0,const int y0, + const T *const fgcolor,const T *const bgcolor, + const CImgl& font,const float opacity=1) { + if (!text) + throw CImgArgumentException("CImg<%s>::draw_text() : Specified input string is (null).",pixel_type()); + if (font.is_empty()) + throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.", + pixel_type(),font.size,font.data); + + if (is_empty()) { + // If needed, pre-compute needed size of the image + int x=0, y=0, w=0; + for (int i=0; iw) w=x; x=0; break; + case '\t': x+=4*font[' '].width; break; + default: if (cw) w=x; + y+=font[' '].height; + } + assign(x0+w,y0+y,1,font[' '].dim,0); + if (bgcolor) cimg_mapV(*this,k) get_shared_channel(k).fill(bgcolor[k]); + } + + int x=x0, y=y0; + CImg letter; + for (int i=0; i=512) draw_image(letter,tqmask,x,y,0,0,(T)1,opacity); else draw_image(letter,x,y,0,0,opacity); + x+=letter.width; + } + break; + } + } + return *this; + } + + //! Draw a text into the instance image. + /** + \param text = a C-string containing the text to display. + \param x0 = X-coordinate of the text in the instance image. + \param y0 = Y-coordinate of the text in the instance image. + \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (NULL means 'transparent'). + \param bgcolor = an array of dimv() values of type \c T, defining the background color (NULL means 'transparent'). + \param font_size = Height of the desired font (11,13,24,38 or 57) + \param opacity = opacity of the drawing. + \note Clipping is supported. + \see get_font(). + **/ + CImg& draw_text(const char *const text, + const int x0,const int y0, + const T *const fgcolor,const T *const bgcolor=0, + const unsigned int font_size=11,const float opacity=1.0f) { + return draw_text(text,x0,y0,fgcolor,bgcolor,CImgl::get_font(font_size),opacity); + } + + + //! Draw a text into the instance image. + /** + \param x0 = X-coordinate of the text in the instance image. + \param y0 = Y-coordinate of the text in the instance image. + \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (NULL means 'transparent'). + \param bgcolor = an array of dimv() values of type \c T, defining the background color (NULL means 'transparent'). + \param opacity = opacity of the drawing. + \param format = a 'printf'-style format, followed by arguments. + \note Clipping is supported. + **/ + CImg& draw_text(const int x0,const int y0, + const T *const fgcolor,const T *const bgcolor, const unsigned int font_size, + const float opacity,const char *format,...) { + char tmp[2048]; + std::va_list ap; + va_start(ap,format); + std::vsprintf(tmp,format,ap); + va_end(ap); + return draw_text(tmp,x0,y0,fgcolor,bgcolor,font_size,opacity); + } + + template CImg& draw_text(const int x0,const int y0, + const T *const fgcolor,const T *const bgcolor, + const CImgl& font, const float opacity, const char *format,...) { + char tmp[2048]; + std::va_list ap; + va_start(ap,format); + std::vsprintf(tmp,format,ap); + va_end(ap); + return draw_text(tmp,x0,y0,fgcolor,bgcolor,font,opacity); + } + + + //! Draw a vector field in the instance image. + /** + \param flow = a 2d image of 2d vectors used as input data. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param sampling = length (in pixels) between each arrow. + \param factor = length factor of each arrow (if <0, computed as a percentage of the maximum length). + \param quiver_type = type of plot. Can be 0 (arrows) or 1 (segments). + \param opacity = opacity of the drawing. + \note Clipping is supported. + **/ + template + CImg& draw_quiver(const CImg& flow,const T *const color,const unsigned int sampling=25,const float factor=-20, + const int quiver_type=0,const float opacity=1) { + if (!is_empty()) { + if (flow.is_empty() || flow.dim!=2) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.", + pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data); + if (!color) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color is (null)", + pixel_type()); + if (sampling<=0) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g", + pixel_type(),sampling); + + float vmax,fact; + if (factor<=0) { + CImgStats st(flow.get_norm_pointwise(2),false); + vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max)); + fact = -factor; + } else { fact = factor; vmax = 1; } + + for (unsigned int y=sampling/2; y + CImg& draw_quiver(const CImg& flow,const CImg& color,const unsigned int sampling=25,const float factor=-20, + const int quiver_type=0,const float opacity=1) { + if (!is_empty()) { + if (flow.is_empty() || flow.dim!=2) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.", + pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data); + if (color.is_empty() || color.width!=flow.width || color.height!=flow.height) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color (%u,%u,%u,%u,%p) has wrong dimensions.", + pixel_type(),color.width,color.height,color.depth,color.dim,color.data); + if (sampling<=0) + throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",pixel_type(),sampling); + + float vmax,fact; + if (factor<=0) { + CImgStats st(flow.get_norm_pointwise(2),false); + vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max)); + fact = -factor; + } else { fact = factor; vmax = 1; } + + for (unsigned int y=sampling/2; y + CImg& draw_graph(const CImg& data,const T *const color,const unsigned int gtype=0, + const double ymin=0,const double ymax=0,const float opacity=1) { + if (!is_empty()) { + if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",pixel_type()); + T *color1 = new T[dim], *color2 = new T[dim]; + cimg_mapV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); } + CImgStats st; + if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; } + if (st.min==st.max) { st.min--; st.max++; } + const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min; + const int Y0 = (int)(-cb/ca); + int pY=0; + cimg_mapoff(data,off) { + const int Y = (int)((data[off]-cb)/ca); + switch (gtype) { + case 0: // plot with segments + if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity); + break; + case 1: { // plot with bars + const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1; + draw_rectangle(X,(int)Y0,nX,Y,color1,opacity); + draw_line(X,Y,X,(int)Y0,color2,~0L,opacity); + draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity); + draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity); + draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity); + } break; + } + pY=Y; + } + if (gtype==2) { // plot with cubic interpolation + const CImg ndata = data.get_shared_points(0,data.size()-1); + cimg_mapX(*this,x) { + const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca); + if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity); + pY=Y; + } + } + delete[] color1; delete[] color2; + } + return *this; + } + + //! Draw a labelled horizontal axis on the instance image. + /** + \param x0 = lower bound of the x-range. + \param x1 = upper bound of the x-range. + \param y = Y-coordinate of the horizontal axis in the instance image. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param precision = precision of the labels. + \param opacity = opacity of the drawing. + \note if \c precision==0, precision of the labels is automatically computed. + \see draw_graph(), draw_axeY(), draw_axeXY(). + **/ + CImg& draw_axeX(const double x0,const double x1,const int y,const T *const color, + const double precision=0,const float opacity=1) { + if (x0==x1) return *this; + if (x0(dimx()/40)) nprecision*=2; + } + const double xmin=x0(dimy()/40)) nprecision*=2; + } + const double ymin=y00) draw_text(txt,xt,yi-5,color,0,11,opacity); + else draw_text(txt,x+3,yi-5,color,0,11,opacity); + } + return *this; + } + + //! Draw a labelled coordinate system (X,Y) on the instance image. + /** + \param x0 = lower bound of the x-range. + \param x1 = upper bound of the x-range. + \param y0 = lower bound of the y-range. + \param y1 = upper bound of the y-range. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param precisionx = precision of the labels along the X-axis. + \param precisiony = precision of the labels along the Y-axis. + \param opacity = opacity of the drawing. + \note if precision==0, precision of the labels along the specified axix is automatically computed. + \see draw_graph(), draw_axeX(), draw_axeY(). + **/ + CImg& draw_axeXY(const double x0,const double x1,const double y0,const double y1,const T *const color, + const double precisionx=0,const double precisiony=0,const float opacity=1) { + if (x0*x1<=0) { + const int xz = (int)(-x0*(width-1)/(x1-x0)); + if (xz>=0 && xz=0 && yz::draw_fill() + template struct _draw_fill { + const T1 *const color; + const float sigma,opacity; + const CImg value; + CImg region; + + _draw_fill(const CImg& img,const int x,const int y,const int z, + const T *const pcolor,const float psigma,const float popacity): + color(pcolor),sigma(psigma),opacity(popacity), + value(img.get_vector(x,y,z)), region(CImg(img.width,img.height,img.depth,1,(T2)false)) { + } + + _draw_fill& operator=(const _draw_fill& d) { + color = d.color; + sigma = d.sigma; + opacity = d.opacity; + value = d.value; + region = d.region; + return *this; + } + + bool comp(const CImg& A,const CImg& B) const { + bool res=true; + const T *pA=A.data+A.size(); + for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) ); + return res; + } + + void fill(CImg& img,const int x,const int y,const int z) { + if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return; + if (!region(x,y,z) && comp(value,img.get_vector(x,y,z))) { + const T *col=color; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + int xmin,xmax; + if (opacity>=1) cimg_mapV(img,k) img(x,y,z,k)=*(col++); + else cimg_mapV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k)); + col-=img.dim; + region(x,y,z) = (T2)true; + for (xmin=x-1; xmin>=0 && comp(value,img.get_vector(xmin,y,z)); xmin--) { + if (opacity>=1) cimg_mapV(img,k) img(xmin,y,z,k) = *(col++); + else cimg_mapV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k)); + col-=img.dim; + region(xmin,y,z)=(T2)true; + } + for (xmax=x+1; xmax=1) cimg_mapV(img,k) img(xmax,y,z,k) = *(col++); + else cimg_mapV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k)); + col-=img.dim; + region(xmax,y,z)=(T2)true; + } + xmin++; xmax--; + for (; xmin<=xmax; xmin++) { + fill(img,xmin,y-1,z); + fill(img,xmin,y+1,z); + fill(img,xmin,y,z-1); + fill(img,xmin,y,z+1); + } + } + } + }; + + //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image. + /** + \param x = X-coordinate of the starting point of the region to fill. + \param y = Y-coordinate of the starting point of the region to fill. + \param z = Z-coordinate of the starting point of the region to fill. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param region = image that will contain the tqmask of the filled region tqmask, as an output. + \param sigma = tolerance concerning neighborhood values. + \param opacity = opacity of the drawing. + + \return \p region is initialized with the binary tqmask of the filled region. + **/ + template CImg& draw_fill(const int x,const int y,const int z, + const T *const color, CImg& region,const float sigma=0, + const float opacity=1) { + _draw_fill F(*this,x,y,z,color,sigma,opacity); + F.fill(*this,x,y,z); + region = F.region; + return *this; + } + + //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image. + /** + \param x = X-coordinate of the starting point of the region to fill. + \param y = Y-coordinate of the starting point of the region to fill. + \param z = Z-coordinate of the starting point of the region to fill. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param sigma = tolerance concerning neighborhood values. + \param opacity = opacity of the drawing. + **/ + CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) { + CImg tmp; + return draw_fill(x,y,z,color,tmp,sigma,opacity); + } + + //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image. + /** + \param x = X-coordinate of the starting point of the region to fill. + \param y = Y-coordinate of the starting point of the region to fill. + \param color = an array of dimv() values of type \c T, defining the drawing color. + \param sigma = tolerance concerning neighborhood values. + \param opacity = opacity of the drawing. + **/ + CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) { + CImg tmp; + return draw_fill(x,y,0,color,tmp,sigma,opacity); + } + + //! Draw a plasma square in the instance image. + /** + \param x0 = X-coordinate of the upper-left corner of the plasma. + \param y0 = Y-coordinate of the upper-left corner of the plasma. + \param x1 = X-coordinate of the lower-right corner of the plasma. + \param y1 = Y-coordinate of the lower-right corner of the plasma. + \param alpha = Alpha-parameter of the plasma. + \param beta = Beta-parameter of the plasma. + \param opacity = opacity of the drawing. + **/ + CImg& draw_plasma(const int x0, const int y0, const int x1, const int y1, + const double alpha=1.0, const double beta=1.0, const float opacity=1) { + if (!is_empty()) { + int nx0=x0,nx1=x1,ny0=y0,ny1=y1; + if (nx1=dimx()) nx1=width-1; + if (ny0<0) ny0=0; + if (ny1>=dimy()) ny1=height-1; + const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0); + const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta; + cimg_mapV(*this,k) { + if (opacity>=1) { + (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))); + (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))); + (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))); + (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))); + (*this)(xc,yc,0,k) = (T)(0.25*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) + + (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand()); + } else { + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + (*this)(xc,ny0,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))*nopacity + copacity*(*this)(xc,ny0,0,k)); + (*this)(xc,ny1,0,k) = (T)(0.5*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(xc,ny1,0,k)); + (*this)(nx0,yc,0,k) = (T)(0.5*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))*nopacity + copacity*(*this)(nx0,yc,0,k)); + (*this)(nx1,yc,0,k) = (T)(0.5*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(nx1,yc,0,k)); + (*this)(xc,yc,0,k) = (T)(0.25*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) + + (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity + + copacity*(*this)(xc,yc,0,k)); + } + } + if (xc!=nx0 || yc!=ny0) { + draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity); + draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity); + draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity); + draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity); + } + } + return *this; + } + + //! Draw a plasma in the instance image. + /** + \param alpha = Alpha-parameter of the plasma. + \param beta = Beta-parameter of the plasma. + \param opacity = opacity of the drawing. + **/ + CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) { + return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity); + } + + //! Draw a 1D gaussian function in the instance image. + /** + \param xc = X-coordinate of the gaussian center. + \param sigma = Standard variation of the gaussian distribution. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + **/ + CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) { + if (!is_empty()) { + if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type()); + const double sigma2 = 2*sigma*sigma; + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + const unsigned int whz = width*height*depth; + const T *col = color; + cimg_mapX(*this,x) { + const float dx = (x-xc); + const double val = std::exp( -dx*dx/sigma2 ); + T *ptrd = ptr(x,0,0,0); + if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } + else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } + col-=dim; + } + } + return *this; + } + + //! Draw an anisotropic 2D gaussian function in the instance image. + /** + \param xc = X-coordinate of the gaussian center. + \param yc = Y-coordinate of the gaussian center. + \param tensor = 2x2 covariance matrix. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + **/ + template CImg& draw_gaussian(const float xc,const float yc,const CImg& tensor, + const T *const color,const float opacity=1) { + if (!is_empty()) { + if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1) + throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.", + pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data); + if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type()); + const CImg invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0); + const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1); + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + const unsigned int whz = width*height*depth; + const T *col = color; + float dy = -yc; + cimg_mapY(*this,y) { + float dx = -xc; + cimg_mapX(*this,x) { + const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy); + T *ptrd = ptr(x,y,0,0); + if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } + else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } + col-=dim; + dx++; + } + dy++; + } + } + return *this; + } + + //! Draw an isotropic 2D gaussian function in the instance image + /** + \param xc = X-coordinate of the gaussian center. + \param yc = Y-coordinate of the gaussian center. + \param sigma = standard variation of the gaussian distribution. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + **/ + CImg& draw_gaussian(const float xc,const float yc,const float sigma,const T *const color,const float opacity=1) { + return draw_gaussian(xc,yc,CImg::diagonal(sigma,sigma),color,opacity); + } + + //! Draw an anisotropic 3D gaussian function in the instance image. + /** + \param xc = X-coordinate of the gaussian center. + \param yc = Y-coordinate of the gaussian center. + \param zc = Z-coordinate of the gaussian center. + \param tensor = 3x3 covariance matrix. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + **/ + template CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg& tensor, + const T *const color,const float opacity=1) { + if (!is_empty()) { + if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1) + throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.", + pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data); + const CImg invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0); + const t a=invT(0,0), b=2*invT(1,0), c=2*invT(2,0), d=invT(1,1), e=2*invT(2,1), f=invT(2,2); + const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); + const unsigned int whz = width*height*depth; + const T *col = color; + cimg_mapXYZ(*this,x,y,z) { + const float dx = (x-xc), dy = (y-yc), dz = (z-zc); + const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz); + T *ptrd = ptr(x,y,z,0); + if (opacity>=1) cimg_mapV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } + else cimg_mapV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } + col-=dim; + } + } + return *this; + } + + //! Draw an isotropic 3D gaussian function in the instance image + /** + \param xc = X-coordinate of the gaussian center. + \param yc = Y-coordinate of the gaussian center. + \param zc = Z-coordinate of the gaussian center. + \param sigma = standard variation of the gaussian distribution. + \param color = array of dimv() values of type \c T, defining the drawing color. + \param opacity = opacity of the drawing. + **/ + CImg& draw_gaussian(const float xc,const float yc,const float zc, + const double sigma,const T *const color,const float opacity=1) { + return draw_gaussian(xc,yc,zc,CImg::diagonal(sigma,sigma,sigma),color,opacity); + } + + //! Draw a 3D object in the instance image + /** + \param X = X-coordinate of the 3d object position + \param Y = Y-coordinate of the 3d object position + \param Z = Z-coordinate of the 3d object position + \param points = Image N*3 describing 3D point coordinates + \param primitives = List of P primitives + \param colors = List of P color (or textures) + \param opacities = Image of P opacities + \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud) + \param double_sided = Tell if object faces have two sides or are oriented. + \param focale = length of the focale + \param lightx = X-coordinate of the light + \param lighty = Y-coordinate of the light + \param lightz = Z-coordinate of the light + \param ambiant_light = Brightness (between 0..1) of the ambiant light + **/ + template + CImg& draw_object3d(const float X, const float Y, const float Z, + const CImg& points, const CImgl& primitives, + const CImgl& colors, const CImg& opacities, + const unsigned int render_type=4, + const bool double_sided=false, const float focale=500, + const float lightx=0, const float lighty=0, const float lightz=-5000, + const float ambiant_light = 0.05f) { + + static CImg light_texture; + if (is_empty() || points.is_empty() || primitives.is_empty() || colors.is_empty()) return *this; + if (opacities.is_empty()) + return draw_object3d(X,Y,Z,points,primitives,colors,CImg(primitives.size,1,1,1,(to)1), + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + if (points.height<3) + return draw_object3d(X,Y,Z,points.get_resize(-100,3,1,1,0),primitives,colors,opacities, + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + if (colors.size::draw_object3d() : Not enough defined colors (size=%u) regarding primitives (size=%u).", + pixel_type(),colors.size,primitives.size); + if (opacities.width::draw_object3d() : Not enough defined opacities (size=%u) regarding primitives (size=%u).", + pixel_type(),opacities.width,primitives.size); + + // Create light texture + if (render_type==5) { + if (colors.size>primitives.size) light_texture = colors[primitives.size]; + else { + static float olightx=0, olighty=0, olightz=0, oambiant_light=0; + if (light_texture.is_empty() || lightx!=olightx || lighty!=olighty || lightz!=olightz || ambiant_light!=oambiant_light) { + light_texture.assign(512,512); + const float white[1]={ 1.0f }, + dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z, + nl = (float)std::sqrt(dlx*dlx+dly*dly+dlz*dlz), + nlx = light_texture.width/2*(1+dlx/nl), + nly = light_texture.height/2*(1+dly/nl); + (light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white)+=ambiant_light).cut(0.0f,1.0f); + olightx = lightx; olighty = lighty; olightz = lightz; oambiant_light = ambiant_light; + } + } + } + + // Compute 3D to 2D projection + CImg projected(points.width,2); + cimg_mapX(points,l) { + const float + x = (float)points(l,0), + y = (float)points(l,1), + z = (float)points(l,2); + const float projectedz = z + Z + focale; + projected(l,1) = Y + focale*y/projectedz; + projected(l,0) = X + focale*x/projectedz; + } + + // Compute and sort visible primitives + CImg visibles(primitives.size); + CImg zrange(primitives.size); + unsigned int nb_visibles = 0; + const float zmin = -focale; + { cimgl_map(primitives,l) { + const CImg& primitive = primitives[l]; + switch (primitive.size()) { + case 1: { // Point + const unsigned int i0 = (unsigned int)primitive(0); + const float z0 = (float)(Z+points(i0,2)); + if (z0>zmin) { + visibles(nb_visibles) = (unsigned int)l; + zrange(nb_visibles++) = z0; + } + } break; + case 2: // Line or textured line + case 6: { + const unsigned int + i0 = (unsigned int)primitive(0), + i1 = (unsigned int)primitive(1); + const float + z0 = (float)(Z+points(i0,2)), + z1 = (float)(Z+points(i1,2)); + if (z0>zmin && z1>zmin) { + visibles(nb_visibles) = (unsigned int)l; + zrange(nb_visibles++) = 0.5f*(z0+z1); + } + } break; + case 3: // Triangle or textured triangle + case 9: { + const unsigned int + i0 = (unsigned int)primitive(0), + i1 = (unsigned int)primitive(1), + i2 = (unsigned int)primitive(2); + const float + z0 = (float)(Z+points(i0,2)), + z1 = (float)(Z+points(i1,2)), + z2 = (float)(Z+points(i2,2)); + if (z0>zmin && z1>zmin && z2>zmin) { + const float + x0 = projected(i0,0), y0 = projected(i0,1), + x1 = projected(i1,0), y1 = projected(i1,1), + x2 = projected(i2,0), y2 = projected(i2,1), + dx1 = x1-x0, dy1 = y1-y0, dx2 = x2-x0, dy2 = y2-y0; + if (double_sided || dx1*dy2-dx2*dy1<0) { + visibles(nb_visibles) = (unsigned int)l; + zrange(nb_visibles++) = (z0+z1+z2)/3; + } + } + } break; + case 4: // Rectangle or textured rectangle + case 12: { + const unsigned int + i0 = (unsigned int)primitive(0), + i1 = (unsigned int)primitive(1), + i2 = (unsigned int)primitive(2), + i3 = (unsigned int)primitive(3); + const float + z0 = (float)(Z+points(i0,2)), + z1 = (float)(Z+points(i1,2)), + z2 = (float)(Z+points(i2,2)), + z3 = (float)(Z+points(i3,2)); + if (z0>zmin && z1>zmin && z2>zmin && z3>zmin) { + const float + x0 = projected(i0,0), y0 = projected(i0,1), + x1 = projected(i1,0), y1 = projected(i1,1), + x2 = projected(i2,0), y2 = projected(i2,1), + dx1 = x1-x0, dy1 = y1-y0, dx2 = x2-x0, dy2 = y2-y0; + if (double_sided || dx1*dy2-dx2*dy1<0) { + visibles(nb_visibles) = (unsigned int)l; + zrange(nb_visibles++) = (z0+z1+z2+z3)/4; + } + } + } break; + default: + throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,6,9 or 12)", + pixel_type(),l,primitive.size()); + }} + } + if (nb_visibles<=0) return *this; + CImg permutations; + CImg(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false); + + // Compute light properties + CImg lightprops; + switch (render_type) { + case 3: { // Flat Shading + lightprops.assign(nb_visibles); + cimg_mapX(lightprops,l) { + const CImg& primitive = primitives(visibles(permutations(l))); + const unsigned int psize = primitive.size(); + if (psize==3 || psize==4 || psize==9 || psize==12) { + const unsigned int + i0 = (unsigned int)primitive(0), + i1 = (unsigned int)primitive(1), + i2 = (unsigned int)primitive(2); + const float + x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2), + x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2), + x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2), + dx1 = x1-x0, dy1 = y1-y0, dz1 = z1-z0, + dx2 = x2-x0, dy2 = y2-y0, dz2 = z2-z0, + nx = dy1*dz2-dz1*dy2, + ny = dz1*dx2-dx1*dz2, + nz = dx1*dy2-dy1*dx2, + norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), + lx = X+(x0+x1+x2)/3-lightx, + ly = Y+(y0+y1+y2)/3-lighty, + lz = Z+(z0+z1+z2)/3-lightz, + nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz), + factor = (-lx*nx-ly*ny-lz*nz)/(norm*nl), + nfactor = double_sided?cimg::abs(factor):cimg::max(factor,0.0f); + lightprops[l] = cimg::min(nfactor+ambiant_light,1.0f); + } else lightprops[l] = 1.0f; + } + } break; + + case 4: // Gouraud Shading + case 5: { // Phong-Shading + CImg points_normals(points.width,3,1,1,0); + cimgl_map(primitives,l) { + const CImg& primitive = primitives[l]; + const unsigned int psize = primitive.size(); + const bool + triangle_flag = (psize==3) || (psize==9), + rectangle_flag = (psize==4) || (psize==12); + if (triangle_flag || rectangle_flag) { + const unsigned int + i0 = (unsigned int)primitive(0), + i1 = (unsigned int)primitive(1), + i2 = (unsigned int)primitive(2), + i3 = rectangle_flag?(unsigned int)primitive(3):0; + const float + x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2)+Z, + x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2)+Z, + x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2)+Z, + dx1 = x1-x0, dy1 = y1-y0, dz1 = z1-z0, + dx2 = x2-x0, dy2 = y2-y0, dz2 = z2-z0, + nx = dy1*dz2-dz1*dy2, + ny = dz1*dx2-dx1*dz2, + nz = dx1*dy2-dy1*dx2, + norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), + nnx = nx/norm, + nny = ny/norm, + nnz = nz/norm; + points_normals(i0,0)+=nnx; points_normals(i0,1)+=nny; points_normals(i0,2)+=nnz; + points_normals(i1,0)+=nnx; points_normals(i1,1)+=nny; points_normals(i1,2)+=nnz; + points_normals(i2,0)+=nnx; points_normals(i2,1)+=nny; points_normals(i2,2)+=nnz; + if (rectangle_flag) { + points_normals(i3,0)+=nnx; points_normals(i3,1)+=nny; points_normals(i3,2)+=nnz; + } + } + } + + if (render_type==4) { + lightprops.assign(points.width); + cimg_mapX(points,ll) { + const float + nx = points_normals(ll,0), + ny = points_normals(ll,1), + nz = points_normals(ll,2), + norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), + lx = (float)(X+points(ll,0)-lightx), + ly = (float)(Y+points(ll,1)-lighty), + lz = (float)(Z+points(ll,2)-lightz), + nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz), + factor = (-lx*nx-ly*ny-lz*nz)/(norm*nl), + nfactor = double_sided?cimg::abs(factor):cimg::max(factor,0.0f); + lightprops[ll] = cimg::min(nfactor+ambiant_light,1.0f); + } + } else { + lightprops.assign(points.width,2); + cimg_mapX(points,ll) { + const float + nx = points_normals(ll,0), + ny = points_normals(ll,1), + nz = points_normals(ll,2), + norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), + nnx = nx/norm, nny = ny/norm; + lightprops(ll,0) = (light_texture.width/2-1)*(1+nnx); + lightprops(ll,1) = (light_texture.height/2-1)*(1+nny); + } + } + } break; + } + + // Draw visible primitives + { for (unsigned int l=0; l& primitive = primitives[n_primitive]; + const CImg& color = colors[n_primitive]; + const float opacity = (float)opacities(n_primitive,0); + + switch (primitive.size()) { + case 1: { // colored point + const unsigned int n0 = (unsigned int)primitive[0]; + const int x0 = (int)projected(n0,0), y0 = (int)projected(n0,1); + draw_point(x0,y0,color.ptr(),opacity); + } break; + case 2: { // colored line + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1); + if (render_type) draw_line(x0,y0,x1,y1,color.ptr(),~0L,opacity); + else draw_point(x0,y0,color.ptr(),opacity).draw_point(x1,y1,color.ptr(),opacity); + } break; + case 6: { // textured line + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1], + tx0 = (unsigned int)primitive[2], + ty0 = (unsigned int)primitive[3], + tx1 = (unsigned int)primitive[4], + ty1 = (unsigned int)primitive[5]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1); + if (render_type) draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opacity); + else draw_point(x0,y0,color.get_vector(tx0,ty0).ptr(),opacity). + draw_point(x1,y1,color.get_vector(tx1,ty1).ptr(),opacity); + } break; + case 3: { // colored triangle + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1], + n2 = (unsigned int)primitive[2]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1), + x2 = (int)projected(n2,0), y2 = (int)projected(n2,1); + switch(render_type) { + case 0: + draw_point(x0,y0,color.ptr(),opacity).draw_point(x1,y1,color.ptr(),opacity).draw_point(x2,y2,color.ptr(),opacity); + break; + case 1: + draw_line(x0,y0,x1,y1,color.ptr(),~0L,opacity).draw_line(x0,y0,x2,y2,color.ptr(),~0L,opacity). + draw_line(x1,y1,x2,y2,color.ptr(),~0L,opacity); + break; + case 2: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opacity); + break; + case 3: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opacity,lightprops(l)); + break; + case 4: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprops(n0),lightprops(n1),lightprops(n2),opacity); + break; + case 5: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture, + (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1), + (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1), + (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1), + opacity); + break; + } + } break; + case 4: { // colored rectangle + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1], + n2 = (unsigned int)primitive[2], + n3 = (unsigned int)primitive[3]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1), + x2 = (int)projected(n2,0), y2 = (int)projected(n2,1), + x3 = (int)projected(n3,0), y3 = (int)projected(n3,1); + switch(render_type) { + case 0: + draw_point(x0,y0,color.ptr(),opacity).draw_point(x1,y1,color.ptr(),opacity). + draw_point(x2,y2,color.ptr(),opacity).draw_point(x3,y3,color.ptr(),opacity); + break; + case 1: + draw_line(x0,y0,x1,y1,color.ptr(),~0L,opacity).draw_line(x1,y1,x2,y2,color.ptr(),~0L,opacity). + draw_line(x2,y2,x3,y3,color.ptr(),~0L,opacity).draw_line(x3,y3,x0,y0,color.ptr(),~0L,opacity); + break; + case 2: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opacity).draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opacity); + break; + case 3: + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opacity,lightprops(l)). + draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opacity,lightprops(l)); + break; + case 4: { + const float + lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), + lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprop0,lightprop1,lightprop2,opacity). + draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),lightprop0,lightprop2,lightprop3,opacity); + } break; + case 5: { + const unsigned int + lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), + lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), + lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), + lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); + draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). + draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); + } break; + } + } break; + case 9: { // Textured triangle + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1], + n2 = (unsigned int)primitive[2], + tx0 = (unsigned int)primitive[3], + ty0 = (unsigned int)primitive[4], + tx1 = (unsigned int)primitive[5], + ty1 = (unsigned int)primitive[6], + tx2 = (unsigned int)primitive[7], + ty2 = (unsigned int)primitive[8]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1), + x2 = (int)projected(n2,0), y2 = (int)projected(n2,1); + switch(render_type) { + case 0: + draw_point(x0,y0,color.get_vector(tx0,ty0).ptr(),opacity). + draw_point(x1,y1,color.get_vector(tx1,ty1).ptr(),opacity). + draw_point(x2,y2,color.get_vector(tx2,ty2).ptr(),opacity); + break; + case 1: + draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opacity). + draw_line(x0,y0,x2,y2,color,tx0,ty0,tx2,ty2,opacity). + draw_line(x1,y1,x2,y2,color,tx1,ty1,tx2,ty2,opacity); + break; + case 2: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity); + break; + case 3: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)); + break; + case 4: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opacity); + break; + case 5: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, + (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1), + (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1), + (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1), + opacity); + break; + } + } break; + case 12: { // Textured rectangle + const unsigned int + n0 = (unsigned int)primitive[0], + n1 = (unsigned int)primitive[1], + n2 = (unsigned int)primitive[2], + n3 = (unsigned int)primitive[3], + tx0 = (unsigned int)primitive[4], + ty0 = (unsigned int)primitive[5], + tx1 = (unsigned int)primitive[6], + ty1 = (unsigned int)primitive[7], + tx2 = (unsigned int)primitive[8], + ty2 = (unsigned int)primitive[9], + tx3 = (unsigned int)primitive[10], + ty3 = (unsigned int)primitive[11]; + const int + x0 = (int)projected(n0,0), y0 = (int)projected(n0,1), + x1 = (int)projected(n1,0), y1 = (int)projected(n1,1), + x2 = (int)projected(n2,0), y2 = (int)projected(n2,1), + x3 = (int)projected(n3,0), y3 = (int)projected(n3,1); + switch(render_type) { + case 0: + draw_point(x0,y0,color.get_vector(tx0,ty0).ptr(),opacity). + draw_point(x1,y1,color.get_vector(tx1,ty1).ptr(),opacity). + draw_point(x2,y2,color.get_vector(tx2,ty2).ptr(),opacity). + draw_point(x3,y3,color.get_vector(tx3,ty3).ptr(),opacity); + break; + case 1: + draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opacity). + draw_line(x1,y1,x2,y2,color,tx1,ty1,tx2,ty2,opacity). + draw_line(x2,y2,x3,y3,color,tx2,ty2,tx3,ty3,opacity). + draw_line(x3,y3,x0,y0,color,tx3,ty3,tx0,ty0,opacity); + break; + case 2: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity). + draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity); + break; + case 3: + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)). + draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l)); + break; + case 4: { + const float + lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), + lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opacity). + draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opacity); + } break; + case 5: { + const unsigned int + lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), + lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), + lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), + lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); + draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). + draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); + } break; + } + } break; + } + } + } + return *this; + } + + //! Draw a 3D object in the instance image + template + CImg& draw_object3d(const float X, const float Y, const float Z, + const CImg& points, const CImgl& primitives, + const CImgl& colors, const CImgl& opacities, + const unsigned int render_type=4, + const bool double_sided=false, const float focale=500, + const float lightx=0, const float lighty=0, const float lightz=-5000, + const float ambiant_light = 0.05f) { + if (opacities.is_empty()) + return draw_object3d(X,Y,Z,points,primitives,colors,CImg(), + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + CImg nopacities(opacities.size); + to *ptrd = nopacities.ptr(); + cimg_mapoff(nopacities,l) if (opacities(l).size()) *(ptrd++) = opacities(l,0); + else + throw CImgArgumentException("CImg<%s>::draw_object3d() : Given opacities (size=%u) contains a null element at " + "position %u.",pixel_type(),opacities.size,l); + return draw_object3d(X,Y,Z,points,primitives,colors,nopacities, + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + } + + //! Draw a 3D object in the instance image + template + CImg& draw_object3d(const float X, const float Y, const float Z, + const CImgl& points, const CImgl& primitives, + const CImgl& colors, const CImg& opacities, + const unsigned int render_type=4, + const bool double_sided=false, const float focale=500, + const float lightx=0, const float lighty=0, const float lightz=-5000, + const float ambiant_light = 0.05f) { + if (points.is_empty()) return *this; + CImg npoints(points.size,3,1,1,0); + tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); + cimg_mapX(npoints,l) { + const CImg& point = points[l]; + const unsigned int siz = point.size(); + if (!siz) + throw CImgArgumentException("CImg<%s>::draw_object3d() : Given points (size=%u) contains a null element at " + "position %u.",pixel_type(),points.size,l); + *(ptrZ++) = (siz>2)?point(2):0; + *(ptrY++) = (siz>1)?point(1):0; + *(ptrX++) = point(0); + } + return draw_object3d(X,Y,Z,npoints,primitives,colors,opacities, + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + } + + //! Draw a 3D object in the instance image + template + CImg& draw_object3d(const float X, const float Y, const float Z, + const CImgl& points, const CImgl& primitives, + const CImgl& colors, const CImgl& opacities, + const unsigned int render_type=4, + const bool double_sided=false, const float focale=500, + const float lightx=0, const float lighty=0, const float lightz=-5000, + const float ambiant_light = 0.05f) { + if (opacities.is_empty()) + return draw_object3d(X,Y,Z,points,primitives,colors,CImg(), + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + CImg nopacities(opacities.size); + to *ptrd = nopacities.ptr(); + cimg_mapoff(nopacities,l) if (opacities(l).size()) *(ptrd++) = opacities(l,0); + else + throw CImgArgumentException("CImg<%s>::draw_object3d() : Given opacities (size=%u) contains a null element at " + "position %u.",pixel_type(),opacities.size,l); + return draw_object3d(X,Y,Z,points,primitives,colors,nopacities, + render_type,double_sided,focale,lightx,lighty,lightz,ambiant_light); + } + + //! Draw a 3D object in the instance image + template + CImg& draw_object3d(const float X, const float Y, const float Z, + const tp& points, const CImgl& primitives, + const CImgl& colors, + const unsigned int render_type=4, + const bool double_sided=false, const float focale=500, + const float lightx=0, const float lighty=0, const float lightz=-5000, + const float ambiant_light = 0.05f, const float opacity=1.0f) { + return draw_object3d(X,Y,Z,points,primitives,colors, + CImg(primitives.size,1,1,1,opacity), + render_type,double_sided,focale,lightx,lighty,lightz, + ambiant_light); + } + + //@} + //---------------------------- + // + //! \name Filtering functions + //@{ + //---------------------------- + + //! Return the correlation of the image by a tqmask. + /** + The result \p res of the correlation of an image \p img by a tqmask \p tqmask is defined to be : + + res(x,y,z) = sum_{i,j,k} img(x+i,y+j,z+k)*tqmask(i,j,k) + + \param tqmask = the correlation kernel. + \param cond = the border condition type (0=zero, 1=dirichlet) + \param weighted_correl = enable local normalization. + **/ + template CImg::type> + get_correlate(const CImg& tqmask,const unsigned int cond=1,const bool weighted_correl=false) const { + typedef typename cimg::largest::type restype; + typedef typename cimg::largest::type fftype; + typedef typename cimg::largest::type ftype; + + if (is_empty()) return CImg(); + if (tqmask.is_empty() || tqmask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_correlate() : Specified tqmask (%u,%u,%u,%u,%p) is not scalar.", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,tqmask.data); + CImg dest(*this,false); + if (cond && tqmask.width==tqmask.height && ((tqmask.depth==1 && tqmask.width<=5) || (tqmask.depth==tqmask.width && tqmask.width<=3))) { + // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 tqmask (with cond=1) + switch (tqmask.depth) { + case 3: { + CImg_3x3x3(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3x3(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum3x3x3(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3x3(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 2: { + CImg_2x2x2(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2x2(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum2x2x2(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2x2(I,tqmask)/std::sqrt(norm)):0; + } + } break; + default: + case 1: + switch (tqmask.width) { + case 5: { + CImg_5x5x1(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map5x5x1(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr5x5x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map5x5x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum5x5x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr5x5x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 4: { + CImg_4x4x1(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map4x4x1(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr4x4x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map4x4x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum4x4x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr4x4x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 3: { + CImg_3x3x1(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map3x3x1(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map3x3x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum3x3x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 2: { + CImg_2x2x1(I,T); + if (!weighted_correl) cimg_mapZV(*this,z,v) cimg_map2x2x1(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map2x2x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum2x2x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 1: dest = tqmask(0)*(*this); break; + } + } + } else { + // Generic version for other tqmasks + const int cxm=tqmask.width/2, cym=tqmask.height/2, czm=tqmask.depth/2, fxm=cxm-1+(tqmask.width%2), fym=cym-1+(tqmask.height%2), fzm=czm-1+(tqmask.depth%2); + cimg_mapV(*this,v) + if (!weighted_correl) { // Classical correlation + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + val+= pix3d(x+xm,y+ym,z+zm,v)*tqmask(cxm+xm,cym+ym,czm+zm,0); + dest(x,y,z,v)=(restype)val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + val+= pix3d(x+xm,y+ym,z+zm,v,0)*tqmask(cxm+xm,cym+ym,czm+zm,0); + dest(x,y,z,v)=(restype)val; + } + } else { // Weighted correlation + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0, norm = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { + const T cval = pix3d(x+xm,y+ym,z+zm,v); + val+= cval*tqmask(cxm+xm,cym+ym,czm+zm,0); + norm+=cval*cval; + } + dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt((double)norm)):0; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0, norm = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { + const T cval = pix3d(x+xm,y+ym,z+zm,v,0); + val+= cval*tqmask(cxm+xm,cym+ym,czm+zm,0); + norm+= cval*cval; + } + dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt((double)norm)):0; + } + } + } + return dest; + } + + + //! Correlate the image by a tqmask + /** + This is the in-place version of get_correlate. + \see get_correlate + **/ + template CImg& correlate(const CImg& tqmask,const unsigned int cond=1,const bool weighted_correl=false) { + return get_correlate(tqmask,cond,weighted_correl).swap(*this); + } + + //! Return the convolution of the image by a tqmask + /** + The result \p res of the convolution of an image \p img by a tqmask \p tqmask is defined to be : + + res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*tqmask(i,j,k) + + \param tqmask = the correlation kernel. + \param cond = the border condition type (0=zero, 1=dirichlet) + \param weighted_convol = enable local normalization. + **/ + template CImg::type> + get_convolve(const CImg& tqmask,const unsigned int cond=1,const bool weighted_convol=false) const { + typedef typename cimg::largest::type restype; + typedef typename cimg::largest::type fftype; + typedef typename cimg::largest::type ftype; + + if (is_empty()) return CImg(); + if (tqmask.is_empty() || tqmask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_convolve() : Specified tqmask (%u,%u,%u,%u,%p) is not scalar.", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,tqmask.data); + CImg dest(*this,false); + if (cond && tqmask.width==tqmask.height && ((tqmask.depth==1 && tqmask.width<=5) || (tqmask.depth==tqmask.width && tqmask.width<=3))) { // optimized version + switch (tqmask.depth) { + case 3: { + CImg_3x3x3(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv3x3x3(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map3x3x3(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum3x3x3(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3x3(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 2: { + CImg_2x2x2(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv2x2x2(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map2x2x2(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum2x2x2(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2x2(I,tqmask)/std::sqrt(norm)):0; + } + } break; + default: + case 1: + switch (tqmask.width) { + case 5: { + CImg_5x5x1(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map5x5x1(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv5x5x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map5x5x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum5x5x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv5x5x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 4: { + CImg_4x4x1(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map4x4x1(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv4x4x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map4x4x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum4x4x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv4x4x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 3: { + CImg_3x3x1(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map3x3x1(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv3x3x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map3x3x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum3x3x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 2: { + CImg_2x2x1(I,T); + if (!weighted_convol) cimg_mapZV(*this,z,v) cimg_map2x2x1(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv2x2x1(I,tqmask); + else cimg_mapZV(*this,z,v) cimg_map2x2x1(*this,x,y,z,v,I) { + const double norm = (double)cimg_squaresum2x2x1(I); + dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2x1(I,tqmask)/std::sqrt(norm)):0; + } + } break; + case 1: dest = tqmask(0)*(*this); break; + } + } + } else { // generic version + + const int cxm=tqmask.width/2, cym=tqmask.height/2, czm=tqmask.depth/2, fxm=cxm-1+(tqmask.width%2), fym=cym-1+(tqmask.height%2), fzm=czm-1+(tqmask.depth%2); + cimg_mapV(*this,v) + if (!weighted_convol) { // Classical convolution + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + val+= pix3d(x-xm,y-ym,z-zm,v)*tqmask(cxm+xm,cym+ym,czm+zm,0); + dest(x,y,z,v)=(restype)val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + val+= pix3d(x-xm,y-ym,z-zm,v,0)*tqmask(cxm+xm,cym+ym,czm+zm,0); + dest(x,y,z,v)=(restype)val; + } + } else { // Weighted convolution + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + ftype val = 0, norm = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { + const T cval = pix3d(x-xm,y-ym,z-zm,v); + val+= cval*tqmask(cxm+xm,cym+ym,czm+zm,0); + norm+=cval*cval; + } + dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt(norm)):0; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + double val = 0, norm = 0; + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { + const T cval = pix3d(x-xm,y-ym,z-zm,v,0); + val+= cval*tqmask(cxm+xm,cym+ym,czm+zm,0); + norm+= cval*cval; + } + dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt(norm)):0; + } + } + } + return dest; + } + + //! Convolve the image by a tqmask + /** + This is the in-place version of get_convolve(). + \see get_convolve() + **/ + template CImg& convolve(const CImg& tqmask,const unsigned int cond=1,const bool weighted_convol=false) { + return get_convolve(tqmask,cond,weighted_convol).swap(*this); + } + + //! Return the erosion of the image by a structuring element. + template CImg::type> + get_erode(const CImg& tqmask, const unsigned int cond=1, const bool weighted_erosion=false) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + if (tqmask.is_empty() || tqmask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_erosion() : Specified tqmask (%u,%u,%u,%u,%p) is not a scalar image.", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,tqmask.data); + CImg dest(*this,false); + const int cxm=tqmask.width/2, cym=tqmask.height/2, czm=tqmask.depth/2, + fxm=cxm-1+(tqmask.width%2), fym=cym-1+(tqmask.height%2), fzm=czm-1+(tqmask.depth%2); + cimg_mapV(*this,v) + if (!weighted_erosion) { // Classical erosion + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, min_val = cimg::get_type_max(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if (tqmask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v),min_val); + dest(x,y,z,v)=min_val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, min_val = cimg::get_type_max(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if (tqmask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v,0),min_val); + dest(x,y,z,v)=min_val; + } + } else { // Weighted erosion + t mval=0; + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, min_val = cimg::get_type_max(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if ((mval=tqmask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v)+mval),min_val); + dest(x,y,z,v)=min_val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, min_val = cimg::get_type_max(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if ((mval=tqmask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v,0)+mval),min_val); + dest(x,y,z,v)=min_val; + } + } + return dest; + } + + //! Erode the image by a structuring element + /** + This is the in-place version of get_erode(). + \see get_erode() + **/ + template CImg& erode(const CImg& tqmask,const unsigned int cond=1,const bool weighted_erosion=false) { + return get_erode(tqmask,cond,weighted_erosion).swap(*this); + } + + //! Erode the image by a square structuring element of size n + CImg get_erode(const unsigned int n=1, const unsigned int cond=1) const { + static const CImg tqmask(3,3,1,1,1); + return get_erode(tqmask,cond,false); + } + + //! Erode the image by a square structuring element of size n + CImg& erode(const unsigned int n=1, const unsigned int cond=1) { + return get_erode(n,cond).swap(*this); + } + + //! Return the dilatation of the image by a structuring element. + template CImg::type> + get_dilate(const CImg& tqmask, const unsigned int cond=1, const bool weighted_dilatation=false) const { + typedef typename cimg::largest::type restype; + if (is_empty()) return CImg(); + if (tqmask.is_empty() || tqmask.dim!=1) + throw CImgArgumentException("CImg<%s>::get_dilate() : Specified tqmask (%u,%u,%u,%u,%p) is not a scalar image.", + pixel_type(),tqmask.width,tqmask.height,tqmask.depth,tqmask.dim,tqmask.data); + CImg dest(*this,false); + const int cxm=tqmask.width/2, cym=tqmask.height/2, czm=tqmask.depth/2, + fxm=cxm-1+(tqmask.width%2), fym=cym-1+(tqmask.height%2), fzm=czm-1+(tqmask.depth%2); + cimg_mapV(*this,v) + if (!weighted_dilatation) { // Classical dilatation + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, max_val = cimg::get_type_min(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if (tqmask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v),max_val); + dest(x,y,z,v)=max_val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, max_val = cimg::get_type_min(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if (tqmask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v,0),max_val); + dest(x,y,z,v)=max_val; + } + } else { // Weighted dilatation + t mval=0; + for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, max_val = cimg::get_type_min(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if ((mval=tqmask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v)-mval),max_val); + dest(x,y,z,v)=max_val; + } + else cimg_mapYZV(*this,y,z,v) + for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { + restype foo, max_val = cimg::get_type_min(foo); + for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) + if ((mval=tqmask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v,0)-mval),max_val); + dest(x,y,z,v)=max_val; + } + } + return dest; + } + + //! Dilate the image by a structuring element + /** + This is the in-place version of get_dilate(). + \see get_dilate() + **/ + template CImg& dilate(const CImg& tqmask,const unsigned int cond=1,const bool weighted_dilatation=false) { + return get_dilate(tqmask,cond,weighted_dilatation).swap(*this); + } + + //! Dilate the image by a square structuring element of size n + CImg get_dilate(const unsigned int n=1, const unsigned int cond=1) const { + static const CImg tqmask(3,3,1,1,1); + return get_dilate(tqmask,cond,false); + } + + //! Dilate the image by a square structuring element of size n + CImg& dilate(const unsigned int n=1, const unsigned int cond=1) { + return get_dilate(n,cond).swap(*this); + } + + //! Add noise to the image + /** + This is the in-place version of get_noise. + \see get_noise. + **/ + CImg& noise(const double sigma=-20,const unsigned int ntype=0) { + if (!is_empty()) { + T tmp; + double nsigma = sigma, max = (double)cimg::get_type_max(tmp), min = (double)cimg::get_type_min(tmp); + static bool first_time = true; + if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; } + CImgStats st; + if (nsigma==0) return *this; + if (nsigma<0 || ntype==2) st = CImgStats(*this,false); + if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0; + switch (ntype) { + case 0: { // Gaussian noise + cimg_map(*this,ptr,T) { + double val = *ptr+nsigma*cimg::grand(); + if (val>max) val = max; + if (valmax) val = max; + if (val(*this).noise(sigma,ntype); } + +#define cimg_deriche_map(x0,y0,z0,k0,nb,offset,T) { \ + ima = ptr(x0,y0,z0,k0); \ + I2 = *ima; ima+=offset; I1 = *ima; ima+=offset; \ + Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2; \ + for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset; \ + Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2; \ + I2=I1; Y2=Y1; Y1=Y0; } \ + ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \ + ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1); \ + for (i=(nb)-3; i>=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset; \ + I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; } \ + } + + //! Apply a deriche filter on the image + /** + This is the in-place version of get_deriche + \see get_deriche. + **/ + CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) { + if (!is_empty()) { + if (sigma<0 || order<0 || order>2) + throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order); + const float alpha=sigma>0?(1.695f/sigma):20,ea=(float)std::exp(alpha),ema=(float)std::exp(-alpha),em2a=ema*ema,b1=2*ema,b2=-em2a; + float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0; + double *Y,Y0,Y1,Y2; + int i,offset,nb; + T *ima,I1,I2; + switch(order) { + case 1: // first derivative + ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0; a2 = ek*ema; a3 = -ek*ema; parity =-1; + if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } + else g0 = sumg0 = sumg1 = 0; + break; + case 2: // second derivative + ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) ); + ek = -(em2a-1)/(2*alpha*ema); a1 = ekn; a2 = -ekn*(1+ek*alpha)*ema; a3 = ekn*(1-ek*alpha)*ema; a4 = -ekn*em2a; parity =1; + if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; } + else g0=sumg0=sumg1=0; + break; + default: // smoothing + ek = (1-ema)*(1-ema) / (1+2*alpha*ema - em2a); a1 = ek; a2 = ek*ema*(alpha-1); a3 = ek*ema*(alpha+1); a4 = -ek*em2a; parity = 1; + if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; } + else g0=sumg0=sumg1=0; + break; + } + // filter init + Y = new double[cimg::max(width,height,depth)]; + switch(cimg::uncase(axe)) { + case 'x': if (width>1) { offset = 1; nb = width; cimg_mapYZV(*this,y,z,k) cimg_deriche_map(0,y,z,k,nb,offset,T); } break; + case 'y': if (height>1) { offset = width; nb = height; cimg_mapXZV(*this,x,z,k) cimg_deriche_map(x,0,z,k,nb,offset,T); } break; + case 'z': if (depth>1) { offset = width*height; nb = depth; cimg_mapXYV(*this,x,y,k) cimg_deriche_map(x,y,0,k,nb,offset,T); } break; + default: throw CImgArgumentException("CImg<%s>::deriche() : unknow axe '%c', must be 'x','y' or 'z'",pixel_type(),axe); + } + delete[] Y; + } + return *this; + } + + //! Return the result of the Deriche filter + /** + The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of + order 0,1 or 2 of an image. + \see blur + **/ + CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const { + return CImg(*this).deriche(sigma,order,axe,cond); + } + + //! Blur the image with a Deriche filter (anisotropically) + /** + This is the in-place version of get_blur(). + \see get_blur(). + **/ + CImg& blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) { + if (!is_empty()) { + if (width>1 && sigmax>0) deriche(sigmax,0,'x',cond); + if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond); + if (depth>1 && sigmaz>0) deriche(sigmaz,0,'z',cond); + } + return *this; + } + + //! Blur the image with a Canny-Deriche filter. + /** This is the in-place version of get_blur(). **/ + CImg& blur(const float sigma,const unsigned int cond=1) { return blur(sigma,sigma,sigma,cond); } + + //! Return a blurred version of the image, using a Canny-Deriche filter. + /** + Blur the image with an anisotropic exponential filter (Deriche filter of order 0). + **/ + CImg get_blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) const { + return CImg(*this).blur(sigmax,sigmay,sigmaz,cond); + } + + //! Return a blurred version of the image, using a Canny-Deriche filter. + CImg get_blur(const float sigma,const unsigned int cond=1) const { return CImg(*this).blur(sigma,cond); } + + //! Blur an image following a field of diffusion tensors. + /** This is the in-place version of get_blur_anisotropic(). **/ + template + CImg& blur_anisotropic(const CImg& G, const float amplitude=30.0f, const float dl=0.8f,const float da=30.0f, + const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) { + + // Check arguments and init variables + if (!is_empty() && amplitude>0) { + if (G.is_empty() || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth) + throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.", + pixel_type(),G.width,G.height,G.depth,G.dim); + + const int dx1 = dimx()-1, dy1 = dimy()-1, dz1 = dimz()-1; + const bool threed = (G.dim>=6); + CImg dest(width,height,depth,dim,0), tmp(dim), W(width,height,depth,threed?4:3); + int N = 0; + const float sqrt2amplitude = (float)std::sqrt(2*amplitude); + + if (threed) + // 3D version of the algorithm + for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) { + const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)), da2 = datmp<1?360.0f:datmp; + for (float theta=0; theta<360; (theta+=da2),N++) { + const float thetar = (float)(theta*cimg::PI/180), + vx = (float)(std::cos(thetar)*std::cos(phir)), + vy = (float)(std::sin(thetar)*std::cos(phir)), + vz = (float)std::sin(phir); + const t + *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2), + *pd = G.ptr(0,0,0,3), *pe = G.ptr(0,0,0,4), *pf = G.ptr(0,0,0,5); + t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2), *pd3 = W.ptr(0,0,0,3); + cimg_mapXYZ(G,xg,yg,zg) { + const t + a = *(pa++), b = *(pb++), c = *(pc++), + d = *(pd++), e = *(pe++), f = *(pf++), + u = a*vx + b*vy + c*vz, + v = b*vx + d*vy + e*vz, + w = c*vx + e*vy + f*vz, + n = (t)std::sqrt(1e-5+u*u+v*v+w*w), + dln = dl/n; + *(pd0++) = u*dln; + *(pd1++) = v*dln; + *(pd2++) = w*dln; + *(pd3++) = n; + } + + cimg_mapXYZ(*this,x,y,z) { + tmp.fill(0); + const t cu = W(x,y,z,0), cv = W(x,y,z,1), cw = W(x,y,z,2), n = W(x,y,z,3); + const float + fsigma = (float)(n*sqrt2amplitude), + length = gauss_prec*fsigma, + fsigma2 = 2*fsigma*fsigma; + float l, S=0, pu=cu, pv=cv, pw=cw, X=(float)x, Y=(float)y, Z=(float)z; + if (fast_approx) switch (interpolation) { + case 0: // Nearest neighbor interpolation + for (l=0; l=dx1?dx1:X), + Yn = Y<0?0:(Y>=dy1?dy1:Y), + Zn = Z<0?0:(Z>=dz1?dz1:Z); + const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f), zi = (int)(Zn+0.5f); + t u = W(xi,yi,zi,0), v = W(xi,yi,zi,1), w = W(xi,yi,zi,2); + if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; } + cimg_mapV(*this,k) tmp[k]+=(t)(*this)(xi,yi,zi,k); + X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S++; + } break; + case 1: // Linear interpolation + for (l=0; l=dx1?dx1:X), + Yn = Y<0?0:(Y>=dy1?dy1:Y), + Zn = Z<0?0:(Z>=dz1?dz1:Z); + const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f), zi = (int)(Zn+0.5f); + t u = W(xi,yi,zi,0), v = W(xi,yi,zi,1), w = W(xi,yi,zi,2); + if ((pu*u+pv*v+pw*w)<0) { u=-u; v=-v; w=-w; } + cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,zi,k)); + X+=(pu=u); Y+=(pv=v); Z+=(pw=w); S+=coef; + } break; + case 1: // Linear interpolation + for (l=0; l0) cimg_mapV(dest,k) dest(x,y,z,k)+=tmp[k]/S; + else cimg_mapV(dest,k) dest(x,y,z,k)+=(t)((*this)(x,y,z,k)); + } + } + } else + // 2D version of the algorithm + for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),N++) { + const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar)); + + const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2); + t *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2); + cimg_mapXY(G,xg,yg) { + const t + a = *(pa++), b = *(pb++), c = *(pc++), + u = a*vx + b*vy, v = b*vx + c*vy, + n = (t)std::sqrt(1e-5+u*u+v*v), + dln = dl/n; + *(pd0++) = u*dln; + *(pd1++) = v*dln; + *(pd2++) = n; + } + + cimg_mapXY(*this,x,y) { + tmp.fill(0); + const t cu = W(x,y,0,0), cv = W(x,y,0,1), n = W(x,y,0,2); + const float + fsigma = (float)(n*sqrt2amplitude), + length = gauss_prec*fsigma, + fsigma2 = 2*fsigma*fsigma; + float l, S=0, pu=cu, pv=cv, X=(float)x, Y=(float)y; + if (fast_approx) switch (interpolation) { + case 0: // Nearest-neighbor interpolation + for (l=0; l=dx1?dx1:X), + Yn = Y<0?0:(Y>=dy1?dy1:Y); + const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f); + t u = W(xi,yi,0,0), v = W(xi,yi,0,1); + if ((pu*u+pv*v)<0) { u=-u; v=-v; } + cimg_mapV(*this,k) tmp[k]+=(t)(*this)(xi,yi,0,k); + X+=(pu=u); Y+=(pv=v); S++; + } break; + case 1: // Linear interpolation + for (l=0; l=dx1?dx1:X), + Yn = Y<0?0:(Y>=dy1?dy1:Y); + const int xi = (int)(Xn+0.5f), yi = (int)(Yn+0.5f); + t u = W(xi,yi,0,0), v = W(xi,yi,0,1); + if ((pu*u+pv*v)<0) { u=-u; v=-v; } + cimg_mapV(*this,k) tmp[k]+=(t)(coef*(*this)(xi,yi,0,k)); + X+=(pu=u); Y+=(pv=v); S+=coef; + } break; + case 1: // Linear interpolation + for (l=0; l0) cimg_mapV(dest,k) dest(x,y,0,k)+=tmp[k]/S; + else cimg_mapV(dest,k) dest(x,y,0,k)+=(t)((*this)(x,y,0,k)); + } + } + const float *ptrs = dest.data+dest.size(); cimg_map(*this,ptrd,T) *ptrd = (T)(*(--ptrs)/N); + } + return *this; + } + + //! Get a blurred version of an image following a field of diffusion tensors. + /** + \param G = Field of square roots of diffusion tensors used to drive the smoothing. + \param amplitude = amplitude of the smoothing. + \param dl = spatial discretization. + \param da = angular discretization. + \param gauss_prec = precision of the gaussian function. + \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta) + \param fast_approx = Tell to use the fast approximation or not. + **/ + template + CImg get_blur_anisotropic(const CImg& G, const float amplitude=30.0f, const float dl=0.8f,const float da=30.0f, + const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) const { + return CImg(*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx); + } + + //! Blur an image following a field of diffusion tensors. + CImg& blur_anisotropic(const float amplitude, const float sharpness=0.8f, const float anisotropy=0.5f, + const float alpha=0.2f,const float sigma=0.8f, const float dl=0.8f,const float da=30.0f, + const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) { + if (!is_empty() && amplitude>0) { + if (amplitude==0) return *this; + if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0) + throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), " + "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n" + "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], " + "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.", + pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec); + const bool threed = (depth>1); + CImg G(width,height,depth,(threed?6:3),0); + const float power1 = 0.5f*sharpness, power2 = power1/(1e-7f+1.0f-anisotropy); + float nmax = 0; + + if (threed) { // Field for 3D volumes + CImg val(3),vec(3,3); + CImg_3x3x3(I,float); + const CImg blurred = get_blur(alpha); + cimg_mapV(*this,k) cimg_map3x3x3(blurred,x,y,z,k,I) { + const float + ixf = Incc-Iccc, iyf = Icnc-Iccc, izf = Iccn-Iccc, + ixb = Iccc-Ipcc, iyb = Iccc-Icpc, izb = Iccc-Iccp; + G(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb); + G(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb); + G(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb); + G(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb); + G(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb); + G(x,y,z,5) += 0.5f*(izf*izf + izb*izb); + } + G.blur(sigma); + cimg_mapXYZ(*this,x,y,z) { + G.get_tensor(x,y,z).symeigen(val,vec); + const float l1 = val[2], l2 = val[1], l3 = val[0], + ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), + vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), + wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), + n1 = (float)std::pow(1.0f+l1+l2+l3,-power1), + n2 = (float)std::pow(1.0f+l1+l2+l3,-power2); + G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx; + G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy; + G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz; + G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy; + G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz; + G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz; + if (n1>nmax) nmax=n1; + } + } else { // Field for 2D images + CImg val(2),vec(2,2); + CImg_3x3x1(I,float); + const CImg blurred = get_blur(alpha); + cimg_mapV(*this,k) cimg_map3x3x1(blurred,x,y,0,k,I) { + const float + ixf = Inc-Icc, iyf = Icn-Icc, + ixb = Icc-Ipc, iyb = Icc-Icp; + G(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb); + G(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb); + G(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb); + } + G.blur(sigma); + cimg_mapXY(*this,x,y) { + G.get_tensor(x,y).symeigen(val,vec); + const float l1 = val[1], l2 = val[0], + ux = vec(1,0), uy = vec(1,1), + vx = vec(0,0), vy = vec(0,1), + n1 = (float)std::pow(1.0f+l1+l2,-power1), + n2 = (float)std::pow(1.0f+l1+l2,-power2); + G(x,y,0,0) = n1*ux*ux + n2*vx*vx; + G(x,y,0,1) = n1*ux*uy + n2*vx*vy; + G(x,y,0,2) = n1*uy*uy + n2*vy*vy; + if (n1>nmax) nmax=n1; + } + } + G/=nmax; + blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx); + } + return *this; + } + + //! Blur an image following a field of diffusion tensors. + /** + \param amplitude = amplitude of the smoothing. + \param sharpness = define the contour preservation. + \param anisotropy = define the smoothing anisotropy. + \param alpha = image pre-blurring (gaussian). + \param sigma = regularity of the tensor-valued tqgeometry. + \param dl = spatial discretization. + \param da = angular discretization. + \param gauss_prec = precision of the gaussian function. + \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta) + \param fast_approx = Tell to use the fast approximation or not + **/ + CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.8f, const float anisotropy=0.5f, + const float alpha=0.2f, const float sigma=0.8f, const float dl=0.8f, + const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, + const bool fast_approx=true) const { + + return CImg(*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx); + } + + //! Return the Fast Fourier Transform of an image (along a specified axis) + CImgl::type> get_FFT(const char axe,const bool inverse=false) const { + typedef typename cimg::largest::type restype; + return CImgl(*this,CImg(width,height,depth,dim,0)).FFT(axe,inverse); + } + + //! Return the Fast Fourier Transform on an image + CImgl::type> get_FFT(const bool inverse=false) const { + typedef typename cimg::largest::type restype; + return CImgl(*this,CImg(width,height,depth,dim,0)).FFT(inverse); + } + + //! Apply a median filter. + CImg get_blur_median(const unsigned int n=3) { + CImg res(*this,false); + if (!n || n==1) return *this; + const int hl=n/2, hr=hl-1+n%2; + if (res.depth!=1) { // 3D median filter + CImg vois; + cimg_mapXYZV(*this,x,y,z,k) { + vois = get_crop(x-hl,y-hl,z-hl,k,x+hr,y+hr,z+hr,k); + res(x,y,z,k) = vois.median(); + } + } else { // 2D median filter +#define _median_sort(a,b) if ((a)>(b)) cimg::swap(a,b) + switch (n) { + case 3: { + CImg_3x3(I,T); + CImg_3x3(J,T); + cimg_mapV(*this,k) cimg_map3x3(*this,x,y,0,k,I) { + cimg_copy3x3x1(I,J); + _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn); + _median_sort(Jpp, Jcp); _median_sort(Jpc, Jcc); _median_sort(Jpn, Jcn); + _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn); + _median_sort(Jpp, Jpc); _median_sort(Jnc, Jnn); _median_sort(Jcc, Jcn); + _median_sort(Jpc, Jpn); _median_sort(Jcp, Jcc); _median_sort(Jnp, Jnc); + _median_sort(Jcc, Jcn); _median_sort(Jcc, Jnp); _median_sort(Jpn, Jcc); + _median_sort(Jcc, Jnp); + res(x,y,0,k) = Jcc; + } + } break; + case 5: { + CImg_5x5(I,T); + CImg_5x5(J,T); + cimg_mapV(*this,k) cimg_map5x5(*this,x,y,0,k,I) { + cimg_copy5x5x1(I,J); + _median_sort(Jbb, Jpb); _median_sort(Jnb, Jab); _median_sort(Jcb, Jab); _median_sort(Jcb, Jnb); + _median_sort(Jpp, Jcp); _median_sort(Jbp, Jcp); _median_sort(Jbp, Jpp); _median_sort(Jap, Jbc); + _median_sort(Jnp, Jbc); _median_sort(Jnp, Jap); _median_sort(Jcc, Jnc); _median_sort(Jpc, Jnc); + _median_sort(Jpc, Jcc); _median_sort(Jbn, Jpn); _median_sort(Jac, Jpn); _median_sort(Jac, Jbn); + _median_sort(Jnn, Jan); _median_sort(Jcn, Jan); _median_sort(Jcn, Jnn); _median_sort(Jpa, Jca); + _median_sort(Jba, Jca); _median_sort(Jba, Jpa); _median_sort(Jna, Jaa); _median_sort(Jcb, Jbp); + _median_sort(Jnb, Jpp); _median_sort(Jbb, Jpp); _median_sort(Jbb, Jnb); _median_sort(Jab, Jcp); + _median_sort(Jpb, Jcp); _median_sort(Jpb, Jab); _median_sort(Jpc, Jac); _median_sort(Jnp, Jac); + _median_sort(Jnp, Jpc); _median_sort(Jcc, Jbn); _median_sort(Jap, Jbn); _median_sort(Jap, Jcc); + _median_sort(Jnc, Jpn); _median_sort(Jbc, Jpn); _median_sort(Jbc, Jnc); _median_sort(Jba, Jna); + _median_sort(Jcn, Jna); _median_sort(Jcn, Jba); _median_sort(Jpa, Jaa); _median_sort(Jnn, Jaa); + _median_sort(Jnn, Jpa); _median_sort(Jan, Jca); _median_sort(Jnp, Jcn); _median_sort(Jap, Jnn); + _median_sort(Jbb, Jnn); _median_sort(Jbb, Jap); _median_sort(Jbc, Jan); _median_sort(Jpb, Jan); + _median_sort(Jpb, Jbc); _median_sort(Jpc, Jba); _median_sort(Jcb, Jba); _median_sort(Jcb, Jpc); + _median_sort(Jcc, Jpa); _median_sort(Jnb, Jpa); _median_sort(Jnb, Jcc); _median_sort(Jnc, Jca); + _median_sort(Jab, Jca); _median_sort(Jab, Jnc); _median_sort(Jac, Jna); _median_sort(Jbp, Jna); + _median_sort(Jbp, Jac); _median_sort(Jbn, Jaa); _median_sort(Jpp, Jaa); _median_sort(Jpp, Jbn); + _median_sort(Jcp, Jpn); _median_sort(Jcp, Jan); _median_sort(Jnc, Jpa); _median_sort(Jbn, Jna); + _median_sort(Jcp, Jnc); _median_sort(Jcp, Jbn); _median_sort(Jpb, Jap); _median_sort(Jnb, Jpc); + _median_sort(Jbp, Jcn); _median_sort(Jpc, Jcn); _median_sort(Jap, Jcn); _median_sort(Jab, Jbc); + _median_sort(Jpp, Jcc); _median_sort(Jcp, Jac); _median_sort(Jab, Jpp); _median_sort(Jab, Jcp); + _median_sort(Jcc, Jac); _median_sort(Jbc, Jac); _median_sort(Jpp, Jcp); _median_sort(Jbc, Jcc); + _median_sort(Jpp, Jbc); _median_sort(Jpp, Jcn); _median_sort(Jcc, Jcn); _median_sort(Jcp, Jcn); + _median_sort(Jcp, Jbc); _median_sort(Jcc, Jnn); _median_sort(Jcp, Jcc); _median_sort(Jbc, Jnn); + _median_sort(Jcc, Jba); _median_sort(Jbc, Jba); _median_sort(Jbc, Jcc); + res(x,y,0,k) = Jcc; + } + } break; + default: { + CImg vois; + cimg_mapXYV(*this,x,y,k) { + vois = get_crop(x-hl,y-hl,0,k,x+hr,y+hr,0,k); + res(x,y,0,k) = vois.median(); + } + } break; + } + } + return res; + } + + //! Apply a median filter + CImg& blur_median(const unsigned int n=3) { return get_blur_median(n).swap(*this); } + + //@} + // + // + // + //! \name Matrix and vector computation + //@{ + // + // + + //! Return a vector with specified coefficients + static CImg vector(const T& a1) { return CImg(1,1).fill(a1); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2) { return CImg(1,2).fill(a1,a2); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3) { return CImg(1,3).fill(a1,a2,a3); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4) { return CImg(1,4).fill(a1,a2,a3,a4); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5) { return CImg(1,5).fill(a1,a2,a3,a4,a5); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) { return CImg(1,6).fill(a1,a2,a3,a4,a5,a6); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7) { return CImg(1,7).fill(a1,a2,a3,a4,a5,a6,a7); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8) { return CImg(1,8).fill(a1,a2,a3,a4,a5,a6,a7,a8); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8,const T& a9) { return CImg(1,9).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8, + const T& a9,const T& a10) { return CImg(1,10).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8, + const T& a9,const T& a10, const T& a11) { + return CImg(1,11).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); + } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8, + const T& a9,const T& a10, const T& a11, const T& a12) { + return CImg(1,12).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + } + + //! Return a vector with specified coefficients + static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8, + const T& a9,const T& a10, const T& a11, const T& a12, + const T& a13) { + return CImg(1,13).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13); + } + + //! Return a square matrix with specified coefficients + static CImg matrix(const T& a1) { return vector(a1); } + + //! Return a square matrix with specified coefficients + static CImg matrix(const T& a1,const T& a2, + const T& a3,const T& a4) { + return CImg(2,2).fill(a1,a2, + a3,a4); + } + + //! Return a square matrix with specified coefficients + static CImg matrix(const T& a1,const T& a2,const T& a3, + const T& a4,const T& a5,const T& a6, + const T& a7,const T& a8,const T& a9) { + return CImg(3,3).fill(a1,a2,a3, + a4,a5,a6, + a7,a8,a9); + } + + //! Return a square matrix with specified coefficients + static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4, + const T& a5,const T& a6,const T& a7,const T& a8, + const T& a9,const T& a10,const T& a11,const T& a12, + const T& a13,const T& a14,const T& a15,const T& a16) { + return CImg(4,4).fill(a1,a2,a3,a4, + a5,a6,a7,a8, + a9,a10,a11,a12, + a13,a14,a15,a16); + } + + //! Return a square matrix with specified coefficients + static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5, + const T& a6,const T& a7,const T& a8,const T& a9,const T& a10, + const T& a11,const T& a12,const T& a13,const T& a14,const T& a15, + const T& a16,const T& a17,const T& a18,const T& a19,const T& a20, + const T& a21,const T& a22,const T& a23,const T& a24,const T& a25) { + return CImg(5,5).fill(a1,a2,a3,a4,a5, + a6,a7,a8,a9,a10, + a11,a12,a13,a14,a15, + a16,a17,a18,a19,a20, + a21,a22,a23,a24,a25); + } + + //! Return a diffusion tensor with specified coefficients + static CImg tensor(const T& a1) { return matrix(a1); } + + //! Return a diffusion tensor with specified coefficients + static CImg tensor(const T& a1,const T& a2,const T& a3) { + return matrix(a1,a2, + a2,a3); + } + + //! Return a diffusion tensor with specified coefficients + static CImg tensor(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) { + return matrix(a1,a2,a3, + a2,a4,a5, + a3,a5,a6); + } + + //! Return a diagonal matrix with specified coefficients + static CImg diagonal(const T& a1) { return matrix(a1); } + + //! Return a diagonal matrix with specified coefficients + static CImg diagonal(const T& a1,const T& a2) { + return matrix(a1,0, + 0,a2); + } + + //! Return a diagonal matrix with specified coefficients + static CImg diagonal(const T& a1,const T& a2,const T& a3) { + return matrix(a1,0,0, + 0,a2,0, + 0,0,a3); + } + + //! Return a diagonal matrix with specified coefficients + static CImg diagonal(const T& a1,const T& a2,const T& a3,const T& a4) { + return matrix(a1,0,0,0, + 0,a2,0,0, + 0,0,a3,0, + 0,0,0,a4); + } + + //! Return a diagonal matrix with specified coefficients + static CImg diagonal(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5) { + return matrix(a1,0,0,0,0, + 0,a2,0,0,0, + 0,0,a3,0,0, + 0,0,0,a4,0, + 0,0,0,0,a5); + } + + + //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image. + CImg get_vector(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const { + CImg dest(1,dim); + cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k); + return dest; + } + + //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image. + CImg get_matrix(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const { + const int n = (int)std::sqrt((double)dim); + CImg dest(n,n); + cimg_mapV(*this,k) dest[k]=(*this)(x,y,z,k); + return dest; + } + + //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image. + CImg get_tensor(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const { + if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2), + (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5)); + if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2)); + return tensor((*this)(x,y,z,0)); + } + + //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. + CImg& set_vector(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { + return draw_point(x,y,z,vec.data,1); + } + //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. + CImg& set_matrix(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { + return set_vector(mat,x,y,z); + } + //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image. + CImg& set_tensor(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { + if (ten.height==2) { + (*this)(x,y,z,0)=ten[0]; + (*this)(x,y,z,1)=ten[1]; + (*this)(x,y,z,2)=ten[3]; + } + else { + (*this)(x,y,z,0)=ten[0]; + (*this)(x,y,z,1)=ten[1]; + (*this)(x,y,z,2)=ten[2]; + (*this)(x,y,z,3)=ten[4]; + (*this)(x,y,z,4)=ten[5]; + (*this)(x,y,z,5)=ten[8]; + } + return *this; + } + //! Set the current matrix to be the identity matrix. + CImg& identity_matrix(const unsigned int N) { return get_identity_matrix(N).swap(*this); } + + //! Return a matrix \p dim * \p dim equal to \p factor * \a Identity. + static CImg get_identity_matrix(const unsigned int N) { + CImg res(N,N,1,1,0); + cimg_mapX(res,x) res(x,x)=1; + return res; + } + + //! Return a rotation matrix along the (x,y,z)-axis with an angle w. + static CImg get_rotation_matrix(const float x,const float y,const float z,const float w, const bool quaternion_data=false) { + float X,Y,Z,W; + if (!quaternion_data) { + const float norm = (float)std::sqrt(x*x + y*y + z*z), + nx = norm>0?x/norm:0, + ny = norm>0?y/norm:0, + nz = norm>0?z/norm:1, + nw = norm>0?w:0, + sina = (float)std::sin(nw/2), + cosa = (float)std::cos(nw/2); + X = nx*sina; + Y = ny*sina; + Z = nz*sina; + W = cosa; + } else { + const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w); + if (norm>0) { X=x/norm; Y=y/norm; Z=z/norm; W=w/norm; } + else { X=Y=Z=0; W=1; } + } + const float xx=X*X, xy=X*Y, xz=X*Z, xw=X*W, yy=Y*Y, yz=Y*Z, yw=Y*W, zz=Z*Z, zw=Z*W; + return CImg::matrix(1-2*(yy+zz), 2*(xy+zw), 2*(xz-yw), + 2*(xy-zw), 1-2*(xx+zz), 2*(yz+xw), + 2*(xz+yw), 2*(yz-xw), 1-2*(xx+yy)); + } + + //! In-place version of get_rotationX_matrix + CImg& rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) { + return get_rotation_matrix(x,y,z,w,quaternion_data).swap(*this); + } + + //! Return the transpose version of the current matrix. + CImg get_transpose() const { + CImg res(height,width,depth,dim); + cimg_mapXYZV(*this,x,y,z,v) res(y,x,z,v) = (*this)(x,y,z,v); + return res; + } + + //! Replace the current matrix by its transpose. + CImg& transpose() { + if (width==1) { width=height; height=1; return *this; } + if (height==1) { height=width; width=1; return *this; } + if (width==height) { + cimg_mapYZV(*this,y,z,v) for (int x=y; x<(int)width; x++) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v)); + return *this; + } + return (*this)=get_transpose(); + } + + //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image + CImg get_diagonal() const { + if (is_empty()) return CImg(); + CImg res(size(),size(),1,1,0); + cimg_mapoff(*this,off) res(off,off)=(*this)(off); + return res; + } + + //! Replace a vector by a diagonal matrix containing the original vector coefficients. + CImg& diagonal() { + return get_diagonal().swap(*this); + } + + //! Inverse the current matrix. + CImg& inverse(const bool use_LU=true) { + if (!is_empty()) { + if (width!=height || depth!=1 || dim!=1) + throw CImgInstanceException("CImg<%s>::inverse() : Instance matrix (%u,%u,%u,%u,%p) is not square.", + pixel_type(),width,height,depth,dim,data); + const double dete = width>3?-1.0:det(); + if (dete!=0.0 && width==2) { + const double + a = data[0], c = data[1], + b = data[2], d = data[3]; + data[0] = (T)(d/dete); data[1] = (T)(-c/dete); + data[2] = (T)(-b/dete), data[3] = (T)(a/dete); + } else if (dete!=0.0 && width==3) { + const double + a = data[0], d = data[1], g = data[2], + b = data[3], e = data[4], h = data[5], + c = data[6], f = data[7], i = data[8]; + data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete); + data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete); + data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete); + } else { + if (use_LU) { // LU-based inverse computation + CImg A(*this), indx, col(1,width); + bool d; + A._LU(indx,d); + cimg_mapX(*this,j) { + col.fill(0); col(j)=1; + col._solve(A,indx); + cimg_mapX(*this,i) (*this)(j,i) = col(i); + } + } else { // SVD-based inverse computation + CImg U(width,width),S(1,width),V(width,width); + SVD(U,S,V,false); + U.transpose(); + cimg_mapY(S,k) if (S[k]!=0) S[k]=1/S[k]; + S.diagonal(); + *this = V*S*U; + } + } + } + return *this; + } + + //! Return the inverse of the current matrix. + CImg::type> get_inverse(const bool use_LU=true) const { + typedef typename cimg::largest::type restype; + return CImg(*this).inverse(use_LU); + } + + //! Return the pseudo-inverse (Moore-Penrose) of the matrix + CImg::type> get_pseudoinverse() const { + typedef typename cimg::largest::type restype; + CImg At = get_transpose(), At2(At); + return (((At*=*this).inverse())*=At2); + } + + //! Replace the matrix by its pseudo-inverse + CImg& pseudoinverse() { + typedef typename cimg::largest::type restype; + CImg At = get_transpose(), At2(At); + ((At*=*this).inverse())*=At2; + return ((*this)=At); + } + + //! Return the trace of the current matrix. + double trace() const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + double res=0; + cimg_mapX(*this,k) res+=(*this)(k,k); + return res; + } + + //! Return the kth smallest element of the image + // (Adapted from the numerical recipies for CImg) + const T kth_smallest(const unsigned int k) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + CImg arr(*this); + unsigned long l=0,ir=size()-1; + for (;;) { + if (ir<=l+1) { + if (ir==l+1 && arr[ir]>1; + cimg::swap(arr[mid],arr[l+1]); + if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); + if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]); + if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]); + unsigned long i = l+1, j = ir; + const T pivot = arr[l+1]; + for (;;) { + do i++; while (arr[i]pivot); + if (j=k) ir=j-1; + if (j<=k) l=i; + } + } + return 0; + } + + //! Return the median of the image + const T median() const { + const unsigned int s = size(); + const T res = kth_smallest(s>>1); + return (s%2)?res:((res+kth_smallest((s>>1)-1))/2); + } + + //! Return the dot product of the current vector/matrix with the vector/matrix \p img. + double dot(const CImg& img) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (img.is_empty()) + throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.", + pixel_type(),img.width,img.height,img.depth,img.dim,img.data); + const unsigned long nb = cimg::min(size(),img.size()); + double res=0; + for (unsigned long off=0; off::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.", + pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data); + const T x = (*this)[0], y = (*this)[1], z = (*this)[2]; + (*this)[0] = y*img[2]-z*img[1]; + (*this)[1] = z*img[0]-x*img[2]; + (*this)[2] = x*img[1]-y*img[0]; + return *this; + } + + //! Return the cross product between two 3d vectors + CImg get_cross(const CImg& img) const { + return CImg(*this).cross(img); + } + + //! Return the determinant of the current matrix. + double det() const { + if (is_empty() || width!=height || depth!=1 || dim!=1) + throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.", + pixel_type(),width,height,depth,dim,data); + switch (width) { + case 1: return (*this)(0,0); + case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0); + case 3: { + const double + a = data[0], d = data[1], g = data[2], + b = data[3], e = data[4], h = data[5], + c = data[6], f = data[7], i = data[8]; + return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e; + } + default: { + typedef typename cimg::largest::type ftype; + CImg lu(*this); + CImg indx; + bool d; + lu._LU(indx,d); + double res = d?1.0:-1.0; + cimg_mapX(lu,i) res*=lu(i,i); + return res; + } + } + return 0; + } + + //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf). + double norm(const int ntype=2) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + double res = 0; + switch (ntype) { + case -1: { + cimg_mapoff(*this,off) { + const double tmp = cimg::abs((double)data[off]); + if (tmp>res) res = tmp; + } + return res; + } break; + case 1 : { + cimg_mapoff(*this,off) res+=cimg::abs((double)data[off]); + return res; + } break; + default: { return std::sqrt(dot(*this)); } + } + return 0; + } + + //! Return the sum of all the pixel values in an image. + double sum() const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::sum() : Instance object (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + double res=0; + cimg_map(*this,ptr,T) res+=*ptr; + return res; + } + + //! Compute the SVD of a general matrix. + template const CImg& SVD(CImg& U, CImg& S, CImg& V, + const bool sorting=true, const unsigned int max_iter=40) const { + if (is_empty()) { U.empty(); S.empty(); V.empty(); } + else { + U = *this; + if (S.size() rv1(width); + t anorm=0,c,f,g=0,h,s,scale=0; + int l=0,nm=0; + + cimg_mapX(U,i) { + l = i+1; rv1[i] = scale*g; g = s = scale = 0; + if (i=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i)=f-g; + for (int j=l; j=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; + { for (int k=l; k=0; i--) { + if (i=0; i--) { + l = i+1; g = S[i]; + for (int j=l; j=0; k--) { + for (unsigned int its=0; its=0; l--) { + nm = l-1; + if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; } + if ((cimg::abs(S[nm])+anorm)==anorm) break; + } + if (flag) { + c = 0; s = 1; + for (int i=l; i<=k; i++) { + f = s*rv1[i]; rv1[i] = c*rv1[i]; + if ((cimg::abs(f)+anorm)==anorm) break; + g = S[i]; h = (t)cimg::pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h; + cimg_mapY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; } + } + } + const t& z = S[k]; + if (l==k) { if (z<0) { S[k] = -z; cimg_mapX(U,j) V(k,j) = -V(k,j); } break; } + nm = k-1; + t x = S[l], y = S[nm]; + g = rv1[nm]; h = rv1[k]; + f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y); + g = (t)cimg::pythagore(f,1.0); + f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x; + c = s = 1; + for (int j=l; j<=nm; j++) { + const int i = j+1; + g = rv1[i]; h = s*g; g = c*g; + t y = S[i]; + t z = (t)cimg::pythagore(f,h); + rv1[j] = z; c = f/z; s = h/z; + f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c; + cimg_mapX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; } + z = (t)cimg::pythagore(f,h); S[j] = z; + if (z) { z = 1/z; c = f*z; s = h*z; } + f = c*g+s*y; x = c*y-s*g; + { cimg_mapY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; }} + } + rv1[l] = 0; rv1[k]=f; S[k]=x; + } + } + + if (sorting) { + CImg permutations(width); + S.sort(permutations,false); + cimg_mapX(permutations,x) { + const int n = permutations(x); + if (x const CImg& SVD(CImgl& USV) const { + if (USV.size<3) USV.assign(3); + return SVD(USV[0],USV[1],USV[2]); + } + + //! Compute the SVD of a general matrix. + CImgl::type> get_SVD(const bool sorting=true) const { + typedef typename cimg::largest::type restype; + CImgl res(3); + SVD(res[0],res[1],res[2],sorting); + return res; + } + + // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies) + template CImg& _LU(CImg& indx, bool& d) { + typedef typename cimg::largest::type ftype; + const int N = dimx(); + int imax=0; + CImg vv(N); + indx.assign(N); + d=true; + cimg_mapX(*this,i) { + ftype vmax=0.0; + cimg_mapX(*this,j) { + const ftype tmp = cimg::abs((*this)(j,i)); + if (tmp>vmax) vmax = tmp; + } + if (vmax==0) return fill(0); + vv[i] = 1/vmax; + } + cimg_mapX(*this,j) { + for (int i=0; i=vmax) { vmax=tmp; imax=i; } + }} + if (j!=imax) { + cimg_mapX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j)); + d =!d; + vv[imax] = vv[j]; + } + indx[j] = (t)imax; + if ((*this)(j,j)==0) (*this)(j,j)=(T)1e-20; + if (j CImg& _solve(const CImg& A, const CImg& indx) { + typedef typename cimg::largest::type ftype; + const int N = size(); + int ii=-1; + ftype sum; + for (int i=0; i=0) for (int j=ii; j<=i-1; j++) sum-=A(j,i)*(*this)(j); + else if (sum!=0) ii=i; + (*this)(i)=sum; + } + { for (int i=N-1; i>=0; i--) { + sum = (*this)(i); + for (int j=i+1; j::solve() : Instance matrix size is (%u,%u,%u,%u) while " + "size of given matrix A is (%u,%u,%u,%u).", + pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim); + if (A.width==A.height) { + CImg lu(A); + CImg indx; + bool d; + lu._LU(indx,d); + _solve(lu,indx); + } else assign(A.get_pseudoinverse()*(*this)); + return *this; + } + + //! Solve a linear system AX=B where B=*this. + CImg::type> get_solve(const CImg& A) const { + typedef typename cimg::largest::type restype; + return CImg(*this).solve(A); + } + + //! Compute the eigenvalues and eigenvectors of a matrix. + template const CImg& eigen(CImg& val, CImg &vec) const { + if (is_empty()) { val.empty(); vec.empty(); } + else { + if (width!=height || depth>1 || dim>1) + throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (val.size()::eigen() : Complex eigenvalues",pixel_type()); + f = std::sqrt(f); + const double l1 = 0.5*(e-f), l2 = 0.5*(e+f); + const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b); + val[0]=(t)l2; + val[1]=(t)l1; + vec(0,0) = (t)std::cos(theta1); + vec(0,1) = (t)std::sin(theta1); + vec(1,0) = (t)std::cos(theta2); + vec(1,1) = (t)std::sin(theta2); + } break; + default: + throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited" + "to 2x2 matrices (given is %ux%u)", pixel_type(),width,height); + } + } + return *this; + } + + //! Return the eigenvalues and eigenvectors of a matrix. + CImgl::type> get_eigen() const { + typedef typename cimg::largest::type restype; + CImgl res(2); + eigen(res[0],res[1]); + return res; + } + + //! Compute the eigenvalues and eigenvectors of a matrix. + template const CImg& eigen(CImgl& eig) const { + if (eig.size<2) eig.assign(2); + eigen(eig[0],eig[1]); + return *this; + } + + //! Compute the eigenvalues and eigenvectors of a symmetric matrix. + template const CImg& symeigen(CImg& val, CImg& vec) const { + if (is_empty()) { val.empty(); vec.empty(); } + else { + if (width!=height || depth>1 || dim>1) + throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + + if (val.size() V(width,width); + SVD(vec,val,V,false); + cimg_mapX(vec,x) { // check for negative eigenvalues + t scal=0; + cimg_mapY(vec,y) scal+=vec(x,y)*V(x,y); + if (scal<0) val[x]=-val[x]; + } + CImg permutations(width); // sort eigenvalues in decreasing order + val.sort(permutations,false); + { cimg_mapX(permutations,x) { + const int n = permutations(x); + if (x::type> get_symeigen() const { + typedef typename cimg::largest::type restype; + CImgl res(2); + symeigen(res[0],res[1]); + return res; + } + + //! Compute the eigenvalues and eigenvectors of a symmetric matrix. + template const CImg& symeigen(CImgl& eig) const { + if (eig.size<2) eig.assign(2); + symeigen(eig[0],eig[1]); + return *this; + } + + template CImg& _quicksort(const int min,const int max,CImg& permutations,const bool increasing) { + if (min(*this)[mid]) { + cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } + if ((*this)[mid]>(*this)[max]) { + cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } + if ((*this)[min]>(*this)[mid]) { + cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } + } else { + if ((*this)[min]<(*this)[mid]) { + cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } + if ((*this)[mid]<(*this)[max]) { + cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } + if ((*this)[min]<(*this)[mid]) { + cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } + } + if (max-min>=3) { + const T pivot = (*this)[mid]; + int i = min, j = max; + if (increasing) { + do { + while ((*this)[i]pivot) j--; + if (i<=j) { + cimg::swap((*this)[i],(*this)[j]); + cimg::swap(permutations[i++],permutations[j--]); + } + } while (i<=j); + } else { + do { + while ((*this)[i]>pivot) i++; + while ((*this)[j] + CImg& sort(CImg& permutations,const bool increasing=true) { + if (is_empty()) permutations.empty(); + else { + if (permutations.size()!=size()) permutations.assign(size()); + cimg_mapoff(permutations,off) permutations[off] = off; + _quicksort(0,size()-1,permutations,increasing); + } + return *this; + } + + //! Sort values of a vector. + CImg& sort(const bool increasing=true) { CImg foo; return sort(foo,increasing); } + + //! Get a sorted version a of vector, with permutations. + template CImg get_sort(CImg& permutations,const bool increasing=true) { + return CImg(*this).sort(permutations,increasing); + } + + //! Get a sorted version of a vector. + CImg get_sort(const bool increasing=true) { + return CImg(*this).sort(increasing); + } + + //@} + //--------------------------- + // + //! \name Display functions + //@{ + //--------------------------- + + + //! Display an image into a CImgDisplay window. + const CImg& display(CImgDisplay& disp) const { disp.display(*this); return *this; } + + //! Same as \ref cimg::wait() + const CImg& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; } + + //! Display an image in a window with a title \p title, and wait a 'closed' or 'keyboard' event.\n + //! Parameters \p min_size and \p max_size set the minimum and maximum dimensions of the display window. + //! If negative, they corresponds to a percentage of the original image size. + const CImg& display(const char* title,const int min_size=128,const int max_size=1024) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + CImgDisplay *disp; + unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3]; + print(title); + const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100; + if (dmin=0?max_size:(-max_size)*dmax/100; + if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); } + disp = new CImgDisplay(CImg(w,h,1,1,0),title,1,3); + XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2; + while (!disp->closed && !disp->key) feature_selection(NULL,1,*disp,XYZ); + delete disp; + return *this; + } + + //! Display an image in a window, with a default title. See also \see display() for details on parameters. + const CImg& display(const int min_size=128,const int max_size=1024) const { return display(" ",min_size,max_size); } + + //! High-level interface to select features from images + const CImg& feature_selection(int* const selection, const int feature_type,CImgDisplay &disp, + unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const { + if (is_empty()) + throw CImgInstanceException("CImg<%s>::feature_selection() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + const unsigned int oevents = disp.events, onormalization = disp.normalization; + disp.events = 3; disp.normalization = 0; + unsigned char fgcolor[3]={255,255,105}, bgcolor[3]={0,0,0}; + if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv())); + int carea=0,area=0,phase=0, + X0=(int)((XYZ?XYZ[0]:width/2)%width), Y0=(int)((XYZ?XYZ[1]:height/2)%height), Z0=(int)((XYZ?XYZ[2]:depth/2)%depth), + X=-1,Y=-1,Z=-1,oX=-1,oY=-1,oZ=-1,X1=-1,Y1=-1,Z1=-1; + unsigned int hatch=feature_type?0xF0F0F0F0:~0L; + bool feature_selected = false, ytext = false, oresized = disp.resized; + CImg visu, visu0; + char text[1024]; + + disp.show().key=0; + while (!disp.key && !disp.closed && !feature_selected) { + + // Init visu0 if necessary + if (disp.resized || !visu0.data) { + if (disp.resized) { disp.resize(); oresized = true; } + if (depth==1) visu0=get_normalize(0,(T)255); else visu0=get_projections2d(X0,Y0,Z0).get_normalize(0,(T)255); + visu0.resize(disp.width,disp.height,1,cimg::min(3,dimv())); + } + visu = visu0; + + // Handle motion and selection + const int mx = disp.mouse_x, my = disp.mouse_y, b = disp.button; + if (mx>=0 && my>=0) { + const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height; + if (mX=dimy()) { area=2; X=mX; Y=phase?Y1:Y0; Z=mY-height; } + if (mX>=dimx() && mY=dimx() && mY>=dimy()) { X=X0; Y=Y0; Z=Z0; } + if ((!(phase%2) && (b&1)) || (phase%2 && !(b&1))) { + if (!carea) carea=area; + if (!(phase++)) { X0=X; Y0=Y; Z0=Z; } + } + if (b&2) { if (!phase) { X0=X; Y0=Y; Z0=Z; } else { X1=Y1=Z1=-1; phase=carea=0; }} + if ((b&2 || phase) && depth>1) + visu0 = get_projections2d(X,Y,Z).normalize(0,(T)255).resize(disp.width,disp.height,1,cimg::min(3,dimv())); + if (phase) { + if (!feature_type) feature_selected = phase?true:false; + else { + if (depth>1) feature_selected = (phase==3)?true:false; + else feature_selected = (phase==2)?true:false; + } + if (!feature_selected) { + if (phase<2) { X1=X; Y1=Y; Z1=Z; } + else switch(carea) { + case 1: Z1=Z; break; + case 2: Y1=Y; break; + case 3: X1=X; break; + } + } + } + if (!phase || !feature_type) { + if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y); + cimg_mapV(*this,k) std::sprintf(text+cimg::strlen(text),"%g ",(double)(*this)(X,Y,Z,k)); + std::sprintf(text+cimg::strlen(text),"}"); + if (!feature_type) { X1=X0; Y1=Y0; Z1=Z0; } + } else + switch (feature_type) { + case 1: { + const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ); + if (depth>1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm); + else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm); + } break; + case 2: + if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)", + X01) std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii=(%d,%d,%d)", + X0,Y0,Z0,X1,Y1,Z1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); + else std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii=(%d,%d)", + X0,Y0,X1,Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); + + break; + } + if (my<12) ytext=true; + if (my>=visu.dimy()-11) ytext=false; + visu.draw_text(text,0,ytext?visu.dimy()-11:0,fgcolor,bgcolor,11,0.7f); + } else { X=Y=Z=-1; if (phase) disp.button=phase%2; } + + // Draw image + selection on display window + if (X>=0 && Y>=0 && Z>=0) { + hatch=cimg::ror(hatch); + if (feature_type==1 && phase) { + const int d=(depth>1)?depth:0, + x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)), + x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d)); + visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch); + if (d) { + const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)), + zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d)); + visu.draw_arrow(zx0,y0,zx1,y1,fgcolor,30.0f,5.0f,hatch).draw_arrow(x0,zy0,x1,zy1,fgcolor,30.0f,5.0f,hatch); + } + } else switch(feature_type) { + case 2: { + const bool cond=(phase&&feature_type); + const int d=(depth>1)?depth:0, + nX0=cond?X0:X, nY0=cond?Y0:Y, nZ0=cond?Z0:Z, + nX1=cond?X1:X, nY1=cond?Y1:Y, nZ1=cond?Z1:Z, + x0=(nX01)?depth:0, + x0=(cond?X0:X)*disp.width/(width+d), + y0=(cond?Y0:Y)*disp.height/(height+d), + x1=(cond?X1:X)*disp.width/(width+d)-1, + y1=(cond?Y1:Y)*disp.height/(height+d)-1; + const unsigned int nhatch=phase?hatch:~0L; + visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f). + draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch); + if (d) { + const int + zx0=(int)((width+(cond?Z0:Z))*disp.width/(width+d)), + zy0=(int)((height+(cond?Z0:Z))*disp.height/(height+d)), + zx1=(int)((width+(cond?Z1:Z)+1)*disp.width/(width+d))-1, + zy1=(int)((height+(cond?Z1:Z)+1)*disp.height/(height+d))-1; + visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f). + draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,nhatch). + draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,0L,0.2f). + draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,nhatch); + } + } break; + } + } + visu.display(disp).wait(32); + if ((!feature_selected && !phase && oX==X && oY==Y && oZ==Z) || (X<0 || Y<0 || Z<0)) disp.wait(); + oX=X; oY=Y; oZ=Z; + } + + // Return result + if (XYZ) { XYZ[0] = (unsigned int)X; XYZ[1] = (unsigned int)Y; XYZ[2] = (unsigned int)Z; } + if (feature_selected) { + if (feature_type==2) { + if (X0>X1) cimg::swap(X0,X1); + if (Y0>Y1) cimg::swap(Y0,Y1); + if (Z0>Z1) cimg::swap(Z0,Z1); + } + if (selection) { + if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1; + switch(feature_type) { + case 1: + case 2: selection[3] = X1; selection[4] = Y1; selection[5] = Z1; + default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0; + } + } + } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1; + disp.button=0; + disp.events = oevents; + disp.normalization = onormalization; + disp.resized = oresized; + return *this; + } + + //! High-level interface to select features in images + const CImg& feature_selection(int *const selection, const int feature_type, + unsigned int *const XYZ=NULL,const unsigned char *const color=NULL) const { + unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0); + const unsigned int dmin = cimg::min(w,h), minsiz = 256; + if (dminmaxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; } + CImgDisplay disp(w,h," ",0,3); + return feature_selection(selection,feature_type,disp,XYZ,color); + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const CImg& points,const CImgl& primitives, + const CImgl& colors, const CImg& opacities, CImgDisplay& disp, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes=true, const bool keep_pos = false) const { + + if (points.is_empty()) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.", + pixel_type()); + if (primitives.is_empty()) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given primitives are empty.", + pixel_type()); + + if (is_empty()) + return CImg(disp.width,disp.height,1,colors[0].size(),0). + display_object3d(points,primitives,colors,opacities,disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light); + if (opacities.is_empty()) + return display_object3d(points,primitives,colors,CImg(primitives.size,1,1,1,(to)1),disp, + centering,render_static,render_motion,double_sided,focale,ambiant_light); + if (points.height<3) + return display_object3d(points.get_resize(-100,3,1,1,0),primitives,colors,opacities,disp, + centering,render_static,render_motion,double_sided,focale,ambiant_light); + + if (colors.size!=primitives.size) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given colors (size=%u) and primitives (size=%u) have " + "different sizes.",pixel_type(),colors.size,primitives.size); + if (opacities.width!=primitives.size) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given opacities (size=%u) and primitives (size=%u) have " + "different sizes", pixel_type(),opacities.width,primitives.size); + + static float oX=0,oY=0,oZ=0; + static CImg rot; + + bool init = true, clicked = false, redraw = true, stopflag = false; + CImg centered_points, rotated_points(points.width,3); + CImg visu0(*this), visu; + int x0=0,y0=0,x1=0,y1=0; + + const unsigned int oevents = disp.events; + disp.show().button=disp.key=0; + disp.events=3; + + // Compute object statistics + cimg_mapX(rotated_points,xx) { + rotated_points(xx,0) = (float)points(xx,0); + rotated_points(xx,1) = (float)points(xx,1); + rotated_points(xx,2) = (float)points(xx,2); + } + const CImg + x = rotated_points.get_shared_line(0), + y = rotated_points.get_shared_line(1), + z = rotated_points.get_shared_line(2); + const CImgStats sx(x,false), sy(y,false), sz(z,false); + const float + xm = (float)sx.min, xM = (float)sx.max, + ym = (float)sy.min, yM = (float)sy.max, + zm = (float)sz.min, zM = (float)sz.max, + delta = cimg::max(xM-xm,yM-ym,zM-zm), + ratio = delta>0?(2.0f*cimg::min(width,height)/(3.0f*delta)):0, + dx = 0.5f*(xM+xm), dy = 0.5f*(yM+ym), dz = 0.5f*(zM+zm); + if (centering) { + centered_points.assign(points.width,3); + cimg_mapX(points,l) { + centered_points(l,0) = (float)((points(l,0)-dx)*ratio); + centered_points(l,1) = (float)((points(l,1)-dy)*ratio); + centered_points(l,2) = (float)((points(l,2)-dz)*ratio); + } + } + + // Create bounding box if necessary + CImgl bbox_colors; + CImgl bbox_primitives; + CImg bbox_points, rotated_bbox_points, bbox_opacities; + const T foo=0, valmax = cimg::get_type_max(foo); + + if (render_static<0 || render_motion<0) { + bbox_colors.assign(12,dim,1,1,1,valmax); + bbox_primitives.assign(12,1,2); + bbox_points.assign(8,3); + rotated_bbox_points.assign(8,3); + bbox_points(0,0) = xm; bbox_points(0,1) = ym; bbox_points(0,2) = zm; + bbox_points(1,0) = xM; bbox_points(1,1) = ym; bbox_points(1,2) = zm; + bbox_points(2,0) = xM; bbox_points(2,1) = yM; bbox_points(2,2) = zm; + bbox_points(3,0) = xm; bbox_points(3,1) = yM; bbox_points(3,2) = zm; + bbox_points(4,0) = xm; bbox_points(4,1) = ym; bbox_points(4,2) = zM; + bbox_points(5,0) = xM; bbox_points(5,1) = ym; bbox_points(5,2) = zM; + bbox_points(6,0) = xM; bbox_points(6,1) = yM; bbox_points(6,2) = zM; + bbox_points(7,0) = xm; bbox_points(7,1) = yM; bbox_points(7,2) = zM; + bbox_primitives[0].fill(0,1); bbox_primitives[1].fill(1,2); bbox_primitives[2].fill(2,3); bbox_primitives[3].fill(3,0); + bbox_primitives[4].fill(4,5); bbox_primitives[5].fill(5,6); bbox_primitives[6].fill(6,7); bbox_primitives[7].fill(7,4); + bbox_primitives[8].fill(0,4); bbox_primitives[9].fill(1,5); bbox_primitives[10].fill(2,6); bbox_primitives[11].fill(3,7); + bbox_opacities.assign(bbox_primitives.size,1,1,1,1.0f); + } + + // Create small axes display on the bottom + CImgl axes_primitives; + CImgl axes_colors; + CImg axes_points, rotated_axes_points, axes_opacities; + if (display_axes) { + axes_points.assign(7,3); + rotated_axes_points.assign(7,3); + axes_opacities.assign(3,1,1,1,1.0f); + axes_colors.assign(3,dim,1,1,1,valmax); + axes_points(0,0) = 0; axes_points(0,1) = 0; axes_points(0,2) = 0; + axes_points(1,0) = 20; axes_points(1,1) = 0; axes_points(1,2) = 0; + axes_points(2,0) = 0; axes_points(2,1) = 20; axes_points(2,2) = 0; + axes_points(3,0) = 0; axes_points(3,1) = 0; axes_points(3,2) = 20; + axes_points(4,0) = 22; axes_points(4,1) = -6; axes_points(4,2) = 0; + axes_points(5,0) = -6; axes_points(5,1) = 22; axes_points(5,2) = 0; + axes_points(6,0) = -6; axes_points(6,1) = -6; axes_points(6,2) = 22; + axes_primitives.insert(CImg::vector(0,1)); + axes_primitives.insert(CImg::vector(0,2)); + axes_primitives.insert(CImg::vector(0,3)); + } + + // Begin user interaction + while (!disp.closed && !stopflag) { + + // Init object position and scale if necessary + if (init) { + if (!keep_pos) { + oX = oY = oZ = 0; + rot = CImg::get_identity_matrix(3); + } + init = false; + redraw = true; + } + + // Handle user interaction + if (disp.button && disp.mouse_x>=0 && disp.mouse_y>=0) { + redraw = true; + if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; clicked = true; } + else { x1 = disp.mouse_x; y1 = disp.mouse_y; } + if (disp.button&1) { + const float + R = 0.4f*cimg::min(disp.width,disp.height), + R2 = R*R, + u0 = (float)(x0-disp.dimx()/2), + v0 = (float)(y0-disp.dimy()/2), + u1 = (float)(x1-disp.dimx()/2), + v1 = (float)(y1-disp.dimy()/2), + n0 = (float)std::sqrt(u0*u0+v0*v0), + n1 = (float)std::sqrt(u1*u1+v1*v1), + nu0 = n0>R?(u0*R/n0):u0, + nv0 = n0>R?(v0*R/n0):v0, + nw0 = (float)std::sqrt(cimg::max(0.0f,R2-nu0*nu0-nv0*nv0)), + nu1 = n1>R?(u1*R/n1):u1, + nv1 = n1>R?(v1*R/n1):v1, + nw1 = (float)std::sqrt(cimg::max(0.0f,R2-nu1*nu1-nv1*nv1)), + u = nv0*nw1-nw0*nv1, + v = nw0*nu1-nu0*nw1, + w = nv0*nu1-nu0*nv1, + n = (float)std::sqrt(u*u+v*v+w*w), + alpha = (float)std::asin(n/R2); + rot = CImg::get_rotation_matrix(u,v,w,alpha)*rot; + x0=x1; y0=y1; + } + if (disp.button&2) { oZ+=(y1-y0); x0=x1; y0=y1; } + if (disp.button&4) { oX+=(x1-x0); oY+=(y1-y0); x0=x1; y0=y1; } + if ((disp.button&1) && (disp.button&2)) { init = true; disp.button=0; x0=x1; y0=y1; } + } else if (clicked) { x0=x1; y0=y1; clicked = false; redraw = true; } + if (disp.key) { redraw = false; stopflag = true; } + if (disp.resized) { disp.resize(); visu0 = get_resize(disp,1); redraw = true; } + + if (redraw) { + + // Rotate object + const float + r00 = (float)rot(0,0), r10 = (float)rot(1,0), r20 = (float)rot(2,0), + r01 = (float)rot(0,1), r11 = (float)rot(1,1), r21 = (float)rot(2,1), + r02 = (float)rot(0,2), r12 = (float)rot(1,2), r22 = (float)rot(2,2); + + if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) { + if (centering) cimg_mapX(points,l) { + const float + x = centered_points(l,0), + y = centered_points(l,1), + z = centered_points(l,2); + rotated_points(l,0) = r00*x + r10*y + r20*z; + rotated_points(l,1) = r01*x + r11*y + r21*z; + rotated_points(l,2) = r02*x + r12*y + r22*z; + } else cimg_mapX(points,l) { + const float + x = (float)points(l,0)-oX, + y = (float)points(l,1)-oY, + z = (float)points(l,2); + rotated_points(l,0) = r00*x + r10*y + r20*z; + rotated_points(l,1) = r01*x + r11*y + r21*z; + rotated_points(l,2) = r02*x + r12*y + r22*z; + } + } else { + if (!centering) cimg_mapX(bbox_points,l) { + const float + x = bbox_points(l,0), + y = bbox_points(l,1), + z = bbox_points(l,2); + rotated_bbox_points(l,0) = r00*x + r10*y + r20*z; + rotated_bbox_points(l,1) = r01*x + r11*y + r21*z; + rotated_bbox_points(l,2) = r02*x + r12*y + r22*z; + } else cimg_mapX(bbox_points,l) { + const float + x = (bbox_points(l,0)-dx)*ratio, + y = (bbox_points(l,1)-dy)*ratio, + z = (bbox_points(l,2)-dz)*ratio; + rotated_bbox_points(l,0) = r00*x + r10*y + r20*z; + rotated_bbox_points(l,1) = r01*x + r11*y + r21*z; + rotated_bbox_points(l,2) = r02*x + r12*y + r22*z; + } + } + + // Draw object + visu=visu0; + if ((clicked && render_motion<0) || (!clicked && render_static<0)) + visu.draw_object3d(visu.width/2.0f + oX, visu.height/2.0f + oY,oZ, + rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,1, + false,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,0.2f); + else visu.draw_object3d(visu.width/2.0f + oX, visu.height/2.0f + oY,oZ, + rotated_points,primitives,colors,opacities,clicked?render_motion:render_static, + double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,ambiant_light); + + // Draw axes + if (display_axes) { + const float Xaxes = 25.0f, Yaxes = visu.height-35.0f; + cimg_mapX(axes_points,l) { + const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2); + rotated_axes_points(l,0) = r00*x + r10*y + r20*z; + rotated_axes_points(l,1) = r01*x + r11*y + r21*z; + rotated_axes_points(l,2) = r02*x + r12*y + r22*z; + } + axes_colors(0)=(rotated_axes_points(1,2)>0)?valmax/2:valmax; + axes_colors(1)=(rotated_axes_points(2,2)>0)?valmax/2:valmax; + axes_colors(2)=(rotated_axes_points(3,2)>0)?valmax/2:valmax; + visu.draw_object3d(Xaxes, Yaxes, 0, rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale,0,0,0,0). + draw_text("X",(int)(Xaxes+rotated_axes_points(4,0)), (int)(Yaxes+rotated_axes_points(4,1)), axes_colors[0].ptr()). + draw_text("Y",(int)(Xaxes+rotated_axes_points(5,0)), (int)(Yaxes+rotated_axes_points(5,1)), axes_colors[1].ptr()). + draw_text("Z",(int)(Xaxes+rotated_axes_points(6,0)), (int)(Yaxes+rotated_axes_points(6,1)), axes_colors[2].ptr()); + } + + visu.display(disp); + if (!clicked || render_motion==render_static) redraw = false; + } + wait(20); + } + + disp.events = oevents; + disp.button = 0; + return *this; + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const CImg& points, const CImgl& primitives, + const CImgl& colors, const CImgl& opacities, CImgDisplay& disp, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes=true, const bool keep_pos = false) const { + if (opacities.is_empty()) + return display_object3d(points,primitives,colors,CImg(),disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + CImg nopacities(opacities.size); + to *ptrd = nopacities.ptr(); + cimg_mapoff(nopacities,l) if (opacities(l).size()) *(ptrd++) = opacities(l,0); + else + throw CImgArgumentException("CImg<%s>::display_object3d() : Given opacities (size=%u) contains a null element at " + "position %u.",pixel_type(),opacities.size,l); + return display_object3d(points,primitives,colors,nopacities,disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const CImgl& points,const CImgl& primitives, + const CImgl& colors, const CImg& opacities, CImgDisplay& disp, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes=true, const bool keep_pos = false) const { + if (points.is_empty()) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.", + pixel_type()); + CImg npoints(points.size,3,1,1,0); + tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); + cimg_mapX(npoints,l) { + const CImg& point = points[l]; + const unsigned int siz = point.size(); + if (!siz) + throw CImgArgumentException("CImg<%s>::display_object3d() : Given points (size=%u) contains a null element at " + "position %u.",pixel_type(),points.size,l); + *(ptrZ++) = (siz>2)?point(2):0; + *(ptrY++) = (siz>1)?point(1):0; + *(ptrX++) = point(0); + } + return display_object3d(npoints,primitives,colors,opacities,disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const CImgl& points,const CImgl& primitives, + const CImgl& colors, const CImgl& opacities, CImgDisplay &disp, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes=true, const bool keep_pos = false) const { + if (opacities.is_empty()) + return display_object3d(points,primitives,colors,CImg(),disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + CImg nopacities(opacities.size); + to *ptrd = nopacities.ptr(); + cimg_mapoff(nopacities,l) if (opacities(l).size()) *(ptrd++) = opacities(l,0); + else + throw CImgArgumentException("CImg<%s>::display_object3d() : Given opacities (size=%u) contains a null element at " + "position %u.",pixel_type(),opacities.size,l); + return display_object3d(points,primitives,colors,nopacities,disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const tp& points, const CImgl& primitives, + const CImgl colors, const to& opacities, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const bool display_axes=true, const bool keep_pos = false) const { + CImgDisplay disp(width,height," ",0); + return display_object3d(points,primitives,colors,opacities,disp,centering, + render_static,render_motion,double_sided,focale,ambiant_light,display_axes,keep_pos); + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const tp& points, const CImgl& primitives, + const CImgl colors, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const float opacity=1.0f, const bool display_axes=true, const bool keep_pos = false) const { + CImgDisplay disp(width,height," ",0); + return display_object3d(points,primitives,colors,CImg(primitives.size,1,1,1,opacity), + disp,centering,render_static,render_motion,double_sided, + focale,ambiant_light,display_axes,keep_pos); + } + + //! High-level interface for displaying a 3d object + template + const CImg& display_object3d(const tp& points, const CImgl& primitives, + const CImgl colors, CImgDisplay &disp, + const bool centering=true, + const int render_static=4, const int render_motion=1, + const bool double_sided=false, + const float focale=500.0f, const float ambiant_light=0.05f, + const float opacity=1.0f, const bool display_axes=true, const bool keep_pos = false) const { + return display_object3d(points,primitives,colors,CImg(primitives.size,1,1,1,opacity), + disp,centering,render_static,render_motion,double_sided, + focale,ambiant_light,display_axes,keep_pos); + } + + //@} + //-------------------------------- + // + //! \name Input-Output functions + //@{ + //-------------------------------- + + //! Load an image from a file. + /** + \param filename = name of the image file to load. + \return A CImg instance containing the pixel data defined in the image file. + \note The extension of \c filename defines the file format. If no filename + extension is provided, CImg::get_load() will try to load a CRAW file (CImg Raw file). + **/ + static CImg get_load(const char *filename) { + if (!filename) throw CImgArgumentException("CImg<%s>::get_load() : Can't load (null) filename",pixel_type()); + const char *ext = cimg::filename_split(filename); + if (!cimg::strcasecmp(ext,"asc")) return get_load_ascii(filename); + if (!cimg::strcasecmp(ext,"dlm")) return get_load_dlm(filename); + if (!cimg::strcasecmp(ext,"inr")) return get_load_inr(filename); + if (!cimg::strcasecmp(ext,"hdr")) return get_load_analyze(filename); + if (!cimg::strcasecmp(ext,"par") || + !cimg::strcasecmp(ext,"rec")) return get_load_parrec(filename); + if (!cimg::strcasecmp(ext,"pan")) return get_load_pandore(filename); + if (!cimg::strcasecmp(ext,"bmp")) return get_load_bmp(filename); + if (!cimg::strcasecmp(ext,"png")) return get_load_png(filename); + if (!cimg::strcasecmp(ext,"jpg") || + !cimg::strcasecmp(ext,"jpeg")) return get_load_jpeg(filename); + if (!cimg::strcasecmp(ext,"ppm") || + !cimg::strcasecmp(ext,"pgm") || + !cimg::strcasecmp(ext,"pnm")) return get_load_pnm(filename); + if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return get_load_cimg(filename); + if (!cimg::strcasecmp(ext,"dcm") || + !cimg::strcasecmp(ext,"dicom")) return get_load_dicom(filename); + return get_load_convert(filename); + } + + //! Load an image from a file + /** This is the in-place version of get_load(). **/ + CImg& load(const char *filename) { return get_load(filename).swap(*this); } + + //! Load an image from an ASCII file. + static CImg get_load_ascii(const char *filename) { + std::FILE *file = cimg::fopen(filename,"rb"); + char line[256] = {0}; + std::fscanf(file,"%255[^\n]",line); + unsigned int off; + int err=1, dx=0, dy=1, dz=1, dv=1; + std::sscanf(line,"%d %d %d %d",&dx,&dy,&dz,&dv); + if (!dx || !dy || !dz || !dv) + throw CImgIOException("CImg<%s>::get_load_ascii() : File '%s' does not appear to be a valid ASC file.\n" + "Specified image dimensions are (%d,%d,%d,%d)",pixel_type(),filename,dx,dy,dz,dv); + CImg dest(dx,dy,dz,dv); + double val; + T *ptr = dest.data; + for (off=0; off::get_load_ascii() : File '%s', only %u values read, instead of %u", + pixel_type(),filename,off,dest.size()); + cimg::fclose(file); + return dest; + } + + //! Load an image from an ASCII file (in-place version). + /** This is the in-place version of get_load_ascii(). **/ + CImg& load_ascii(const char *filename) { return get_load_ascii(filename).swap(*this); } + + //! Load an image from a DLM file + static CImg get_load_dlm(const char *filename) { + std::FILE *file = cimg::fopen(filename,"r"); + CImg dest(256,256); + unsigned int cdx=0,dx=0,dy=0; + double val; + char c, delimiter[256]={0}, tmp[256]; + int oerr=0, err; + while ((err = std::fscanf(file,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) { + oerr = err; + if (err>0) dest(cdx++,dy) = (T)val; + if (cdx>=dest.width) dest.resize(dest.width+256,1,1,1,0); + c=0; if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { + dx = cimg::max(cdx,dx); + dy++; + if (dy>=dest.height) dest.resize(dest.width,dest.height+256,1,1,0); + cdx=0; + } + } + if (cdx && oerr==1) { dx=cdx; dy++; } + if (!dx || !dy) throw CImgIOException("CImg<%s>::get_load_dlm() : File '%s' does not appear to be a " + "valid DLM file (width = %d, height = %d)\n",pixel_type(),filename,dx,dy); + dest.resize(dx,dy,1,1,0); + cimg::fclose(file); + return dest; + } + + //! Load an image from a DLM file (in-place version). + /** This is the in-place version of get_load_dlm(). **/ + CImg& load_dlm(const char *filename) { return get_load_dlm(filename).swap(*this); } + + //! Load an image from a PNM file + static CImg get_load_pnm(const char *filename) { + std::FILE *file=cimg::fopen(filename,"rb"); + char item[1024]={0}; + unsigned int ppm_type,width,height,colormax=255; + int err; + + while ((err=std::fscanf(file,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file); + if(std::sscanf(item," P%u",&ppm_type)!=1) + throw CImgIOException("CImg<%s>::get_load_pnm() : file '%s',PPM header 'P?' not found",pixel_type(),filename); + while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file); + if ((err=std::sscanf(item," %u %u %u",&width,&height,&colormax))<2) + throw CImgIOException("CImg<%s>::get_load_pnm() : file '%s',WIDTH and HEIGHT not defined",pixel_type(),filename); + if (err==2) { + while ((err=std::fscanf(file," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(file); + cimg::warn(std::sscanf(item,"%u",&colormax)!=1, + "CImg<%s>::get_load_pnm() : file '%s',COLORMAX not defined",pixel_type(),filename); + } + std::fgetc(file); + + CImg dest; + int rval,gval,bval; + + switch (ppm_type) { + case 2: { // Grey Ascii + dest.assign(width,height,1,1); + T* rdata = dest.ptr(); + cimg_mapoff(dest,off) { std::fscanf(file,"%d",&rval); *(rdata++)=(T)rval; } + } break; + case 3: { // Color Ascii + dest.assign(width,height,1,3); + T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); + cimg_mapXY(dest,x,y) { + std::fscanf(file,"%d %d %d",&rval,&gval,&bval); + *(rdata++)=(T)rval; + *(gdata++)=(T)gval; + *(bdata++)=(T)bval; } + } break; + case 5: { // Grey Binary + if (colormax<256) { // 8 bits + CImg raw(width,height,1,1); + cimg::fread(raw.data,width*height,file); + dest=raw; + } else { // 16 bits + CImg raw(width,height,1,1); + cimg::fread(raw.data,width*height,file); + if (!cimg::endian()) cimg::endian_swap(raw.data,width*height); + dest=raw; + } + } break; + case 6: { // Color Binary + if (colormax<256) { // 8 bits + CImg raw(width,height,1,3); + cimg::fread(raw.data,width*height*3,file); + dest.assign(width,height,1,3); + T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); + const unsigned char *ptrs = raw.ptr(); + for (unsigned int off = raw.width*raw.height; off; --off) { + *(rdata++) = (T)(*(ptrs++)); + *(gdata++) = (T)(*(ptrs++)); + *(bdata++) = (T)(*(ptrs++)); + } + } else { // 16 bits + CImg raw(width,height,1,3); + cimg::fread(raw.data,width*height*3,file); + if (!cimg::endian()) cimg::endian_swap(raw.data,width*height*3); + dest.assign(width,height,1,3); + T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); + const unsigned short *ptrs = raw.ptr(); + for (unsigned int off = raw.width*raw.height; off; --off) { + *(rdata++) = (T)(*(ptrs++)); + *(gdata++) = (T)(*(ptrs++)); + *(bdata++) = (T)(*(ptrs++)); + } + } + } break; + default: + cimg::fclose(file); + throw CImgIOException("CImg<%s>::get_load_pnm() : file '%s', PPM type 'P%d' not supported",pixel_type(),filename,ppm_type); + } + cimg::fclose(file); + return dest; + } + + //! Load an image from a PNM file (in-place version). + CImg& load_pnm(const char *filename) { return get_load_pnm(filename).swap(*this); } + + //! Load a YUV image sequence file. + static CImg get_load_yuv(const char *filename, + const unsigned int sizex, const unsigned int sizey, + const unsigned int first_frame=0, const int last_frame=-1, + const bool yuv2rgb = true) { + return CImgl::get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).get_append('z','c'); + } + + //! Load a YUV image sequence file (in-place). + CImg& load_yuv(const char *filename, + const unsigned int sizex, const unsigned int sizey, + const unsigned int first_frame=0, const int last_frame=-1, + const bool yuv2rgb = true) { + return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); + } + + //! Load an image from a BMP file. + static CImg get_load_bmp(const char *filename) { + unsigned char header[64]; + std::FILE *file = cimg::fopen(filename,"rb"); + cimg::fread(header,54,file); + if (header[0]!='B' || header[1]!='M') + throw CImgIOException("CImg<%s>::get_load_bmp() : filename '%s' does not appear to be a valid BMP file", + pixel_type(),filename); + + // Read header and pixel buffer + int + file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24), + offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24), + dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24), + dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24), + compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24), + nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24), + bpp = header[0x1C] + (header[0x1D]<<8), + *palette = NULL; + const int + dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)), + align = (4-dx_bytes%4)%4, + buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset); + + if (bpp<16) { if (!nb_colors) nb_colors=1<0) std::fseek(file,xoffset,SEEK_CUR); + unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer; + cimg::fread(buffer,buf_size,file); + cimg::fclose(file); + + // Decompress buffer (if necessary) + if (compression) return get_load_convert(filename); + + // Read pixel data + CImg res(dx,cimg::abs(dy),1,3); + switch (bpp) { + case 1: { // Monochrome + for (int y=res.height-1; y>=0; y--) { + unsigned char tqmask = 0x80, val = 0; + cimg_mapX(res,x) { + if (tqmask==0x80) val = *(ptrs++); + const unsigned char *col = (unsigned char*)(palette+(val&tqmask?1:0)); + res(x,y,2) = (T)*(col++); + res(x,y,1) = (T)*(col++); + res(x,y,0) = (T)*(col++); + tqmask = cimg::ror(tqmask); + } ptrs+=align; } + } break; + case 4: { // 16 colors + for (int y=res.height-1; y>=0; y--) { + unsigned char tqmask = 0xF0, val = 0; + cimg_mapX(res,x) { + if (tqmask==0xF0) val = *(ptrs++); + const unsigned char color = (tqmask<16)?(val&tqmask):((val&tqmask)>>4); + unsigned char *col = (unsigned char*)(palette+color); + res(x,y,2) = (T)*(col++); + res(x,y,1) = (T)*(col++); + res(x,y,0) = (T)*(col++); + tqmask = cimg::ror(tqmask,4); + } ptrs+=align; } + } break; + case 8: { // 256 colors + for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) { + const unsigned char *col = (unsigned char*)(palette+*(ptrs++)); + res(x,y,2) = (T)*(col++); + res(x,y,1) = (T)*(col++); + res(x,y,0) = (T)*(col++); + } ptrs+=align; } + } break; + case 16: { // 16 bits colors + for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) { + const unsigned char c1 = *(ptrs++), c2 = *(ptrs++); + const unsigned short col = c1+(c2<<8); + res(x,y,2) = (T)(col&0x1F); + res(x,y,1) = (T)((col>>5)&0x1F); + res(x,y,0) = (T)((col>>10)&0x1F); + } ptrs+=align; } + } break; + case 24: { // 24 bits colors + for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) { + res(x,y,2) = (T)*(ptrs++); + res(x,y,1) = (T)*(ptrs++); + res(x,y,0) = (T)*(ptrs++); + } ptrs+=align; } + } break; + case 32: { // 32 bits colors + for (int y=res.height-1; y>=0; y--) { cimg_mapX(res,x) { + res(x,y,2) = (T)*(ptrs++); + res(x,y,1) = (T)*(ptrs++); + res(x,y,0) = (T)*(ptrs++); + ptrs++; + } ptrs+=align; } + } break; + } + + if (palette) delete[] palette; + delete[] buffer; + if (dy<0) res.mirror('y'); + return res; + } + + //! Load an image from a BMP file + CImg& load_bmp(const char *filename) { return get_load_bmp(filename).swap(*this); } + + //! Load an image from a PNG file. + // Note : Most of this function has been written by Eric Fausett + static CImg get_load_png(const char *filename) { +#ifndef cimg_use_png + return get_load_convert(filename); +#else + // Open file and check for PNG validity + unsigned char pngCheck[8]; + std::FILE *file = cimg::fopen(filename,"rb"); + cimg::fread(pngCheck,8,file); + if(png_sig_cmp(pngCheck,0,8)){ + cimg::fclose(file); + throw CImgIOException("CImg<%s>::get_load_png() : filename '%s' does not appear to be a valid PNG file",pixel_type(),filename); + } + + // Setup PNG structures for read + png_voidp user_error_ptr=0; + png_error_ptr user_error_fn=0, user_warning_fn=0; + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, // Verifies libpng version correct + user_error_ptr, user_error_fn, user_warning_fn); + if(!png_ptr){ + cimg::fclose(file); + throw CImgIOException("CImg<%s>::get_load_png() : trouble initializing 'png_ptr' data structure",pixel_type()); + } + png_infop info_ptr = png_create_info_struct(png_ptr); + if(!info_ptr){ + cimg::fclose(file); + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + throw CImgIOException("CImg<%s>::get_load_png() : trouble initializing 'info_ptr' data structure",pixel_type()); + } + png_infop end_info = png_create_info_struct(png_ptr); + if(!end_info){ + cimg::fclose(file); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + throw CImgIOException("CImg<%s>::get_load_png() : trouble initializing 'end_info' data structure",pixel_type()); + } + + // Error handling callback for png file reading + if (setjmp(png_jmpbuf(png_ptr))){ + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + cimg::fclose(file); + throw CImgIOException("CImg<%s>::get_load_png() : unspecified error reading PNG file '%s'",pixel_type(),filename); + } + png_init_io(png_ptr, file); + png_set_sig_bytes(png_ptr, 8); + + // Get PNG Header Info up to data block + png_read_info(png_ptr, info_ptr); + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, + int_p_NULL, int_p_NULL); + int new_bit_depth = bit_depth; + int new_color_type = color_type; + + // Transforms to unify image data + if (new_color_type == PNG_COLOR_TYPE_PALETTE){ + png_set_palette_to_rgb(png_ptr); + new_color_type -= PNG_COLOR_MASK_PALETTE; + new_bit_depth = 8; + } + if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){ + png_set_gray_1_2_4_to_8(png_ptr); + new_bit_depth = 8; + } + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){ + png_set_gray_to_rgb(png_ptr); + new_color_type |= PNG_COLOR_MASK_COLOR; + } + if (new_color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER); + png_read_update_info(png_ptr, info_ptr); + if (!(new_bit_depth==8 || new_bit_depth==16)) + throw CImgIOException("CImg<%s>::get_load_png() : Wrong bit coding 'bit_depth=%u'",pixel_type(),new_bit_depth); + const int byte_depth = new_bit_depth>>3; + + // Allocate Memory for Image Read + png_bytep *imgData = new png_bytep[height]; + for (unsigned int row=0; row < height; row++) imgData[row] = new png_byte[byte_depth * 4 * width]; + png_read_image(png_ptr, imgData); + png_read_end(png_ptr, end_info); + + // Read pixel data + if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) + throw CImgIOException("CImg<%s>::get_load_png() : Wrong color coding new_color_type=%u",pixel_type(),new_color_type); + const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB); + CImg res(width,height,1,no_alpha_channel?3:4); + const unsigned long off = width*height; + T *ptr1 = res.data, *ptr2 = ptr1+off, *ptr3 = ptr2+off, *ptr4 = ptr3+off; + switch(new_bit_depth){ + case 8: { + cimg_mapY(res,y){ + const unsigned char *ptrs = (unsigned char*)imgData[y]; + cimg_mapX(res,x){ + *(ptr1++) = (T)*(ptrs++); + *(ptr2++) = (T)*(ptrs++); + *(ptr3++) = (T)*(ptrs++); + if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++); + } + } + } break; + case 16: { + cimg_mapY(res,y){ + const unsigned short *ptrs = (unsigned short*)(imgData[y]); + cimg_mapX(res,x){ + *(ptr1++) = (T)*(ptrs++); + *(ptr2++) = (T)*(ptrs++); + *(ptr3++) = (T)*(ptrs++); + if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++); + } + } + } break; + } + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + + // Deallocate Image Read Memory + for (unsigned int n=0; n::get_load_jpeg() : Don't know how to read image '%s' with libpeg," + "trying ImageMagick's convert", + pixel_type(),filename); + return get_load_convert(filename); + } + + const unsigned int row_stride = cinfo.output_width * cinfo.output_components; + unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf; + JSAMPROW row_pointer[1]; + while (cinfo.output_scanline < cinfo.output_height) { + row_pointer[0] = &buf[cinfo.output_scanline*row_stride]; + jpeg_read_scanlines(&cinfo,row_pointer,1); + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + cimg::fclose(file); + + CImg dest(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); + switch (dest.dim) { + case 1: { + T *ptr_g = dest.ptr(); + cimg_mapXY(dest,x,y) *(ptr_g++) = (T)*(buf2++); + } break; + case 3: { + T *ptr_r = dest.ptr(0,0,0,0), *ptr_g = dest.ptr(0,0,0,1), *ptr_b = dest.ptr(0,0,0,2); + cimg_mapXY(dest,x,y) { + *(ptr_r++) = (T)*(buf2++); + *(ptr_g++) = (T)*(buf2++); + *(ptr_b++) = (T)*(buf2++); + } + } break; + case 4: { + T *ptr_r = dest.ptr(0,0,0,0), *ptr_g = dest.ptr(0,0,0,1), + *ptr_b = dest.ptr(0,0,0,2), *ptr_a = dest.ptr(0,0,0,3); + cimg_mapXY(dest,x,y) { + *(ptr_r++) = (T)*(buf2++); + *(ptr_g++) = (T)*(buf2++); + *(ptr_b++) = (T)*(buf2++); + *(ptr_a++) = (T)*(buf2++); + } + } break; + } + delete[] buf; + return dest; +#endif + } + + //! Load an image from a JPEG file + CImg& load_jpeg(const char *filename) { return get_load_jpeg(filename).swap(*this); } + + //! Load an image from a RAW file. + static CImg get_load_raw(const char *filename, + const unsigned int sizex, const unsigned int sizey=1, + const unsigned int sizez=1, const unsigned int sizev=1, + const bool multiplexed = false, const bool endian_swap = false) { + CImg res(sizex,sizey,sizez,sizev,0); + if (res.is_empty()) return res; + std::FILE *file = cimg::fopen(filename,"rb"); + if (!multiplexed) { + cimg::fread(res.ptr(),res.size(),file); + if (endian_swap) cimg::endian_swap(res.ptr(),res.size()); + } + else { + CImg buf(1,1,1,sizev); + cimg_mapXYZ(res,x,y,z) { + cimg::fread(buf.ptr(),sizev,file); + if (endian_swap) cimg::endian_swap(buf.ptr(),sizev); + res.set_vector(buf,x,y,z); } + } + cimg::fclose(file); + return res; + } + + //! In-place version of get_load_raw() + CImg& load_raw(const char *filename, + const unsigned int sizex, const unsigned int sizey=1, + const unsigned int sizez=1, const unsigned int sizev=1, + const bool multiplexed = false, const bool endian_swap = false) { + return get_load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap).swap(*this); + } + + //! Load an image from a RGBA file. + static CImg get_load_rgba(const char *filename,const unsigned int dimw,const unsigned int dimh) { + std::FILE *file = cimg::fopen(filename,"rb"); + unsigned char *buffer = new unsigned char[dimw*dimh*4]; + cimg::fread(buffer,dimw*dimh*4,file); + cimg::fclose(file); + CImg res(dimw,dimh,1,4); + T *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2), *pA = res.ptr(0,0,0,3); + const unsigned char *ptrs = buffer; + for (unsigned int off=res.width*res.height; off>0; --off) { + *(pR++) = *(ptrs++); + *(pG++) = *(ptrs++); + *(pB++) = *(ptrs++); + *(pA++) = *(ptrs++); + } + delete[] buffer; + return res; + } + + //! In-place version of get_load_rgba() + CImg& load_rgba(const char *filename,const unsigned int dimw,const unsigned int dimh) { + return get_load_rgba(filename,dimw,dimh).swap(*this); + } + + //! Load an image from a RGB file. + static CImg get_load_rgb(const char *filename,const unsigned int dimw,const unsigned int dimh) { + std::FILE *file = cimg::fopen(filename,"rb"); + unsigned char *buffer = new unsigned char[dimw*dimh*3]; + cimg::fread(buffer,dimw*dimh*3,file); + cimg::fclose(file); + CImg res(dimw,dimh,1,3); + T *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB=res.ptr(0,0,0,2); + const unsigned char *ptrs = buffer; + for (unsigned int off=res.width*res.height; off>0; --off) { + *(pR++) = *(ptrs++); + *(pG++) = *(ptrs++); + *(pB++) = *(ptrs++); + } + delete[] buffer; + return res; + } + + //! In-place version of get_load_rgb() + CImg& load_rgb(const char *filename,const unsigned int dimw,const unsigned int dimh) { + return get_load_rgb(filename,dimw,dimh).swap(*this); + } + +#define cimg_load_inr_case(Tf,sign,pixsize,Ts) \ + if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ + Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \ + cimg_mapYZ(dest,y,z) { \ + cimg::fread(val,fopt[0]*fopt[3],file); \ + if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]); \ + xval = val; cimg_mapX(dest,x) cimg_mapV(dest,k) \ + dest(x,y,z,k) = (T)*(xval++); \ + } \ + delete[] val; \ + loaded = true; \ + } + + static void _load_inr(std::FILE *file,int out[8],float *voxsize=NULL) { + char item[1024],tmp1[64],tmp2[64]; + out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1; + std::fscanf(file,"%63s",item); + if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) + throw CImgIOException("CImg<%s>::get_load_inr() : File does not appear to be a valid INR file.\n" + "(INRIMAGE-4 identifier not found)",pixel_type()); + while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) { + std::sscanf(item," XDIM%*[^0-9]%d",out); + std::sscanf(item," YDIM%*[^0-9]%d",out+1); + std::sscanf(item," ZDIM%*[^0-9]%d",out+2); + std::sscanf(item," VDIM%*[^0-9]%d",out+3); + std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6); + if (voxsize) { + std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize); + std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1); + std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2); + } + if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; + switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { + case 0: break; + case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2); + case 1: + if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4]=0; + if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4]=1; + if (!cimg::strncasecmp(tmp1,"packed",6)) out[4]=2; + if (out[4]>=0) break; + default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2); + } + } + if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) + throw CImgIOException("CImg<%s>::get_load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )", + pixel_type(),out[0],out[1],out[2],out[3]); + if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::get_load_inr() : TYPE is not fully defined",pixel_type()); + if(out[6]<0) throw CImgIOException("CImg<%s>::get_load_inr() : PIXSIZE is not fully defined",pixel_type()); + if(out[7]<0) throw CImgIOException("CImg<%s>::get_load_inr() : Big/Little Endian coding type is not defined",pixel_type()); + } + + //! Load an image from an INRIMAGE-4 file. + static CImg get_load_inr(const char *filename, float *voxsize = NULL) { + std::FILE *file = cimg::fopen(filename,"rb"); + int fopt[8], endian=cimg::endian()?1:0; + bool loaded = false; + if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1; + _load_inr(file,fopt,voxsize); + CImg dest(fopt[0],fopt[1],fopt[2],fopt[3]); + cimg_load_inr_case(0,0,8, unsigned char); + cimg_load_inr_case(0,1,8, char); + cimg_load_inr_case(0,0,16,unsigned short); + cimg_load_inr_case(0,1,16,short); + cimg_load_inr_case(0,0,32,unsigned int); + cimg_load_inr_case(0,1,32,int); + cimg_load_inr_case(1,0,32,float); + cimg_load_inr_case(1,1,32,float); + cimg_load_inr_case(1,0,64,double); + cimg_load_inr_case(1,1,64,double); + if (!loaded) throw CImgIOException("CImg<%s>::get_load_inr() : File '%s', can't read images of the type specified in the file", + pixel_type(),filename); + cimg::fclose(file); + return dest; + } + + //! In-place version of get_load_inr() + CImg& load_inr(const char *filename, float *voxsize = NULL) { return get_load_inr(filename,voxsize).swap(*this); } + +#define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype) \ + case nid: { \ + cimg::fread(dims,nbdim,file); \ + if (endian) cimg::endian_swap(dims,nbdim); \ + dest.assign(nwidth,nheight,ndepth,ndim); \ + stype *buffer = new stype[dest.size()]; \ + cimg::fread(buffer,dest.size(),file); \ + if (endian) cimg::endian_swap(buffer,dest.size()); \ + T *ptrd = dest.ptr(); \ + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); \ + buffer-=dest.size(); \ + delete[] buffer; \ + } \ + break; + + //! Load an image from a PANDORE-5 file. + static CImg get_load_pandore(const char *filename) { + std::FILE *file = cimg::fopen(filename,"rb"); + typedef unsigned char uchar; + typedef unsigned short ushort; + typedef unsigned int uint; + typedef unsigned long ulong; + CImg dest; + char tmp[32]; + cimg::fread(tmp,12,file); + if (cimg::strncasecmp("PANDORE",tmp,7)) + throw CImgIOException("CImg<%s>::get_load_pandore() : File '%s' does not appear to be a valid PANDORE file.\n" + "(PANDORE identifier not found)",pixel_type(),filename); + unsigned int imageid,dims[8]; + int ptbuf[4]; + cimg::fread(&imageid,1,file); + const bool endian = (imageid>255); + if (endian) cimg::endian_swap(imageid); + + cimg::fread(tmp,20,file); + switch (imageid) { + cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar); + cimg_load_pandore_case(3,2,dims[1],1,1,1,long); + cimg_load_pandore_case(4,2,dims[1],1,1,1,float); + cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar); + cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long); + cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float); + cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar); + cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long); + cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float); + + case 11: { // Region 1D + cimg::fread(dims,3,file); + if (endian) cimg::endian_swap(dims,3); + dest.assign(dims[1],1,1,1); + if (dims[2]<256) { + unsigned char *buffer = new unsigned char[dest.size()]; + cimg::fread(buffer,dest.size(),file); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + if (dims[2]<65536) { + unsigned short *buffer = new unsigned short[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + unsigned int *buffer = new unsigned int[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } + } + } + break; + case 12: { // Region 2D + cimg::fread(dims,4,file); + if (endian) cimg::endian_swap(dims,4); + dest.assign(dims[2],dims[1],1,1); + if (dims[3]<256) { + unsigned char *buffer = new unsigned char[dest.size()]; + cimg::fread(buffer,dest.size(),file); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + if (dims[3]<65536) { + unsigned short *buffer = new unsigned short[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + unsigned long *buffer = new unsigned long[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } + } + } + break; + case 13: { // Region 3D + cimg::fread(dims,5,file); + if (endian) cimg::endian_swap(dims,5); + dest.assign(dims[3],dims[2],dims[1],1); + if (dims[4]<256) { + unsigned char *buffer = new unsigned char[dest.size()]; + cimg::fread(buffer,dest.size(),file); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + if (dims[4]<65536) { + unsigned short *buffer = new unsigned short[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } else { + unsigned int *buffer = new unsigned int[dest.size()]; + cimg::fread(buffer,dest.size(),file); + if (endian) cimg::endian_swap(buffer,dest.size()); + T *ptrd = dest.ptr(); + cimg_mapoff(dest,off) *(ptrd++) = (T)(*(buffer++)); + buffer-=dest.size(); + delete[] buffer; + } + } + } + break; + cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar); + cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long); + cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float); + cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar); + cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long); + cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float); + cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar); + cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long); + cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong); + cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float); + cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar); + cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long); + cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong); + cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float); + cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar); + cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long); + cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong); + cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float); + case 34: // Points 1D + cimg::fread(ptbuf,1,file); + if (endian) cimg::endian_swap(ptbuf,1); + dest.assign(1); dest[0]=(T)ptbuf[0]; + break; + case 35: // Points 2D + cimg::fread(ptbuf,2,file); + if (endian) cimg::endian_swap(ptbuf,2); + dest.assign(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0]; + break; + case 36: // Points 3D + cimg::fread(ptbuf,3,file); + if (endian) cimg::endian_swap(ptbuf,3); + dest.assign(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0]; + break; + default: + throw CImgIOException("CImg<%s>::get_load_pandore() : File '%s', can't read images with ID_type=%u",pixel_type(),filename,imageid); + } + return dest; + } + + //! In-place version of get_load_pandore() + CImg& load_pandore(const char *filename) { return get_load_pandore(filename).swap(*this); } + + //! Load an image from an ANALYZE7.5 file + static CImg get_load_analyze(const char *filename, float *voxsize = NULL) { + + // Open header and data files + std::FILE *file_header=NULL, *file=NULL; + char body[1024]; + const char *ext = cimg::filename_split(filename,body); + if (!cimg::strcasecmp(ext,"hdr") || !cimg::strcasecmp(ext,"img")) { + std::sprintf(body+cimg::strlen(body),".hdr"); + file_header = cimg::fopen(body,"rb"); + std::sprintf(body+cimg::strlen(body)-3,"img"); + file = cimg::fopen(body,"rb"); + } else throw CImgIOException("CImg<%s>::get_load_analyze() : Cannot load filename '%s' as an analyze format",pixel_type(),filename); + + // Read header + bool endian = false; + unsigned int header_size; + cimg::fread(&header_size,1,file_header); + if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); } + unsigned char *header = new unsigned char[header_size]; + cimg::fread(header+4,header_size-4,file_header); + cimg::fclose(file_header); + if (endian) { + cimg::endian_swap((short*)(header+40),5); + cimg::endian_swap((short*)(header+70),1); + cimg::endian_swap((short*)(header+72),1); + cimg::endian_swap((float*)(header+76),4); + cimg::endian_swap((float*)(header+112),1); + } + unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1; + cimg::warn(!dim[0],"CImg<%s>::get_load_analyze() : Specified image has zero dimensions.",pixel_type()); + cimg::warn(dim[0]>4,"CImg<%s>::get_load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions", + pixel_type(),dim[0]); + if (dim[0]>=1) dimx = dim[1]; + if (dim[0]>=2) dimy = dim[2]; + if (dim[0]>=3) dimz = dim[3]; + if (dim[0]>=4) dimv = dim[4]; + + float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1; + const unsigned short datatype = *(short*)(header+70); + if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; } + delete[] header; + + // Read pixel data + CImg dest(dimx,dimy,dimz,dimv); + switch (datatype) { + case 2: { + unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv]; + cimg::fread(buffer,dimx*dimy*dimz*dimv,file); + cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); + delete[] buffer; + } break; + case 4: { + short *buffer = new short[dimx*dimy*dimz*dimv]; + cimg::fread(buffer,dimx*dimy*dimz*dimv,file); + if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); + cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); + delete[] buffer; + } break; + case 8: { + int *buffer = new int[dimx*dimy*dimz*dimv]; + cimg::fread(buffer,dimx*dimy*dimz*dimv,file); + if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); + cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); + delete[] buffer; + } break; + case 16: { + float *buffer = new float[dimx*dimy*dimz*dimv]; + cimg::fread(buffer,dimx*dimy*dimz*dimv,file); + if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); + cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); + delete[] buffer; + } break; + case 64: { + double *buffer = new double[dimx*dimy*dimz*dimv]; + cimg::fread(buffer,dimx*dimy*dimz*dimv,file); + if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); + cimg_mapoff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); + delete[] buffer; + } break; + default: throw CImgIOException("CImg<%s>::get_load_analyze() : Cannot read images width 'datatype = %d'",pixel_type(),datatype); + } + cimg::fclose(file); + return dest; + } + + //! In-place version of get_load_analyze() + CImg& load_analyze(const char *filename, float *voxsize = NULL) { return get_load_analyze(filename,voxsize).swap(*this); } + + //! Load PAR-REC (Philips) image file + static CImg get_load_parrec(const char *filename,const char axe='v',const char align='p') { + return CImgl::get_load_parrec(filename).get_append(axe,align); + } + + //! In-place version of get_load_parrec() + CImg& load_parrec(const char *filename, const char axis='v', const char align='p') { + return get_load_parrec(filename,axis,align).swap(*this); + } + + //! Load an image from a CImg RAW file + static CImg get_load_cimg(const char *filename, const char axis='v', const char align='p') { + return CImgl(filename).get_append(axis,align); + } + + //! In-place version of get_load_cimg() + CImg& load_cimg(const char* filename, const char axis='v', const char align='p') { + return get_load_cimg(filename,axis,align).swap(*this); + } + + //! Function that loads the image for other file formats that are not natively handled by CImg, using the tool 'convert' from the ImageMagick package.\n + //! This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install the ImageMagick package in order to get + //! this function working properly (see http://www.imagemagick.org ). + static CImg get_load_convert(const char *filename) { + static bool first_time = true; + char command[1024], filetmp[512]; + if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; } + std::FILE *file = NULL; + do { + if (file) std::fclose(file); + std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),std::rand()%10000); + file = std::fopen(filetmp,"rb"); + } while (file); + std::sprintf(command,"\"%s\" \"%s\" %s",cimg::convert_path(),filename,filetmp); + cimg::system(command); + file = std::fopen(filetmp,"rb"); + if (!file) { + std::fclose(cimg::fopen(filename,"r")); + throw CImgIOException("CImg<%s>::get_load_convert() : Failed to open image '%s' with 'convert'.\n" + "Check that you have installed the ImageMagick package in a standard directory.", + pixel_type(),filename); + } else cimg::fclose(file); + const CImg dest = CImg::get_load_pnm(filetmp); + std::remove(filetmp); + return dest; + } + + //! In-place version of get_load_convert() + CImg& load_convert(const char *filename) { return get_load_convert(filename).swap(*this); } + + //! Load an image from a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net ) + static CImg get_load_dicom(const char *filename) { + static bool first_time = true; + char command[1024], filetmp[512], body[512]; + if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; } + cimg::fclose(cimg::fopen(filename,"r")); + std::FILE *file = NULL; + do { + if (file) std::fclose(file); + std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000); + file = std::fopen(filetmp,"rb"); + } while (file); + std::sprintf(command,"\"%s\" -w -c anlz -o \"%s\" -f \"%s\"",cimg::medcon_path(),filetmp,filename); + cimg::system(command); + cimg::filename_split(filetmp,body); + std::sprintf(command,"m000-%s.hdr",body); + file = std::fopen(command,"rb"); + if (!file) { + std::fclose(cimg::fopen(filename,"r")); + throw CImgIOException("CImg<%s>::get_load_dicom() : Failed to open image '%s' with 'medcon'.\n" + "Check that you have installed the XMedCon package in a standard directory.", + pixel_type(),filename); + } else cimg::fclose(file); + const CImg dest = CImg::get_load_analyze(command); + std::remove(command); + std::sprintf(command,"m000-%s.img",body); + std::remove(command); + return dest; + } + + //! In-place version of get_load_dicom() + CImg& load_dicom(const char *filename) { return get_load_dicom(filename).swap(*this); } + + //! Load OFF files (GeomView 3D object files) + template + static CImg get_load_off(const char *filename, CImgl& primitives, CImgl& colors, const bool invert_faces=false) { + std::FILE *file=cimg::fopen(filename,"r"); + unsigned int nb_points=0, nb_triangles=0; + int err; + if ((err = std::fscanf(file,"OFF%u%u%*[^\n]",&nb_points,&nb_triangles))!=2) + throw CImgIOException("CImg<%s>::get_load_off() : File '%s' does not appear to be a valid OFF file.\n", + pixel_type(),filename); + + // Read points data + CImg points(nb_points,3); + float X=0,Y=0,Z=0; + cimg_mapX(points,l) { + if ((err = std::fscanf(file,"%f%f%f%*[^\n]",&X,&Y,&Z))!=3) + throw CImgIOException("CImg<%s>::get_load_off() : File '%s', cannot read point %u.\n", + pixel_type(),filename,l); + points(l,0) = (T)X; points(l,1) = (T)Y; points(l,2) = (T)Z; + } + + // Read primitive data + primitives.empty(); + colors.empty(); + bool stopflag = false; + while (!stopflag) { + unsigned int prim=0; + if ((err = std::fscanf(file,"%u",&prim))!=1) stopflag=true; + else switch (prim) { + case 3: { + unsigned int i0=0,i1=0,i2=0; + float c0=0.5,c1=0.5,c2=0.5; + if ((err = std::fscanf(file,"%u%u%u%f%f%f%*[^\n]",&i0,&i1,&i2,&c0,&c1,&c2))<3) stopflag = true; + else { + if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2)); + else primitives.insert(CImg::vector(i0,i2,i1)); + colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); + } + } break; + case 4: { + unsigned int i0=0,i1=0,i2=0,i3=0; + float c0=0.5,c1=0.5,c2=0.5; + if ((err = std::fscanf(file,"%u%u%u%u%f%f%f%*[^\n]",&i0,&i1,&i2,&i3,&c0,&c1,&c2))<4) stopflag = true; + else { + if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2,i3)); + else primitives.insert(CImg::vector(i0,i3,i2,i1)); + colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); + } + } break; + default: stopflag = true; + } + } + cimg::fclose(file); + cimg::warn(primitives.size!=nb_triangles, + "CImg<%s>::get_load_off() : File '%s' contained %u triangles instead of %u as claimed in the header.", + pixel_type(),filename,primitives.size,nb_triangles); + return points; + } + + //! In-place version of get_load_off() + template + CImg& load_off(const char *filename, CImgl& primitives, CImgl& colors, const bool invert_faces=false) { + return get_load_off(filename,primitives,colors,invert_faces).swap(*this); + } + + //! Save the image as a file. + /** + The used file format is defined by the file extension in the filename \p filename.\n + Parameter \p number can be used to add a 6-digit number to the filename before saving.\n + If \p normalize is true, a normalized version of the image (between [0,255]) is saved. + **/ + const CImg& save(const char *filename,const int number=-1) const { + if (!filename) throw CImgArgumentException("CImg<%s>::save() : Specified filename is (null).",pixel_type()); + const char *ext = cimg::filename_split(filename); + char nfilename[1024]; + if (number>=0) filename = cimg::filename_number(filename,number,6,nfilename); + if (!cimg::strcasecmp(ext,"asc")) return save_ascii(filename); + if (!cimg::strcasecmp(ext,"dlm")) return save_dlm(filename); + if (!cimg::strcasecmp(ext,"inr")) return save_inr(filename); + if (!cimg::strcasecmp(ext,"hdr")) return save_analyze(filename); + if (!cimg::strcasecmp(ext,"dcm")) return save_dicom(filename); + if (!cimg::strcasecmp(ext,"pan")) return save_pandore(filename); + if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(filename); + if (!cimg::strcasecmp(ext,"png")) return save_png(filename); + if (!cimg::strcasecmp(ext,"jpg") || + !cimg::strcasecmp(ext,"jpeg")) return save_jpeg(filename); + if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(filename); + if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(filename); + if (!cimg::strcasecmp(ext,"raw")) return save_raw(filename); + if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(filename); + if (!cimg::strcasecmp(ext,"pgm") || + !cimg::strcasecmp(ext,"ppm") || + !cimg::strcasecmp(ext,"pnm")) return save_pnm(filename); + if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(filename,true); + return save_convert(filename); + } + + //! Save the image as an ASCII file. + const CImg& save_ascii(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_ascii() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"w"); + std::fprintf(file,"%u %u %u %u\n",width,height,depth,dim); + const T* ptrs = data; + cimg_mapYZV(*this,y,z,v) { + cimg_mapX(*this,x) std::fprintf(file,"%g ",(double)*(ptrs++)); + std::fputc('\n',file); + } + cimg::fclose(file); + return *this; + } + + //! Save the image as a DLM file. + const CImg& save_dlm(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_dlm() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"w"); + const T* ptrs = data; + cimg_mapYZV(*this,y,z,v) { + cimg_mapX(*this,x) std::fprintf(file,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":","); + std::fputc('\n',file); + } + cimg::fclose(file); + return *this; + } + + //! Save the image as a PNM file. + const CImg& save_pnm(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_pnm() : Specified filename is (null).",pixel_type()); + const char *ext = cimg::filename_split(filename); + const CImgStats st(*this,false); + + if (dim>1 && !cimg::strcasecmp(ext,"pgm")) { + get_norm_pointwise().normalize(0.0f,(float)st.max).save_pnm(filename); + return *this; + } + std::FILE *file = cimg::fopen(filename,"wb"); + const T + *ptrR = ptr(0,0,0,0), + *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR, + *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR; + const unsigned int buf_size = width*height*(dim==1?1:3); + + std::fprintf(file,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n", + (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535); + + switch(dim) { + case 1: { + if ((st.max)<256) { // Binary PGM 8 bits + unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd; + cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++); + cimg::fwrite(ptrd,buf_size,file); + delete[] ptrd; + } else { // Binary PGM 16 bits + unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd; + cimg_mapXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++); + if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size); + cimg::fwrite(ptrd,buf_size,file); + delete[] ptrd; + } + } break; + default: { + if ((st.max)<256) { // Binary PPM 8 bits + unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd; + cimg_mapXY(*this,x,y) { + *(xptrd++) = (unsigned char)*(ptrR++); + *(xptrd++) = (unsigned char)*(ptrG++); + *(xptrd++) = (unsigned char)*(ptrB++); + } + cimg::fwrite(ptrd,buf_size,file); + delete[] ptrd; + } else { // Binary PPM 16 bits + unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd; + cimg_mapXY(*this,x,y) { + *(xptrd++) = (unsigned short)*(ptrR++); + *(xptrd++) = (unsigned short)*(ptrG++); + *(xptrd++) = (unsigned short)*(ptrB++); + } + if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size); + cimg::fwrite(ptrd,buf_size,file); + delete[] ptrd; + } + } break; + } + cimg::fclose(file); + + return *this; + } + + //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net ) + const CImg& save_dicom(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dicom() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_dicom() : Specified filename is (null).",pixel_type()); + static bool first_time = true; + char command[1024], filetmp[512], body[512]; + if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; } + std::FILE *file = NULL; + do { + if (file) std::fclose(file); + std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000); + file = std::fopen(filetmp,"rb"); + } while (file); + save_analyze(filetmp); + std::sprintf(command,"\"%s\" -w -c dicom -o \"%s\" -f \"%s\"",cimg::medcon_path(),filename,filetmp); + cimg::system(command); + std::remove(filetmp); + cimg::filename_split(filetmp,body); + std::sprintf(filetmp,"%s.img",body); + std::remove(filetmp); + std::sprintf(command,"m000-%s",filename); + file = std::fopen(command,"rb"); + if (!file) { + std::fclose(cimg::fopen(filename,"r")); + throw CImgIOException("CImg<%s>::save_dicom() : Failed to save image '%s' with 'medcon'.\n" + "Check that you have installed the XMedCon package in a standard directory.", + pixel_type(),filename); + } else cimg::fclose(file); + std::rename(command,filename); + return *this; + } + + //! Save the image as an ANALYZE7.5 file. + const CImg& save_analyze(const char *filename,const float *const voxsize=NULL) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_analyze() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_analyze() : Specified filename is (null).",pixel_type()); + std::FILE *file; + char header[348],hname[1024],iname[1024]; + const char *ext = cimg::filename_split(filename); + short datatype=-1; + std::memset(header,0,348); + if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); } + if (!cimg::strncasecmp(ext,"hdr",3)) { + std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img"); + } + if (!cimg::strncasecmp(ext,"img",3)) { + std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr"); + } + ((int*)(header))[0] = 348; + std::sprintf(header+4,"CImg"); + std::sprintf(header+14," "); + ((short*)(header+36))[0] = 4096; + ((char*)(header+38))[0] = 114; + ((short*)(header+40))[0] = 4; + ((short*)(header+40))[1] = width; + ((short*)(header+40))[2] = height; + ((short*)(header+40))[3] = depth; + ((short*)(header+40))[4] = dim; + if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; + if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; + if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; + if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4; + if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4; + if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8; + if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8; + if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8; + if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8; + if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16; + if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64; + if (datatype<0) + throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)" + "is not handled in Analyze7.5 specifications.\n", + pixel_type(),filename,pixel_type()); + ((short*)(header+70))[0] = datatype; + ((short*)(header+72))[0] = sizeof(T); + ((float*)(header+112))[0] = 1; + ((float*)(header+76))[0] = 0; + if (voxsize) { + ((float*)(header+76))[1] = voxsize[0]; + ((float*)(header+76))[2] = voxsize[1]; + ((float*)(header+76))[3] = voxsize[2]; + } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1; + file = cimg::fopen(hname,"wb"); + cimg::fwrite(header,348,file); + cimg::fclose(file); + file = cimg::fopen(iname,"wb"); + cimg::fwrite(data,size(),file); + cimg::fclose(file); + return *this; + } + + //! Save the image as a CImg RAW file + const CImg& save_cimg(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_cimg() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_cimg() : Specified filename is (null).",pixel_type()); + CImgl tmp(1); + tmp[0].width = width; + tmp[0].height = height; + tmp[0].depth = depth; + tmp[0].dim = dim; + tmp[0].data = data; + tmp.save_cimg(filename); + tmp[0].width = tmp[0].height = tmp[0].depth = tmp[0].dim = 0; + tmp[0].data = NULL; + return *this; + } + + //! Save the image as a RAW file + const CImg& save_raw(const char *filename, const bool multiplexed=false) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_raw() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + if (!multiplexed) cimg::fwrite(data,size(),file); + else { + CImg buf(dim); + cimg_mapXYZ(*this,x,y,z) { + cimg_mapV(*this,k) buf[k] = (*this)(x,y,z,k); + cimg::fwrite(buf.data,dim,file); + } + } + cimg::fclose(file); + return *this; + } + + //! Save the image using ImageMagick's convert. + /** Function that saves the image for other file formats that are not natively handled by CImg, + using the tool 'convert' from the ImageMagick package.\n + This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install + the ImageMagick package in order to get + this function working properly (see http://www.imagemagick.org ). + **/ + const CImg& save_convert(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_convert() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_convert() : Specified filename is (null).",pixel_type()); + static bool first_time = true; + char command[512],filetmp[512]; + if (first_time) { std::srand((unsigned int)::time(NULL)); first_time = false; } + std::FILE *file = NULL; + do { + if (file) std::fclose(file); + std::sprintf(filetmp,"%s/CImg%.4d.ppm",cimg::temporary_path(),std::rand()%10000); + file = std::fopen(filetmp,"rb"); + } while (file); + save_pnm(filetmp); + std::sprintf(command,"\"%s\" -quality 100%% %s \"%s\"",cimg::convert_path(),filetmp,filename); + cimg::system(command); + file = std::fopen(filename,"rb"); + if (!file) throw CImgIOException("CImg<%s>::save_convert() : Failed to save image '%s' with 'convert'.\n" + "Check that you have installed the ImageMagick package in a standard directory.", + pixel_type(),filename); + if (file) cimg::fclose(file); + std::remove(filetmp); + return *this; + } + + //! Save the image as an INRIMAGE-4 file. + const CImg& save_inr(const char *filename,const float *const voxsize = NULL) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_inr() : Specified filename is (null).",pixel_type()); + int inrpixsize=-1; + const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; + if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } + if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } + if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; } + if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; } + if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; } + if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; } + if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; } + if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; } + if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",pixel_type(),pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + char header[257]; + int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim); + if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]); + err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm"); + std::memset(header+err,'\n',252-err); + std::memcpy(header+252,"##}\n",4); + cimg::fwrite(header,256,file); + cimg_mapXYZ(*this,x,y,z) cimg_mapV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,file); + cimg::fclose(file); + return *this; + } + +#define cimg_save_pandore_case(sy,sz,sv,stype,id) \ + if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \ + unsigned int *iheader = (unsigned int*)(header+12); \ + nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ + cimg::fwrite(header,36,file); \ + cimg::fwrite(dims,nbdims,file); \ + if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ + unsigned char *buffer = new unsigned char[size()]; \ + const T *ptrs = ptr(); \ + cimg_mapoff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++)); \ + buffer-=size(); \ + cimg::fwrite(buffer,size(),file); \ + delete[] buffer; \ + } \ + if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ + unsigned long *buffer = new unsigned long[size()]; \ + const T *ptrs = ptr(); \ + cimg_mapoff(*this,off) *(buffer++)=(long)(*(ptrs++)); \ + buffer-=size(); \ + cimg::fwrite(buffer,size(),file); \ + delete[] buffer; \ + } \ + if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ + float *buffer = new float[size()]; \ + const T *ptrs = ptr(); \ + cimg_mapoff(*this,off) *(buffer++)=(float)(*(ptrs++)); \ + buffer-=size(); \ + cimg::fwrite(buffer,size(),file); \ + delete[] buffer; \ + } \ + saved = true; \ + } + + unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims,const unsigned int colorspace=0) const { + unsigned int nbdims=0; + if (id==2 || id==3 || id==4) { dims[0]=1; dims[1]=width; nbdims=2; } + if (id==5 || id==6 || id==7) { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; } + if (id==8 || id==9 || id==10) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; } + if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=colorspace; nbdims=4; } + if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=colorspace; nbdims=5; } + if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; } + if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; } + if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; } + return nbdims; + } + + //! Save the image as a PANDORE-5 file. + const CImg& save_pandore(const char* filename, const unsigned int colorspace=0) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_pandore() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, + 0,0,0,0, + 'C','I','m','g',0,0,0,0,0, + 'N','o',' ','d','a','t','e',0,0,0, + 0 }; + unsigned int nbdims,dims[5]; + bool saved=false; + cimg_save_pandore_case(1,1,1,"unsigned char",2); + cimg_save_pandore_case(1,1,1,"char",3); + cimg_save_pandore_case(1,1,1,"short",3); + cimg_save_pandore_case(1,1,1,"unsigned short",3); + cimg_save_pandore_case(1,1,1,"unsigned int",3); + cimg_save_pandore_case(1,1,1,"int",3); + cimg_save_pandore_case(1,1,1,"unsigned long",4); + cimg_save_pandore_case(1,1,1,"long",3); + cimg_save_pandore_case(1,1,1,"float",4); + cimg_save_pandore_case(1,1,1,"double",4); + + cimg_save_pandore_case(0,1,1,"unsigned char",5); + cimg_save_pandore_case(0,1,1,"char",6); + cimg_save_pandore_case(0,1,1,"short",6); + cimg_save_pandore_case(0,1,1,"unsigned short",6); + cimg_save_pandore_case(0,1,1,"unsigned int",6); + cimg_save_pandore_case(0,1,1,"int",6); + cimg_save_pandore_case(0,1,1,"unsigned long",7); + cimg_save_pandore_case(0,1,1,"long",6); + cimg_save_pandore_case(0,1,1,"float",7); + cimg_save_pandore_case(0,1,1,"double",7); + + cimg_save_pandore_case(0,0,1,"unsigned char",8); + cimg_save_pandore_case(0,0,1,"char",9); + cimg_save_pandore_case(0,0,1,"short",9); + cimg_save_pandore_case(0,0,1,"unsigned short",9); + cimg_save_pandore_case(0,0,1,"unsigned int",9); + cimg_save_pandore_case(0,0,1,"int",9); + cimg_save_pandore_case(0,0,1,"unsigned long",10); + cimg_save_pandore_case(0,0,1,"long",9); + cimg_save_pandore_case(0,0,1,"float",10); + cimg_save_pandore_case(0,0,1,"double",10); + + cimg_save_pandore_case(0,1,3,"unsigned char",16); + cimg_save_pandore_case(0,1,3,"char",17); + cimg_save_pandore_case(0,1,3,"short",17); + cimg_save_pandore_case(0,1,3,"unsigned short",17); + cimg_save_pandore_case(0,1,3,"unsigned int",17); + cimg_save_pandore_case(0,1,3,"int",17); + cimg_save_pandore_case(0,1,3,"unsigned long",18); + cimg_save_pandore_case(0,1,3,"long",17); + cimg_save_pandore_case(0,1,3,"float",18); + cimg_save_pandore_case(0,1,3,"double",18); + + cimg_save_pandore_case(0,0,3,"unsigned char",19); + cimg_save_pandore_case(0,0,3,"char",20); + cimg_save_pandore_case(0,0,3,"short",20); + cimg_save_pandore_case(0,0,3,"unsigned short",20); + cimg_save_pandore_case(0,0,3,"unsigned int",20); + cimg_save_pandore_case(0,0,3,"int",20); + cimg_save_pandore_case(0,0,3,"unsigned long",21); + cimg_save_pandore_case(0,0,3,"long",20); + cimg_save_pandore_case(0,0,3,"float",21); + cimg_save_pandore_case(0,0,3,"double",21); + + cimg_save_pandore_case(1,1,0,"unsigned char",22); + cimg_save_pandore_case(1,1,0,"char",23); + cimg_save_pandore_case(1,1,0,"short",23); + cimg_save_pandore_case(1,1,0,"unsigned short",23); + cimg_save_pandore_case(1,1,0,"unsigned int",23); + cimg_save_pandore_case(1,1,0,"int",23); + cimg_save_pandore_case(1,1,0,"unsigned long",25); + cimg_save_pandore_case(1,1,0,"long",23); + cimg_save_pandore_case(1,1,0,"float",25); + cimg_save_pandore_case(1,1,0,"double",25); + + cimg_save_pandore_case(0,1,0,"unsigned char",26); + cimg_save_pandore_case(0,1,0,"char",27); + cimg_save_pandore_case(0,1,0,"short",27); + cimg_save_pandore_case(0,1,0,"unsigned short",27); + cimg_save_pandore_case(0,1,0,"unsigned int",27); + cimg_save_pandore_case(0,1,0,"int",27); + cimg_save_pandore_case(0,1,0,"unsigned long",29); + cimg_save_pandore_case(0,1,0,"long",27); + cimg_save_pandore_case(0,1,0,"float",29); + cimg_save_pandore_case(0,1,0,"double",29); + + cimg_save_pandore_case(0,0,0,"unsigned char",30); + cimg_save_pandore_case(0,0,0,"char",31); + cimg_save_pandore_case(0,0,0,"short",31); + cimg_save_pandore_case(0,0,0,"unsigned short",31); + cimg_save_pandore_case(0,0,0,"unsigned int",31); + cimg_save_pandore_case(0,0,0,"int",31); + cimg_save_pandore_case(0,0,0,"unsigned long",33); + cimg_save_pandore_case(0,0,0,"long",31); + cimg_save_pandore_case(0,0,0,"float",33); + cimg_save_pandore_case(0,0,0,"double",33); + + cimg::fclose(file); + return *this; + } + + //! Save the image as a YUV file + const CImg& save_yuv(const char *filename, const bool rgb2yuv=true) const { + CImgl(*this).save_yuv(filename,rgb2yuv); + return *this; + } + + //! Save the image as a BMP file + const CImg& save_bmp(const char* filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_bmp() : Specified filename is (null).",pixel_type()); + + std::FILE *file = cimg::fopen(filename,"wb"); + unsigned char header[54]={0}, align_buf[4]={0}; + const unsigned int + align = (4-(3*width)%4)%4, + buf_size = (3*width+align)*dimy(), + file_size = 54+buf_size; + header[0] = 'B'; header[1] = 'M'; + header[0x02]=file_size&0xFF; header[0x03]=(file_size>>8)&0xFF; + header[0x04]=(file_size>>16)&0xFF; header[0x05]=(file_size>>24)&0xFF; + header[0x0A]=0x36; + header[0x0E]=0x28; + header[0x12]=width&0xFF; header[0x13]=(width>>8)&0xFF; + header[0x14]=(width>>16)&0xFF; header[0x15]=(width>>24)&0xFF; + header[0x16]=height&0xFF; header[0x17]=(height>>8)&0xFF; + header[0x18]=(height>>16)&0xFF; header[0x19]=(height>>24)&0xFF; + header[0x1A]=1; header[0x1B]=0; + header[0x1C]=24; header[0x1D]=0; + header[0x22]=buf_size&0xFF; header[0x23]=(buf_size>>8)&0xFF; + header[0x24]=(buf_size>>16)&0xFF; header[0x25]=(buf_size>>24)&0xFF; + header[0x27]=0x1; header[0x2B]=0x1; + cimg::fwrite(header,54,file); + + const T + *pR = ptr(0,height-1,0,0), + *pG = (dim>=2)?ptr(0,height-1,0,1):pR, + *pB = (dim>=3)?ptr(0,height-1,0,2):pR; + + cimg_mapY(*this,y) { + cimg_mapX(*this,x) { + std::fputc((unsigned char)(*(pB++)),file); + std::fputc((unsigned char)(*(pG++)),file); + std::fputc((unsigned char)(*(pR++)),file); + } + std::fwrite(align_buf,1,align,file); + pR-=2*width; pG-=2*width; pB-=2*width; + } + cimg::fclose(file); + return *this; + } + + //! Save an image to a PNG file. + // Most of this function has been written by Eric Fausett + /** + \param filename = name of the png image file to load + \return *this + \note The png format specifies a variety of possible data formats. Grey scale, Grey + scale with Alpha, RGB color, RGB color with Alpha, and Palletized color are supported. + Per channel bit depths of 1, 2, 4, 8, and 16 are natively supported. The + type of file saved depends on the number of channels in the CImg file. If there is 4 or more + channels, the image will be saved as an RGB color with Alpha image using the bottom 4 channels. + If there are 3 channels, the saved image will be an RGB color image. If 2 channels then the + image saved will be Grey scale with Alpha, and if 1 channel will be saved as a Grey scale + image. + **/ + const CImg& save_png(const char* filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_png() : Specified filename is (null).",pixel_type()); +#ifndef cimg_use_png + return save_convert(filename); +#else + std::FILE *file = cimg::fopen(filename,"wb"); + + // Setup PNG structures for write + png_voidp user_error_ptr=0; + png_error_ptr user_error_fn=0, user_warning_fn=0; + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + user_error_ptr, user_error_fn, user_warning_fn); + if(!png_ptr){ + cimg::fclose(file); + throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'png_ptr' data structure",pixel_type()); + } + png_infop info_ptr = png_create_info_struct(png_ptr); + if(!info_ptr){ + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + cimg::fclose(file); + throw CImgIOException("CImg<%s>::save_png() : trouble initializing 'info_ptr' data structure",pixel_type()); + } + if (setjmp(png_jmpbuf(png_ptr))){ + png_destroy_write_struct(&png_ptr, &info_ptr); + cimg::fclose(file); + throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename); + } + + png_init_io(png_ptr, file); + png_uint_32 width = dimx(); + png_uint_32 height = dimy(); + CImgStats stats(*this,false); + const int bit_depth = (stats.min<0 || stats.max>=256)?16:8; + int color_type; + switch (dimv()) { + case 1: color_type = PNG_COLOR_TYPE_GRAY; break; + case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; + case 3: color_type = PNG_COLOR_TYPE_RGB; break; + default: color_type = PNG_COLOR_TYPE_RGB_ALPHA; + } + const int interlace_type = PNG_INTERLACE_NONE; + const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; + const int filter_method = PNG_FILTER_TYPE_DEFAULT; + png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, + compression_type, filter_method); + png_write_info(png_ptr, info_ptr); + const int byte_depth = bit_depth>>3; + const int numChan = dimv()>4?4:dimv(); + const int pixel_bit_depth_flag = numChan * (bit_depth-1); + + // Allocate Memory for Image Save and Fill pixel data + png_bytep *imgData = new png_byte*[height]; + for(unsigned int row=0; row(imgData[y]); + cimg_mapX(*this,x) *(ptrs++) = (unsigned short)*(pC0++); + } + } break; + case 30: { // Gray w/ Alpha 16-bit + const T *pC1 = ptr(0,0,0,1); + cimg_mapY(*this,y){ + unsigned short *ptrs = reinterpret_cast(imgData[y]); + cimg_mapX(*this,x) { + *(ptrs++) = (unsigned short)*(pC0++); + *(ptrs++) = (unsigned short)*(pC1++); + } + } + } break; + case 45: { // RGB 16-bit + const T *pC1 = ptr(0,0,0,1); + const T *pC2 = ptr(0,0,0,2); + cimg_mapY(*this,y) { + unsigned short *ptrs = reinterpret_cast(imgData[y]); + cimg_mapX(*this,x) { + *(ptrs++) = (unsigned short)*(pC0++); + *(ptrs++) = (unsigned short)*(pC1++); + *(ptrs++) = (unsigned short)*(pC2++); + } + } + } break; + case 60: { // RGB w/ Alpha 16-bit + const T *pC1 = ptr(0,0,0,1); + const T *pC2 = ptr(0,0,0,2); + const T *pC3 = ptr(0,0,0,3); + cimg_mapY(*this,y) { + unsigned short *ptrs = reinterpret_cast(imgData[y]); + cimg_mapX(*this,x) { + *(ptrs++) = (unsigned short)*(pC0++); + *(ptrs++) = (unsigned short)*(pC1++); + *(ptrs++) = (unsigned short)*(pC2++); + *(ptrs++) = (unsigned short)*(pC3++); + } + } + } break; + default: + throw CImgIOException("CImg<%s>::save_png() : unspecified error reading PNG file '%s'",pixel_type(),filename); + break; + } + png_write_image(png_ptr, imgData); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + + // Deallocate Image Write Memory + for (unsigned int n=0; n& save_jpeg(const char *filename,const unsigned int quality=100) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_jpeg() : Specified filename is (null).",pixel_type()); +#ifndef cimg_use_jpeg + return save_convert(filename); +#else + + // Fill pixel buffer + unsigned char *buf; + unsigned int dimbuf=0; + J_COLOR_SPACE colortype=JCS_RGB; + switch (dim) { + case 1: { // Greyscale images + unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)]; + colortype = JCS_GRAYSCALE; + const T *ptr_g = ptr(); + cimg_mapXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++); + } break; + case 2: + case 3: { // RGB images + unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)]; + const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,dim>2?2:0); + colortype = JCS_RGB; + cimg_mapXY(*this,x,y) { + *(buf2++) = (unsigned char)*(ptr_r++); + *(buf2++) = (unsigned char)*(ptr_g++); + *(buf2++) = (unsigned char)*(ptr_b++); + } + } break; + default: { // YCMYK images + unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)]; + const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3); + colortype = JCS_CMYK; + cimg_mapXY(*this,x,y) { + *(buf2++) = (unsigned char)*(ptr_r++); + *(buf2++) = (unsigned char)*(ptr_g++); + *(buf2++) = (unsigned char)*(ptr_b++); + *(buf2++) = (unsigned char)*(ptr_a++); + } + } break; + } + + // Call libjpeg functions + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + std::FILE *file = cimg::fopen(filename,"wb"); + jpeg_stdio_dest(&cinfo,file); + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = dimbuf; + cinfo.in_color_space = colortype; + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE); + jpeg_start_compress(&cinfo,TRUE); + + const unsigned int row_stride = width*dimbuf; + JSAMPROW row_pointer[1]; + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = &buf[cinfo.next_scanline*row_stride]; + jpeg_write_scanlines(&cinfo,row_pointer,1); + } + jpeg_finish_compress(&cinfo); + + delete[] buf; + cimg::fclose(file); + jpeg_destroy_compress(&cinfo); + return *this; +#endif + } + + //! Save the image as a RGBA file + const CImg& save_rgba(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_rgba() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + const unsigned int wh = width*height; + unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer; + const T + *ptr1 = ptr(0,0,0,0), + *ptr2 = dim>1?ptr(0,0,0,1):ptr1, + *ptr3 = dim>2?ptr(0,0,0,2):ptr1, + *ptr4 = dim>3?ptr(0,0,0,3):NULL; + for (unsigned int k=0; k::save_rgb() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_rgb() : Specified filename is (null).",pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + const unsigned int wh = width*height; + unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer; + const T + *ptr1 = ptr(0,0,0,0), + *ptr2 = dim>1?ptr(0,0,0,1):ptr1, + *ptr3 = dim>2?ptr(0,0,0,2):ptr1; + for (unsigned int k=0; k res(40,38,1,3); + if (first_time) { + const unsigned char *ptrs = cimg::logo40x38; + T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2); + for (unsigned int off = 0; off + const CImg& save_off(const char *filename, const CImgl& primitives, const CImgl& colors, const bool invert_faces=false) const { + if (is_empty()) throw CImgInstanceException("CImg<%s>::save_off() : Instance image (%u,%u,%u,%u,%p) is empty.", + pixel_type(),width,height,depth,dim,data); + if (!filename) throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",pixel_type()); + std::FILE *file=cimg::fopen(filename,"w"); + std::fprintf(file,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size); + cimg_mapX(*this,i) std::fprintf(file,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2))); + cimgl_map(primitives,l) { + const unsigned int prim = primitives[l].size(); + switch (prim) { + case 3: { + if (invert_faces) + std::fprintf(file,"3 %u %u %u %f %f %f\n", + (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2), + (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); + else + std::fprintf(file,"3 %u %u %u %f %f %f\n", + (unsigned int)primitives(l,0),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1), + (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); + } break; + case 4: { + if (invert_faces) + std::fprintf(file,"4 %u %u %u %u %f %f %f\n", + (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3), + (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); + else + std::fprintf(file,"4 %u %u %u %u %f %f %f\n", + (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1), + (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); + } break; + } + } + cimg::fclose(file); + return *this; + } + + //@} + //--------------------------- + // + //! \name Plugins functions + //@{ + //--------------------------- +#ifdef cimg_plugin +#include cimg_plugin +#endif + //@} + }; + + + /* + #----------------------------------------- + # + # + # + # Definition of the CImgl<> structure + # + # + # + #------------------------------------------ + */ + + //! Class representing list of images CImg. + template struct CImgl { + + //! This variable represents the number of images in the image list. + /** + \note if \c size==0, the image list is empty. + **/ + unsigned int size; + + // This variable represents the size of the allocated block for the list. + unsigned int allocsize; + + //! This variable defines if the instance list uses shared memory. + const bool shared; + + //! This variable represents a pointer to the first \c CImg image of the list. + CImg *data; + + //! Define a CImgl::iterator + typedef CImg* iterator; + + //! Define a CImgl::const_iterator + typedef const CImg* const_iterator; + + //------------------------------------------ + // + //! \name Constructors - Destructor - Copy + //@{ + //------------------------------------------ + + //! Return a string describing the type of the image pixels in the list (template parameter \p T). + static const char* pixel_type() { T val; return cimg::get_type(val); } + + //! Create a list of \p n new images, each having size (\p width,\p height,\p depth,\p dim). + CImgl(const unsigned int n=0, const unsigned int width=0, const unsigned int height=1, + const unsigned int depth=1, const unsigned int dim=1):shared(false) { + if (n) { + data = new CImg[allocsize=cimg::nearest_pow2(n)]; + size = n; + cimgl_map(*this,l) data[l].assign(width,height,depth,dim); + } else { size = allocsize = 0; data = 0; } + } + + //! In-place version of the previous constructor. + CImgl& assign(const unsigned int n=0, const unsigned int width=0, const unsigned int height=1, + const unsigned int depth=1, const unsigned int dim=1) { + return CImgl(n,width,height,depth,dim).swap(*this); + } + + //! Create a list of \p n new images, each having size (\p width,\p height,\p depth,\p dim). + CImgl(const unsigned int n, const unsigned int width, const unsigned int height, + const unsigned int depth, const unsigned int dim, const T& val):shared(false) { + if (n) { + data = new CImg[allocsize=cimg::nearest_pow2(n)]; + size = n; + cimgl_map(*this,l) data[l].assign(width,height,depth,dim,val); + } else { size = allocsize = 0; data = 0; } + } + + //! In-place version of previous constructor. + CImgl& assign(const unsigned int n,const unsigned int width,const unsigned int height, + const unsigned int depth, const unsigned int dim,const T& val) { + return CImgl(n,width,height,depth,dim,val).swap(*this); + } + + // ! Create a list of \p n copies of the input image. + template CImgl(const unsigned int n, const CImg& img):shared(false) { + if (n) { + data = new CImg[allocsize=cimg::nearest_pow2(n)]; + size = n; + cimgl_map(*this,l) data[l]=img; + } else { size = allocsize = 0; data = 0; } + } + + //! In-place version of previous constructor. + template CImgl& assign(const unsigned int n, const CImg& img) { + return CImgl(n,img).swap(*this); + } + + //! Copy constructor. + template CImgl(const CImgl& list):shared(false) { + if (list.data && list.size) { + data = new CImg[allocsize=cimg::nearest_pow2(list.size)]; + size = list.size; + cimgl_map(*this,l) data[l] = list[l]; + } else { size = allocsize = 0; data = 0; } + } + + //! Copy constructor (fast version). + CImgl(const CImgl& list):shared(list.shared) { + if (list.data && list.size) { + if (shared) { + data = list.data; + size = list.size; + allocsize = 0; + } else { + data = new CImg[allocsize=cimg::nearest_pow2(list.size)]; + size = list.size; + cimgl_map(*this,l) data[l] = list[l]; + } + } else { size = allocsize = 0; data = 0; } + } + + //! In-place version of previous constructor. + template CImgl& assign(const CImgl& list) { + return CImgl(list).swap(*this); + } + + //! Create a list by loading a file. + CImgl(const char* filename):size(0),shared(false),data(0) { + load(filename); + } + + //! Create a list from a single image \p img. + CImgl(const CImg& img):size(0),shared(false),data(0) { + CImgl(1,img).swap(*this); + } + + //! In-place version of previous constructor. + CImgl assign(const CImg& img) { + return CImgl(1,img).swap(*this); + } + + //! Create a list from two images \p img1 and \p img2 (images are copied). + CImgl(const CImg& img1, const CImg& img2):size(2),shared(false) { + data = new CImg[allocsize=2]; + data[0] = img1; data[1] = img2; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2) { + return CImgl(img1,img2).swap(*this); + } + + //! Create a list from three images \p img1,\p img2 and \p img3 (images are copied). + CImgl(const CImg& img1, const CImg& img2, const CImg& img3):size(3),shared(false) { + data = new CImg[allocsize=4]; + data[0] = img1; data[1] = img2; data[2] = img3; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3) { + return CImgl(img1,img2,img3).swap(*this); + } + + //! Create a list from four images \p img1,\p img2,\p img3 and \p img4 (images are copied). + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4):size(4),shared(false) { + data = new CImg[allocsize=4]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4) { + return CImgl(img1,img2,img3,img4).swap(*this); + } + + //! Create a list from five images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5):size(5),shared(false) { + data = new CImg[allocsize=8]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5) { + return CImgl(img1,img2,img3,img4,img5).swap(*this); + } + + //! Create a list from six images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6):size(6),shared(false) { + data = new CImg[allocsize=8]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; data[5] = img6; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6) { + return CImgl(img1,img2,img3,img4,img5,img6).swap(*this); + } + + //! Create a list from seven images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7):size(7),shared(false) { + data = new CImg[allocsize=8]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; data[5] = img6; data[6] = img7; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7) { + return CImgl(img1,img2,img3,img4,img5,img6,img7).swap(*this); + } + + //! Create a list from eight images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8):size(8),shared(false) { + data = new CImg[allocsize=8]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; data[5] = img6; data[6] = img7; data[7] = img8; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8) { + return CImgl(img1,img2,img3,img4,img5,img6,img7,img8).swap(*this); + } + + //! Create a list from nine images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, + const CImg& img9):size(9),shared(false) { + data = new CImg[allocsize=16]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; data[5] = img6; data[6] = img7; data[7] = img8; + data[8] = img9; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, + const CImg& img9) { + return CImgl(img1,img2,img3,img4,img5,img6,img7,img8,img9).swap(*this); + } + + //! Create a list from ten images. + CImgl(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, + const CImg& img9, const CImg& img10):size(10),shared(false) { + data = new CImg[allocsize=16]; + data[0] = img1; data[1] = img2; data[2] = img3; data[3] = img4; + data[4] = img5; data[5] = img6; data[6] = img7; data[7] = img8; + data[8] = img9; data[9] = img10; + } + + //! In-place version of previous constructor. + CImgl& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, + const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, + const CImg& img9, const CImg& img10) { + return CImgl(img1,img2,img3,img4,img5,img6,img7,img8,img9,img10).swap(*this); + } + + //! Create a list from an array of CImg + template CImgl(const CImg *const list, const unsigned int nb):shared(false) { + if (list && nb) { + data = new CImg[allocsize=cimg::nearest_pow2(nb)]; + size = nb; + cimgl_map(*this,l) data[l]=list[l]; + } else { size = allocsize = 0; data = 0; } + } + + // In-place version of the previous constructor. + template CImgl& assign(const CImg *const list, const unsigned int nb) { + return CImgl(list,nb).swap(*this); + } + + //! Create a list from an array of CImg + CImgl(const CImg *const list, const unsigned int nb, const bool shared_memory):shared(shared_memory) { + if (list && nb) { + size = nb; + if (shared) { data = const_cast*>(list); allocsize = 0; } + else { + data = new CImg[allocsize=cimg::nearest_pow2(nb)]; + cimgl_map(*this,l) (*this)[l]=list[l]; + } + } else { size = allocsize = 0; data = 0; } + } + + // In-place version of the previous constructor. + template CImgl& assign(const CImg *const list, const unsigned int nb, const bool shared_memory) { + return CImgl(list,nb,shared_memory).swap(*this); + } + + //! Copy constructor. + template CImgl& operator=(const CImgl& list) { + if (list.data && list.size) { + if (shared) { + if (list.size==size) cimgl_map(*this,l) data[l]=list[l]; + else throw CImgArgumentException("CImgl<%s>::operator=() : Given list (size=%u) and instance list (size=%u) must have same dimensions, " + "since instance list has shared-memory.", + pixel_type(),list.size,size); + } else { + if (list.allocsize!=allocsize) { if (data) delete[] data; data = new CImg[allocsize=cimg::nearest_pow2(list.size)]; } + size = list.size; + cimgl_map(*this,l) data[l]=list[l]; + } + } else { + if (data) delete[] data; + size = allocsize = 0; data = 0; + } + return *this; + } + + //! Assignment constructor (fast version) + CImgl& operator=(const CImgl& list) { + if (this!=&list) { + if (list.data && list.size) { + if (shared) { + if (list.size==size) cimgl_map(*this,l) data[l]=list[l]; + else throw CImgArgumentException("CImgl<%s>::operator=() : Given list (size=%u) and instance list (size=%u) must have same dimensions, " + "since instance list has shared-memory.", + pixel_type(),list.size,size); + } else { + if (list.allocsize!=allocsize) { if (data) delete[] data; data = new CImg[allocsize=cimg::nearest_pow2(list.size)]; } + size = list.size; + cimgl_map(*this,l) data[l]=list[l]; + } + } else { + if (data) delete[] data; + size = allocsize = 0; data = 0; + } + } + return *this; + } + + //! Destructor + ~CImgl() { + if (data && !shared) delete[] data; + } + + //! Empty list + CImgl& empty() { + return CImgl().swap(*this); + } + + //! same as empty() + CImgl& clear() { + return empty(); + } + + //! Get an empty list + static CImgl get_empty() { + return CImgl(); + } + + //@} + //------------------------------ + // + //! \name Arithmetics operators + //@{ + //------------------------------ + + //! Return \p true if list is empty + bool is_empty() const { return (!data || !size); } + + //! Add each image of the current list with the corresponding image in the list \p list. + template CImgl& operator+=(const CImgl& list) { + const unsigned int sizemax = min(size,list.size); + for (unsigned int l=0; l CImgl& operator-=(const CImgl& list) { + const unsigned int sizemax = min(size,list.size); + for (unsigned int l=0; l(*this)+=val; } + + //! Return a new image list corresponding to the multiplication of each image of the current list by a value \p val. + CImgl operator*(const double val) const { return CImgl(*this)*=val; } + + //! Return a new image list corresponding to the substraction of each image of the current list with a value \p val. + CImgl operator-(const T& val) const { return CImgl(*this)-=val; } + + //! Return a new image list corresponding to the division of each image of the current list by a value \p val. + CImgl operator/(const double val) const { return CImgl(*this)/=val; } + + //! Return a new image list corresponding to the addition of each image of the current list with the corresponding image in the list \p list. + CImgl operator+(const CImgl& list) const { return CImgl(*this)+=list; } + + //! Return a new image list corresponding to the substraction of each image of the current list with the corresponding image in the list \p list. + CImgl operator-(const CImgl& list) const { return CImgl(*this)-=list; } + + //! Return a new image list corresponding to the addition of each image of the current list with a value \p val; + friend CImgl operator+(const T& val, const CImgl& list) { return CImgl(list)+=val; } + + //! Return a new image list corresponding to the scalar multiplication of each image of the current list by a value \p val. + friend CImgl operator*(const double val, const CImgl& list) { return CImgl(list)*=val; } + + //@} + //------------------------- + // + //! \name List operations + //@{ + //------------------------- + + //! Return a reference to the i-th element of the image list. + CImg& operator[](const unsigned int pos) { +#if cimg_debug>1 + if (pos>=size) { + cimg::warn(true,"CImgl<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size); + return *data; + } +#endif + return data[pos]; + } + + const CImg& operator[](const unsigned int pos) const { +#if cimg_debug>1 + if (pos>=size) { + cimg::warn(true,"CImgl<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size); + return *data; + } +#endif + return data[pos]; + } + + //! Equivalent to CImgl::operator[] + CImg& operator()(const unsigned int pos) { return (*this)[pos]; } + const CImg& operator()(const unsigned int pos) const { return (*this)[pos]; } + + //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list + T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, + const unsigned int z=0, const unsigned int v=0) { + return (*this)[pos](x,y,z,v); + } + const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, + const unsigned int z=0, const unsigned int v=0) const { + return (*this)[pos](x,y,z,v); + } + + //! Equivalent to CImgl::operator[], with boundary checking + CImg& at(const unsigned int pos) { + if (pos>=size) + throw CImgArgumentException("CImgl<%s>::at() : bad list position %u, in a list of %u images", + pixel_type(),pos,size); + return data[pos]; + } + + const CImg& at(const unsigned int pos) const { + if (pos>=size) + throw CImgArgumentException("CImgl<%s>::at() : bad list position %u, in a list of %u images", + pixel_type(),pos,size); + return data[pos]; + } + + //! Returns a reference to last element + CImg& back() { return (*this)(size-1); } + const CImg& back() const { return (*this)(size-1); } + + //! Returns a reference to the first element + CImg& front() { return *data; } + const CImg& front() const { return *data; } + + //! Returns an iterator to the beginning of the vector. + iterator begin() { return data; } + const_iterator begin() const { return data; } + + //! Returns an iterator just past the last element. + iterator end() { return data + size; } + const_iterator end() const { return data + size; } + + //! Insert a copy of the image \p img into the current image list, at position \p pos. + CImgl& insert(const CImg& img,const unsigned int pos) { + if (shared) + throw CImgInstanceException("CImgl<%s>::insert() : Insertion in a shared list is not possible",pixel_type()); + if (pos>size) + throw CImgArgumentException("CImgl<%s>::insert() : Can't insert at position %u into a list with %u elements", + pixel_type(),pos,size); + CImg *new_data = (++size>allocsize)?new CImg[allocsize?(allocsize<<=1):(allocsize=1)]:NULL; + if (!size || !data) { data=new_data; *data=img; } + else { + if (new_data) { // Insert with reallocation + if (pos) std::memcpy(new_data,data,sizeof(CImg)*pos); + if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); + std::memset(data,0,sizeof(CImg)*(size-1)); + delete[] data; + data = new_data; + } + else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); + data[pos].width = data[pos].height = data[pos].depth = data[pos].dim = 0; data[pos].data = NULL; + data[pos] = img; + } + return *this; + } + + //! Insert n copies of the image \p img into the current image list, at position \p pos. + CImgl& insert(const unsigned int n, const CImg& img, const unsigned int pos) { + for (unsigned int i=0; i& img) { return insert(img,size); } + + //! Insert n copies of the image \p img at the end of the list. + CImgl& insert(const unsigned int n, const CImg& img) { + for (unsigned int i=0; i& img) { return insert(img); } + + //! Insert image \p img at the front of the list. + CImgl& push_front(const CImg& img) { return insert(img,0); } + + //! Insert a copy of the image list \p list into the current image list, starting from position \p pos. + CImgl& insert(const CImgl& list,const unsigned int pos) { + if (this!=&list) cimgl_map(list,l) insert(list[l],pos+l); + else insert(CImgl(list),pos); + return *this; + } + + //! Insert n copies of the list \p list at position \p pos of the current list. + CImgl& insert(const unsigned int n, const CImgl& list, const unsigned int pos) { + for (unsigned int i=0; i& list) { return insert(list,size); } + + //! Insert n copies of the list at the end of the current list + CImgl& insert(const unsigned int n, const CImgl& list) { + for (unsigned int i=0; i& list) { return insert(list); } + + //! Insert list \p list at the front of the current list. + CImgl& push_front(const CImgl& list) { return insert(list,0); } + + //! Remove the image at position \p pos from the image list. + CImgl& remove(const unsigned int pos) { + if (shared) + throw CImgInstanceException("CImgl<%s>::remove() : Removing from a shared list is not allowed.",pixel_type()); + if (pos>=size) + cimg::warn(true,"CImgl<%s>::remove() : Cannot remove an image from a list (%p,%u), at position %u.", + pixel_type(),data,size,pos); + else { + data[pos].empty(); + if (!(--size)) return empty(); + if (size<8 || size>(allocsize>>2)) { // Removing item without reallocation. + if (pos!=size) { + std::memmove(data+pos,data+pos+1,sizeof(CImg)*(size-pos)); + CImg &tmp = data[size]; + tmp.width = tmp.height = tmp.depth = tmp.dim = 0; tmp.data = 0; + } + } else { // Removing item with reallocation. + allocsize>>=2; + CImg *new_data = new CImg[allocsize]; + if (pos) std::memcpy(new_data,data,sizeof(CImg)*pos); + if (pos!=size) std::memcpy(new_data+pos,data+pos+1,sizeof(CImg)*(size-pos)); + std::memset(data,0,sizeof(CImg)*(size+1)); + delete[] data; + data = new_data; + } + } + return *this; + } + + //! Remove last element of the list; + CImgl& pop_back() { return remove(size-1); } + + //! Remove first element of the list; + CImgl& pop_front() { return remove(0); } + + //! Remove the element pointed by iterator \p iter; + CImgl& erase(const iterator iter) { return remove(iter-data); } + + //! Remove the last image from the image list. + CImgl& remove() { + if (size) return remove(size-1); + else cimg::warn(true,"CImgl<%s>::remove() : List is empty",pixel_type()); + return *this; + } + + //! Reverse list order + CImgl& reverse() { + for (unsigned int l=0; l(*this).reverse(); } + + //! Insert image at the end of the list + CImgl& operator<<(const CImg& img) { + return insert(img); + } + + //! Remove last image of the list + CImgl& operator>>(CImg& img) { + if (size) { img = (*this)[size-1]; return remove(size-1); } + cimg::warn(true,"CImgl<%s>::operator>>() : List is empty",pixel_type()); + img.empty(); + return *this; + } + + //@} + //---------------------------- + // + //! \name Fourier transforms + //@{ + //---------------------------- + + //! Compute the Fast Fourier Transform (along the specified axis). + CImgl& FFT(const char axe, const bool inverse=false) { + if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance list have less than 2 images",pixel_type()); + CImg &Ir = data[0], &Ii = data[1]; + if (Ir.is_empty()) + throw CImgInstanceException("CImg<%s>::FFT() : Real part (first image of the instance list) is empty.",pixel_type()); + if (Ii.is_empty()) + throw CImgInstanceException("CImg<%s>::FFT() : Imaginary part (second image of the instance list) is empty.",pixel_type()); + if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim) + throw CImgInstanceException("CImg<%s>::FFT() : Real and Imaginary parts of the instance have different dimensions",pixel_type()); + + switch (cimg::uncase(axe)) { + case 'x': { // Fourier along X + const unsigned int N = Ir.width, N2 = (N>>1); + if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N", + pixel_type(),N); + for (unsigned int i=0,j=0; ii) cimg_mapYZV(Ir,y,z,v) { cimg::swap(Ir(i,y,z,v),Ir(j,y,z,v)); cimg::swap(Ii(i,y,z,v),Ii(j,y,z,v)); + if (j=m; j-=m, m=n, n>>=1); + } + for (unsigned int delta=2; delta<=N; delta<<=1) { + const unsigned int delta2 = (delta>>1); + for (unsigned int i=0; i>1); + if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N", + pixel_type(),N); + for (unsigned int i=0,j=0; ii) cimg_mapXZV(Ir,x,z,v) { cimg::swap(Ir(x,i,z,v),Ir(x,j,z,v)); cimg::swap(Ii(x,i,z,v),Ii(x,j,z,v)); + if (j=m; j-=m, m=n, n>>=1); + } + for (unsigned int delta=2; delta<=N; delta<<=1) { + const unsigned int delta2 = (delta>>1); + for (unsigned int i=0; i>1); + if (((N-1)&N) && N!=1) throw CImgInstanceException("CImg<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N", + pixel_type(),N); + for (unsigned int i=0,j=0; ii) cimg_mapXYV(Ir,x,y,v) { cimg::swap(Ir(x,y,i,v),Ir(x,y,j,v)); cimg::swap(Ii(x,y,i,v),Ii(x,y,j,v)); + if (j=m; j-=m, m=n, n>>=1); + } + for (unsigned int delta=2; delta<=N; delta<<=1) { + const unsigned int delta2 = (delta>>1); + for (unsigned int i=0; i::FFT() : unknown axe '%c', must be 'x','y' or 'z'"); + } + return *this; + } + + //! Compute the Fast Fourier Transform of a complex image. + CImgl& FFT(const bool inverse=false) { + if (size<2) throw CImgInstanceException("CImg<%s>::FFT() : Instance have less than 2 images",pixel_type()); + CImg &Ir = data[0]; + if (Ir.depth>1) FFT('z',inverse); + if (Ir.height>1) FFT('y',inverse); + if (Ir.width>1) FFT('x',inverse); + return *this; + } + + //! Return the Fast Fourier Transform of a complex image + CImgl::type> get_FFT(const bool inverse=false) const { + typedef typename cimg::largest::type restype; + return CImgl(*this).FFT(inverse); + } + + //! Return the Fast Fourier Transform of a complex image (along a specified axis). + CImgl::type> get_FFT(const char axe,const bool inverse=false) const { + typedef typename cimg::largest::type restype; + return CImgl(*this).FFT(axe,inverse); + } + + //@} + //---------------------------------- + // + //! \name IO and display functions + //@{ + //---------------------------------- + + //! Print informations about the list on the standard error stream. + const CImgl& print(const char* title=NULL,const int print_flag=1) const { + char tmp[1024]; + std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p (%s) }\n",title?title:"CImgl", + (void*)this,size,(void*)data,shared?"shared":"not shared"); + if (print_flag>0) cimgl_map(*this,l) { + std::sprintf(tmp,"%s[%d]",title?title:"CImgl",l); + data[l].print(tmp,print_flag); + } + return *this; + } + + //! Load an image list from a file. + static CImgl get_load(const char *filename) { + CImgl res; + const char *ext = cimg::filename_split(filename); + if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return get_load_cimg(filename); + if (!cimg::strcasecmp(ext,"rec") || !cimg::strcasecmp(ext,"par")) return get_load_parrec(filename); + return CImg(filename); + } + + //! In-place version of load(). + CImgl& load(const char* filename) { return get_load(filename).swap(*this); } + +#define cimg_load_cimg_case(Ts,Tss) \ + if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l0) { \ + Tss *buf = new Tss[w*h*z*k]; cimg::fread(buf,w*h*z*k,file); \ + if (endian) cimg::endian_swap(buf,w*h*z*k); \ + CImg idest(w,h,z,k); cimg_mapoff(idest,off) \ + idest[off] = (T)(buf[off]); idest.swap(res[l]); \ + delete[] buf; \ + } \ + loaded = true; \ + } + + //! Load an image list from a file (.raw format). + static CImgl get_load_cimg(const char *filename) { + typedef unsigned char uchar; + typedef unsigned short ushort; + typedef unsigned int uint; + typedef unsigned long ulong; + std::FILE *file = cimg::fopen(filename,"rb"); + char tmp[256],tmp2[256]; + int i; + bool loaded = false; + unsigned int n,j,w,h,z,k,err; + j=0; while((i=std::fgetc(file))!='\n' && i!=EOF && j<256) tmp[j++]=i; tmp[j]='\0'; + err=std::sscanf(tmp,"%u%*c%255[A-Za-z ]",&n,tmp2); + if (err!=2) throw CImgIOException("CImgl<%s>::get_load_cimg() : file '%s', Unknow CImg RAW header",pixel_type(),filename); + CImgl res(n); + cimg_load_cimg_case("unsigned char",uchar); + cimg_load_cimg_case("uchar",uchar); + cimg_load_cimg_case("char",char); + cimg_load_cimg_case("unsigned short",ushort); + cimg_load_cimg_case("ushort",ushort); + cimg_load_cimg_case("short",short); + cimg_load_cimg_case("unsigned int",uint); + cimg_load_cimg_case("uint",uint); + cimg_load_cimg_case("int",int); + cimg_load_cimg_case("unsigned long",ulong); + cimg_load_cimg_case("ulong",ulong); + cimg_load_cimg_case("long",long); + cimg_load_cimg_case("float",float); + cimg_load_cimg_case("double",double); + if (!loaded) throw CImgIOException("CImgl<%s>::get_load_cimg() : file '%s', can't read images of %s", + pixel_type(),filename,tmp2); + cimg::fclose(file); + return res; + } + + //! In-place version of get_load_cimg(). + CImgl& load_cimg(const char *filename) { return get_load_cimg(filename).swap(*this); } + + //! Load PAR-REC (Philips) image file + static CImgl get_load_parrec(const char *filename) { + char body[1024], filenamepar[1024], filenamerec[1024]; + const char *ext = cimg::filename_split(filename,body); + if (!cimg::strncmp(ext,"par",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.rec",body); } + if (!cimg::strncmp(ext,"PAR",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.REC",body); } + if (!cimg::strncmp(ext,"rec",3)) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.par",body); } + if (!cimg::strncmp(ext,"REC",3)) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.PAR",body); } + std::FILE *file = cimg::fopen(filenamepar,"r"); + + // Parse header file + CImgl st_slices; + CImgl st_global; + int err; + char line[256]={0}; + do { err=std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.')); + do { + unsigned int sn,sizex,sizey,pixsize; + float rs,ri,ss; + err=std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss); + if (err==7) { + st_slices.insert(CImg::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0)); + unsigned int i; for (i=0; i::vector(sizex,sizey,sn)); + else { + CImg &vec = st_global[i]; + if (sizex>vec[0]) vec[0] = sizex; + if (sizey>vec[1]) vec[1] = sizey; + vec[2] = sn; + } + st_slices[st_slices.size-1][7] = (float)i; + } + } while (err==7); + + // Read data + std::FILE *file2 = cimg::fopen(filenamerec,"rb"); + CImgl dest; + { cimgl_map(st_global,l) { + const CImg& vec = st_global[l]; + dest.insert(CImg(vec[0],vec[1],vec[2])); + }} + + cimgl_map(st_slices,l) { + const CImg& vec = st_slices[l]; + const unsigned int + sn = (unsigned int)vec[0]-1, + pixsize = (unsigned int)vec[1], + sizex = (unsigned int)vec[2], + sizey = (unsigned int)vec[3], + imn = (unsigned int)vec[7]; + const float ri = vec[4], rs = vec[5], ss = vec[6]; + switch (pixsize) { + case 8: { + CImg buf(sizex,sizey); + cimg::fread(buf.data,sizex*sizey,file2); + if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); + CImg& img = dest[imn]; + cimg_mapXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); + } break; + case 16: { + CImg buf(sizex,sizey); + cimg::fread(buf.data,sizex*sizey,file2); + if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); + CImg& img = dest[imn]; + cimg_mapXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); + } break; + case 32: { + CImg buf(sizex,sizey); + cimg::fread(buf.data,sizex*sizey,file2); + if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); + CImg& img = dest[imn]; + cimg_mapXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); + } break; + default: + throw CImgIOException("CImg<%s>::get_load_parrec() : Cannot handle image with pixsize = %d bits\n", + pixel_type(),pixsize); + + } + } + + cimg::fclose(file); + cimg::fclose(file2); + if (!dest.size) + throw CImgIOException("CImg<%s>::get_load_parrec() : filename '%s' does not appear to be a valid PAR-REC file", + pixel_type(),filename); + return dest; + } + + //! In-place version of get_load_parrec(). + CImgl& load_parrec(const char *filename) { return get_load_parrec(filename).swap(*this); } + + //! Load YUV image sequence. + static CImgl get_load_yuv(const char *filename, + const unsigned int sizex, const unsigned int sizey, + const unsigned int first_frame=0, const int last_frame=-1, + const bool yuv2rgb=true) { + + if (sizex%2 || sizey%2) + throw CImgArgumentException("CImgl<%s>::get_load_yuv() : Image dimensions along X and Y must be even (given are %ux%u)\n", + pixel_type(),sizex,sizey); + if (!sizex || !sizey) + throw CImgArgumentException("CImgl<%s>::get_load_yuv() : Given image sequence size (%u,%u) is invalid", + pixel_type(),sizex,sizey); + if (last_frame>0 && first_frame>(unsigned int)last_frame) + throw CImgArgumentException("CImgl<%s>::get_load_yuv() : Given first frame %u is posterior to last frame %d.", + pixel_type(),first_frame,last_frame); + if (!sizex || !sizey) + throw CImgArgumentException("CImgl<%s>::get_load_yuv() : Given frame size (%u,%u) is invalid.", + pixel_type(),sizex,sizey); + CImgl res; + CImg tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2); + std::FILE *file = cimg::fopen(filename,"rb"); + bool stopflag = false; + int err; + if (first_frame) { + err = std::fseek(file,first_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR); + if (err) throw CImgIOException("CImgl<%s>::get_load_yuv() : File '%s' doesn't contain frame number %u " + "(out of range error).",pixel_type(),filename,first_frame); + } + unsigned int frame; + for (frame = first_frame; !stopflag && (last_frame<0 || frame<=(unsigned int)last_frame); frame++) { + tmp.fill(0); + // TRY to read the luminance, don't replace by cimg::fread ! + err = (int)std::fread((void*)(tmp.ptr()),1,(size_t)(tmp.width*tmp.height),file); + if (err!=(int)(tmp.width*tmp.height)) { + stopflag = true; + cimg::warn(err>0,"CImgl<%s>::get_load_yuv() : File '%s' contains incomplete data," + " or given image dimensions (%u,%u) are incorrect.",pixel_type(),filename,sizex,sizey); + } else { + UV.fill(0); + // TRY to read the luminance, don't replace by cimg::fread ! + err = (int)std::fread((void*)(UV.ptr()),1,(size_t)(UV.size()),file); + if (err!=(int)(UV.size())) { + stopflag = true; + cimg::warn(err>0,"CImgl<%s>::get_load_yuv() : File '%s' contains incomplete data," + " or given image dimensions (%u,%u) are incorrect.",pixel_type(),filename,sizex,sizey); + } else { + cimg_mapXY(UV,x,y) { + const int x2=2*x, y2=2*y; + tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0); + tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1); + } + if (yuv2rgb) tmp.YCbCrtoRGB(); + res.insert(tmp); + } + } + } + cimg::warn(stopflag && last_frame>=0 && frame!=(unsigned int)last_frame, + "CImgl<%s>::get_load_yuv() : Frame %d not reached, only %u frames found in the file '%s'.", + pixel_type(),last_frame,frame-1,filename); + return res; + } + + //! In-place version of get_load_yuv(). + CImgl& load_yuv(const char *filename, + const unsigned int sizex, const unsigned int sizey, + const unsigned int first_frame=0, const int last_frame=-1, + const bool yuv2rgb=true) { + return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); + } + + //! Save an image sequence into a YUV file + const CImgl& save_yuv(const char *filename, const bool rgb2yuv=true) const { + if (is_empty()) + throw CImgInstanceException("CImgl<%s>::save_yuv() : Instance list (%u,%p) is empty.", + pixel_type(),size,data); + if (!filename) + throw CImgArgumentException("CImgl<%s>::save_yuv() : Specified filename is (null).", + pixel_type()); + if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2) + throw CImgInstanceException("CImgl<%s>::save_yuv() : Image dimensions along X and Y must be even (current are %ux%u)\n", + pixel_type(),(*this)[0].dimx(),(*this)[0].dimy()); + + std::FILE *file = cimg::fopen(filename,"wb"); + cimgl_map(*this,l) { + CImg YCbCr((*this)[l]); + if (rgb2yuv) YCbCr.RGBtoYCbCr(); + cimg::fwrite(YCbCr.ptr(),YCbCr.width*YCbCr.height,file); + cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1), + YCbCr.width*YCbCr.height/2,file); + } + cimg::fclose(file); + return *this; + } + + //! Save an image list into a file. + /** + Depending on the extension of the given filename, a file format is chosen for the output file. + **/ + const CImgl& save(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImgl<%s>::save() : Instance list (%u,%p) is empty.", + pixel_type(),size,data); + if (!filename) throw CImgArgumentException("CImgl<%s>::save() : Specified filename is (null).",pixel_type()); + const char *ext = cimg::filename_split(filename); + if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(filename); + if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(filename,true); + if (size==1) data[0].save(filename,-1); + else cimgl_map(*this,l) data[l].save(filename,l); + return *this; + } + + //! Save an image list into a CImg RAW file. + /** + A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg images. + \param filename : name of the output file. + \return A reference to the current CImgl instance is returned. + **/ + const CImgl& save_cimg(const char *filename) const { + if (is_empty()) throw CImgInstanceException("CImgl<%s>::save_cimg() : Instance list (%u,%p) is empty.", + pixel_type(),size,data); + if (!filename) throw CImgArgumentException("CImgl<%s>::save_cimg() : Specified filename is (null).", + pixel_type()); + std::FILE *file = cimg::fopen(filename,"wb"); + std::fprintf(file,"%u %s\n",size,pixel_type()); + cimgl_map(*this,l) { + const CImg& img = data[l]; + std::fprintf(file,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim); + if (img.data) { + if (cimg::endian()) { + CImg tmp(img); + cimg::endian_swap(tmp.data,tmp.size()); + cimg::fwrite(tmp.data,img.width*img.height*img.depth*img.dim,file); + } else cimg::fwrite(img.data,img.width*img.height*img.depth*img.dim,file); + } + } + cimg::fclose(file); + return *this; + } + + + //! Load from OFF file format + template + static CImgl get_load_off(const char *filename, CImgl& primitives, CImgl& colors, const bool invert_faces=false) { + return CImg::get_load_off(filename,primitives,colors,invert_faces).get_split('x'); + } + + //! In-place version of get_load_off() + template + CImgl& load_off(const char *filename, CImgl& primitives, CImgl& colors, const bool invert_faces=false) { + return get_load_off(filename,primitives,colors,invert_faces).swap(*this); + } + + //! Save an image list into a OFF file. + template + const CImgl& save_off(const char *filename, const CImgl& primitives, const CImgl& colors, const bool invert_faces=false) const { + get_append('x').save_off(filename,primitives,colors,invert_faces); + return *this; + } + + //! Return a single image which is the concatenation of all images of the current CImgl instance. + /** + \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. + \param align : specify the tqalignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). + \return A CImg image corresponding to the concatenation is returned. + **/ + CImg get_append(const char axe='x',const char align='c') const { + if (is_empty()) return CImg(); + unsigned int dx=0,dy=0,dz=0,dv=0,pos=0; + CImg res; + switch(cimg::uncase(axe)) { + case 'x': { + cimgl_map(*this,l) { + const CImg& img = (*this)[l]; + dx += img.width; + dy = cimg::max(dy,img.height); + dz = cimg::max(dz,img.depth); + dv = cimg::max(dv,img.dim); + } + res.assign(dx,dy,dz,dv,0); + switch (cimg::uncase(align)) { + case 'p' : { cimgl_map(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break; + case 'n' : { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width; + }} break; + default : { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2); + pos+=(*this)[ll].width; + }} break; + } + } break; + case 'y': { + cimgl_map(*this,l) { + const CImg& img = (*this)[l]; + dx = cimg::max(dx,img.width); + dy += img.height; + dz = cimg::max(dz,img.depth); + dv = cimg::max(dv,img.dim); + } + res.assign(dx,dy,dz,dv,0); + switch (cimg::uncase(align)) { + case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break; + case 'n': { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height; + }} break; + default : { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2); + pos+=(*this)[ll].height; + }} break; + } + } break; + case 'z': { + cimgl_map(*this,l) { + const CImg& img = (*this)[l]; + dx = cimg::max(dx,img.width); + dy = cimg::max(dy,img.height); + dz += img.depth; + dv = cimg::max(dv,img.dim); + } + res.assign(dx,dy,dz,dv,0); + switch (cimg::uncase(align)) { + case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break; + case 'n': { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth; + }} break; + case 'c': { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2); + pos+=(*this)[ll].depth; + }} break; + } + } break; + case 'v': { + cimgl_map(*this,l) { + const CImg& img = (*this)[l]; + dx = cimg::max(dx,img.width); + dy = cimg::max(dy,img.height); + dz = cimg::max(dz,img.depth); + dv += img.dim; + } + res.assign(dx,dy,dz,dv,0); + switch (cimg::uncase(align)) { + case 'p': { cimgl_map(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break; + case 'n': { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim; + }} break; + case 'c': { cimgl_map(*this,ll) { + res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos); + pos+=(*this)[ll].dim; + }} break; + } + } break; + default: throw CImgArgumentException("CImg<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); + } + return res; + } + + // Create an auto-cropped font (along the X axis) from a input font \p font. + CImgl get_crop_font() const { + CImgl res; + cimgl_map(*this,l) { + const CImg& letter = (*this)[l]; + int xmin=letter.width, xmax = 0; + cimg_mapXY(letter,x,y) if (letter(x,y)) { if (xxmax) xmax=x; } + if (xmin>xmax) res.insert(CImg(letter.width,letter.height,1,letter.dim,0)); + else res.insert(letter.get_crop(xmin,0,xmax,letter.height)); + } + res[' '].resize(res['f'].width); + res[' '+256].resize(res['f'].width); + return res; + } + + CImgl& crop_font() { + return get_crop_font().swap(*this); + } + + static CImgl get_font(const unsigned int *const font,const unsigned int w,const unsigned int h, + const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) { + CImgl res = CImgl(256,w,h,1,3).insert(CImgl(256,w,h,1,1)); + const unsigned int *ptr = font; + unsigned int m = 0, val = 0; + for (unsigned int y=0; y>=1; if (!m) { m=0x80000000; val = *(ptr++); } + CImg& img = res[x/w], &tqmask = res[x/w+256]; + unsigned int xm = x%w; + img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = tqmask(xm,y,0) = (T)((val&m)?1:0); + } + if (variable_size) res.crop_font(); + if (paddingx || paddingy) cimgl_map(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0); + return res; + } + + //! Return a CImg pre-defined font with desired size + /** + \param font_height = height of the desired font (can be 11,13,24,38 or 57) + \param fixed_size = tell if the font has a fixed or variable width. + **/ + static CImgl get_font(const unsigned int font_width, const bool variable_size=true) { + if (font_width<=11) { + static CImgl font7x11, nfont7x11; + if (!variable_size && font7x11.is_empty()) font7x11 = get_font(cimg::font7x11,7,11,1,0,false); + if (variable_size && nfont7x11.is_empty()) nfont7x11 = get_font(cimg::font7x11,7,11,1,0,true); + return variable_size?nfont7x11:font7x11; + } + if (font_width<=13) { + static CImgl font10x13, nfont10x13; + if (!variable_size && font10x13.is_empty()) font10x13 = get_font(cimg::font10x13,10,13,1,0,false); + if (variable_size && nfont10x13.is_empty()) nfont10x13 = get_font(cimg::font10x13,10,13,1,0,true); + return variable_size?nfont10x13:font10x13; + } + if (font_width<=17) { + static CImgl font8x17, nfont8x17; + if (!variable_size && font8x17.is_empty()) font8x17 = get_font(cimg::font8x17,8,17,1,0,false); + if (variable_size && nfont8x17.is_empty()) nfont8x17 = get_font(cimg::font8x17,8,17,1,0,true); + return variable_size?nfont8x17:font8x17; + } + if (font_width<=19) { + static CImgl font10x19, nfont10x19; + if (!variable_size && font10x19.is_empty()) font10x19 = get_font(cimg::font10x19,10,19,2,0,false); + if (variable_size && nfont10x19.is_empty()) nfont10x19 = get_font(cimg::font10x19,10,19,2,0,true); + return variable_size?nfont10x19:font10x19; + } + if (font_width<=24) { + static CImgl font12x24, nfont12x24; + if (!variable_size && font12x24.is_empty()) font12x24 = get_font(cimg::font12x24,12,24,2,0,false); + if (variable_size && nfont12x24.is_empty()) nfont12x24 = get_font(cimg::font12x24,12,24,2,0,true); + return variable_size?nfont12x24:font12x24; + } + if (font_width<=32) { + static CImgl font16x32, nfont16x32; + if (!variable_size && font16x32.is_empty()) font16x32 = get_font(cimg::font16x32,16,32,2,0,false); + if (variable_size && nfont16x32.is_empty()) nfont16x32 = get_font(cimg::font16x32,16,32,2,0,true); + return variable_size?nfont16x32:font16x32; + } + if (font_width<=38) { + static CImgl font19x38, nfont19x38; + if (!variable_size && font19x38.is_empty()) font19x38 = get_font(cimg::font19x38,19,38,3,0,false); + if (variable_size && nfont19x38.is_empty()) nfont19x38 = get_font(cimg::font19x38,19,38,3,0,true); + return variable_size?nfont19x38:font19x38; + } + static CImgl font29x57, nfont29x57; + if (!variable_size && font29x57.is_empty()) font29x57 = get_font(cimg::font29x57,29,57,5,0,false); + if (variable_size && nfont29x57.is_empty()) nfont29x57 = get_font(cimg::font29x57,29,57,5,0,true); + return variable_size?nfont29x57:font29x57; + } + + //! Display the current CImgl instance in an existing CImgDisplay window (by reference). + /** + This function displays the list images of the current CImgl instance into an existing CImgDisplay window. + Images of the list are concatenated in a single temporarly image for visualization purposes. + The function returns immediately. + \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed. + \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. + \param align : specify the tqalignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). + \return A reference to the current CImgl instance is returned. + **/ + const CImgl& display(CImgDisplay& disp,const char axe='x',const char align='c') const { + get_append(axe,align).display(disp); + return *this; + } + + //! Display the current CImgl instance in a new display window. + /** + This function opens a new window with a specific title and displays the list images of the current CImgl instance into it. + Images of the list are concatenated in a single temporarly image for visualization purposes. + The function returns when a key is pressed or the display window is closed by the user. + \param title : specify the title of the opening display window. + \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. + \param align : specify the tqalignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). + \param min_size : specify the minimum size of the opening display window. Images having dimensions below this + size will be upscaled. + \param max_size : specify the maximum size of the opening display window. Images having dimensions above this + size will be downscaled. + \return A reference to the current CImgl instance is returned. + **/ + const CImgl& display(const char* title,const char axe='x',const char align='c', + const int min_size=128,const int max_size=1024) const { + get_append(axe,align).display(title,min_size,max_size); + return *this; + } + + //! Display the current CImgl instance in a new display window. + /** + This function opens a new window and displays the list images of the current CImgl instance into it. + Images of the list are concatenated in a single temporarly image for visualization purposes. + The function returns when a key is pressed or the display window is closed by the user. + \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. + \param align : specify the tqalignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). + \param min_size : specify the minimum size of the opening display window. Images having dimensions below this + size will be upscaled. + \param max_size : specify the maximum size of the opening display window. Images having dimensions above this + size will be downscaled. + \return A reference to the current CImgl instance is returned. + **/ + const CImgl& display(const char axe='x',const char align='c', + const int min_size=128,const int max_size=1024) const { + return display(" ",axe,align,min_size,max_size); + } + + //! Same as \ref cimg::wait() + /** + \see cimg::wait(). + **/ + const CImgl& wait(const unsigned int milliseconds) const { cimg::wait(milliseconds); return *this; } + + // Swap fields of two CImgl instances. + CImgl& swap(CImgl& list) { + if (list.shared==shared) { + cimg::swap(size,list.size); + cimg::swap(allocsize,list.allocsize); + cimg::swap(data,list.data); + } else { + if (list.shared) list=*this; + if (shared) *this=list; + } + return list; + } + + //! Return a reference to a set of images (I0->I1) of the list. + const CImgl get_shared_images(const unsigned int i0, const unsigned int i1) const { + if (i0>i1 || i0>=size || i1>=size) + throw CImgArgumentException("CImgl<%s>::get_shared_images() : Cannot get a subset (%u->%u) from a list of size %u", + pixel_type(),i0,i1,size); + return CImgl(data+i0,i1-i0+1,true); + } + + CImgl get_shared_images(const unsigned int i0, const unsigned int i1) { + if (i0>i1 || i0>=size || i1>=size) + throw CImgArgumentException("CImgl<%s>::get_shared_images() : Cannot get a subset (%u->%u) from a list of size %u", + pixel_type(),i0,i1,size); + return CImgl(data+i0,i1-i0+1,true); + } + + //! Return a sublist + CImgl get_images(const unsigned int i0, const unsigned int i1) const { + const CImgl sh = get_shared_images(i0,i1); + return CImgl(data,sh.size); + } + + //@} + //--------------------------- + // + //! \name Plugins functions + //@{ + //--------------------------- +#ifdef cimgl_plugin +#include cimgl_plugin +#endif + //@} + }; + + /* + #----------------------------------------- + # + # + # + # Complete some already defined functions + # + # + # + #------------------------------------------ + */ + +namespace cimg { + + //! Display a dialog box, where a user can click standard buttons. + /** + Up to 6 buttons can be defined in the dialog window. + This function returns when a user clicked one of the button or closed the dialog window. + \param title = Title of the dialog window. + \param msg = Main message displayed inside the dialog window. + \param button1_txt = Label of the 1st button. + \param button2_txt = Label of the 2nd button. + \param button3_txt = Label of the 3rd button. + \param button4_txt = Label of the 4th button. + \param button5_txt = Label of the 5th button. + \param button6_txt = Label of the 6th button. + \param logo = Logo image displayed at the left of the main message. This parameter is optional. + \param centering = Tell to center the dialog window on the screen. + \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user. + \note If a button text is set to NULL, then the corresponding button (and the followings) won't appear in + the dialog box. At least one button is necessary. + **/ + + template + inline int dialog(const char *title,const char *msg, + const char *button1_txt,const char *button2_txt, + const char *button3_txt,const char *button4_txt, + const char *button5_txt,const char *button6_txt, + const CImg& logo, const bool centering = false) { +#if cimg_display_type!=0 + const unsigned char + black[3]={0,0,0}, white[3]={255,255,255}, gray[3]={200,200,200}, gray2[3]={150,150,150}; + + // Create buttons and canvas graphics + CImgl buttons, cbuttons, sbuttons; + if (button1_txt) { buttons.insert(CImg().draw_text(button1_txt,0,0,black,gray,13)); + if (button2_txt) { buttons.insert(CImg().draw_text(button2_txt,0,0,black,gray,13)); + if (button3_txt) { buttons.insert(CImg().draw_text(button3_txt,0,0,black,gray,13)); + if (button4_txt) { buttons.insert(CImg().draw_text(button4_txt,0,0,black,gray,13)); + if (button5_txt) { buttons.insert(CImg().draw_text(button5_txt,0,0,black,gray,13)); + if (button6_txt) { buttons.insert(CImg().draw_text(button6_txt,0,0,black,gray,13)); + }}}}}} + if (!buttons.size) throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary"); + + unsigned int bw=0, bh=0; + cimgl_map(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); } + bw+=8; bh+=8; + if (bw<64) bw=64; + if (bw>128) bw=128; + if (bh<24) bh=24; + if (bh>48) bh=48; + + CImg button = CImg(bw,bh,1,3). + draw_rectangle(0,0,bw-1,bh-1,gray). + draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white). + draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black). + draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2); + CImg sbutton = CImg(bw,bh,1,3). + draw_rectangle(0,0,bw-1,bh-1,gray). + draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black). + draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black). + draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white). + draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black). + draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2). + draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA). + draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA); + CImg cbutton = CImg(bw,bh,1,3). + draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray). + draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA). + draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA); + + cimgl_map(buttons,ll) { + cbuttons.insert(CImg(cbutton).draw_image(buttons[ll],1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2)); + sbuttons.insert(CImg(sbutton).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2)); + buttons[ll] = CImg(button).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2); + } + + CImg canvas; + if (msg) canvas = CImg().draw_text(msg,0,0,black,gray,13); + const unsigned int + bwall = (buttons.size-1)*(12+bw) + bw, + w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall), + h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh), + lx = 12 + (canvas.data?0:((w-24-logo.width)/2)), + ly = (h-12-bh-logo.height)/2, + tx = lx+logo.width+12, + ty = (h-12-bh-canvas.height)/2, + bx = (w-bwall)/2, + by = h-12-bh; + + if (canvas.data) + canvas = CImg(w,h,1,3). + draw_rectangle(0,0,w-1,h-1,gray). + draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). + draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black). + draw_image(canvas,tx,ty); + else + canvas = CImg(w,h,1,3). + draw_rectangle(0,0,w-1,h-1,gray). + draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). + draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black); + if (logo.data) canvas.draw_image(logo,lx,ly); + + unsigned int xbuttons[6]; + cimgl_map(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(buttons[lll],xbuttons[lll],by); } + + // Open window and enter events loop + CImgDisplay disp(canvas,title?title:" ",0,3,false,centering?true:false); + if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2, + (CImgDisplay::screen_dimy()-disp.dimy())/2); + bool stopflag = false, refresh = false; + int oselected = -1, oclicked = -1, selected = -1, clicked = -1; + while (!disp.closed && !stopflag) { + if (refresh) { + if (clicked>=0) CImg(canvas).draw_image(cbuttons[clicked],xbuttons[clicked],by).display(disp); + else { + if (selected>=0) CImg(canvas).draw_image(sbuttons[selected],xbuttons[selected],by).display(disp); + else canvas.display(disp); + } + refresh = false; + } + disp.wait(40); + if (disp.resized) disp.resize(disp); + + if (disp.button&1) { + oclicked = clicked; + clicked = -1; + cimgl_map(buttons,l) + if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) && + disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) { + clicked = selected = l; + refresh = true; + } + if (clicked!=oclicked) refresh = true; + } else if (clicked>=0) stopflag = true; + + if (disp.key) { + oselected = selected; + switch (disp.key) { + case cimg::keyESC: selected=-1; stopflag=true; break; + case cimg::keyENTER: if (selected<0) selected=0; stopflag = true; break; + case cimg::keyTAB: + case cimg::keyARROWRIGHT: + case cimg::keyARROWDOWN: selected = (selected+1)%buttons.size; break; + case cimg::keyARROWLEFT: + case cimg::keyARROWUP: selected = (selected+buttons.size-1)%buttons.size; break; + } + disp.key=0; + if (selected!=oselected) refresh = true; + } + } + if (disp.closed) selected = -1; + return selected; +#else + std::fprintf(stderr,"<%s>\n\n%s\n\n",title,msg); + return -1; +#endif + } + + inline int dialog(const char *title,const char *msg, + const char *button1_txt,const char *button2_txt,const char *button3_txt, + const char *button4_txt,const char *button5_txt,const char *button6_txt, + const bool centering) { + return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt, + CImg::get_logo40x38(),centering); + } + + + // Inner routine used by the Marching cube algorithm + template inline int _marching_cubes_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, + const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) { + switch (edge) { + case 0: return indices1(x,y,0); + case 1: return indices1(nx,y,1); + case 2: return indices1(x,ny,0); + case 3: return indices1(x,y,1); + case 4: return indices2(x,y,0); + case 5: return indices2(nx,y,1); + case 6: return indices2(x,ny,0); + case 7: return indices2(x,y,1); + case 8: return indices1(x,y,2); + case 9: return indices1(nx,y,2); + case 10: return indices1(nx,ny,2); + case 11: return indices1(x,ny,2); + } + return 0; + } + + //! Polygonize an implicit function + // This function uses the Marching Cubes Tables published on the web page : + // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ + template + inline void marching_cubes(const tfunc& func, const float isovalue, + const float x0,const float y0,const float z0, + const float x1,const float y1,const float z1, + const float resx,const float resy,const float resz, + CImgl& points, CImgl& primitives, + const bool invert_faces) { + + static unsigned int edges[256]={ + 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, + 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, + 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, + 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, + 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, + 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, + 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, + 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, + 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, + 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, + 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, + 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, + 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, + 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, + 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, + 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 }; + + static int triangles[256][16] = + {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1}, + {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}, {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1}, + {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1}, + {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}, {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1}, + {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1}, + {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1}, {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1}, {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1}, {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1}, + {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1}, {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1}, + {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1}, {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1}, {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1}, + {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1}, {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, + {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}, + {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1}, + {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1}, + {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1}, {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1}, + {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1}, + {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1}, + {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1}, {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1}, + {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}, {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1}, + {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}, {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1}, + {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1}, {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1}, + {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1}, {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1}, + {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}, + {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1}, + {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1}, + {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1}, + {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1}, {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1}, + {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1}, {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1}, + {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1}, {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1}, {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1}, + {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1}, {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1}, + {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1}, {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1}, {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1}, + {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1}, {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1}, + {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1}, {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1}, {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, + {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1}, + {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}, {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1}, + {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1}, + {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1}, {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1}, + {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}, {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1}, + {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}, {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1}, + {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1}, {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1}, + {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1}, {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1}, + {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1}, {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1}, + {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1}, {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1}, + {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1}, + {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}, {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1}, + {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1}, {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1}, + {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1}, + {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1}, {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1}, + {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1}, {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1}, + {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1}, {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1}, + {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1}, + {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1}, {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1}, {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1}, + {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1}, {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1}, + {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1}, {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1}, + {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1}, {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1}, {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1}, + {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}, + {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}, {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1}, + {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1}, + {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1}, {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1}, + {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1}, {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1}, + {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1}, {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1}, + {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1}, + {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1}, {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1}, + {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1}, {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1}, + {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1}, {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1}, + {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1}, {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1}, {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1}, + {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1}, {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1}, {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1}, {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1}, + {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1}, {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1}, + {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1}, {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1}, + {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1}, {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1}, + {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1}, {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1}, + {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1}, {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1}, {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1}, + {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1}, + {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1}, {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1}, {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1}, + {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1}, {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1}, {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; + + const unsigned int + nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1, + ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1, + nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1; + + if (!nxm1 || !nym1 || !nzm1) return; + + CImg indices1(nx,ny,1,3,-1), indices2(indices1); + CImg values1(nx,ny), values2(nx,ny); + float X=0, Y=0, Z=0, nX=0, nY=0, nZ=0; + + // Fill the first plane with function values + Y=y0; + cimg_mapY(values1,y) { + X = x0; + cimg_mapX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; } + Y+=resy; + } + + // Run Marching Cubes algorithm + Z = z0; nZ = Z + resz; + for (unsigned int zi=0; zi::vector(Xi,Y,Z)); + } + if ((edge&2) && indices1(nxi,yi,1)<0) { + const float Yi = Y + (isovalue-val1)*resy/(val2-val1); + indices1(nxi,yi,1) = points.size; + points.insert(CImg::vector(nX,Yi,Z)); + } + if ((edge&4) && indices1(xi,nyi,0)<0) { + const float Xi = X + (isovalue-val3)*resx/(val2-val3); + indices1(xi,nyi,0) = points.size; + points.insert(CImg::vector(Xi,nY,Z)); + } + if ((edge&8) && indices1(xi,yi,1)<0) { + const float Yi = Y + (isovalue-val0)*resy/(val3-val0); + indices1(xi,yi,1) = points.size; + points.insert(CImg::vector(X,Yi,Z)); + } + if ((edge&16) && indices2(xi,yi,0)<0) { + const float Xi = X + (isovalue-val4)*resx/(val5-val4); + indices2(xi,yi,0) = points.size; + points.insert(CImg::vector(Xi,Y,nZ)); + } + if ((edge&32) && indices2(nxi,yi,1)<0) { + const float Yi = Y + (isovalue-val5)*resy/(val6-val5); + indices2(nxi,yi,1) = points.size; + points.insert(CImg::vector(nX,Yi,nZ)); + } + if ((edge&64) && indices2(xi,nyi,0)<0) { + const float Xi = X + (isovalue-val7)*resx/(val6-val7); + indices2(xi,nyi,0) = points.size; + points.insert(CImg::vector(Xi,nY,nZ)); + } + if ((edge&128) && indices2(xi,yi,1)<0) { + const float Yi = Y + (isovalue-val4)*resy/(val7-val4); + indices2(xi,yi,1) = points.size; + points.insert(CImg::vector(X,Yi,nZ)); + } + if ((edge&256) && indices1(xi,yi,2)<0) { + const float Zi = Z+ (isovalue-val0)*resz/(val4-val0); + indices1(xi,yi,2) = points.size; + points.insert(CImg::vector(X,Y,Zi)); + } + if ((edge&512) && indices1(nxi,yi,2)<0) { + const float Zi = Z + (isovalue-val1)*resz/(val5-val1); + indices1(nxi,yi,2) = points.size; + points.insert(CImg::vector(nX,Y,Zi)); + } + if ((edge&1024) && indices1(nxi,nyi,2)<0) { + const float Zi = Z + (isovalue-val2)*resz/(val6-val2); + indices1(nxi,nyi,2) = points.size; + points.insert(CImg::vector(nX,nY,Zi)); + } + if ((edge&2048) && indices1(xi,nyi,2)<0) { + const float Zi = Z + (isovalue-val3)*resz/(val7-val3); + indices1(xi,nyi,2) = points.size; + points.insert(CImg::vector(X,nY,Zi)); + } + + // Create triangles + for (int *triangle=triangles[configuration]; *triangle!=-1; ) { + const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++); + const tf + i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)), + i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)), + i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi)); + if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2)); + else primitives.insert(CImg::vector(i0,i2,i1)); + } + } + } + } + cimg::swap(values1,values2); + cimg::swap(indices1,indices2); + } + } + + // Inner routine used by the Marching square algorithm + template inline int _marching_squares_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, + const unsigned int x, const unsigned int nx) { + switch (edge) { + case 0: return (int)indices1(x,0); + case 1: return (int)indices1(nx,1); + case 2: return (int)indices2(x,0); + case 3: return (int)indices1(x,1); + } + return 0; + } + + //! Polygonize an implicit 2D function by the marching squares algorithm + template + inline void marching_squares(const tfunc& func, const float isovalue, + const float x0,const float y0, + const float x1,const float y1, + const float resx,const float resy, + CImgl& points, CImgl& primitives) { + + static unsigned int edges[16]={ 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 }; + static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 }, + { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 }, + { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 }, + { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } }; + const unsigned int + nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1, + ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1; + + if (!nxm1 || !nym1) return; + + CImg indices1(nx,1,1,2,-1), indices2(nx,1,1,2); + CImg values1(nx), values2(nx); + float X = 0, Y = 0, nX = 0, nY = 0; + + // Fill first line with values + cimg_mapX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; } + + // Run the marching squares algorithm + Y = y0; nY = Y + resy; + for (unsigned int yi=0, nyi=1; yi::vector(Xi,Y)); + } + if ((edge&2) && indices1(nxi,1)<0) { + const float Yi = Y + (isovalue-val1)*resy/(val2-val1); + indices1(nxi,1) = points.size; + points.insert(CImg::vector(nX,Yi)); + } + if ((edge&4) && indices2(xi,0)<0) { + const float Xi = X + (isovalue-val3)*resx/(val2-val3); + indices2(xi,0) = points.size; + points.insert(CImg::vector(Xi,nY)); + } + if ((edge&8) && indices1(xi,1)<0) { + const float Yi = Y + (isovalue-val0)*resy/(val3-val0); + indices1(xi,1) = points.size; + points.insert(CImg::vector(X,Yi)); + } + + // Create segments + for (int *segment=segments[configuration]; *segment!=-1; ) { + const unsigned int p0 = *(segment++), p1 = *(segment++); + const tf + i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)), + i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi)); + primitives.insert(CImg::vector(i0,i1)); + } + } + } + values1.swap(values2); + indices1.swap(indices2); + } + } + + // End of cimg:: namespace +} + + + // End of cimg_library:: namespace +} + +// Overcome VisualC++ 6.0 and DMC compilers namespace bug +#if ( defined(_MSC_VER) || defined(__DMC__) ) && defined(std) +#undef std +#endif + +/* + #------------------------------------------------------------------------------------ + # + # + # Additional documentation for the generation of the reference page (using doxygen) + # + # + #------------------------------------------------------------------------------------ + */ + +/** + \mainpage + + This is the reference documentation of the CImg Library. + These HTML pages have been generated using doxygen. + It contains a detailed description of all classes and functions of the %CImg Library. + If you have downloaded the CImg package, you actually have a local copy of these pages in the + \c CImg/documentation/reference/ directory. + + Use the menu above to navigate through the documentation pages. + As a first step, you may look at the list of available modules. + + A complete PDF version of this reference documentation is + available here for off-line reading. + +**/ + +/** \addtogroup cimg_structure Introduction to the CImg Library */ +/*@{*/ +/** + \page foo2 + + The CImg Library is an image processing library, designed for C++ programmers. + It provides useful classes and functions to load/save, display and process various types of images. + + \section s1 Library structure + + The %CImg Library consists in a single header file CImg.h providing a set of C++ template classes that + can be used in your own sources, to load/save, process and display images or list of images. + Very portable (Unix/X11,Windows, MacOS X, FreeBSD,..), efficient, simple to use, it's a pleasant toolkit + for coding image processing stuffs in C++. + + The header file CImg.h contains all the classes and functions that compose the library itself. + This is one originality of the %CImg Library. This particularly means that : + - No pre-compilation of the library is needed, since the compilation of the CImg functions is done at the same time as + the compilation of your own C++ code. + - No complex dependencies have to be handled : Just include the CImg.h file, and you get a working C++ image processing toolkit. + - The compilation is done on the fly : only CImg functionalities really used by your program are compiled and appear in the + compiled executable program. This leads to very compact code, without any unused stuffs. + - Class members and functions are inlined, leading to better performance during the program execution. + + The %CImg Library is structured as follows : + + - All library classes and functions are defined in the namespace \ref cimg_library. This namespace + encapsulates the library functionalities and avoid any class name collision that could happen with + other includes. Generally, one uses this namespace as a default namespace : + \code + #include "CImg.h" + using namespace cimg_library; + ... + \endcode + + - The namespace \ref cimg_library::cimg defines a set of \e low-level functions and variables used by the library. + Documented functions in this namespace can be safely used in your own program. But, \b never use the + \ref cimg_library::cimg namespace as a default namespace, since it contains functions whose names are already + defined in the standard C/C++ library. + + - The class \ref cimg_library::CImg represents images up to 4-dimensions wide, containing pixels of type \c T + (template parameter). This is actually the main class of the library. + + - The class \ref cimg_library::CImgl represents lists of cimg_library::CImg images. It can be used for instance + to store different frames of an image sequence. + + - The class \ref cimg_library::CImgDisplay is able to display images or image lists into graphical display windows. + As you may guess, the code of this class is highly system-dependent but this is transparent for the programmer, + as environment variables are automatically set by the CImg library (see also \ref cimg_environment). + + - The class \ref cimg_library::CImgStats represents image statistics. Use it to compute the + minimum, maximum, mean and variance of pixel values of images, as well as the corresponding min/max pixel location. + + - The class \ref cimg_library::CImgException (and its subclasses) are used by the library to throw exceptions + when errors occur. Those exceptions can be catched with a bloc try { ..} catch (CImgException) { .. }. + Subclasses define precisely the type of encountered errors. + + Knowing these five classes is \b enough to get benefit of the %CImg Library functionalities. + + + \section s2 CImg version of "Hello world". + + Below is a very simple code that creates a "Hello World" image. This shows you basically how a CImg program looks like. + + \code + #include "CImg.h" + using namespace cimg_library; + + int main() { + CImg img(640,400,1,3); // Define a 640x400 color image with 8 bits per color component. + img.fill(0); // Set pixel values to 0 (color : black) + unsigned char purple[3]={255,0,255}; // Define a purple color + img.draw_text("Hello World",100,100,purple); // Draw a purple "Hello world" at coordinates (100,100). + img.display("My first CImg code"); // Display the image in a display window. + return 0; + } + \endcode + + Which can be also written in a more compact way as : + + \code + #include "CImg.h" + using namespace cimg_library; + + int main() { + const unsigned char purple[3]={255,0,255}; + CImg(640,400,1,3,0).draw_text("Hello World",100,100,purple).display("My first CImg code"); + return 0; + } + \endcode + + Generally, you can write very small code that performs complex image processing tasks. The %CImg Library is very simple + to use and provide a lot of interesting algorithms for image manipulation. + + \section s3 How to compile ? + + The CImg library is a very light and user-friendly library : only standard system libraries are used. + It avoid to handle complex dependancies and problems with library compatibility. + The only thing you need is a (quite modern) C++ compiler : + + - Microsoft Visual C++ 6.0 and Visual Studio.NET : Use project files and solution files provided in the + %CImg Library package (directory 'compilation/') to see how it works. + - Intel ICL compiler : Use the following command to compile a CImg-based program with ICL : + \code + icl /Ox hello_world.cpp user32.lib gdi32.lib + \endcode + - g++ (MingW windows version) : Use the following command to compile a CImg-based program with g++, on Windows : + \code + g++ -o hello_word.exe hello_word.cpp -O2 -lgdi32 + \endcode + - g++ (Linux version) : Use the following command to compile a CImg-based program with g++, on Linux : + \code + g++ -o hello_word.exe hello_world.cpp -O2 -L/usr/X11R6/lib -lm -lpthread -lX11 + \endcode + - g++ (Solaris version) : Use the following command to compile a CImg-based program with g++, on Solaris : + \code + g++ -o hello_word.exe hello_world.cpp -O2 -lm -lpthread -R/usr/X11R6/lib -lrt -lnsl -lsocket + \endcode + - g++ (Mac OS X version) : Use the following command to compile a CImg-based program with g++, on Mac OS X : + \code + g++ -o hello_word.exe hello_world.cpp -O2 -lm -lpthread -L/usr/X11R6/lib -lm -lpthread -lX11 + \endcode + - Dev-Cpp : Use the project file provided in the CImg library package to see how it works. + + If you are using another compilers and encounter problems, please + write me since maintaining compatibility is one + of the priority of the %CImg Library. Nevertheless, old compilers that does not respect the C++ norm will not + support the %CImg Library. + + \section s4 What's next ? + + If you are ready to get more, and to start writing more serious programs + with CImg, you are invited to go to the \ref cimg_tutorial section. + +**/ +/*@}*/ + +/** \addtogroup cimg_environment Setting Environment Variables */ +/*@{*/ +/** + \page foo1 + + The CImg library is a multiplatform library, working on a wide variety of systems. + This implies the existence of some \e environment \e variables that must be correctly defined + depending on your current system. + Most of the time, the %CImg Library defines these variables automatically + (for popular systems). Anyway, if your system is not recognized, you will have to set the environment + variables by hand. Here is a quick explanations of environment variables.\n + + Setting the environment variables is done with the #define keyword. + This setting must be done before including the file CImg.h in your source code. + For instance, + defining the environment variable \c cimg_display_type would be done like this : + \code + #define cimg_display_type 0 + #include "CImg.h" + ... + \endcode + + Here are the different environment variables used by the %CImg Library : + + - \b \c cimg_OS : This variable defines the type of your Operating System. It can be set to \b 1 (\e Unix), + \b 2 (\e Windows), or \b 0 (\e Other \e configuration). + It should be actually auto-detected by the CImg library. If this is not the case (cimg_OS=0), you + will probably have to tune the environment variables described below. + + - \b \c cimg_display_type : This variable defines the type of graphical library used to + display images in windows. It can be set to 0 (no display library available), \b 1 (X11-based display) or + \b 2 (Windows-GDI display). + If you are running on a system without X11 or Windows-GDI ability, please set this variable to \c 0. + This will disable the display support, since the %CImg Library doesn't contain the necessary code to display + images on systems other than X11 or Windows GDI. + + - \b \c cimg_color_terminal : This variable tells the library if the system terminal has VT100 color capabilities. + It can be \e defined or \e not \e defined. Define this variable to get colored output on your terminal, + when using the %CImg Library. + + - \b \c cimg_debug : This variable defines the level of run-time debug messages that will be displayed by + the %CImg Library. It can be set to 0 (no debug messages), 1 (normal debug messages, which is + the default value), or 2 (high debug messages). Note that setting this value to 2 may slow down your + program since more debug tests are made by the library (particularly to check if pixel access is made outside + image boundaries). See also CImgException to better understand how debug messages are working. + + - \b \c cimg_convert_path : This variables tells the library where the ImageMagick's \e convert tool is located. + Setting this variable should not be necessary if ImageMagick is installed on a standard directory, or + if \e convert is in your system PATH variable. This macro should be defined only if the ImageMagick's + \e convert tool is not found automatically, when trying to read compressed image format (GIF,PNG,...). + See also cimg_library::CImg::get_load_convert() and cimg_library::CImg::save_convert() for more informations. + + - \b \c cimg_temporary_path : This variable tells the library where it can find a directory to store + temporary files. Setting this variable should not be necessary if you are running on a standard system. + This macro should be defined only when troubles are encountered when trying to read + compressed image format (GIF,PNG,...). + See also cimg_library::CImg::get_load_convert() and cimg_library::CImg::save_convert() for more informations. + + - \b \c cimg_plugin : This variable tells the library to use a plugin file to add features to the CImg class. + Define it with the path of your plugin file, if you want to add member functions to the CImg class, + without having to modify directly the \c "CImg.h" file. An include of the plugin file is performed in the CImg + class. If \c cimg_plugin if not specified (default), no include is done. + + - \b \c cimgl_plugin : Same as \c cimg_plugin, but to add features to the CImgl class. + + - \b \c cimgdisplay_plugin : Same as \c cimg_plugin, but to add features to the CImgDisplay class. + + - \b \c cimgstats_plugin : Same as \c cimg_plugin, but to add features to the CImgStats class. + + All these compilation variables can be checked, using the function cimg_library::cimg::info(), which + displays a list of the different configuration variables and their values on the standard error output. +**/ +/*@}*/ + +/** \addtogroup cimg_tutorial Tutorial : Getting Started. */ +/*@{*/ +/** + \page foo3 + + Let's start to write our first program to get the idea. This will demonstrate how to load and create images, as well as handle image + display and mouse events. + Assume we want to load a color image lena.jpg, smooth it, display it in a windows, and enter an event loop so that clicking a + point in the image with the mouse will draw the intensity profiles of (R,G,B) of the corresponding image line (in another window). + Yes, that sounds quite complex for a first code, but don't worry, it will be very simple using the CImg library ! Well, just look + at the code below, it does the task : + + \code + #include "CImg.h" + using namespace cimg_library; + + int main() { + CImg image("lena.jpg"), visu(500,400,1,3,0); + const unsigned char red[3]={255,0,0}, green[3]={0,255,0}, blue[3]={0,0,255}; + image.blur(2.5); + CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile"); + while (!main_disp.closed && !draw_disp.closed) { + main_disp.wait(); + if (main_disp.button && main_disp.mouse_y>=0) { + const int y = main_disp.mouse_y; + visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,0,256,0); + visu.draw_graph(image.get_crop(0,y,0,1,image.dimx()-1,y,0,1),green,0,256,0); + visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,0,256,0).display(draw_disp); + } + } + return 0; + } + \endcode + + Here is a screenshot of the resulting program : + + + + And here is the detailled explanation of the source, line by line : + + \code #include "CImg.h" \endcode + Include the main and only header file of the CImg library. + \code using namespace cimg_library; \endcode + Use the library namespace to ease the declarations afterward. + \code int main() { \endcode + Definition of the main function. + \code CImg image("lena.jpg"), visu(500,400,1,3,0); \endcode + Creation of two instances of images of \c unsigned \c char pixels. + The first image \c image is initialized by reading an image file from the disk. + Here, lena.jpg must be in the same directory than the current program. + Note that you must also have installed the \e ImageMagick package in order to be able to read JPG images. + The second image \c visu is initialized as a black color image with dimension dx=500, dy=400, + dz=1 (here, it is a 2D image, not a 3D one), and dv=3 (each pixel has 3 'vector' channels R,G,B). + The last argument in the constructor defines the default value of the pixel values + (here \c 0, which means that \c visu will be initially black). + \code const unsigned char red[3]={255,0,0}, green[3]={0,255,0}, blue[3]={0,0,255}; \endcode + Definition of three different colors as array of unsigned char. This will be used to draw plots with different colors. + \code image.blur(2.5); \endcode + Blur the image, with a gaussian blur and a standard variation of 2.5. Note that most of the CImg functions have two versions : + one that acts in-place (which is the case of blur), and one that returns the result as a new image (the name of the function + begins then with get_ ). In this case, one could have also written image = image.get_blur(2.5); + (more expensive, since it needs an additional copy operation). + \code CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile"); \endcode + Creation of two display windows, one for the input image image, and one for the image visu which will be display intensity profiles. + By default, CImg displays handles events (mouse,keyboard,..). On Windows, there is a way to create fullscreen displays. + \code while (!main_disp.closed && !draw_disp.closed) { \endcode + Enter the event loop, the code will exit when one of the two display windows is closed. + \code main_disp.wait(); \endcode + Wait for an event (mouse, keyboard,..) in the display window \c main_disp. + \code if (main_disp.button && main_disp.mouse_y>=0) { \endcode + Test if the mouse button has been clicked on the image area. + One may distinguish between the 3 different mouse buttons, + but in this case it is not necessary + \code const int y = main_disp.mouse_y; \endcode + Get the image line y-coordinate that has been clicked. + \code visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,0,256,0); \endcode + This line illustrates the pipeline property of most of the CImg class functions. The first function fill(0) simply sets + all pixel values with 0 (i.e. clear the image \c visu). The interesting thing is that it returns a reference to + \c visu and then, can be pipelined with the function \c draw_graph() which draws a plot in the image \c visu. + The plot data are given by another image (the first argument of \c draw_graph()). In this case, the given image is + the red-component of the line y of the original image, retrieved by the function \c get_crop() which returns a + sub-image of the image \c image. Remember that images coordinates are 4D (x,y,z,v) and for color images, + the R,G,B channels are respectively given by v=0, v=1 and v=2. + \code visu.draw_graph(image.get_crop(0,y,0,1,image.dimx()-1,y,0,1),green,0,256,0); \endcode + Plot the intensity profile for the green channel of the clicked line. + \code visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,0,256,0).display(draw_disp); \endcode + Same thing for the blue channel. Note how the function (which return a reference to \c visu) is pipelined with the function + \c display() that just paints the image visu in the corresponding display window. + \code ...till the end \endcode + I don't think you need more explanations ! + + As you have noticed, the CImg library allows to write very small and intuitive code. Note also that this source will perfectly + work on Unix and Windows systems. Take also a look to the examples provided in the CImg package ( + directory \c examples/ ). It will show you how CImg-based code can be surprisingly small. + Moreover, there is surely one example close to what you want to do. + A good start will be to look at the file CImg_demo.cpp which contains small and various examples of what you can do + with the %CImg Library. All CImg classes are used in this source, and the code can be easily modified to see what happens. + +**/ +/*@}*/ + +/** \addtogroup cimg_drawing Using Drawing Functions. */ +/*@{*/ +/** + \page foo5 + + \section s5 Using Drawing Functions. + + This section tells more about drawing features in CImg images. + Drawing functions list can be found in the CImg functions list + (section \b Drawing Functions), + and are all defined on a common basis. Here are the important points to understand before using + drawing functions : + + - Drawing is performed on the instance image. Drawing functions parameters + are defined as \e const variables and return a reference to the current instance (*this), + so that drawing functions can be pipelined (see examples below). + Drawing is usually done in 2D color images but can be performed in 3D images with any vector-valued dimension, + and with any possible pixel type. + + - A color parameter is always needed to draw features in an image. The color must be defined as a C-style array + whose dimension is at least + +**/ +/*@}*/ + +/** \addtogroup cimg_loops Using Image Loops. */ +/*@{*/ +/** + \page foo_lo + The %CImg Library provides different macros that define useful iterative loops over an image. + Basically, it can be used to replace one or several for(..) instructions, but it also proposes + interesting extensions to classical loops. + Below is a list of all existing loop macros, classified in four different categories : + - \ref lo1 + - \ref lo4 + - \ref lo5 + - \ref lo6 + + \section lo1 Loops over the pixel buffer + + Loops over the pixel buffer are really basic loops that iterate a pointer on the pixel data buffer + of a \c cimg_library::CImg image. Two macros are defined for this purpose : + + - \b cimg_map(img,ptr,T) : + This macro loops over the pixel data buffer of the image \c img, using a pointer T* ptr, + starting from the end of the buffer (last pixel) till the beginning of the buffer (first pixel). + - \c img must be a (non empty) \c cimg_library::CImg image of pixels \c T. + - \c ptr is a pointer of type \c T*. + This kind of loop should not appear a lot in your own source code, since this is a low-level loop + and many functions of the CImg class may be used instead. Here is an example of use : + \code + CImg img(320,200); + cimg_map(img,ptr,float) { *ptr=0; } // Equivalent to 'img.fill(0);' + \endcode + + - \b cimg_mapoff(img,off) : + This macro loops over the pixel data buffer of the image \c img, using an offset \c , + starting from the beginning of the buffer (first pixel, \c off=0) + till the end of the buffer (last pixel value, off = img.size()-1). + - \c img must be a (non empty) cimg_library::CImg image of pixels \c T. + - \c off is an inner-loop variable, only defined inside the scope of the loop. + + Here is an example of use : + \code + CImg img(320,200); + cimg_mapoff(img,off) { img[off]=0; } // Equivalent to 'img.fill(0);' + \endcode + + \section lo4 Loops over image dimensions + + The following loops are probably the most used loops in image processing programs. + They allow to loop over the image along one or several dimensions, along a raster scan course. + Here is the list of such loop macros for a single dimension : + - \b cimg_mapX(img,x) : equivalent to : for (int x=0; x. + - \b cimg_mapY(img,y) : equivalent to : for (int y=0; y. + - \b cimg_mapZ(img,z) : equivalent to : for (int z=0; z. + - \b cimg_mapV(img,v) : equivalent to : for (int v=0; v. + + Combinations of these macros are also defined as other loop macros, allowing to loop directly over 2D, 3D or 4D images : + - \b cimg_mapXY(img,x,y) : equivalent to : \c cimg_mapY(img,y) \c cimg_mapX(img,x). + - \b cimg_mapXZ(img,x,z) : equivalent to : \c cimg_mapZ(img,z) \c cimg_mapX(img,x). + - \b cimg_mapYZ(img,y,z) : equivalent to : \c cimg_mapZ(img,z) \c cimg_mapY(img,y). + - \b cimg_mapXV(img,x,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapX(img,x). + - \b cimg_mapYV(img,y,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapY(img,y). + - \b cimg_mapZV(img,z,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapZ(img,z). + - \b cimg_mapXYZ(img,x,y,z) : equivalent to : \c cimg_mapZ(img,z) \c cimg_mapXY(img,x,y). + - \b cimg_mapXYV(img,x,y,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapXY(img,x,y). + - \b cimg_mapXZV(img,x,z,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapXZ(img,x,z). + - \b cimg_mapYZV(img,y,z,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapYZ(img,y,z). + - \b cimg_mapXYZV(img,x,y,z,v) : equivalent to : \c cimg_mapV(img,v) \c cimg_mapXYZ(img,x,y,z). + + - For all these loops, \c x,\c y,\c z and \c v are inner-defined variables only visible inside the scope of the loop. + They don't have to be defined before the call of the macro. + - \c img must be a (non empty) cimg_library::CImg image. + + Here is an example of use that creates an image with a smooth color gradient : + \code + CImg img(256,256,1,3); // Define a 256x256 color image + cimg_mapXYV(img,x,y,v) { img(x,y,v) = (x+y)*(v+1)/6; } + img.display("Color gradient"); + \endcode + + \section lo5 Loops over interior regions and borders. + + Similar macros are also defined to loop only on the border of an image, or inside the image (excluding the border). + The border may be several pixel wide : + + - \b cimg_imapX(img,x,n) : Loop along the x-axis, except for pixels inside a border of \p n pixels wide. + - \b cimg_imapY(img,y,n) : Loop along the y-axis, except for pixels inside a border of \p n pixels wide. + - \b cimg_imapZ(img,z,n) : Loop along the z-axis, except for pixels inside a border of \p n pixels wide. + - \b cimg_imapV(img,v,n) : Loop along the v-axis, except for pixels inside a border of \p n pixels wide. + - \b cimg_imapXY(img,x,y,n) : Loop along the (x,y)-axes, excepted for pixels inside a border of \p n pixels wide. + - \b cimg_imapXYZ(img,x,y,z,n) : Loop along the (x,y,z)-axes, excepted for pixels inside a border of \p n pixels wide. + + And also : + + - \b cimg_bmapX(img,x,n) : Loop along the x-axis, only for pixels inside a border of \p n pixels wide. + - \b cimg_bmapY(img,y,n) : Loop along the y-axis, only for pixels inside a border of \p n pixels wide. + - \b cimg_bmapZ(img,z,n) : Loop along the z-axis, only for pixels inside a border of \p n pixels wide. + - \b cimg_bmapV(img,v,n) : Loop along the z-axis, only for pixels inside a border of \p n pixels wide. + - \b cimg_bmapXY(img,x,y,n) : Loop along the (x,y)-axes, only for pixels inside a border of \p n pixels wide. + - \b cimg_bmapXYZ(img,x,y,z,n) : Loop along the (x,y,z)-axes, only for pixels inside a border of \p n pixels wide. + + - For all these loops, \c x,\c y,\c z and \c v are inner-defined variables only visible inside the scope of the loop. + They don't have to be defined before the call of the macro. + - \c img must be a (non empty) cimg_library::CImg image. + - The constant \c n stands for the size of the border. + + Here is an example of use, to create a 2d grayscale image with two different intensity gradients : + \code + CImg<> img(256,256); + cimg_imapXY(img,x,y,50) img(x,y) = x+y; + cimg_bmapXY(img,x,y,50) img(x,y) = x-y; + img.display(); + \endcode + + \section lo6 Loops using neighborhoods. + + Inside an image loop, it is often useful to get values of neighborhood pixels of the + current pixel at the loop location. + The %CImg Library provides a very smart and fast mechanism for this purpose, with the definition + of several loop macros that remember the neighborhood values of the pixels. + The use of these macros can highly optimize your code, and also simplify your program. + + \subsection lo7 Neighborhood-based loops for 2D images + + For 2D images, the neighborhood-based loop macros are : + + - \b cimg_map2x2x1(img,x,y,z,v,I) : Loop along the (x,y)-axes using a centered 2x2 neighborhood. + - \b cimg_map3x3x1(img,x,y,z,v,I) : Loop along the (x,y)-axes using a centered 3x3 neighborhood. + - \b cimg_map4x4x1(img,x,y,z,v,I) : Loop along the (x,y)-axes using a centered 4x4 neighborhood. + - \b cimg_map5x5x1(img,x,y,z,v,I) : Loop along the (x,y)-axes using a centered 5x5 neighborhood. + + For all these loops, \c x and \c y are inner-defined variables only visible inside the scope of the loop. + They don't have to be defined before the call of the macro. + \c img is a non empty CImg image. \c z and \c v are constants that define on which image slice and + vector channel the loop must apply (usually both 0 for grayscale 2D images). + Finally, \c I is the 2x2, 3x3, 4x4 or 5x5 neighborhood that will be updated with the correct pixel values + during the loop (see \ref lo9). + + \subsection lo8 Neighborhood-based loops for 3D images + + For 3D images, the neighborhood-based loop macros are : + + - \b cimg_map2x2x2(img,x,y,z,v,I) : Loop along the (x,y,z)-axes using a centered 2x2x2 neighborhood. + - \b cimg_map3x3x3(img,x,y,z,v,I) : Loop along the (x,y,z)-axes using a centered 3x3x3 neighborhood. + + For all these loops, \c x, \c y and \c z are inner-defined variables only visible inside the scope of the loop. + They don't have to be defined before the call of the macro. + \c img is a non empty CImg image. \c v is a constant that defines on which image channel + the loop must apply (usually 0 for grayscale 3D images). + Finally, \c I is the 2x2x2 or 3x3x3 neighborhood that will be updated with the correct pixel values + during the loop (see \ref lo9). + + \subsection lo9 Defining neighborhoods + + The CImg library defines a neighborhood as a set of named \e variables or \e references, declared + using specific CImg macros : + + - \b CImg_2x2x1(I,type) : Define a 2x2 neighborhood named \c I, of type \c type. + - \b CImg_3x3x1(I,type) : Define a 3x3 neighborhood named \c I, of type \c type. + - \b CImg_4x4x1(I,type) : Define a 4x4 neighborhood named \c I, of type \c type. + - \b CImg_5x5x1(I,type) : Define a 5x5 neighborhood named \c I, of type \c type. + - \b CImg_2x2x2(I,type) : Define a 2x2x2 neighborhood named \c I, of type \c type. + - \b CImg_3x3x3(I,type) : Define a 3x3x3 neighborhood named \c I, of type \c type. + + Actually, \c I is a \e generic \e name for the neighborhood. In fact, these macros declare + a \e set of new variables. + For instance, defining a 3x3 neighborhood \c CImg_3x3x1(I,float) declares 9 different float variables + \c Ipp,\c Icp,\c Inp,\c Ipc,\c Icc,\c Inc,\c Ipn,\c Icn,\c Inn which correspond to each pixel value of + a 3x3 neighborhood. + Variable indices are \c p,\c c or \c n, and stand respectively for \e 'previous', \e 'current' and \e 'next'. + First indice denotes the \c x-axis, second indice denotes the \c y-axis. + Then, the names of the variables are directly related to the position of the corresponding pixels + in the neighborhood. For 3D neighborhoods, a third indice denotes the \c z-axis. + Then, inside a neighborhood loop, you will have the following equivalence : + - Ipp = img(x-1,y-1) + - Icn = img(x,y+1) + - Inp = img(x+1,y-1) + - Inpc = img(x+1,y-1,z) + - Ippn = img(x-1,y-1,z+1) + - and so on... + + For bigger neighborhoods, such as 4x4 or 5x5 neighborhoods, two additionnal indices are introduced : + \c a (stands for \e 'after') and \c b (stands for \e 'before'), so that : + - Ibb = img(x-2,y-2) + - Ina = img(x+1,y+2) + - and so on... + + The value of a neighborhood pixel outside the image range (image border problem) is automatically set to the same + values than the nearest valid pixel in the image (this is also called the \e Neumann \e border \e condition). + + \subsection lo10 Neighborhood as a reference + It is also possible to define neighborhood variables as references to classical C-arrays or CImg images, instead of + allocating new variables. This is done by adding \c _ref to the macro names used for the neighborhood definition : + + - \b CImg_2x2x1_ref(I,type,tab) : Define a 2x2 neighborhood named \c I, of type \c type, as a reference to \c tab. + - \b CImg_3x3x1_ref(I,type,tab) : Define a 3x3 neighborhood named \c I, of type \c type, as a reference to \c tab. + - \b CImg_4x4x1_ref(I,type,tab) : Define a 4x4 neighborhood named \c I, of type \c type, as a reference to \c tab. + - \b CImg_5x5x1_ref(I,type,tab) : Define a 5x5 neighborhood named \c I, of type \c type, as a reference to \c tab. + - \b CImg_2x2x2_ref(I,type,tab) : Define a 2x2x2 neighborhood named \c I, of type \c type, as a reference to \c tab. + - \b CImg_3x3x3_ref(I,type,tab) : Define a 3x3x3 neighborhood named \c I, of type \c type, as a reference to \c tab. + + \c tab can be a one-dimensionnal C-style array, or a non empty \c CImg image. Both objects must have + same sizes as the considered neighborhoods. + + \subsection lo11 Example codes + More than a long discussion, the above example will demonstrate how to compute the gradient norm of a 3D volume + using the \c cimg_map3x3x3() loop macro : + + \code + CImg volume("IRM.hdr"); // Load an IRM volume from an Analyze7.5 file + CImg_3x3x3(I,float); // Define a 3x3x3 neighborhood + CImg gradnorm(volume,false); // Create an image with same size as 'volume' + cimg_map3x3x3(volume,x,y,z,0,I) { // Loop over the volume, using the neighborhood I + const float ix = 0.5f*(Incc-Ipcc); // Compute the derivative along the x-axis. + const float iy = 0.5f*(Icnc-Icpc); // Compute the derivative along the y-axis. + const float iz = 0.5f*(Iccn-Iccp); // Compute the derivative along the z-axis. + gradnorm(x,y,z) = std::sqrt(ix*ix+iy*iy+iz*iz); // Set the gradient norm in the destination image + } + gradnorm.display("Gradient norm"); + \endcode + + And the following example shows how to deal with neighborhood references to blur a color image by averaging + pixel values on a 5x5 neighborhood. + + \code + CImg src("image_color.jpg"), dest(src,false), neighbor(5,5); // Image definitions. + typedef unsigned char uchar; // Avoid space in the second parameter of the macro CImg_5x5x1 below. + CImg_5x5x1_ref(N,uchar,neighbor); // Define a 5x5 neighborhood as a reference to the 5x5 image neighbor. + cimg_mapV(src,k) // Standard loop on color channels + cimg_map5x5x1(src,x,y,0,k,N) // 5x5 neighborhood loop. + dest(x,y,k) = neighbor.sum()/(5*5); // Averaging pixels to filter the color image. + CImgl visu(src,dest); + visu.display("Original + Filtered"); // Display both original and filtered image. + \endcode + + Note that in this example, we didn't use directly the variables Nbb,Nbp,..,Ncc,... since + there are only references to the neighborhood image \c neighbor. We rather used a member function of \c neighbor. + + As you can see, explaining the use of the CImg neighborhood macros is actually more difficult than using them ! + +**/ +/*@}*/ + +/** \addtogroup cimg_displays Using Display Windows. */ +/*@{*/ +/** + \page foo_di + + When opening a display window, you can choose the way the pixel values will be normalized + before being displayed on the screen. Screen displays only support color values between [0,255], + and some + + When displaying an image into the display window using CImgDisplay::display(), values of + the image pixels can be eventually linearly normalized between [0,255] for visualization purposes. + This may be useful for instance when displaying \p CImg images with pixel values + between [0,1]. + The normalization behavior depends on the value of \p normalize which can be either \p 0,\p 1 or \p 2 : + - \p 0 : No pixel normalization is performed when displaying an image. This is the fastest + process, but you must be sure your displayed image have pixel values inside the range [0,255]. + - \p 1 : Pixel value normalization is done for each new image display. Image pixels are + not modified themselves, only displayed pixels are normalized. + - \p 2 : Pixel value normalization is done for the first image display, then the + normalization parameters are kept and used for all the next image displays. + +**/ +/*@}*/ + +/** \addtogroup cimg_storage How pixel data are stored with CImg. */ +/*@{*/ +/** + \page foo_store + + TODO +**/ +/*@}*/ + +/** \addtogroup cimg_files_io Files IO in CImg. */ +/*@{*/ +/** + \page foo_fi + + The %CImg Library can NATIVELY handle the following file formats : + - RAW : consists in a very simple header (in ascii), then the image data. + - ASC (Ascii) + - HDR (Analyze 7.5) + - INR (Inrimage) + - PPM/PGM (Portable Pixmap) + - BMP (uncompressed) + - PAN (Pandore-5) + - DLM (Matlab ASCII) + + If ImageMagick is installed, The %CImg Library can save image in formats handled by ImageMagick : JPG, GIF, PNG, TIF,... + +**/ +/*@}*/ + +/** \addtogroup cimg_options Retrieving Command Line Arguments. */ +/*@{*/ +/** + \page foo_so + + The CImg library offers facilities to retrieve command line arguments in a console-based + program, as it is a commonly needed operation. + Two macros \c cimg_usage() and \c cimg_option() are defined for this purpose. + Using these macros allows to easily retrieve options values from the command line. + Moreover, invoking the corresponding executable with the option \c -h or \c --help will + automatically display the program usage, followed by the list of requested options. + + \section so1 The cimg_usage() macro + + The macro \c cimg_usage(usage) may be used to describe the program goal and usage. + It is generally inserted one time after the int main(int argc,char **argv) definition. + + \param usage : A string describing the program goal and usage. + \pre The function where \c cimg_usage() is used must have correctly defined \c argc and \c argv variables. + + \section so2 The cimg_option() macro + + The macro \c cimg_option(name,default,usage) may be used to retrieve an option value from the command line. + + \param name : The name of the option to be retrieved from the command line. + \param default : The default value returned by the macro if no options \p name has been specified when running the program. + \param usage : A brief explanation of the option. If \c usage==NULL, the option won't appear on the option list + when invoking the executable with options \c -h or \c --help (hidden option). + + \return \c cimg_option() returns an object that has the \e same \e type than the default value \c default. + The return value is equal to the one specified on the command line. If no such option have been specified, + the return value is equal to the default value \c default. + Warning, this can be confusing in some situations (look at the end of the next section). + \pre The function where \c cimg_option() is used must have correctly defined \c argc and \c argv variables. + + \section so3 Example of use + + The code below uses the macros \c cimg_usage() and \c cimg_option(). + It loads an image, smoothes it an quantifies it with a specified number of values. + \code + #include "CImg.h" + using namespace cimg_library; + int main(int argc,char **argv) { + cimg_usage("Retrieve command line arguments"); + const char* filename = cimg_option("-i","image.gif","Input image file"); + const char* output = cimg_option("-o",(const char*)NULL,"Output image file"); + const double sigma = cimg_option("-s",1.0,"Standard variation of the gaussian smoothing"); + const int nblevels = cimg_option("-n",16,"Number of quantification levels"); + const bool hidden = cimg_option("-hidden",false,NULL); // This is a hidden option + + CImg img(filename); + img.blur(sigma).quantize(nblevels); + if (output) img.save(output); else img.display("Output image"); + if (hidden) std::fprintf(stderr,"You found me !\n"); + return 0; + } + \endcode + + Invoking the corresponding executable with test -h -hidden -n 20 -i foo.jpg will display : + \verbatim + ./test -h -hidden -n 20 -i foo.jpg + + test : Retrieve command line arguments (Oct 16 2004, 12:34:26) + + -i = foo.jpg : Input image file + -o = NULL : Output image file + -s = 1 : Standard variation of the gaussian smoothing + -n = 20 : Number of quantification levels + + You found me ! +\endverbatim + + \warning As the type of object returned by the macro \c cimg_option(option,default,usage) + is defined by the type of \c default, undesired casts may appear when writting code such as : + \code + const double sigma = cimg_option("-val",0,"A floating point value"); + \endcode + In this case, \c sigma will always be equal to an integer (since the default value \c 0 is an integer). + When passing a float value on the command line, a \e float \e to \e integer cast is then done, + truncating the given parameter to an integer value (this is surely not a desired behavior). + You must specify 0.0 as the default value in this case. + + \section so4 How to learn more about command line options ? + You should take a look at the examples examples/inrcast.cpp provided in the %CImg Library package. + This is a command line based image converter which intensively uses the \c cimg_option() and \c cimg_usage() + macros to retrieve command line parameters. +**/ +/*@}*/ + +#endif + +// Local Variables: +// mode: c++ +// End: diff --git a/chalk/plugins/filters/cimg/Makefile.am b/chalk/plugins/filters/cimg/Makefile.am new file mode 100644 index 00000000..5bedb23b --- /dev/null +++ b/chalk/plugins/filters/cimg/Makefile.am @@ -0,0 +1,35 @@ +KDE_CXXFLAGS = $(USE_EXCEPTIONS) -D_GNU_SOURCE + +kde_services_DATA = chalkcimg.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkcimg_la_SOURCES = \ + wdg_cimg.ui\ + kis_cimg_filter.cc\ + kis_cimg_plugin.cc\ + kis_cimgconfig_widget.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalkcimg.la + +noinst_HEADERS = \ + CImg.h\ + kis_cimg_filter.h\ + kis_cimg_plugin.h\ + kis_cimgconfig_widget.h + +chalkcimg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkcimg_la_LIBADD = ../../../libchalkcommon.la + +chalkcimg_la_METASOURCES = AUTO + + +KDE_OPTIONS = nofinal diff --git a/chalk/plugins/filters/cimg/chalkcimg.desktop b/chalk/plugins/filters/cimg/chalkcimg.desktop new file mode 100644 index 00000000..ae7bd2c3 --- /dev/null +++ b/chalk/plugins/filters/cimg/chalkcimg.desktop @@ -0,0 +1,79 @@ +[Desktop Entry] +Name=CImg Image Restoration Filter +Name[bg]=Филтър за възстановяване на изображение CImg +Name[ca]=Filtre de restauració d'imatges Clmg +Name[cy]=Hidlen adfer Delwedd CImg +Name[da]=Cimg-billedrestaureringsfilter +Name[de]=CImg Filter zur Bildrestauration +Name[el]=Φίλτρο αποκατάστασης εικόνων CImg +Name[es]=Filtro para restauración de imágenes CImg +Name[et]=CImg pilditaastamisfilter +Name[eu]=CImg irudiak zaharberritzeko iragazkia +Name[fa]=پالایۀ بازگردانی تصویر CImg +Name[fr]=Filtre de restauration d'images de CImg +Name[fy]=CImg ôfbyldingsrestauraasjefilter +Name[gl]=Filtro de Restauración de Imaxe CImg +Name[hu]=CImg képhelyreállító szűrő +Name[is]=CImg myndbjörgunarsía +Name[it]=Filtro CImg di restauro delle immagini +Name[ja]=Cimg 画像復元フィルタ +Name[km]=តម្រង​សម្រាប់​ស្ដារ​រូបភាព CImg +Name[ms]=Penapis Pemulihan Imej Clmg +Name[nb]=CImg-filter for bilderestaurering +Name[nds]=CImg-Filter för't Bild-Wedderherstellen +Name[ne]=सीआईएमजी छवि आरोग्यता फिल्टर +Name[nl]=CImg afbeeldingsrestauratiefilter +Name[nn]=CImg-filter for biletrestaurering +Name[pl]=Filtr CImg do restaurowania obrazków +Name[pt]=Filtro de Restauro de Imagem CImg +Name[pt_BR]=Filtro de Restauração de Imagens CImg +Name[ru]=Восстановление изображения CImg +Name[sk]=CImg filter pre obnovu obrázkov +Name[sl]=Filter CImg za obnavljanje slik +Name[sr]=CImg, филтер за обнову слика +Name[sr@Latn]=CImg, filter za obnovu slika +Name[sv]=Cimg-bildrestaureringsfilter +Name[uk]=Фільтр (CImg) відновлення зображень +Name[zh_CN]=CImg 图像修复滤镜 +Name[zh_TW]=CImg 圖片修復過濾器 +Comment=CImg Image restoration filter +Comment[bg]=Филтър за възстановяване на изображение CImg +Comment[ca]=Filtre de restauració d'imatges Clmg +Comment[cy]=Hidlen adfer Delwedd CImg +Comment[da]=Cimg-billedforbedringsfilter +Comment[de]=CImg basierter Filter zur Bildrestauration +Comment[el]=Φίλτρο αποκατάστασης εικόνων CImg +Comment[es]=Filtro para restauración de imágenes CImg +Comment[et]=CImg pilditaastamisfilter +Comment[eu]=CImg irudiak zaharberritzeko iragazkia +Comment[fa]=پالایۀ بازگردانی تصویر CImg +Comment[fr]=Filtre de restauration d'images de CImg +Comment[fy]=CImg ôfbyldingsrestauraasjefilter +Comment[gl]=Filtro de restauración de imaxe CImg +Comment[hu]=CImg képhelyreállító szűrő +Comment[is]=CImg mynda endurheimtasía +Comment[it]=Filtro CImg di restauro delle immagini +Comment[ja]=Cimg 画像復元フィルタ +Comment[km]=តម្រង​សម្រាប់​ស្ដារ​រូបភាព CImg +Comment[ms]=Penapis pemulihan Imej Clmg +Comment[nb]=CImg-filter for bilderestaurering +Comment[nds]=Op CImg opbuut Filter för't Bild-Wedderherstellen +Comment[ne]=सिआईएमजी छवि आरोग्यता फिल्टर +Comment[nl]=CImg afbeeldingrestauratiefilter +Comment[nn]=CImg-filter for biletrestaurering +Comment[pl]=Filtr CImg do restaurowania obrazków +Comment[pt]=Filtro de restauro de imagem CImg +Comment[pt_BR]=Filtro de restauração de imagens CImg +Comment[ru]=Восстановление изображения на основе CImg +Comment[sk]=CImg filter pre obnovu obrázkov +Comment[sl]=Filter CImg za obnavljanje slik +Comment[sr]=CImg, филтер за обнову слика +Comment[sr@Latn]=CImg, filter za obnovu slika +Comment[sv]=Cimg-bildförbättringsfilter +Comment[uk]=Фільтр (CImg) відновлення зображень +Comment[zh_CN]=CImg 图像修复滤镜 +Comment[zh_TW]=CImg 圖片修復過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkcimg +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/cimg/kis_cimg_filter.cc b/chalk/plugins/filters/cimg/kis_cimg_filter.cc new file mode 100644 index 00000000..dc074e7b --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimg_filter.cc @@ -0,0 +1,711 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Ported from the CImg Gimp plugin by Victor Stinner and uses CImg by David Tschumperlé. + * See: http://www.girouette-stinner.com/castor/gimp.html?girouette=ad761bc2f4dcfda1cb44c587da17f86c + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_cimgconfig_widget.h" +#include "kis_cimg_filter.h" + +#include "CImg.h" + +using namespace cimg_library; +typedef unsigned char uchar; + + +KisCImgFilterConfiguration::KisCImgFilterConfiguration() + : KisFilterConfiguration("cimg", 1) +{ + nb_iter = 1; + dt = 20.0; + sigma = 1.4; + dlength = 0.8; + dtheta = 45.0; + onormalize = false; + power1 = 0.1; + power2 = 0.9; + gauss_prec = 3.0; + linear = true; +} + +void KisCImgFilterConfiguration::fromXML(const TQString & s) +{ + KisFilterConfiguration::fromXML( s ); + + nb_iter = getInt("nb_iter", 1); + dt = getDouble("dt", 20.0); + sigma = getDouble("sigma", 1.4); + dlength = getDouble("dlength", 0.8); + dtheta = getDouble("dtheta", 45.0); + onormalize = getBool("onormalize", false); + power1 = getDouble("power1", 0.1); + power2 = getDouble("power2", 0.9); + gauss_prec = getDouble("gauss_pref", 3.0); + linear = getBool("linear", true); +} + + +TQString KisCImgFilterConfiguration::toString() +{ + m_properties.clear(); + + setProperty("nb_iter", nb_iter); + setProperty("dt", dt); + setProperty("sigma", sigma); + setProperty("dlength", dlength); + setProperty("dtheta", dtheta); + setProperty("onormalize", onormalize); + setProperty("power1", power1); + setProperty("power2", power2); + setProperty("gauss_prec", gauss_prec); + setProperty("linear", linear); + + return KisFilterConfiguration::toString(); +} + +KisCImgFilter::KisCImgFilter() + : KisFilter(id(), "enhance", i18n("&CImg Image Restoration...")), + eigen(CImg<>(2,1), CImg<>(2,2)) +{ + restore = true; + inpaint = false; + resize = false; + visuflow = NULL; + + /* restore */ + nb_iter = 1; + dt = 20.0f; + sigma = 0.8f; + dlength = 0.8; + dtheta = 45.0; + onormalize = false; + power1 = 0.5; + power2 = 0.9; + + /* inpainting * + nb_iter = 100; + dt = 50.0f; + sigma = 2.0; + power1 = 0.1; + power2 = 100; + dlength = 0.8; + dtheta = 45.0; + */ + + /* resize * + nb_iter = 1; + dt = 30.0f; + sigma = 2.0; + dlength = 0.8; + dtheta = 45.0; + power1 = 0.01; + power2 = 100.0; + */ + + /* visualflow * + nb_iter = 1; + dt = 30.0f; + dlength = 0.5; + dtheta = 20.0; + onormalize = false; + */ + + gauss_prec = 3.0f; + linear = true; +} + + +void KisCImgFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + Q_UNUSED(dst); + + TQ_INT32 width = rect.width(); + TQ_INT32 height = rect.height(); + + // Copy the src data into a CImg type image with three channels and no alpha. + // XXX: This means that a CImg is always rgba; find the quickest way to get 8-bit rgb from any colorspace & find a way + // to warn in the gui of loss of precision. XXX: Add this to the ColorSpaceAPI doc. + + img = CImg<>(width, height, 1, 3); + + KisColorSpace * cs = src->colorSpace(); + KisColorSpace* rgb16CS = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA16"),""); + KisPaintDeviceSP srcRGB16; + if(rgb16CS) + { + srcRGB16 = new KisPaintDevice(*src.data()); + srcRGB16->convertTo(rgb16CS); + KisRectIteratorPixel it = srcRGB16->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + while (!it.isDone()) { + TQ_UINT16* data = reinterpret_cast(it.rawData()); + + TQ_INT32 x = it.x() - rect.x(); + TQ_INT32 y = it.y() - rect.y(); + + img(x, y, 0) = data[0]; + img(x, y, 1) = data[1]; + img(x, y, 2) = data[2]; + + ++it; + } + } else { + kdDebug() << "The RGB16 colorspace is not available, will work in 8bit." << endl; + KisRectIteratorPixel it = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + while (!it.isDone()) { + + TQColor color; + cs->toTQColor(it.rawData(), &color); + + TQ_INT32 x = it.x() - rect.x(); + TQ_INT32 y = it.y() - rect.y(); + + img(x, y, 0) = color.red(); + img(x, y, 1) = color.green(); + img(x, y, 2) = color.blue(); + + ++it; + } + } + + // Copy the config data into local variables for easy cut & pasting from the original plugin + + KisCImgFilterConfiguration * cfg = (KisCImgFilterConfiguration*)configuration; + + nb_iter = cfg->nb_iter; + dt = cfg->dt; + dlength = cfg->dlength; + dtheta = cfg->dtheta; + sigma = cfg->sigma; + power1 = cfg->power1; + power2 = cfg->power2; + gauss_prec = cfg->gauss_prec; + onormalize = cfg->onormalize; + linear = cfg->linear; + + if (process() && !cancelRequested()) { + + + if(rgb16CS) + { + { + KisRectIteratorPixel it = srcRGB16->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true); + while (!it.isDone()) { + TQ_INT32 x = it.x() - rect.x(); + TQ_INT32 y = it.y() - rect.y(); + + TQ_UINT16* data = reinterpret_cast(it.rawData()); + + data[0] = img(x, y, 0) ; + data[1] = img(x, y, 1) ; + data[2] = img(x, y, 2) ; + + ++it; + } + } + srcRGB16->convertTo(cs); + KisPainter p(dst); + p.bitBlt(rect.x(), rect.y(), COMPOSITE_OVER, srcRGB16, rect.x(), rect.y(), rect.width(), rect.height() ); + } else { + KisRectIteratorPixel it = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true); + + while (!it.isDone()) { + + if (it.isSelected()) { + + TQ_INT32 x = it.x() - rect.x(); + TQ_INT32 y = it.y() - rect.y(); + + TQColor color((int)img(x, y, 0), (int)img(x, y, 1), (int)img(x, y, 2)); + + cs->fromTQColor(color, it.rawData()); + } + + ++it; + } + } + } else { + // Everything went wrong; notify user and restore old state + } + +} + +//---------------------------------------------------------------------------- +// Cut & Pasted code starts here.... +//---------------------------------------------------------------------------- + +void get_geom(const char *geom, int &geom_w, int &geom_h) +{ + char tmp[16]; + std::sscanf(geom,"%d%7[^0-9]%d%7[^0-9]",&geom_w,tmp,&geom_h,tmp+1); + if (tmp[0]=='%') geom_w=-geom_w; + if (tmp[1]=='%') geom_h=-geom_h; +} + + +//---------------------------------------------------------------------------- + +void KisCImgFilter::cleanup() +{ + img0 = flow = G = dest = sum= W = CImg<>(); + tqmask = CImg (); +} + +//---------------------------------------------------------------------------- + +bool KisCImgFilter::prepare() +{ + if (!restore && !inpaint && !resize && !visuflow) + { + // XXX: Do KDE messagebox + // g_message ("You must specify one of the restore, inpaint, resize or flow mode !"); + return false; + } + + // Init algorithm parameters + //--------------------------- + if (restore) if (!prepare_restore()) return false; + if (inpaint) if (!prepare_inpaint()) return false; + if (resize) if (!prepare_resize()) return false; + if (visuflow) if (!prepare_visuflow()) return false; + + if (!check_args()) return false; + + // Init images + //------------ + dest = CImg<>(img.width,img.height,1,img.dim); + sum = CImg<>(img.width,img.height,1); + W = CImg<>(img.width,img.height,1,2); + + return true; +} + +//---------------------------------------------------------------------------- + +bool KisCImgFilter::check_args() +{ + if (power2 < power1) + { + // XXX: Do KDE messagebox + // g_message ("Error : p2(img.width,img.height,1,3); + return true; +} + +//---------------------------------------------------------------------------- + +bool KisCImgFilter::prepare_inpaint() +{ + const char *file_m = NULL; //cimg_option("-m",(const char*)NULL,"Input inpainting tqmask"); + if (!file_m) + { + // XXX: Do KDE messagebox + // g_message ("You need to specify an inpainting tqmask (option '-m') !"); + return false; + } + + const unsigned int dilate = 0; //cimg_option("-dilate",0,"Inpainting tqmask dilatation"); + const unsigned int ip_init = 3; //cimg_option("-init",3,"Inpainting init (0=black, 1=white, 2=noise, 3=unchanged, 4=interpol)"); + if (cimg::strncasecmp("block",file_m,5)) + tqmask = CImg(file_m); + else { + int l=16; std::sscanf(file_m,"block%d",&l); + tqmask = CImg(img.width/l,img.height/l); + cimg_mapXY(tqmask,x,y) tqmask(x,y)=(x+y)%2; + } + tqmask.resize(img.width,img.height,1,1); + if (dilate) tqmask.dilate(dilate); + switch (ip_init) { + case 0 : { cimg_mapXYV(img,x,y,k) if (tqmask(x,y)) img(x,y,k) = 0; } break; + case 1 : { cimg_mapXYV(img,x,y,k) if (tqmask(x,y)) img(x,y,k) = 255; } break; + case 2 : { cimg_mapXYV(img,x,y,k) if (tqmask(x,y)) img(x,y,k) = (float)(255*cimg::rand()); } break; + case 3 : break; + case 4 : { + CImg ttqmask(tqmask),nttqmask(ttqmask); + CImg_3x3(M,uchar); + CImg_3x3(I,float); + while (CImgStats(nttqmask,false).max>0) { + cimg_map3x3(ttqmask,x,y,0,0,M) if (Mcc && (!Mpc || !Mnc || !Mcp || !Mcn)) { + const float ccp = Mcp?0.0f:1.0f, cpc = Mpc?0.0f:1.0f, + cnc = Mnc?0.0f:1.0f, ccn = Mcn?0.0f:1.0f, csum = ccp + cpc + cnc + ccn; + cimg_mapV(img,k) { + cimg_get3x3(img,x,y,0,k,I); + img(x,y,k) = (ccp*Icp + cpc*Ipc + cnc*Inc + ccn*Icn)/csum; + } + nttqmask(x,y) = 0; + } + ttqmask = nttqmask; + } + } break; + default: break; + } + img0=img; + G = CImg<>(img.width,img.height,1,3,0); + CImg_3x3(g,uchar); + CImg_3x3(I,float); + cimg_map3x3(tqmask,x,y,0,0,g) if (!gcc && !(gnc-gcc) && !(gcc-gpc) && !(gcn-gcc) && !(gcc-gcp)) cimg_mapV(img,k) { + cimg_get3x3(img,x,y,0,k,I); + const float ix = 0.5f*(Inc-Ipc), iy = 0.5f*(Icn-Icp); + G(x,y,0)+= ix*ix; G(x,y,1)+= ix*iy; G(x,y,2)+= iy*iy; + } + G.blur(sigma); + { cimg_mapXY(G,x,y) + { + G.get_tensor(x,y).symeigen(eigen(0),eigen(1)); + const float + l1 = eigen(0)[0], + l2 = eigen(0)[1], + u = eigen(1)[0], + v = eigen(1)[1], + ng = (float)std::sqrt(l1+l2), + n1 = (float)(1.0/std::pow(1+ng,power1)), + n2 = (float)(1.0/std::pow(1+ng,power2)), + sr1 = (float)std::sqrt(n1), + sr2 = (float)std::sqrt(n2); + G(x,y,0) = sr1*u*u + sr2*v*v; + G(x,y,1) = u*v*(sr1-sr2); + G(x,y,2) = sr1*v*v + sr2*u*u; + } + } + return true; +} + +//---------------------------------------------------------------------------- + +bool KisCImgFilter::prepare_resize() +{ + const char *geom = NULL; //cimg_option("-g",(const char*)NULL,"Output image tqgeometry"); + const bool anchor = true; //cimg_option("-anchor",true,"Anchor original pixels"); + if (!geom) throw CImgArgumentException("You need to specify an output geomety (option -g)"); + int w,h; get_geom(geom,w,h); + tqmask = CImg(img.width,img.height,1,1,255); + if (!anchor) tqmask.resize(w,h,1,1,1); else tqmask = ~tqmask.resize(w,h,1,1,4); + img0 = img.get_resize(w,h,1,-100,1); + img.resize(w,h,1,-100,3); + G = CImg<>(img.width,img.height,1,3); + return true; +} + +//---------------------------------------------------------------------------- + +bool KisCImgFilter::prepare_visuflow() +{ + const char *geom = "100%x100%"; //cimg_option("-g","100%x100%","Output tqgeometry"); + //const char *file_i = (const char *)NULL; //cimg_option("-i",(const char*)NULL,"Input init image"); + const bool normalize = false; //cimg_option("-norm",false,"Normalize input flow"); + + int w,h; get_geom(geom,w,h); + if (!cimg::strcasecmp(visuflow,"circle")) { // Create a circular vector flow + flow = CImg<>(400,400,1,2); + cimg_mapXY(flow,x,y) { + const float ang = (float)(std::atan2(y-0.5*flow.dimy(),x-0.5*flow.dimx())); + flow(x,y,0) = -(float)std::sin(ang); + flow(x,y,1) = (float)std::cos(ang); + } + } + if (!cimg::strcasecmp(visuflow,"radial")) { // Create a radial vector flow + flow = CImg<>(400,400,1,2); + cimg_mapXY(flow,x,y) { + const float ang = (float)(std::atan2(y-0.5*flow.dimy(),x-0.5*flow.dimx())); + flow(x,y,0) = (float)std::cos(ang); + flow(x,y,1) = (float)std::sin(ang); + } + } + if (!flow.data) flow = CImg<>(visuflow); + flow.resize(w,h,1,2,3); + if (normalize) flow.orientation_pointwise(); + /* if (file_i) img = CImg<>(file_i); + else img = CImg<>(flow.width,flow.height,1,1,0).noise(100,2); */ + img0=img; + img0.fill(0); + float color[3]={255,255,255}; + img0.draw_quiver(flow,color,15,-10); + G = CImg<>(img.width,img.height,1,3); + return true; +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_smoothed_tensor() +{ + if (visuflow || inpaint) return; + CImg_3x3(I,float); + G.fill(0); + cimg_mapV(img,k) cimg_map3x3(img,x,y,0,k,I) { + const float ix = 0.5f*(Inc-Ipc), iy = 0.5f*(Icn-Icp); + G(x,y,0)+= ix*ix; G(x,y,1)+= ix*iy; G(x,y,2)+= iy*iy; + } + G.blur(sigma); +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_normalized_tensor() +{ + if (restore || resize) cimg_mapXY(G,x,y) { + G.get_tensor(x,y).symeigen(eigen(0),eigen(1)); + const float + l1 = eigen(0)[0], + l2 = eigen(0)[1], + u = eigen(1)[0], + v = eigen(1)[1], + n1 = (float)(1.0/std::pow(1.0f+l1+l2,0.5f*power1)), + n2 = (float)(1.0/std::pow(1.0f+l1+l2,0.5f*power2)); + G(x,y,0) = n1*u*u + n2*v*v; + G(x,y,1) = u*v*(n1-n2); + G(x,y,2) = n1*v*v + n2*u*u; + } + if (visuflow) cimg_mapXY(G,x,y) { + const float + u = flow(x,y,0), + v = flow(x,y,1), + n = (float)std::pow(u*u+v*v,0.25f), + nn = n < 1e-5 ? 1 : n; + G(x,y,0) = u*u/nn; + G(x,y,1) = u*v/nn; + G(x,y,2) = v*v/nn; + } + + const CImgStats stats(G,false); + G /= cimg::max(std::fabs(stats.max), std::fabs(stats.min)); +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_W(float cost, float sint) +{ + cimg_mapXY(W,x,y) { + const float + a = G(x,y,0), + b = G(x,y,1), + c = G(x,y,2), + u = a*cost + b*sint, + v = b*cost + c*sint; + W(x,y,0) = u; + W(x,y,1) = v; + } +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_LIC_back_forward(int x, int y) +{ + float l, X,Y, cu, cv, lsum=0; + const float + fsigma2 = 2*dt*(W(x,y,0)*W(x,y,0) + W(x,y,1)*W(x,y,1)), + length = gauss_prec*(float)std::sqrt(fsigma2); + + if (linear) { + + // Integrate with linear interpolation + cu = W(x,y,0); cv = W(x,y,1); X=(float)x; Y=(float)y; + for (l=0; l=0 && Y>=0 && X<=W.dimx()-1 && Y<=W.dimy()-1; l+=dlength) { + float u = (float)(W.linear_pix2d(X,Y,0)), v = (float)(W.linear_pix2d(X,Y,1)); + const float coef = (float)std::exp(-l*l/fsigma2); + if ((cu*u+cv*v)<0) { u=-u; v=-v; } + cimg_mapV(dest,k) dest(x,y,k)+=(float)(coef*img.linear_pix2d(X,Y,k)); + X+=dlength*u; Y+=dlength*v; cu=u; cv=v; lsum+=coef; + } + cu = W(x,y,0); cv = W(x,y,1); X=x-dlength*cu; Y=y-dlength*cv; + for (l=dlength; l=0 && Y>=0 && X<=W.dimx()-1 && Y<=W.dimy()-1; l+=dlength) { + float u = (float)(W.linear_pix2d(X,Y,0)), v = (float)(W.linear_pix2d(X,Y,1)); + const float coef = (float)std::exp(-l*l/fsigma2); + if ((cu*u+cv*v)<0) { u=-u; v=-v; } + cimg_mapV(dest,k) dest(x,y,k)+=(float)(coef*img.linear_pix2d(X,Y,k)); + X-=dlength*u; Y-=dlength*v; cu=u; cv=v; lsum+=coef; + } + } else { + + // Integrate with non linear interpolation + cu = W(x,y,0); cv = W(x,y,1); X=(float)x; Y=(float)y; + for (l=0; l=0 && Y>=0 && X<=W.dimx()-1 && Y<=W.dimy()-1; l+=dlength) { + float u = W((int)X,(int)Y,0), v = W((int)X,(int)Y,1); + const float coef = (float)std::exp(-l*l/fsigma2); + if ((cu*u+cv*v)<0) { u=-u; v=-v; } + cimg_mapV(dest,k) dest(x,y,k)+=(float)(coef*img.linear_pix2d(X,Y,k)); + X+=dlength*u; Y+=dlength*v; cu=u; cv=v; lsum+=coef; + } + cu = W(x,y,0); cv = W(x,y,1); X=x-dlength*cu; Y=y-dlength*cv; + for (l=dlength; l=0 && Y>=0 && X<=W.dimx()-1 && Y<=W.dimy()-1; l+=dlength) { + float u = W((int)X,(int)Y,0), v = W((int)X,(int)Y,1); + const float coef = (float)std::exp(-l*l/fsigma2); + if ((cu*u+cv*v)<0) { u=-u; v=-v; } + cimg_mapV(dest,k) dest(x,y,k)+=(float)(coef*img.linear_pix2d(X,Y,k)); + X-=dlength*u; Y-=dlength*v; cu=u; cv=v; lsum+=coef; + } + } + sum(x,y)+=lsum; +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_LIC(int &progressSteps) +{ + dest.fill(0); + sum.fill(0); + for (float theta=(180%(int)dtheta)/2.0f; theta<180; theta+=dtheta) + { + const float + rad = (float)(theta*cimg::PI/180.0), + cost = (float)std::cos(rad), + sint = (float)std::sin(rad); + + // Compute vector field w = sqrt(T)*a_alpha + compute_W(cost, sint); + + // Compute the LIC along w in backward and forward directions + cimg_mapXY(dest,x,y) + { + setProgress(progressSteps); + progressSteps++; + + if (cancelRequested()) { + return; + } + + if (!tqmask.data || tqmask(x,y)) compute_LIC_back_forward(x,y); + } + } + +} + +//---------------------------------------------------------------------------- + +void KisCImgFilter::compute_average_LIC() +{ + cimg_mapXY(dest,x,y) + { + if (sum(x,y)>0) + cimg_mapV(dest,k) dest(x,y,k) /= sum(x,y); + else + cimg_mapV(dest,k) dest(x,y,k) = img(x,y,k); + } +} + + +bool KisCImgFilter::process() +{ + if (!prepare()) return false; + + setProgressTotalSteps(dest.width * dest.height * nb_iter * (int)ceil(180 / dtheta)); + setProgressStage(i18n("Applying image restoration filter..."), 0); + + //------------------------------------- + // Begin regularization PDE iterations + //------------------------------------- + int progressSteps = 0; + for (unsigned int iter=0; iterconfig(); + } +} + +ColorSpaceIndependence KisCImgFilter::colorSpaceIndependence() +{ + KisColorSpace* rgb16CS = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA16"),""); + if(rgb16CS) + { + return TO_RGBA16; + } else { + return TO_RGBA8; + } +} diff --git a/chalk/plugins/filters/cimg/kis_cimg_filter.h b/chalk/plugins/filters/cimg/kis_cimg_filter.h new file mode 100644 index 00000000..3b745476 --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimg_filter.h @@ -0,0 +1,124 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CIMG_FILTER_H_ +#define _KIS_CIMG_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" +#include "CImg.h" + +class KisCImgFilterConfiguration : public KisFilterConfiguration +{ + +public: + + KisCImgFilterConfiguration(); + virtual TQString toString(); + virtual void fromXML(const TQString & s); + +public: + + TQ_INT32 nb_iter; // Number of smoothing iterations + double dt; // Time step + double dlength; // Integration step + double dtheta; // Angular step (in degrees) + double sigma; // Structure tensor blurring + double power1; // Diffusion limiter along isophote + double power2; // Diffusion limiter along gradient + double gauss_prec; // Precision of the gaussian function + bool onormalize; // Output image normalization (in [0,255]) + bool linear; // Use linear interpolation for integration ? +}; + + +class KisCImgFilter : public KisFilter +{ +public: + KisCImgFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("cimg", i18n("Image Restoration (cimg-based)")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence(); +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return new KisCImgFilterConfiguration();}; +private: + + bool process(); + + // Compute smoothed structure tensor field G + void compute_smoothed_tensor(); + + // Compute normalized tensor field sqrt(T) in G + void compute_normalized_tensor(); + + // Compute LIC's along different angle projections a_\alpha + void compute_LIC(int &counter); + void compute_LIC_back_forward(int x, int y); + void compute_W(float cost, float sint); + + // Average all the LIC's + void compute_average_LIC(); + + // Prepare datas + bool prepare(); + bool prepare_restore(); + bool prepare_inpaint(); + bool prepare_resize(); + bool prepare_visuflow(); + + // Check arguments + bool check_args(); + + // Clean up memory (CImg datas) to save memory + void cleanup(); + +private: + unsigned int nb_iter; // Number of smoothing iterations + float dt; // Time step + float dlength; // Integration step + float dtheta; // Angular step (in degrees) + float sigma; // Structure tensor blurring + float power1; // Diffusion limiter along isophote + float power2; // Diffusion limiter along gradient + float gauss_prec; // Precision of the gaussian function + bool onormalize; // Output image normalization (in [0,255]) + bool linear; // Use linear interpolation for integration + + + // internal use + bool restore; + bool inpaint; + bool resize; + const char* visuflow; + cimg_library::CImg<> dest, sum, W; + cimg_library::CImg<> img, img0, flow,G; + cimg_library::CImgl<> eigen; + cimg_library::CImg tqmask; + + + +}; + +#endif diff --git a/chalk/plugins/filters/cimg/kis_cimg_plugin.cc b/chalk/plugins/filters/cimg/kis_cimg_plugin.cc new file mode 100644 index 00000000..6c3e9522 --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimg_plugin.cc @@ -0,0 +1,44 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include "kis_cimg_plugin.h" +#include "kis_cimg_filter.h" + + +typedef KGenericFactory KisCImgPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcimg, KisCImgPluginFactory( "chalk" ) ) + +KisCImgPlugin::KisCImgPlugin(TQObject *tqparent, const char *name, const TQStringList &) : KParts::Plugin(tqparent, name) +{ + setInstance(KisCImgPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisCImgFilter()); + } +} + +KisCImgPlugin::~KisCImgPlugin() +{ +} + diff --git a/chalk/plugins/filters/cimg/kis_cimg_plugin.h b/chalk/plugins/filters/cimg/kis_cimg_plugin.h new file mode 100644 index 00000000..2d35bff4 --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimg_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_CIMG_PLUGIN_H_ +#define _KIS_CIMG_PLUGIN_H_ + +#include + +class KisCImgPlugin : public KParts::Plugin +{ +public: + KisCImgPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisCImgPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/cimg/kis_cimgconfig_widget.cc b/chalk/plugins/filters/cimg/kis_cimgconfig_widget.cc new file mode 100644 index 00000000..c12ebf5f --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimgconfig_widget.cc @@ -0,0 +1,94 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Ported from the CImg Gimp plugin by Victor Stinner and David Tschumperlé. + */ +#include "tqlayout.h" +#include "tqcheckbox.h" +#include "tqpushbutton.h" + +#include "knuminput.h" + +#include "wdg_cimg.h" +#include "kis_cimgconfig_widget.h" +#include "kis_cimg_filter.h" + +KisCImgconfigWidget::KisCImgconfigWidget(KisFilter* nfilter, TQWidget * tqparent, const char * name, WFlags f) + : KisFilterConfigWidget(tqparent, name, f) +{ + m_page = new WdgCImg(this); + Q_CHECK_PTR(m_page); + + TQHBoxLayout * l = new TQHBoxLayout(this); + Q_CHECK_PTR(l); + + l->add(m_page); + nfilter->setAutoUpdate(false); + +// connect( m_page->bnRefresh, TQT_SIGNAL(clicked()), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numDetail, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numGradient, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numTimeStep, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numBlur, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numBlurIterations, TQT_SIGNAL(valueChanged (int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numAngularStep, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numIntegralStep, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->numGaussian, TQT_SIGNAL(valueChanged (double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkLinearInterpolation, TQT_SIGNAL(toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->chkNormalize, TQT_SIGNAL(toggled(bool)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + + +KisCImgFilterConfiguration * KisCImgconfigWidget::config() +{ + KisCImgFilterConfiguration * cfg = new KisCImgFilterConfiguration(); + Q_CHECK_PTR(cfg); + + cfg->power1 = m_page->numDetail->value(); + cfg->power2 = m_page->numGradient->value(); + cfg->dt = m_page->numTimeStep->value(); + cfg->sigma = m_page->numBlur->value(); + cfg->nb_iter = m_page->numBlurIterations->value(); + cfg->dtheta = m_page->numAngularStep->value(); + cfg->dlength = m_page->numIntegralStep->value(); + cfg->gauss_prec = m_page->numGaussian->value(); + cfg->linear = m_page->chkLinearInterpolation->isChecked(); + cfg->onormalize = m_page->chkNormalize->isChecked(); + + return cfg; + +} + +void KisCImgconfigWidget::setConfiguration(KisFilterConfiguration * config) +{ + KisCImgFilterConfiguration * cfg = dynamic_cast(config); + if (!cfg) return; + + m_page->numDetail->setValue(cfg->power1); + m_page->numGradient->setValue(cfg->power2); + m_page->numTimeStep->setValue(cfg->dt); + m_page->numBlur->setValue(cfg->sigma); + m_page->numAngularStep->setValue(cfg->nb_iter); + m_page->numIntegralStep->setValue(cfg->dlength); + m_page->numGaussian->setValue(cfg->gauss_prec); + m_page->chkLinearInterpolation->setChecked(cfg->linear); + m_page->chkNormalize->setChecked(cfg->onormalize); +} + +#include "kis_cimgconfig_widget.moc" diff --git a/chalk/plugins/filters/cimg/kis_cimgconfig_widget.h b/chalk/plugins/filters/cimg/kis_cimgconfig_widget.h new file mode 100644 index 00000000..aba373ca --- /dev/null +++ b/chalk/plugins/filters/cimg/kis_cimgconfig_widget.h @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Ported from the CImg Gimp plugin by Victor Stinner and David Tschumperlé. + */ +#ifndef _KIS_CIMGCONFIG_WIDGET_ +#define _KIS_CIMGCONFIG_WIDGET_ + +#include "wdg_cimg.h" +#include "kis_cimg_filter.h" +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisCImgconfigWidget : public KisFilterConfigWidget { + + Q_OBJECT + TQ_OBJECT + +public: + + KisCImgconfigWidget(KisFilter* nfilter, TQWidget * tqparent = 0, const char * name = 0, WFlags f = 0 ); + virtual ~KisCImgconfigWidget() {}; + +public: + + KisCImgFilterConfiguration * config(); + void setConfiguration(KisFilterConfiguration * config); + +private: + WdgCImg * m_page; + +}; + +#endif // _KIS_CIMGCONFIG_WIDGET_ diff --git a/chalk/plugins/filters/cimg/wdg_cimg.ui b/chalk/plugins/filters/cimg/wdg_cimg.ui new file mode 100644 index 00000000..80476616 --- /dev/null +++ b/chalk/plugins/filters/cimg/wdg_cimg.ui @@ -0,0 +1,298 @@ + +WdgCImg + + + WdgCImg + + + + 0 + 0 + 600 + 249 + + + + CImg Configuration + + + + unnamed + + + + textLabel1_2 + + + + 1 + + + + Warning: this filter may take a long time. + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 51 + 20 + + + + + + grpPrecision + + + &Mathematical Precision + + + + unnamed + + + + textLabel6 + + + Angular step: + + + + + numAngularStep + + + 45 + + + 5 + + + 90 + + + + + numIntegralStep + + + 0.8 + + + 0.1 + + + 10 + + + + + numGaussian + + + 3 + + + 0.1 + + + 10 + + + + + chkNormalize + + + &Normalize picture + + + false + + + + + chkLinearInterpolation + + + &Use linear interpolation + + + true + + + + + textLabel7 + + + Integral step: + + + + + textLabel8 + + + Gaussian: + + + + + + + grpSmooth + + + &Smoothing + + + + unnamed + + + + numDetail + + + 0.1 + + + 100 + + + + + numGradient + + + 0.9 + + + 100 + + + + + numTimeStep + + + 20 + + + 500 + + + + + numBlur + + + 1.4 + + + 10 + + + + + textLabel5 + + + Blurring iterations: + + + + + textLabel4 + + + Blur: + + + + + textLabel3 + + + Time step: + + + + + textLabel2 + + + Gradient factor: + + + + + textLabel1 + + + Detail factor: + + + + + numBlurIterations + + + 1 + + + 1 + + + 16 + + + + + + + + + + numDetail + numGradient + numTimeStep + numBlur + numAngularStep + numIntegralStep + numGaussian + chkLinearInterpolation + chkNormalize + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/colorify/Colorify.cpp b/chalk/plugins/filters/colorify/Colorify.cpp new file mode 100644 index 00000000..0b5010cf --- /dev/null +++ b/chalk/plugins/filters/colorify/Colorify.cpp @@ -0,0 +1,122 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "Colorify.h" + +#include +#include + +#include + +#include "WdgColorifyBase.h" +#include "KisWdgColorify.h" + +typedef KGenericFactory ChalkColorifyFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcolorify, ChalkColorifyFactory( "chalk" ) ) + +ChalkColorify::ChalkColorify(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkColorifyFactory::instance()); + + + kdDebug(41006) << "Colorify Filter plugin. Class: " + << className() + << ", Parent: " + << tqparent -> className() + << "\n"; + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisColorify()); + } +} + +ChalkColorify::~ChalkColorify() +{ +} + + + +KisColorify::KisColorify() : KisFilter(id(), "colors", i18n("&Colorify...")) +{ +} + +KisFilterConfigWidget * KisColorify::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + return new KisWdgColorify(this, tqparent, "configuration of colorify"); +} + +KisFilterConfiguration* KisColorify::configuration(TQWidget* w) +{ + KisWdgColorify * wCTA = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration("colorify", 1); + if(wCTA) + { + config->setProperty("color", wCTA->widget()->colorTarget->color() ); + } + return config; +} + +void KisColorify::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + if(config == 0) config = new KisFilterConfiguration("colorify", 1); + + TQVariant value; + TQColor cTA = (config->getProperty("color", value)) ? value.toColor() : TQColor(200,175,125); + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + KisColorSpace * cs = src->colorSpace(); + TQ_UINT8* colorpixel = new TQ_UINT8[ cs->pixelSize() ]; + + cs->fromTQColor(cTA, colorpixel); + + TQ_UINT16 labcTA[4]; + TQ_UINT16 lab[4]; + + cs->toLabA16(colorpixel, (TQ_UINT8*)labcTA, 1); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + //TQ_INT32 pixelsize = cs->pixelSize(); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + cs->toLabA16(srcIt.oldRawData(), (TQ_UINT8*)lab, 1); + labcTA[0] = lab[0]; + cs->fromLabA16((TQ_UINT8*)labcTA, dstIt.rawData(), 1); + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + delete[] colorpixel; + setProgressDone(); // Must be called even if you don't really support progression +} + + diff --git a/chalk/plugins/filters/colorify/Colorify.h b/chalk/plugins/filters/colorify/Colorify.h new file mode 100644 index 00000000..36378505 --- /dev/null +++ b/chalk/plugins/filters/colorify/Colorify.h @@ -0,0 +1,56 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLORIFY_H +#define COLORIFY_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +#include "kis_filter.h" + +class ChalkColorify : public KParts::Plugin +{ +public: + ChalkColorify(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkColorify(); +}; + + +class KisColorify : public KisFilter { + public: + KisColorify(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("colorify", i18n("Colorify...")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual ColorSpaceIndependence colorSpaceIndendendence() { return TO_LAB16; }; + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/colorify/KisWdgColorify.cpp b/chalk/plugins/filters/colorify/KisWdgColorify.cpp new file mode 100644 index 00000000..3d1e2413 --- /dev/null +++ b/chalk/plugins/filters/colorify/KisWdgColorify.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "KisWdgColorify.h" + +#include +#include +#include + +#include + +#include + +#include "WdgColorifyBase.h" + +KisWdgColorify::KisWdgColorify( KisFilter* nfilter, TQWidget * tqparent, const char * name) : KisFilterConfigWidget ( tqparent, name ) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgColorifyBase(this); + widgetLayout -> addWidget(m_widget,0,0); + connect( m_widget->colorTarget, TQT_SIGNAL( changed(const TQColor&)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgColorify::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if(config->getProperty("color", value)) + { + m_widget->colorTarget->setColor( value.toColor() ); + } +} + +#include "KisWdgColorify.moc" diff --git a/chalk/plugins/filters/colorify/KisWdgColorify.h b/chalk/plugins/filters/colorify/KisWdgColorify.h new file mode 100644 index 00000000..662a24cd --- /dev/null +++ b/chalk/plugins/filters/colorify/KisWdgColorify.h @@ -0,0 +1,45 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_WDG_COLORIFY_H_ +#define _KIS_WDG_COLORIFY_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class KisFilter; +class WdgColorifyBase; + +class KisWdgColorify : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgColorify( KisFilter* nfilter, TQWidget * tqparent, const char * name); + inline WdgColorifyBase* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgColorifyBase* m_widget; +}; + +#endif diff --git a/chalk/plugins/filters/colorify/Makefile.am b/chalk/plugins/filters/colorify/Makefile.am new file mode 100644 index 00000000..d3e348e9 --- /dev/null +++ b/chalk/plugins/filters/colorify/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkcolorifyfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + + +kde_module_LTLIBRARIES = chalkcolorify.la + + +chalkcolorify_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkcolorify_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO +chalkcolorify_la_SOURCES = Colorify.cpp KisWdgColorify.cpp\ + WdgColorifyBase.ui diff --git a/chalk/plugins/filters/colorify/WdgColorifyBase.ui b/chalk/plugins/filters/colorify/WdgColorifyBase.ui new file mode 100644 index 00000000..a5fcebf9 --- /dev/null +++ b/chalk/plugins/filters/colorify/WdgColorifyBase.ui @@ -0,0 +1,97 @@ + +WdgColorifyBase + + + WdgColorifyBase + + + + 0 + 0 + 133 + 63 + + + + + unnamed + + + 0 + + + + spacer2 + + + Horizontal + + + Expanding + + + + 61 + 20 + + + + + + tqlayout1 + + + + unnamed + + + + textLabel1 + + + Color: + + + + + colorTarget + + + + + + + 255 + 255 + 255 + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + + + + + kcolorbutton.h + + diff --git a/chalk/plugins/filters/colorify/chalkcolorifyfilter.desktop b/chalk/plugins/filters/colorify/chalkcolorifyfilter.desktop new file mode 100644 index 00000000..78aa2b93 --- /dev/null +++ b/chalk/plugins/filters/colorify/chalkcolorifyfilter.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Icon= +Name=Color Filters (Extension) +Name[bg]=Цветови филтри (разширения) +Name[ca]=Filtres de color (Extensió) +Name[da]=Farvefiltre (Udvidelse) +Name[de]=Farbfilter (Erweiterung) +Name[el]=Χρωματικά φίλτρα (Επέκταση) +Name[eo]=Kolorfiltriloj (etendaĵo) +Name[es]=Filtros de color (Extensión) +Name[et]=Värvifiltrid (laiendus) +Name[fa]=پالایه‌های رنگ )پسوند( +Name[fr]=Filtres de couleurs (extension) +Name[fy]=Kleurfilters (útwreiding) +Name[ga]=Scagairí Datha (Eisínteacht) +Name[gl]=Filtros de Cores (Extensións) +Name[hu]=Színszűrők (kiterjesztés) +Name[it]=Filtri dei colori (estensione) +Name[ja]=カラーフィルタ (拡張) +Name[km]=តម្រង​ពណ៌​ (ផ្នែក​បន្ថែម) +Name[nb]=Fargefiltre (utvidelse) +Name[nds]=Klörenfilters (Verwiedern) +Name[ne]=रङ फिल्टरहरू (अपवाद) +Name[nl]=Kleurfilters (extensie) +Name[pl]=Filtry kolorów (rozszerzenie) +Name[pt]=Filtros de Cores (Extensão) +Name[pt_BR]=Filtros de Cores (Extensão) +Name[ru]=Цвет (расширение) +Name[se]=Ivdnesillit (viiddádus) +Name[sk]=Farebné filtre (rozšírenie) +Name[sl]=Barvni filtri (razširitev) +Name[sr]=Филтери боја (проширење) +Name[sr@Latn]=Filteri boja (proširenje) +Name[sv]=Färgfilter (utökning) +Name[uk]=Фільтри кольору (розширення) +Name[uz]=Rang filterlari (kengaytma) +Name[uz@cyrillic]=Ранг филтерлари (кенгайтма) +Name[zh_TW]=色彩過濾器(延伸) +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkcolorify +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/colors/Makefile.am b/chalk/plugins/filters/colors/Makefile.am new file mode 100644 index 00000000..70121166 --- /dev/null +++ b/chalk/plugins/filters/colors/Makefile.am @@ -0,0 +1,21 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkextensioncolorsfilters.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkextensioncolorsfilters_la_SOURCES = colors.cc kis_minmax_filters.cc kis_color_to_alpha.cc wdgcolortoalphabase.ui kis_wdg_color_to_alpha.cc + +kde_module_LTLIBRARIES = chalkextensioncolorsfilters.la +noinst_HEADERS = colors.h + +chalkextensioncolorsfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkextensioncolorsfilters_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO diff --git a/chalk/plugins/filters/colors/chalkextensioncolorsfilters.desktop b/chalk/plugins/filters/colors/chalkextensioncolorsfilters.desktop new file mode 100644 index 00000000..26b3adf4 --- /dev/null +++ b/chalk/plugins/filters/colors/chalkextensioncolorsfilters.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Icon= +Name=Color Filters (Extension) +Name[bg]=Цветови филтри (разширения) +Name[ca]=Filtres de color (Extensió) +Name[da]=Farvefiltre (Udvidelse) +Name[de]=Farbfilter (Erweiterung) +Name[el]=Χρωματικά φίλτρα (Επέκταση) +Name[eo]=Kolorfiltriloj (etendaĵo) +Name[es]=Filtros de color (Extensión) +Name[et]=Värvifiltrid (laiendus) +Name[fa]=پالایه‌های رنگ )پسوند( +Name[fr]=Filtres de couleurs (extension) +Name[fy]=Kleurfilters (útwreiding) +Name[ga]=Scagairí Datha (Eisínteacht) +Name[gl]=Filtros de Cores (Extensións) +Name[hu]=Színszűrők (kiterjesztés) +Name[it]=Filtri dei colori (estensione) +Name[ja]=カラーフィルタ (拡張) +Name[km]=តម្រង​ពណ៌​ (ផ្នែក​បន្ថែម) +Name[nb]=Fargefiltre (utvidelse) +Name[nds]=Klörenfilters (Verwiedern) +Name[ne]=रङ फिल्टरहरू (अपवाद) +Name[nl]=Kleurfilters (extensie) +Name[pl]=Filtry kolorów (rozszerzenie) +Name[pt]=Filtros de Cores (Extensão) +Name[pt_BR]=Filtros de Cores (Extensão) +Name[ru]=Цвет (расширение) +Name[se]=Ivdnesillit (viiddádus) +Name[sk]=Farebné filtre (rozšírenie) +Name[sl]=Barvni filtri (razširitev) +Name[sr]=Филтери боја (проширење) +Name[sr@Latn]=Filteri boja (proširenje) +Name[sv]=Färgfilter (utökning) +Name[uk]=Фільтри кольору (розширення) +Name[uz]=Rang filterlari (kengaytma) +Name[uz@cyrillic]=Ранг филтерлари (кенгайтма) +Name[zh_TW]=色彩過濾器(延伸) +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkextensioncolorsfilters +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/colors/colors.cc b/chalk/plugins/filters/colors/colors.cc new file mode 100644 index 00000000..d9a42134 --- /dev/null +++ b/chalk/plugins/filters/colors/colors.cc @@ -0,0 +1,53 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "colors.h" + +#include + +#include "kis_minmax_filters.h" +#include "kis_color_to_alpha.h" + +typedef KGenericFactory ChalkExtensionsColorsFactory; +K_EXPORT_COMPONENT_FACTORY( chalkextensioncolorsfilters, ChalkExtensionsColorsFactory( "chalk" ) ) + +ChalkExtensionsColors::ChalkExtensionsColors(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkExtensionsColorsFactory::instance()); + + + kdDebug(41006) << "Extensions Colors Filter plugin. Class: " + << className() + << ", Parent: " + << tqparent -> className() + << "\n"; + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterMax()); + manager->add(new KisFilterMin()); + manager->add(new KisFilterColorToAlpha()); + } +} + +ChalkExtensionsColors::~ChalkExtensionsColors() +{ +} diff --git a/chalk/plugins/filters/colors/colors.h b/chalk/plugins/filters/colors/colors.h new file mode 100644 index 00000000..d93ae1cc --- /dev/null +++ b/chalk/plugins/filters/colors/colors.h @@ -0,0 +1,37 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLORS_H +#define COLORS_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class ChalkExtensionsColors : public KParts::Plugin +{ +public: + ChalkExtensionsColors(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkExtensionsColors(); +}; + +#endif diff --git a/chalk/plugins/filters/colors/kis_color_to_alpha.cc b/chalk/plugins/filters/colors/kis_color_to_alpha.cc new file mode 100644 index 00000000..28814910 --- /dev/null +++ b/chalk/plugins/filters/colors/kis_color_to_alpha.cc @@ -0,0 +1,95 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_color_to_alpha.h" + +#include +#include + +#include + +#include + +#include "wdgcolortoalphabase.h" +#include "kis_wdg_color_to_alpha.h" + +KisFilterColorToAlpha::KisFilterColorToAlpha() : KisFilter(id(), "colors", i18n("&Color to Alpha...")) +{ +} + +KisFilterConfigWidget * KisFilterColorToAlpha::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + return new KisWdgColorToAlpha(this, tqparent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisFilterColorToAlpha::configuration(TQWidget* w) +{ + KisWdgColorToAlpha * wCTA = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration("colortoalpha", 1); + if(wCTA) + { + config->setProperty("targetcolor", wCTA->widget()->colorTarget->color() ); + config->setProperty("threshold", wCTA->widget()->intThreshold->value()); + } + return config; +} + +void KisFilterColorToAlpha::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + if(config == 0) config = new KisFilterConfiguration("colortoalpha", 1); + + TQVariant value; + TQColor cTA = (config->getProperty("targetcolor", value)) ? value.toColor() : TQColor(255,255,255); + int threshold = (config->getProperty("threshold", value)) ? value.toInt() : 0; + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 pixelsize = cs->pixelSize(); + + TQ_UINT8* color = new TQ_UINT8[pixelsize]; + cs->fromTQColor(cTA, color); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + TQ_UINT8 d = cs->difference(color, srcIt.oldRawData()); + if( d >= threshold ) + { + cs->setAlpha(dstIt.rawData(), 255, 1); + } else { + cs->setAlpha(dstIt.rawData(), (255 * d ) / threshold, 1 ); + } + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + delete[] color; + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/colors/kis_color_to_alpha.h b/chalk/plugins/filters/colors/kis_color_to_alpha.h new file mode 100644 index 00000000..9161b38e --- /dev/null +++ b/chalk/plugins/filters/colors/kis_color_to_alpha.h @@ -0,0 +1,47 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_COLOR_TO_ALPHA_H_ +#define KIS_COLOR_TO_ALPHA_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include "kis_filter.h" + +class KisFilterColorToAlpha : public KisFilter { + public: + KisFilterColorToAlpha(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("colortoalpha", i18n("Color to Alpha")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + + +#endif diff --git a/chalk/plugins/filters/colors/kis_minmax_filters.cc b/chalk/plugins/filters/colors/kis_minmax_filters.cc new file mode 100644 index 00000000..eac48ad3 --- /dev/null +++ b/chalk/plugins/filters/colors/kis_minmax_filters.cc @@ -0,0 +1,162 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_minmax_filters.h" + +#include + +typedef void (*funcMaxMin)(const TQ_UINT8* , TQ_UINT8* , uint ); + +template +void maximize(const TQ_UINT8* s, TQ_UINT8* d, uint nbpixels) +{ + const _TYPE* sT = (_TYPE*)(s); + _TYPE* dT = (_TYPE*)(d); + _TYPE vmax = *sT; + for(uint i = 1; i < nbpixels; i ++) + { + if(sT[i] > vmax) + { + vmax = sT[i]; + } + } + for(uint i = 0; i < nbpixels; i ++) + { + if(dT[i] != vmax) + { + dT[i] = 0; + } + } +} + +template + void minimize(const TQ_UINT8* s, TQ_UINT8* d, uint nbpixels) +{ + const _TYPE* sT = (_TYPE*)(s); + _TYPE* dT = (_TYPE*)(d); + _TYPE vmin = *sT; + for(uint i = 1; i < nbpixels; i ++) + { + if(sT[i] < vmin) + { + vmin = sT[i]; + } + } + for(uint i = 0; i < nbpixels; i ++) + { + if(dT[i] != vmin) + { + dT[i] = 0; + } + } +} + +KisFilterMax::KisFilterMax() : KisFilter(id(), "colors", i18n("M&aximize Channel")) +{ +} + +void KisFilterMax::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 nC = cs->nColorChannels(); + + funcMaxMin F; + KisChannelInfo::enumChannelValueType cT = cs->channels()[0]->channelValueType(); + if( cT == KisChannelInfo::UINT8 || cT == KisChannelInfo::INT8 ) + { + F = & maximize; + } else if( cT == KisChannelInfo::UINT16 || cT == KisChannelInfo::INT16 ) + { + F = & maximize; + } else if( cT == KisChannelInfo::FLOAT32 ) + { + F = & maximize; + } else { + return; + } + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + F( srcIt.oldRawData(), dstIt.rawData(), nC); + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + setProgressDone(); // Must be called even if you don't really support progression +} + +KisFilterMin::KisFilterMin() : KisFilter(id(), "colors", i18n("M&inimize Channel")) +{ +} + +void KisFilterMin::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 nC = cs->nColorChannels(); + + funcMaxMin F; + KisChannelInfo::enumChannelValueType cT = cs->channels()[0]->channelValueType(); + if( cT == KisChannelInfo::UINT8 || cT == KisChannelInfo::INT8 ) + { + F = & minimize; + } else if( cT == KisChannelInfo::UINT16 || cT == KisChannelInfo::INT16 ) + { + F = & minimize; + } else if( cT == KisChannelInfo::FLOAT32 ) + { + F = & minimize; + } else { + return; + } + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + F( srcIt.oldRawData(), dstIt.rawData(), nC); + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + setProgressDone(); // Must be called even if you don't really support progression +} + diff --git a/chalk/plugins/filters/colors/kis_minmax_filters.h b/chalk/plugins/filters/colors/kis_minmax_filters.h new file mode 100644 index 00000000..db95dc12 --- /dev/null +++ b/chalk/plugins/filters/colors/kis_minmax_filters.h @@ -0,0 +1,56 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_MINMAX_FILTERS_H +#define KIS_MINMAX_FILTERS_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include "kis_filter.h" + +class KisFilterMax : public KisFilter +{ + public: + KisFilterMax(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("maximize", i18n("Maximize Channel")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; +}; + +class KisFilterMin : public KisFilter +{ + public: + KisFilterMin(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("minimize", i18n("Minimize Channel")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; +}; + +#endif diff --git a/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.cc b/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.cc new file mode 100644 index 00000000..e70fbc85 --- /dev/null +++ b/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.cc @@ -0,0 +1,55 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_color_to_alpha.h" + +#include +#include +#include + +#include + +#include + +#include "wdgcolortoalphabase.h" + +KisWdgColorToAlpha::KisWdgColorToAlpha( KisFilter* nfilter, TQWidget * tqparent, const char * name) : KisFilterConfigWidget ( tqparent, name ) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgColorToAlphaBase(this); + widgetLayout -> addWidget(m_widget,0,0); + connect( m_widget->colorTarget, TQT_SIGNAL( changed(const TQColor&)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_widget->intThreshold, TQT_SIGNAL( valueChanged ( int value) ), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgColorToAlpha::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if(config->getProperty("targetcolor", value)) + { + m_widget->colorTarget->setColor( value.toColor() ); + } + if(config->getProperty("threshold", value)) + { + m_widget->intThreshold->setValue( value.toInt() ); + } +} + +#include "kis_wdg_color_to_alpha.moc" diff --git a/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.h b/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.h new file mode 100644 index 00000000..d2b5c9b9 --- /dev/null +++ b/chalk/plugins/filters/colors/kis_wdg_color_to_alpha.h @@ -0,0 +1,45 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_WDG_COLOR_TO_ALPHA_H_ +#define _KIS_WDG_COLOR_TO_ALPHA_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class KisFilter; +class WdgColorToAlphaBase; + +class KisWdgColorToAlpha : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgColorToAlpha( KisFilter* nfilter, TQWidget * tqparent, const char * name); + inline WdgColorToAlphaBase* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgColorToAlphaBase* m_widget; +}; + +#endif diff --git a/chalk/plugins/filters/colors/wdgcolortoalphabase.ui b/chalk/plugins/filters/colors/wdgcolortoalphabase.ui new file mode 100644 index 00000000..f824a9ab --- /dev/null +++ b/chalk/plugins/filters/colors/wdgcolortoalphabase.ui @@ -0,0 +1,113 @@ + +WdgColorToAlphaBase + + + WdgColorToAlphaBase + + + + 0 + 0 + 133 + 63 + + + + + unnamed + + + 0 + + + + spacer2 + + + Horizontal + + + Expanding + + + + 61 + 20 + + + + + + tqlayout1 + + + + unnamed + + + + textLabel1 + + + Color: + + + + + colorTarget + + + + + + + 255 + 255 + 255 + + + + + + + + intThreshold + + + 255 + + + + + textLabel1_2 + + + Threshold: + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + + + + + kcolorbutton.h + + diff --git a/chalk/plugins/filters/colorsfilters/Makefile.am b/chalk/plugins/filters/colorsfilters/Makefile.am new file mode 100644 index 00000000..843402a3 --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/Makefile.am @@ -0,0 +1,26 @@ +kde_services_DATA = chalkcolorsfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkcolorsfilters_la_SOURCES = colorsfilters.cc \ + kis_perchannel_filter.cc \ + wdg_perchannel.ui \ + wdg_brightness_contrast.ui \ + kis_brightness_contrast_filter.cc + +noinst_HEADERS = colorsfilters.h \ + kis_perchannel_filter.h \ + kis_brightness_contrast_filter.h + +chalkcolorsfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkcolorsfilters_la_LIBADD = ../../../libchalkcommon.la + +kde_module_LTLIBRARIES = chalkcolorsfilters.la + +chalkcolorsfilters_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/colorsfilters/chalkcolorsfilter.desktop b/chalk/plugins/filters/colorsfilters/chalkcolorsfilter.desktop new file mode 100644 index 00000000..2c2747f2 --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/chalkcolorsfilter.desktop @@ -0,0 +1,94 @@ +[Desktop Entry] +Name=Color Filters +Name[bg]=Цветови филтри +Name[br]=Siloù liv +Name[ca]=Filtres de color +Name[cy]=Hidlau lliw +Name[da]=Farvefilter +Name[de]=Farbfilter +Name[el]=Χρωματικά φίλτρα +Name[en_GB]=Colour Filters +Name[eo]=Kolorfiltriloj +Name[es]=Filtros de color +Name[et]=Värvifiltrid +Name[fa]=پالایه‌های رنگ +Name[fi]=Värisuotimet +Name[fr]=Filtres de couleurs +Name[fy]=Kleurfilters +Name[ga]=Scagairí Datha +Name[gl]=Filtros de Cores +Name[he]=מסנני צבעים +Name[hu]=Színszűrők +Name[is]=Litasíur +Name[it]=Filtri dei colori +Name[ja]=カラーフィルタ +Name[km]=តម្រង​ពណ៌​ +Name[lt]=Spalvų filtrai +Name[lv]=Krāsu filtri +Name[nb]=Fargefiltre +Name[nds]=Klörenfilters +Name[ne]=रङ फिल्टरहरू +Name[nl]=Kleurfilters +Name[pl]=Filtry kolorów +Name[pt]=Filtros de Cores +Name[pt_BR]=Filtros de Cores +Name[ru]=Цвет +Name[se]=Ivdnesillit +Name[sk]=Farebné filtre +Name[sl]=Barvni filtri +Name[sr]=Филтери боја +Name[sr@Latn]=Filteri boja +Name[sv]=Färgfilter +Name[uk]=Фільтри кольору +Name[uz]=Rang filterlari +Name[uz@cyrillic]=Ранг филтерлари +Name[zh_TW]=色彩過濾器 +Comment=Color filters +Comment[bg]=Цветови филтри +Comment[br]=Siloù liv +Comment[ca]=Filtres de color +Comment[cy]=Hidlau lliw +Comment[da]=Farvefilter +Comment[de]=Farbfilter +Comment[el]=Χρωματικά φίλτρα +Comment[en_GB]=Colour filters +Comment[eo]=Kolorfiltriloj +Comment[es]=Filtros de color +Comment[et]=Värvifiltrid +Comment[fa]=پالایه‌های رنگ +Comment[fi]=Värisuotimet +Comment[fr]=Filtres de couleurs +Comment[fy]=Kleurfilters +Comment[ga]=Scagairí datha +Comment[gl]=Filtros de cores +Comment[he]=מסנני צבעים +Comment[hu]=Színszűrők +Comment[is]=Litasíur +Comment[it]=Filtri dei colori +Comment[ja]=カラーフィルタ +Comment[km]=តម្រង​ពណ៌​ +Comment[lt]=Spalvų filtrai +Comment[lv]=Krāsu filtri +Comment[nb]=Fargefiltre +Comment[nds]=Klörenfilters +Comment[ne]=रङ फिल्टरहरू +Comment[nl]=Kleurfilters +Comment[pl]=Filtry kolorów +Comment[pt]=Filtros de cores +Comment[pt_BR]=Filtros de cores +Comment[ru]=Цвет +Comment[se]=Ivdnesillit +Comment[sk]=Farebné filtre +Comment[sl]=Bravni filtri +Comment[sr]=Филтери боја +Comment[sr@Latn]=Filteri boja +Comment[sv]=Färgfilter +Comment[uk]=Фільтри кольору +Comment[uz]=Rang filterlari +Comment[uz@cyrillic]=Ранг филтерлари +Comment[zh_CN]=颜色滤镜 +Comment[zh_TW]=色彩過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkcolorsfilters +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/colorsfilters/colorsfilters.cc b/chalk/plugins/filters/colorsfilters/colorsfilters.cc new file mode 100644 index 00000000..cdc7dede --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/colorsfilters.cc @@ -0,0 +1,315 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_histogram.h" +#include "kis_basic_histogram_producers.h" +#include "colorsfilters.h" +#include "kis_brightness_contrast_filter.h" +#include "kis_perchannel_filter.h" + +typedef KGenericFactory ColorsFiltersFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcolorsfilters, ColorsFiltersFactory( "chalk" ) ) + +ColorsFilters::ColorsFilters(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ColorsFiltersFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisBrightnessContrastFilter()); + manager->add(new KisAutoContrast()); + manager->add(new KisPerChannelFilter()); + manager->add(new KisDesaturateFilter()); + } +} + +ColorsFilters::~ColorsFilters() +{ +} + + +//================================================================== + + +KisAutoContrast::KisAutoContrast() : KisFilter(id(), "adjust", i18n("&Auto Contrast")) +{ +} + +bool KisAutoContrast::workWith(KisColorSpace* cs) +{ + return (cs->getProfile() != 0); +} + +void KisAutoContrast::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* , const TQRect& rect) +{ + // initialize + KisHistogramProducerSP producer = new KisGenericLabHistogramProducer(); + KisHistogram histogram(src, producer, LINEAR); + int minvalue = int(255*histogram.calculations().getMin() + 0.5); + int maxvalue = int(255*histogram.calculations().getMax() + 0.5); + + if(maxvalue>255) + maxvalue= 255; + + histogram.setChannel(0); + int twoPercent = int(0.005*histogram.calculations().getCount()); + int pixCount = 0; + int binnum = 0; + + while(binnumnumberOfBins()) + { + pixCount += histogram.getValue(binnum); + if(pixCount > twoPercent) + { + minvalue = binnum; + break; + } + binnum++; + } + pixCount = 0; + binnum = histogram.producer()->numberOfBins()-1; + while(binnum>0) + { + pixCount += histogram.getValue(binnum); + if(pixCount > twoPercent) + { + maxvalue = binnum; + break; + } + binnum--; + } + // build the transferfunction + int diff = maxvalue - minvalue; + + KisBrightnessContrastFilterConfiguration * cfg = new KisBrightnessContrastFilterConfiguration(); + + for(int i=0; i <255; i++) + cfg->transfer[i] = 0xFFFF; + + if (diff != 0) + { + for(int i=0; i transfer[i] = 0x0; + for(int i=minvalue; i 0xFFFF) + val=0xFFFF; + if(val <0) + val = 0; + + cfg->transfer[i] = val; + } + for(int i=maxvalue; i <256; i++) + cfg->transfer[i] = 0xFFFF; + } + + KisSelectionSP dstSel = 0; + if (dst != src) { + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + if (src->hasSelection()) { + dstSel = dst->selection(); + dst->setSelection(src->selection()); + } + } + + // apply + KisColorAdjustment *adj = src->colorSpace()->createBrightnessContrastAdjustment(cfg->transfer); + + KisRectIteratorPixel iter = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + setProgressTotalSteps(rect.width() * rect.height()); + TQ_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + TQ_UINT32 npix=0, maxpix = iter.nConseqPixels(); + TQ_UINT8 selectedness = iter.selectedness(); + // The idea here is to handle stretches of completely selected and completely unselected pixels. + // Partially selected pixels are handled one pixel at a time. + switch(selectedness) + { + case MIN_SELECTED: + while(iter.selectedness()==MIN_SELECTED && maxpix) + { + --maxpix; + ++iter; + ++npix; + } + pixelsProcessed += npix; + break; + + case MAX_SELECTED: + { + TQ_UINT8 *firstPixel = iter.rawData(); + while(iter.selectedness()==MAX_SELECTED && maxpix) + { + --maxpix; + if (maxpix != 0) + ++iter; + ++npix; + } + // adjust + src->colorSpace()->applyAdjustment(firstPixel, firstPixel, adj, npix); + pixelsProcessed += npix; + ++iter; + break; + } + + default: + // adjust, but since it's partially selected we also only partially adjust + src->colorSpace()->applyAdjustment(iter.oldRawData(), iter.rawData(), adj, 1); + const TQ_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + TQ_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + // Restore selection + if (src != dst && src->hasSelection()) { + dst->setSelection(dstSel); + } + delete adj; + setProgressDone(); +} + + +//================================================================== + +KisDesaturateFilter::KisDesaturateFilter() + : KisFilter(id(), "adjust", i18n("&Desaturate")) +{ + m_lastCS = 0; + m_adj = 0; + +} + +KisDesaturateFilter::~KisDesaturateFilter() +{ + delete m_adj; +} + +bool KisDesaturateFilter::workWith(KisColorSpace* cs) +{ + return (cs->getProfile() != 0); +} + +void KisDesaturateFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + if (dst != src) { + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + } + + if (m_adj == 0 || (m_lastCS && m_lastCS != src->colorSpace())) { + m_adj = src->colorSpace()->createDesaturateAdjustment(); + m_lastCS = src->colorSpace(); + } + + KisRectIteratorPixel iter = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + setProgressTotalSteps(rect.width() * rect.height()); + TQ_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + TQ_UINT32 npix=0, maxpix = iter.nConseqPixels(); + TQ_UINT8 selectedness = iter.selectedness(); + // The idea here is to handle stretches of completely selected and completely unselected pixels. + // Partially selected pixels are handled one pixel at a time. + switch(selectedness) + { + case MIN_SELECTED: + while(iter.selectedness()==MIN_SELECTED && maxpix) + { + --maxpix; + ++iter; + ++npix; + } + pixelsProcessed += npix; + break; + + case MAX_SELECTED: + { + TQ_UINT8 *firstPixel = iter.rawData(); + while(iter.selectedness()==MAX_SELECTED && maxpix) + { + --maxpix; + if (maxpix != 0) + ++iter; + ++npix; + } + // adjust + src->colorSpace()->applyAdjustment(firstPixel, firstPixel, m_adj, npix); + pixelsProcessed += npix; + ++iter; + break; + } + + default: + // adjust, but since it's partially selected we also only partially adjust + src->colorSpace()->applyAdjustment(iter.oldRawData(), iter.rawData(), m_adj, 1); + const TQ_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + TQ_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + setProgressDone(); +} diff --git a/chalk/plugins/filters/colorsfilters/colorsfilters.h b/chalk/plugins/filters/colorsfilters/colorsfilters.h new file mode 100644 index 00000000..ebf2dfeb --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/colorsfilters.h @@ -0,0 +1,73 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef BRIGHTNESSCONTRAST_H +#define BRIGHTNESSCONTRAST_H + +#include +#include "kis_perchannel_filter.h" + +class KisColorSpace; +class KisColorAdjustment; + +class ColorsFilters : public KParts::Plugin +{ + public: + ColorsFilters(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ColorsFilters(); +}; + +class KisAutoContrast : public KisFilter { +public: + KisAutoContrast(); +public: + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("autocontrast", i18n("Auto Contrast")); }; + virtual bool supportsPreview() { return true; } + virtual bool supportsPainting() { return false; } + virtual bool supportsThreading() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; + virtual bool workWith(KisColorSpace* cs); + +}; + + +class KisDesaturateFilter : public KisFilter { + public: + KisDesaturateFilter(); + ~KisDesaturateFilter(); + public: + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("desaturate", i18n("Desaturate")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; + virtual bool workWith(KisColorSpace* cs); + + private: + + KisColorSpace * m_lastCS; + KisColorAdjustment * m_adj; +}; + +#endif diff --git a/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc b/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc new file mode 100644 index 00000000..c42223fb --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.cc @@ -0,0 +1,347 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * Copyright (c) 2005 Casper Boemann +* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_filter_config_widget.h" +#include "kis_brightness_contrast_filter.h" +#include "wdg_brightness_contrast.h" +#include "kis_colorspace.h" +#include "kis_paint_device.h" +#include "kis_iterators_pixel.h" +#include "kis_iterator.h" +#include "kcurve.h" +#include "kis_histogram.h" +#include "kis_basic_histogram_producers.h" +#include "kis_painter.h" + +KisBrightnessContrastFilterConfiguration::KisBrightnessContrastFilterConfiguration() + : KisFilterConfiguration( "brightnesscontrast", 1 ) +{ + for (TQ_UINT32 i = 0; i < 256; ++i) { + transfer[i] = i * 257; + } + curve.setAutoDelete(true); + m_adjustment = 0; +} + +KisBrightnessContrastFilterConfiguration::~KisBrightnessContrastFilterConfiguration() +{ + delete m_adjustment; +} + +void KisBrightnessContrastFilterConfiguration::fromXML( const TQString& s ) +{ + TQDomDocument doc; + doc.setContent( s ); + TQDomElement e = doc.documentElement(); + TQDomNode n = e.firstChild(); + + while (!n.isNull()) { + e = n.toElement(); + if (!e.isNull()) { + if (e.tagName() == "transfer") { + TQStringList data = TQStringList::split( ",", e.text() ); + TQStringList::Iterator start = data.begin(); + TQStringList::Iterator end = data.end(); + int i = 0; + for ( TQStringList::Iterator it = start; it != end && i < 256; ++it ) { + TQString s = *it; + transfer[i] = s.toUShort(); + i++; + } + } + else if (e.tagName() == "curve") { + TQStringList data = TQStringList::split( ";", e.text() ); + TQStringList::Iterator pairStart = data.begin(); + TQStringList::Iterator pairEnd = data.end(); + curve.clear(); // XXX TQPtrList, sure I won't leak stuff here? + for (TQStringList::Iterator it = pairStart; it != pairEnd; ++it) { + TQString pair = * it; + if (pair.tqfind(",") > -1) { + TQPair *p = new TQPair; + p->first = pair.section(",", 0, 0).toDouble(); + p->second = pair.section(",", 1, 1).toDouble(); + curve.append(p); + } + } + } + } + n = n.nextSibling(); + } + // If the adjustment was cached, it now has changed - tqinvalidate it + delete m_adjustment; + m_adjustment = 0; +} + +TQString KisBrightnessContrastFilterConfiguration::toString() +{ + TQDomDocument doc = TQDomDocument("filterconfig"); + TQDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + doc.appendChild( root ); + + TQDomElement e = doc.createElement( "transfer" ); + TQString sTransfer; + for ( uint i = 0; i < 255 ; ++i ) { + sTransfer += TQString::number( transfer[i] ); + sTransfer += ","; + } + TQDomText text = doc.createCDATASection(sTransfer); + e.appendChild(text); + root.appendChild(e); + + e = doc.createElement("curve"); + TQString sCurve; + TQPair * pair; + for ( pair = curve.first(); pair; pair = curve.next() ) { + sCurve += TQString::number(pair->first); + sCurve += ","; + sCurve += TQString::number(pair->second); + sCurve += ";"; + } + text = doc.createCDATASection(sCurve); + e.appendChild(text); + root.appendChild(e); + + return doc.toString(); +} + +KisBrightnessContrastFilter::KisBrightnessContrastFilter() + : KisFilter( id(), "adjust", i18n("&Brightness/Contrast...")) +{ + +} + +KisFilterConfigWidget * KisBrightnessContrastFilter::createConfigurationWidget(TQWidget *tqparent, KisPaintDeviceSP dev) +{ + return new KisBrightnessContrastConfigWidget(tqparent, dev); +} + +KisFilterConfiguration* KisBrightnessContrastFilter::configuration(TQWidget *nwidget) +{ + KisBrightnessContrastConfigWidget* widget = (KisBrightnessContrastConfigWidget*)nwidget; + + if ( widget == 0 ) + { + return new KisBrightnessContrastFilterConfiguration(); + } else { + return widget->config(); + } +} + +std::list KisBrightnessContrastFilter::listOfExamplesConfiguration(KisPaintDeviceSP /*dev*/) +{ + //XXX should really come up with a list of configurations + std::list list; + list.insert(list.begin(), new KisBrightnessContrastFilterConfiguration( )); + return list; +} + +bool KisBrightnessContrastFilter::workWith(KisColorSpace* cs) +{ + return (cs->getProfile() != 0); +} + + +void KisBrightnessContrastFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + + if (!config) { + kdWarning() << "No configuration object for brightness/contrast filter\n"; + return; + } + + KisBrightnessContrastFilterConfiguration* configBC = (KisBrightnessContrastFilterConfiguration*) config; + Q_ASSERT(config); + + if (src!=dst) { + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + } + + if (configBC->m_adjustment == 0) { + configBC->m_adjustment = src->colorSpace()->createBrightnessContrastAdjustment(configBC->transfer); + } + + KisRectIteratorPixel iter = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + setProgressTotalSteps(rect.width() * rect.height()); + TQ_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + TQ_UINT32 npix=0, maxpix = iter.nConseqPixels(); + TQ_UINT8 selectedness = iter.selectedness(); + // The idea here is to handle stretches of completely selected and completely unselected pixels. + // Partially selected pixels are handled one pixel at a time. + switch(selectedness) + { + case MIN_SELECTED: + while(iter.selectedness()==MIN_SELECTED && maxpix) + { + --maxpix; + ++iter; + ++npix; + } + pixelsProcessed += npix; + break; + + case MAX_SELECTED: + { + TQ_UINT8 *firstPixel = iter.rawData(); + while(iter.selectedness()==MAX_SELECTED && maxpix) + { + --maxpix; + if (maxpix != 0) + ++iter; + ++npix; + } + // adjust + src->colorSpace()->applyAdjustment(firstPixel, firstPixel, configBC->m_adjustment, npix); + pixelsProcessed += npix; + ++iter; + break; + } + + default: + // adjust, but since it's partially selected we also only partially adjust + src->colorSpace()->applyAdjustment(iter.oldRawData(), iter.rawData(), configBC->m_adjustment, 1); + const TQ_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + TQ_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + + setProgressDone(); +} + +KisBrightnessContrastConfigWidget::KisBrightnessContrastConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(tqparent, name, f) +{ + int i; + int height; + m_page = new WdgBrightnessContrast(this); + TQHBoxLayout * l = new TQHBoxLayout(this); + Q_CHECK_PTR(l); + + //Hide these buttons and labels as they are not implemented in 1.5 + m_page->pb_more_contrast->hide(); + m_page->pb_less_contrast->hide(); + m_page->pb_more_brightness->hide(); + m_page->pb_less_brightness->hide(); + m_page->textLabelBrightness->hide(); + m_page->textLabelContrast->hide(); + + l->addWidget(m_page, 0, TQt::AlignTop); + height = 256; + connect( m_page->kCurve, TQT_SIGNAL(modified()), TQT_SIGNAL(sigPleaseUpdatePreview())); + + // Create the horizontal gradient label + TQPixmap hgradientpix(256, 1); + TQPainter hgp(&hgradientpix); + hgp.setPen(TQPen::TQPen(TQColor(0,0,0),1, TQt::SolidLine)); + for( i=0; i<256; ++i ) + { + hgp.setPen(TQColor(i,i,i)); + hgp.drawPoint(i, 0); + } + m_page->hgradient->setPixmap(hgradientpix); + + // Create the vertical gradient label + TQPixmap vgradientpix(1, 256); + TQPainter vgp(&vgradientpix); + vgp.setPen(TQPen::TQPen(TQColor(0,0,0),1, TQt::SolidLine)); + for( i=0; i<256; ++i ) + { + vgp.setPen(TQColor(i,i,i)); + vgp.drawPoint(0, 255-i); + } + m_page->vgradient->setPixmap(vgradientpix); + + KisHistogramProducerSP producer = new KisGenericLabHistogramProducer(); + KisHistogram histogram(dev, producer, LINEAR); + TQPixmap pix(256, height); + pix.fill(); + TQPainter p(&pix); + p.setPen(TQPen::TQPen(TQt::gray,1, TQt::SolidLine)); + + double highest = (double)histogram.calculations().getHighest(); + TQ_INT32 bins = histogram.producer()->numberOfBins(); + + if (histogram.getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( i=0; ikCurve->setPixmap(pix); + +} + +KisBrightnessContrastFilterConfiguration * KisBrightnessContrastConfigWidget::config() +{ + KisBrightnessContrastFilterConfiguration * cfg = new KisBrightnessContrastFilterConfiguration(); + + for(int i=0; i <256; i++) + { + TQ_INT32 val; + val = int(0xFFFF * m_page->kCurve->getCurveValue( i / 255.0)); + if(val >0xFFFF) + val=0xFFFF; + if(val <0) + val = 0; + + cfg->transfer[i] = val; + } + cfg->curve = m_page->kCurve->getCurve(); + return cfg; +} + +void KisBrightnessContrastConfigWidget::setConfiguration( KisFilterConfiguration * config ) +{ + KisBrightnessContrastFilterConfiguration * cfg = dynamic_cast(config); + m_page->kCurve->setCurve(cfg->curve); +} diff --git a/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h b/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h new file mode 100644 index 00000000..598e4bcc --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/kis_brightness_contrast_filter.h @@ -0,0 +1,84 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_BRIGHTNESS_CONTRAST_FILTER_H_ +#define _KIS_BRIGHTNESS_CONTRAST_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class WdgBrightnessContrast; +class TQWidget; +class KisColorAdjustment; + +class KisBrightnessContrastFilterConfiguration : public KisFilterConfiguration { + +public: + + KisBrightnessContrastFilterConfiguration(); + virtual ~KisBrightnessContrastFilterConfiguration(); + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + TQ_UINT16 transfer[256]; + TQPtrList > curve; + KisColorAdjustment * m_adjustment; +}; + +/** + * This class affect Intensity Y of the image + */ +class KisBrightnessContrastFilter : public KisFilter +{ + +public: + + KisBrightnessContrastFilter(); + +public: + + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget *); + virtual KisFilterConfiguration * configuration() { return new KisBrightnessContrastFilterConfiguration(); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("brightnesscontrast", i18n("Brightness / Contrast")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP dev); + + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; + virtual bool workWith(KisColorSpace* cs); +}; + + +class KisBrightnessContrastConfigWidget : public KisFilterConfigWidget { + +public: + KisBrightnessContrastConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name = 0, WFlags f = 0 ); + virtual ~KisBrightnessContrastConfigWidget() {}; + + KisBrightnessContrastFilterConfiguration * config(); + void setConfiguration( KisFilterConfiguration * config ); + WdgBrightnessContrast * m_page; +}; + +#endif diff --git a/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.cc b/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.cc new file mode 100644 index 00000000..8d3aad84 --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.cc @@ -0,0 +1,421 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include + +#include "kis_filter_configuration.h" +#include "kis_filter_config_widget.h" +#include "kis_perchannel_filter.h" +#include "wdg_perchannel.h" +#include "kis_colorspace.h" +#include "kis_paint_device.h" +#include "kis_iterators_pixel.h" +#include "kcurve.h" +#include "kis_histogram.h" +#include "kis_basic_histogram_producers.h" +#include "kis_painter.h" + +KisPerChannelFilterConfiguration::KisPerChannelFilterConfiguration(int n) + : KisFilterConfiguration( "perchannel", 1 ) +{ + curves = new TQSortedList >[n]; + for(int i=0;i >[nTransfers]; + while (!curvesNode.isNull()) { + TQDomElement curvesElement = curvesNode.toElement(); + if (!curvesElement.isNull() && +!curvesElement.text().isEmpty()) { + TQStringList data = TQStringList::split( ";", +curvesElement.text() ); + TQStringList::Iterator pairStart = data.begin(); + TQStringList::Iterator pairEnd = data.end(); + for (TQStringList::Iterator it = pairStart; it != pairEnd; ++it) { + TQString pair = * it; + if (pair.tqfind(",") > -1) { + TQPair *p = new TQPair; + p->first = pair.section(",", 0, 0).toDouble(); + p->second = pair.section(",", 1, 1).toDouble(); + curves[count].append(p); + } + } + } + count++; + curvesNode = curvesNode.nextSibling(); + } + } + } + n = n.nextSibling(); + } + + for(int ch = 0; ch < nTransfers; ++ch) + { + transfers[ch] = new TQ_UINT16[256]; + for(int i = 0; i < 256; ++i) + { + TQ_INT32 val; + val = int(0xFFFF * KCurve::getCurveValue(curves[ch], i / +255.0)); + if(val > 0xFFFF) + val = 0xFFFF; + if(val < 0) + val = 0; + + transfers[ch][i] = val; + } + } + dirty = true; +} + +TQString KisPerChannelFilterConfiguration::toString() +{ + TQDomDocument doc = TQDomDocument("filterconfig"); + TQDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + TQDomElement c = doc.createElement("curves"); + c.setAttribute("number", nTransfers); + c.setAttribute("name", "curves"); + for (int i = 0; i < nTransfers; ++i) { + TQDomElement t = doc.createElement("curve"); + TQPtrList > curve = curves[i]; + TQString sCurve; + TQPair * pair; + for ( pair = curve.first(); pair; pair = curve.next() ) { + sCurve += TQString::number(pair->first); + sCurve += ","; + sCurve += TQString::number(pair->second); + sCurve += ";"; + } + TQDomText text = doc.createCDATASection(sCurve); + t.appendChild(text); + c.appendChild(t); + } + root.appendChild(c); + + + doc.appendChild( root ); + return doc.toString(); +} + + +KisFilterConfigWidget * KisPerChannelFilter::createConfigurationWidget(TQWidget *tqparent, KisPaintDeviceSP dev) +{ + return new KisPerChannelConfigWidget(tqparent, dev); +} + +KisFilterConfiguration* KisPerChannelFilter::configuration(TQWidget *nwidget) +{ + KisPerChannelConfigWidget* widget = (KisPerChannelConfigWidget*)nwidget; + + if ( widget == 0 ) + { + return 0; + } else { + return widget->config(); + } +} + +std::list KisPerChannelFilter::listOfExamplesConfiguration(KisPaintDeviceSP dev) +{ + std::list list; + list.insert(list.begin(), new KisPerChannelFilterConfiguration(dev->colorSpace()->nColorChannels())); + return list; +} + + +void KisPerChannelFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + if (!config) { + kdWarning() << "No configuration object for per-channel filter\n"; + return; + } + + KisPerChannelFilterConfiguration* configBC = + dynamic_cast(config); + if (configBC->nTransfers != src->colorSpace()->nColorChannels()) { + // We got an illegal number of colorchannels.KisFilter + return; + } + + if (configBC->dirty || (src->colorSpace() != configBC->oldCs)) { + delete configBC->adjustment; + configBC->adjustment = + src->colorSpace()->createPerChannelAdjustment(configBC->transfers); + kdDebug() << configBC->adjustment << endl; + configBC->oldCs = src->colorSpace(); + configBC->dirty = false; + } + + KisColorAdjustment *adj = configBC->adjustment; + + if (src!=dst) { + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + } + + KisRectIteratorPixel iter = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + setProgressTotalSteps(rect.width() * rect.height()); + TQ_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + TQ_UINT32 npix=0, maxpix = iter.nConseqPixels(); + TQ_UINT8 selectedness = iter.selectedness(); + // The idea here is to handle stretches of completely selected and completely unselected pixels. + // Partially selected pixels are handled one pixel at a time. + switch(selectedness) + { + case MIN_SELECTED: + while(iter.selectedness()==MIN_SELECTED && maxpix) + { + --maxpix; + ++iter; + ++npix; + } + pixelsProcessed += npix; + break; + + case MAX_SELECTED: + { + TQ_UINT8 *firstPixel = iter.rawData(); + while(iter.selectedness()==MAX_SELECTED && maxpix) + { + --maxpix; + if (maxpix != 0) + ++iter; + ++npix; + } + // adjust + src->colorSpace()->applyAdjustment(firstPixel, firstPixel, adj, npix); + pixelsProcessed += npix; + ++iter; + break; + } + + default: + // adjust, but since it's partially selected we also only partially adjust + src->colorSpace()->applyAdjustment(iter.oldRawData(), iter.rawData(), adj, 1); + const TQ_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + TQ_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + + setProgressDone(); +} + +void KisPerChannelConfigWidget::setActiveChannel(int ch) +{ + int i; + int height = 256; + TQPixmap pix(256, height); + pix.fill(); + TQPainter p(&pix); + p.setPen(TQPen::TQPen(TQt::gray,1, TQt::SolidLine)); + + m_histogram->setChannel(ch); + + double highest = (double)m_histogram->calculations().getHighest(); + TQ_INT32 bins = m_histogram->producer()->numberOfBins(); + + if (m_histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( i=0; igetValue(i) * factor)); + } + } else { + double factor = (double)height / (double)log(highest); + for( i = 0; i < bins; ++i ) { + p.drawLine(i, height, i, height - int(log((double)m_histogram->getValue(i)) * factor)); + } + } + + m_curves[m_activeCh].setAutoDelete(true); + m_curves[m_activeCh] = m_page->kCurve->getCurve(); + m_activeCh = ch; + m_page->kCurve->setCurve(m_curves[m_activeCh]); + + m_page->kCurve->setPixmap(pix); +} + +KisPerChannelConfigWidget::KisPerChannelConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(tqparent, name, f) +{ + int i; + int height; + m_page = new WdgPerChannel(this); + TQHBoxLayout * l = new TQHBoxLayout(this); + Q_CHECK_PTR(l); + + m_dev = dev; + m_curves = new TQSortedList >[m_dev->colorSpace()->nColorChannels()]; + m_activeCh = 0; + for(unsigned int ch=0; ch colorSpace()->nColorChannels(); ch++) + { + m_curves[ch].append(new TQPair(0, 0)); + m_curves[ch].append(new TQPair(1, 1)); + } + + l->add(m_page); + height = 256; + connect( m_page->kCurve, TQT_SIGNAL(modified()), TQT_SIGNAL(sigPleaseUpdatePreview())); + + // Fill in the channel chooser + TQValueVector channels = dev->colorSpace()->channels(); + for(unsigned int val=0; val < dev->colorSpace()->nColorChannels(); val++) + m_page->cmbChannel->insertItem(channels.at(val)->name()); + connect( m_page->cmbChannel, TQT_SIGNAL(activated(int)), this, TQT_SLOT(setActiveChannel(int))); + + // Create the horizontal gradient label + TQPixmap hgradientpix(256, 1); + TQPainter hgp(&hgradientpix); + hgp.setPen(TQPen::TQPen(TQColor(0,0,0),1, TQt::SolidLine)); + for( i=0; i<256; ++i ) + { + hgp.setPen(TQColor(i,i,i)); + hgp.drawPoint(i, 0); + } + m_page->hgradient->setPixmap(hgradientpix); + + // Create the vertical gradient label + TQPixmap vgradientpix(1, 256); + TQPainter vgp(&vgradientpix); + vgp.setPen(TQPen::TQPen(TQColor(0,0,0),1, TQt::SolidLine)); + for( i=0; i<256; ++i ) + { + vgp.setPen(TQColor(i,i,i)); + vgp.drawPoint(0, 255-i); + } + m_page->vgradient->setPixmap(vgradientpix); + + KisIDList keys = + KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_dev->colorSpace()); + KisHistogramProducerFactory *hpf; + hpf = KisHistogramProducerFactoryRegistry::instance()->get(*(keys.at(0))); + m_histogram = new KisHistogram(m_dev, hpf->generate(), LINEAR); + + setActiveChannel(0); +} + +KisPerChannelFilterConfiguration * KisPerChannelConfigWidget::config() +{ + int nCh = m_dev->colorSpace()->nColorChannels(); + KisPerChannelFilterConfiguration * cfg = new KisPerChannelFilterConfiguration(nCh); + + m_curves[m_activeCh].setAutoDelete(true); + m_curves[m_activeCh] = m_page->kCurve->getCurve(); + + for(int ch = 0; ch < nCh; ch++) + { + cfg->curves[ch].setAutoDelete(true); + cfg->curves[ch].clear(); + TQPair *p, *inpoint; + inpoint = m_curves[ch].first(); + while(inpoint) + { + p = new TQPair(inpoint->first, inpoint->second); + cfg->curves[ch].append(p); + inpoint = m_curves[ch].next(); + } + + for(int i=0; i <256; i++) + { + TQ_INT32 val; + val = int(0xFFFF * m_page->kCurve->getCurveValue(m_curves[ch], i / 255.0)); + if ( val > 0xFFFF ) + val = 0xFFFF; + if ( val < 0 ) + val = 0; + + cfg->transfers[ch][i] = val; + } + } + cfg->dirty = true; + + return cfg; +} + +void KisPerChannelConfigWidget::setConfiguration(KisFilterConfiguration * config) +{ + KisPerChannelFilterConfiguration * cfg = dynamic_cast(config); + + for(unsigned int ch = 0; ch < cfg->nTransfers; ch++) + { + m_curves[ch].setAutoDelete(true); + m_curves[ch].clear(); + TQPair *p, *inpoint; + inpoint = cfg->curves[ch].first(); + while(inpoint) + { + p = new TQPair(inpoint->first, inpoint->second); + m_curves[ch].append(p); + inpoint = cfg->curves[ch].next(); + } + } + m_page->kCurve->setCurve(m_curves[m_activeCh]); + setActiveChannel( 0 ); +} + +#include "kis_perchannel_filter.moc" diff --git a/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.h b/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.h new file mode 100644 index 00000000..6d11ab43 --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/kis_perchannel_filter.h @@ -0,0 +1,100 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _KIS_PERCHANNEL_FILTER_H_ +#define _KIS_PERCHANNEL_FILTER_H_ + +#include +#include +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_filter_config_widget.h" + +class WdgPerChannel; + +class KisPerChannelFilterConfiguration + : public KisFilterConfiguration +{ +public: + KisPerChannelFilterConfiguration(int n); + ~KisPerChannelFilterConfiguration(); + + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + TQPtrList > *curves; + TQ_UINT16 *transfers[256]; + TQ_UINT16 nTransfers; + // Caching of adjustment + bool dirty; + KisColorSpace* oldCs; + KisColorAdjustment* adjustment; +}; + + +/** + * This class is generic for filters that affect channel separately + */ +class KisPerChannelFilter + : public KisFilter +{ +public: + KisPerChannelFilter() : KisFilter( id(), "adjust", i18n("&Color Adjustment...")) {}; +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration* configuration() { return new KisPerChannelFilterConfiguration(0); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("perchannel", i18n("Color Adjustment")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP dev); + + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; +private: +}; + +class KisPerChannelConfigWidget : public KisFilterConfigWidget { + + typedef KisFilterConfigWidget super; + Q_OBJECT + TQ_OBJECT + +public: + KisPerChannelConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name = 0, WFlags f = 0 ); + virtual ~KisPerChannelConfigWidget() {}; + + KisPerChannelFilterConfiguration * config(); + void setConfiguration(KisFilterConfiguration * config); + +private slots: + virtual void setActiveChannel(int ch); + +private: + WdgPerChannel * m_page; + KisPaintDeviceSP m_dev; + KisHistogram *m_histogram; + TQPtrList > *m_curves; + int m_activeCh; +}; + +#endif diff --git a/chalk/plugins/filters/colorsfilters/wdg_brightness_contrast.ui b/chalk/plugins/filters/colorsfilters/wdg_brightness_contrast.ui new file mode 100644 index 00000000..9474462b --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/wdg_brightness_contrast.ui @@ -0,0 +1,292 @@ + +WdgBrightnessContrast + + + WdgBrightnessContrast + + + + 0 + 0 + 284 + 346 + + + + + 0 + 0 + 0 + 0 + + + + BrightnessCon + + + + unnamed + + + 0 + + + + tqlayout4 + + + + unnamed + + + + hgradient + + + + 5 + 0 + 0 + 0 + + + + + 250 + 20 + + + + + 250 + 20 + + + + Panel + + + Sunken + + + true + + + + + frame3 + + + + 5 + 5 + 0 + 0 + + + + + 254 + 254 + + + + + 254 + 254 + + + + Panel + + + Sunken + + + 0 + + + + unnamed + + + 3 + + + + kCurve + + + + 250 + 250 + + + + + 250 + 250 + + + + + + + + vgradient + + + + 0 + 5 + 0 + 0 + + + + + 20 + 250 + + + + + 20 + 250 + + + + Panel + + + Sunken + + + true + + + + + + + tqlayout7 + + + + unnamed + + + + pb_more_contrast + + + + + + + + + + + + textLabelContrast + + + Contrast + + + AlignCenter + + + + + pb_less_contrast + + + - + + + + + + + + pb_less_brightness + + + - + + + + + + + + textLabelBrightness + + + Brightness + + + AlignCenter + + + + + pb_more_brightness + + + + + + + + + + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 131 + 20 + + + + + + + + KCurve +
kcurve.h
+ + 33 + 23 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f + + + + + kcurve.h + +
diff --git a/chalk/plugins/filters/colorsfilters/wdg_perchannel.ui b/chalk/plugins/filters/colorsfilters/wdg_perchannel.ui new file mode 100644 index 00000000..243d628f --- /dev/null +++ b/chalk/plugins/filters/colorsfilters/wdg_perchannel.ui @@ -0,0 +1,190 @@ + +WdgPerChannel + + + WdgPerChannel + + + + 0 + 0 + 609 + 698 + + + + BrightnessCon + + + + unnamed + + + 0 + + + + tqlayout4 + + + + unnamed + + + + textLabel1 + + + Channel: + + + + + cmbChannel + + + + + + + tqlayout8 + + + + unnamed + + + + hgradient + + + + 5 + 0 + 0 + 0 + + + + + 0 + 20 + + + + + 32767 + 20 + + + + Panel + + + Sunken + + + true + + + + + frame3 + + + + 5 + 5 + 0 + 0 + + + + Panel + + + Sunken + + + 0 + + + + unnamed + + + 3 + + + + kCurve + + + + + + + vgradient + + + + 0 + 5 + 0 + 0 + + + + + 20 + 0 + + + + + 20 + 32767 + + + + Panel + + + Sunken + + + true + + + + + + + + + KCurve +
../../../ui/kcurve.h
+ + 33 + 23 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + kcurve.h + +
diff --git a/chalk/plugins/filters/convolutionfilters/Makefile.am b/chalk/plugins/filters/convolutionfilters/Makefile.am new file mode 100644 index 00000000..069ff51f --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/Makefile.am @@ -0,0 +1,28 @@ +kde_services_DATA = chalkconvolutionfilters.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I../../../ui/ \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkconvolutionfilters.la + +chalkconvolutionfilters_la_SOURCES = kis_custom_convolution_filter_configuration_base_widget.ui \ + kis_custom_convolution_filter_configuration_widget.cc \ + kis_custom_convolution_filter.cc \ + convolutionfilters.cc \ + kis_convolution_filter.cc + +noinst_HEADERS = convolutionfilters.h \ + kis_custom_convolution_filter_configuration_widget.h \ + kis_convolution_filter.h + +chalkconvolutionfilters_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkconvolutionfilters_la_LIBADD = ../../../libchalkcommon.la + +chalkconvolutionfilters_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/convolutionfilters/chalkconvolutionfilters.desktop b/chalk/plugins/filters/convolutionfilters/chalkconvolutionfilters.desktop new file mode 100644 index 00000000..ee0b9842 --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/chalkconvolutionfilters.desktop @@ -0,0 +1,75 @@ +[Desktop Entry] +Name=Convolution Filters +Name[bg]=Изкривяващи филтри +Name[ca]=Filtres de convolució +Name[cy]=Hidlau cordeddiadau +Name[da]=Foldningsfilter +Name[de]=Faltungsfilter +Name[el]=Φίλτρα περιέλιξης +Name[eo]=Volvaĵfiltriloj +Name[es]=Filtros de convolución +Name[et]=Konvolutsioonifiltrid +Name[fa]=پالایه‌های هم‌پیچش +Name[fr]=Filtres de convolution +Name[fy]=Verdraaïngsfilters +Name[ga]=Scagairí Conbhlóide +Name[gl]=Filtros de Convolución +Name[hu]=Konvolúciószűrők +Name[is]=Fléttunarsíur +Name[it]=Filtri di convoluzione +Name[ja]=コンボリューションフィルタ +Name[km]=តម្រង​អង្កាញ់ +Name[nb]=Konvolusjonsfiltre +Name[nds]=Fooldenfilters +Name[ne]=कुण्डलीकरण फिल्टरहरू +Name[nl]=Verdraaïngs +Name[pl]=Filtry splotowe +Name[pt]=Filtros de Convolução +Name[pt_BR]=Filtros de Convolução +Name[ru]=Cвёртка +Name[sk]=Filtre zvinutia +Name[sl]=Konvolucijski filtri +Name[sr]=Конволуциони филтери +Name[sr@Latn]=Konvolucioni filteri +Name[sv]=Faltningsfilter +Name[uk]=Фільтри згортки +Name[zh_TW]=皺褶過濾器 +Comment=Convolution filters +Comment[bg]=Изкривяващи филтри +Comment[ca]=Filtres de convolució +Comment[cy]=Hidlau cordeddiadau +Comment[da]=Foldningsfilter +Comment[de]=Faltungsfilter +Comment[el]=Φίλτρα περιέλιξης +Comment[eo]=Volvaĵfiltriloj +Comment[es]=Filtros de convoluciones +Comment[et]=Konvolutsioonifiltrid +Comment[fa]=پالایه‌های هم‌پیچش +Comment[fr]=Filtres de déformations +Comment[fy]=Verdraaïngsfilters +Comment[ga]=Scagairí conbhlóide +Comment[gl]=Filtros de convolución +Comment[hu]=CImg képhelyreállító szűrő +Comment[is]=Fléttunarsíur +Comment[it]=Filtri di convoluzione +Comment[ja]=コンボリューションフィルタ +Comment[km]=តម្រង​អង្កាញ់ +Comment[nb]=Konvolusjonsfiltre +Comment[nds]=Fooldenfilters +Comment[ne]=कुण्डलीकरण फिल्टरहरू +Comment[nl]=Verdraaiingsfilters +Comment[pl]=Filtry splotowe +Comment[pt]=Filtros de convolução +Comment[pt_BR]=Filtros de convolução +Comment[ru]=Cвёртка +Comment[sk]=Filtre zvinutia +Comment[sl]=Konvolucijski filtri +Comment[sr]=Конволуциони филтери +Comment[sr@Latn]=Konvolucioni filteri +Comment[sv]=Faltningsfilter +Comment[uk]=Фільтри згортки +Comment[zh_TW]=皺褶過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkconvolutionfilters +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/convolutionfilters/convolutionfilters.cc b/chalk/plugins/filters/convolutionfilters/convolutionfilters.cc new file mode 100644 index 00000000..ddf2332f --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/convolutionfilters.cc @@ -0,0 +1,176 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include +#include "convolutionfilters.h" + +#include "kis_custom_convolution_filter.h" + +KisKernelSP createKernel( TQ_INT32 i0, TQ_INT32 i1, TQ_INT32 i2, + TQ_INT32 i3, TQ_INT32 i4, TQ_INT32 i5, + TQ_INT32 i6, TQ_INT32 i7, TQ_INT32 i8, + TQ_INT32 factor, TQ_INT32 offset ) +{ + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->factor = factor; + kernel->offset = offset; + + kernel->data = new TQ_INT32[9]; + kernel->data[0] = i0; + kernel->data[1] = i1; + kernel->data[2] = i2; + kernel->data[3] = i3; + kernel->data[4] = i4; + kernel->data[5] = i5; + kernel->data[6] = i6; + kernel->data[7] = i7; + kernel->data[8] = i8; + + return kernel; +} + + + +typedef KGenericFactory ChalkConvolutionFiltersFactory; +K_EXPORT_COMPONENT_FACTORY( chalkconvolutionfilters, ChalkConvolutionFiltersFactory( "chalk" ) ) + +ChalkConvolutionFilters::ChalkConvolutionFilters(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkConvolutionFiltersFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisGaussianBlurFilter()); + manager->add(new KisSharpenFilter()); + manager->add(new KisMeanRemovalFilter()); + manager->add(new KisEmbossLaplascianFilter()); + manager->add(new KisEmbossInAllDirectionsFilter()); + manager->add(new KisEmbossHorizontalVerticalFilter()); + manager->add(new KisEmbossVerticalFilter()); + manager->add(new KisEmbossHorizontalFilter()); + manager->add(new KisTopEdgeDetectionFilter()); + manager->add(new KisRightEdgeDetectionFilter()); + manager->add(new KisBottomEdgeDetectionFilter()); + manager->add(new KisLeftEdgeDetectionFilter()); + manager->add(new KisCustomConvolutionFilter()); + } +} + +ChalkConvolutionFilters::~ChalkConvolutionFilters() +{ +} + +KisGaussianBlurFilter::KisGaussianBlurFilter() + : KisConvolutionConstFilter(id(), "blur", i18n("&Gaussian Blur")) +{ + m_matrix = createKernel( 1, 2, 1, 2, 4, 2, 1, 2, 1, 16, 0); +} + + +KisSharpenFilter::KisSharpenFilter() + : KisConvolutionConstFilter(id(), "enhance", i18n("&Sharpen")) +{ + m_matrix = createKernel( 0, -2, 0, -2, 11, -2, 0, -2, 0, 3, 0); +} + +KisMeanRemovalFilter::KisMeanRemovalFilter() + : KisConvolutionConstFilter(id(), "enhance", i18n("&Mean Removal")) +{ + m_matrix = createKernel( -1, -1, -1, -1, 9, -1, -1, -1, -1, 1, 0); +} + +KisEmbossLaplascianFilter::KisEmbossLaplascianFilter() + : KisConvolutionConstFilter(id(), "emboss", i18n("Emboss Laplascian")) +{ + m_matrix = createKernel( -1, 0, -1 , 0, 4, 0 , -1, 0, -1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + +KisEmbossInAllDirectionsFilter::KisEmbossInAllDirectionsFilter() + : KisConvolutionConstFilter(id(), "emboss", i18n("Emboss in All Directions")) +{ + m_matrix = createKernel( -1, -1, -1 , -1, 8, -1 , -1, -1, -1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + +KisEmbossHorizontalVerticalFilter::KisEmbossHorizontalVerticalFilter() + : KisConvolutionConstFilter(id(), "emboss", i18n("EmbossQt::Horizontal &&Qt::Vertical")) +{ + m_matrix = createKernel( 0, -1, 0 , -1, 4, -1 , 0, -1, 0, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + +KisEmbossVerticalFilter::KisEmbossVerticalFilter() + : KisConvolutionConstFilter(id(), "emboss", i18n("EmbossQt::Vertical Only")) +{ + m_matrix = createKernel( 0, -1, 0 , 0, 2, 0 , 0, -1, 0, 1, 127); +} + +KisEmbossHorizontalFilter::KisEmbossHorizontalFilter() : + KisConvolutionConstFilter(id(), "emboss", i18n("EmbossQt::Horizontal Only")) +{ + m_matrix = createKernel( 0, 0, 0 , -1, 4, -1 , 0, 0, 0, 1, 127); + +} + +KisEmbossDiagonalFilter::KisEmbossDiagonalFilter() + : KisConvolutionConstFilter(id(), "edge", i18n("Top Edge Detection")) +{ + m_matrix = createKernel( -1, 0, -1 , 0, 4, 0 , -1, 0, -1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + + +KisTopEdgeDetectionFilter::KisTopEdgeDetectionFilter() + : KisConvolutionConstFilter(id(), "edge", i18n("Top Edge Detection")) +{ + m_matrix = createKernel( 1, 1, 1 , 0, 0, 0 , -1, -1, -1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; + +} + +KisRightEdgeDetectionFilter::KisRightEdgeDetectionFilter() + : KisConvolutionConstFilter(id(), "edge", i18n("Right Edge Detection")) +{ + m_matrix = createKernel( -1, 0, 1 , -1, 0, 1 , -1, 0, 1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + +KisBottomEdgeDetectionFilter::KisBottomEdgeDetectionFilter() : KisConvolutionConstFilter(id(), "edge", i18n("Bottom Edge Detection")) +{ + m_matrix = createKernel( -1, -1, -1 , 0, 0, 0 , 1, 1, 1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} + +KisLeftEdgeDetectionFilter::KisLeftEdgeDetectionFilter() : KisConvolutionConstFilter(id(), "edge", i18n("Left Edge Detection")) +{ + m_matrix = createKernel( 1, 0, -1 , 1, 0, -1 , 1, 0, -1, 1, 127); + m_channelFlags = KisChannelInfo::FLAG_COLOR; +} diff --git a/chalk/plugins/filters/convolutionfilters/convolutionfilters.h b/chalk/plugins/filters/convolutionfilters/convolutionfilters.h new file mode 100644 index 00000000..94e4654c --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/convolutionfilters.h @@ -0,0 +1,152 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CONVOLUTIONFILTERS_H +#define CONVOLUTIONFILTERS_H + +#include +#include "kis_convolution_filter.h" + +class KisGaussianBlurFilter : public KisConvolutionConstFilter { +public: + KisGaussianBlurFilter(); +public: + static inline KisID id() { return KisID("gaussian blur", i18n("Gaussian Blur")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsIncrementalPainting() { return false; } +}; + +class KisSharpenFilter : public KisConvolutionConstFilter { +public: + KisSharpenFilter(); +public: + static inline KisID id() { return KisID("sharpen", i18n("Sharpen")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsIncrementalPainting() { return false; } +}; + +class KisMeanRemovalFilter : public KisConvolutionConstFilter { +public: + KisMeanRemovalFilter(); +public: + static inline KisID id() { return KisID("mean removal", i18n("Mean Removal")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossLaplascianFilter : public KisConvolutionConstFilter { +public: + KisEmbossLaplascianFilter(); +public: + static inline KisID id() { return KisID("emboss laplascian", i18n("Emboss Laplascian")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossInAllDirectionsFilter : public KisConvolutionConstFilter { +public: + KisEmbossInAllDirectionsFilter(); +public: + static inline KisID id() { return KisID("emboss all directions", i18n("Emboss in All Directions")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossHorizontalVerticalFilter : public KisConvolutionConstFilter { +public: + KisEmbossHorizontalVerticalFilter(); +public: + static inline KisID id() { return KisID("", i18n("EmbossQt::Horizontal &Qt::Vertical")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossVerticalFilter : public KisConvolutionConstFilter { +public: + KisEmbossVerticalFilter(); +public: + static inline KisID id() { return KisID("emboss vertical only", i18n("EmbossQt::Vertical Only")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossHorizontalFilter : public KisConvolutionConstFilter { +public: + KisEmbossHorizontalFilter(); +public: + static inline KisID id() { return KisID("emboss horizontal only", i18n("EmbossQt::Horizontal Only")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisEmbossDiagonalFilter : public KisConvolutionConstFilter { +public: + KisEmbossDiagonalFilter(); +public: + static inline KisID id() { return KisID("emboss diagonal", i18n("Emboss Diagonal")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisTopEdgeDetectionFilter : public KisConvolutionConstFilter { +public: + KisTopEdgeDetectionFilter(); +public: + static inline KisID id() { return KisID("top edge detections", i18n("Top Edge Detection")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisRightEdgeDetectionFilter : public KisConvolutionConstFilter { +public: + KisRightEdgeDetectionFilter(); +public: + static inline KisID id() { return KisID("right edge detections", i18n("Right Edge Detection")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisBottomEdgeDetectionFilter : public KisConvolutionConstFilter { +public: + KisBottomEdgeDetectionFilter(); +public: + static inline KisID id() { return KisID("bottom edge detections", i18n("Bottom Edge Detection")); }; + virtual bool supportsPainting() { return false; } + +}; + +class KisLeftEdgeDetectionFilter : public KisConvolutionConstFilter { +public: + KisLeftEdgeDetectionFilter(); +public: + static inline KisID id() { return KisID("left edge detections", i18n("Left Edge Detection")); }; + virtual bool supportsPainting() { return false; } + +}; + + +class ChalkConvolutionFilters : public KParts::Plugin +{ +public: + ChalkConvolutionFilters(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkConvolutionFilters(); +}; + +#endif diff --git a/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.cc b/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.cc new file mode 100644 index 00000000..39a395b4 --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.cc @@ -0,0 +1,138 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "tqdom.h" +#include "klocale.h" +#include "kdebug.h" + +#include "kis_painter.h" +#include "kis_convolution_filter.h" +#include "kis_convolution_painter.h" +#include "kis_progress_display_interface.h" +#include "kis_progress_subject.h" + +void KisConvolutionConfiguration::fromXML(const TQString & s) +{ + m_matrix = new KisKernel(); + + TQDomDocument doc; + doc.setContent( s ); + TQDomElement e = doc.documentElement(); + TQDomNode n = e.firstChild(); + + m_name = e.attribute("name"); + m_version = e.attribute("version").toInt(); + + TQDomElement matrix = n.toElement(); + m_matrix->width = TQString( matrix.attribute( "width" ) ).toInt(); + m_matrix->height = TQString( matrix.attribute( "height" ) ).toInt(); + m_matrix->offset = TQString( matrix.attribute( "offset" ) ).toInt(); + m_matrix->factor = TQString( matrix.attribute( "factor" ) ).toInt(); + + m_matrix->data = new TQ_INT32[m_matrix->width * m_matrix->height]; + + TQStringList data = TQStringList::split( ",", e.text() ); + TQStringList::Iterator start = data.begin(); + TQStringList::Iterator end = data.end(); + int i = 0; + for ( TQStringList::Iterator it = start; it != end; ++it ) { + TQString s = *it; + m_matrix->data[i] = s.toInt(); + i++; + } +} + +TQString KisConvolutionConfiguration::toString() +{ + TQDomDocument doc = TQDomDocument("filterconfig"); + TQDomElement root = doc.createElement( "filterconfig" ); + root.setAttribute( "name", name() ); + root.setAttribute( "version", version() ); + + doc.appendChild( root ); + + TQDomElement e = doc.createElement( "kernel" ); + e.setAttribute( "width", m_matrix->width ); + e.setAttribute( "height", m_matrix->height ); + e.setAttribute( "offset", m_matrix->offset ); + e.setAttribute( "factor", m_matrix->factor ); + + TQString data; + + for ( uint i = 0; i < m_matrix->width * m_matrix->height; ++i ) { + data += TQString::number( m_matrix->data[i] ); + data += ","; + } + + TQDomText text = doc.createCDATASection(data); + e.appendChild(text); + root.appendChild(e); + + return doc.toString(); + +} + +void KisConvolutionFilter::process(KisPaintDeviceSP src, + KisPaintDeviceSP dst, + KisFilterConfiguration* configuration, + const TQRect& rect) +{ + if (!configuration) { + setProgressDone(); + return; + } + + if (dst != src) { + kdDebug() << "src != dst\n"; + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + } + + + KisConvolutionPainter painter( dst ); + if (m_progressDisplay) + m_progressDisplay->setSubject( &painter, true, true ); + + KisKernelSP kernel = ((KisConvolutionConfiguration*)configuration)->matrix(); + KisChannelInfo::enumChannelFlags channels = ((KisConvolutionConfiguration*)configuration)->channels(); + + painter.applyMatrix(kernel, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_REPEAT, channels ); + + if (painter.cancelRequested()) { + cancel(); + } + + setProgressDone(); +} + +int KisConvolutionFilter::overlapMarginNeeded(KisFilterConfiguration* c) const { + KisConvolutionConfiguration* config = dynamic_cast(c); + if (!config) + return 0; + KisKernelSP kernel = config->matrix(); + return TQMAX(kernel->width / 2, kernel->height / 2); +} + +KisFilterConfiguration* KisConvolutionConstFilter::configuration(TQWidget*) +{ + return new KisConvolutionConfiguration( id().id(), m_matrix, m_channelFlags); +} + +#include "kis_convolution_filter.moc" diff --git a/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.h b/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.h new file mode 100644 index 00000000..87b3d2b8 --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_convolution_filter.h @@ -0,0 +1,99 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CONVOLUTION_FILTER_H_ +#define _KIS_CONVOLUTION_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_convolution_painter.h" + +class KisConvolutionConfiguration : public KisFilterConfiguration { +public: + KisConvolutionConfiguration(const TQString & name, KisKernel * matrix, + KisChannelInfo::enumChannelFlags channelFlags = KisChannelInfo::FLAG_COLOR_AND_ALPHA) + : KisFilterConfiguration( name, 1 ) + , m_matrix(matrix) + , m_channelFlags(channelFlags) + {}; + + void fromXML(const TQString & s); + TQString toString(); + +public: + + inline KisKernelSP matrix() { return m_matrix; } + inline KisChannelInfo::enumChannelFlags channels() { return m_channelFlags; } + +private: + + KisKernelSP m_matrix; + KisChannelInfo::enumChannelFlags m_channelFlags; + +}; + + +class KisConvolutionFilter : public KisFilter { + + Q_OBJECT + TQ_OBJECT + +public: + + KisConvolutionFilter(const KisID& id, const TQString & category, const TQString & entry) + : KisFilter( id, category, entry ) + {}; + +public: + + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + virtual bool supportsIncrementalPainting() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + virtual int overlapMarginNeeded(KisFilterConfiguration* c) const; +}; + + +/** + * This class is used for a convolution filter with a constant matrix + */ +class KisConvolutionConstFilter : public KisConvolutionFilter { + +public: + + KisConvolutionConstFilter(const KisID& id, const TQString & category, const TQString & entry) + : KisConvolutionFilter(id, category, entry) + { + m_channelFlags = KisChannelInfo::FLAG_COLOR_AND_ALPHA; + }; + + virtual ~KisConvolutionConstFilter() {}; + +public: + + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return configuration(0); }; + +protected: + + KisKernelSP m_matrix; + KisChannelInfo::enumChannelFlags m_channelFlags; +}; + +#endif diff --git a/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc new file mode 100644 index 00000000..8d48d25d --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.cc @@ -0,0 +1,93 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "kis_custom_convolution_filter.h" + +#include + +#include "kis_convolution_painter.h" +#include "kis_custom_convolution_filter_configuration_widget.h" +#include "kis_custom_convolution_filter_configuration_base_widget.h" +#include "kis_matrix_widget.h" + + +KisFilterConfigWidget * KisCustomConvolutionFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP) +{ + KisCustomConvolutionFilterConfigurationWidget* ccfcw = new KisCustomConvolutionFilterConfigurationWidget(this,tqparent, "custom convolution config widget"); + Q_CHECK_PTR(ccfcw); + return ccfcw; +} + +KisFilterConfiguration * KisCustomConvolutionFilter::configuration(TQWidget* nwidget) +{ + KisCustomConvolutionFilterConfigurationWidget* widget = (KisCustomConvolutionFilterConfigurationWidget*) nwidget; + + if ( widget == 0 ) + { + // Create the identity matrix: + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->factor = 1; + kernel->offset = 127; + + kernel->data = new TQ_INT32[9]; + kernel->data[0] = 0; + kernel->data[1] = 0; + kernel->data[2] = 0; + kernel->data[3] = 0; + kernel->data[4] = 1; + kernel->data[5] = 0; + kernel->data[6] = 0; + kernel->data[7] = 0; + kernel->data[8] = 0; + + return new KisConvolutionConfiguration( "custom convolution", kernel ); + + } else { + + // Create the identity matrices: + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->data = new TQ_INT32[9]; + + KisCustomConvolutionFilterConfigurationBaseWidget* mw = widget->matrixWidget(); + + kernel->data[0] = mw->matrixWidget->m11->value(); + kernel->data[1] = mw->matrixWidget->m21->value(); + kernel->data[2] = mw->matrixWidget->m31->value(); + kernel->data[3] = mw->matrixWidget->m12->value(); + kernel->data[4] = mw->matrixWidget->m22->value(); + kernel->data[5] = mw->matrixWidget->m32->value(); + kernel->data[6] = mw->matrixWidget->m13->value(); + kernel->data[7] = mw->matrixWidget->m23->value(); + kernel->data[8] = mw->matrixWidget->m33->value(); + + kernel->factor = mw->spinBoxFactor->value(); + kernel->offset = mw->spinBoxOffset->value(); + + return new KisConvolutionConfiguration( "custom convolution", kernel ); + } +} diff --git a/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h new file mode 100644 index 00000000..cbfd375e --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter.h @@ -0,0 +1,54 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CUSTOM_CONVOLUTION_FILTER_H_ +#define _KIS_CUSTOM_CONVOLUTION_FILTER_H_ + +#include "kis_convolution_filter.h" +#include "kis_filter_config_widget.h" +#include "kis_id.h" +#include "kis_types.h" + +class TQWidget; + +class KisCustomConvolutionFilter : public KisConvolutionFilter { + +public: + KisCustomConvolutionFilter() : KisConvolutionFilter(id(), "enhance", i18n("&Custom Convolution...")) {}; + +public: + static inline KisID id() { return KisID("custom convolution", i18n("Custom Convolution")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsIncrementalPainting() { return true; } + +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return configuration(0); }; +protected: + virtual KisKernelSP matrix() { return m_matrix; }; +private: + KisKernelSP m_matrix; +}; + + + + +#endif diff --git a/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui new file mode 100644 index 00000000..495fd3bc --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_base_widget.ui @@ -0,0 +1,189 @@ + +KisCustomConvolutionFilterConfigurationBaseWidget + + + KisCustomConvolutionFilterConfigurationBaseWidget + + + + 0 + 0 + 138 + 230 + + + + Custom Convolution Filter Configuration Widget + + + + unnamed + + + + tqlayout5 + + + + unnamed + + + + matrixWidget + + + + + tqlayout4 + + + + unnamed + + + + textLabelFactor + + + Factor: + + + + + spinBoxFactor + + + 1 + + + 1 + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + + + tqlayout3 + + + + unnamed + + + + textLabelOffset + + + Offset: + + + + + spinBoxOffset + + + 255 + + + -255 + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 24 + 20 + + + + + + + + spacer24 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + + spacer5 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + + + KisMatrixWidget +
kis_matrix_widget.h
+ + 150 + 100 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042c49444154789cb5954f6c14551cc73fefcd7476b65bdaae4bb78bb5502a14d404e4801c88182d1c4c2c693da847400f9c24c68b878684238660e2b1e01f12c19493012ef2478c814412d354a46017a8a564bb6da5bbedccee767776e63d0ffb073751d483bfe49799974c3eeffb7ebf37df9fd05a530b2184040cc0042420aaf9a4d0d554800f045a6b256ae0e1e1e1d6bebebe838ee31c48a7d39b5cd7fd075e251cc7617272f2ded8d8d819cff33e0316819259537aead4a9839d5dd6d1784f91f55b0a94830242088404d304292bef68a89f520802a598fecddaa04f1a876f5c250c7c0a64cdeac686e33807e23d45e6b297c8b877f1831542614550b6599835c83c2a81b6786a75134faf2f1169f12997350881d9021d0903e06de0745d3160a6d3e94dbd5b0a64dcbb94b5831d0e3375ab892b1772dcf9790528543f8dd0d367b36768153b5e31503a0f1aecb004580b44ffac58baae8b1714f0833c7638cc8dab303a320f4822ab4c7a37c69196203de3319d5ce1c4d13c733331dedc67a129a154fd128401ab0616d55a130ac3d42d93d1913940d13fd0c9ee0183685c60da01c5421bd72f7a8c8efccef9afd374267ad93d642365be0636a0d28ec7600941d9e6f23917f0e97f23ce5bef35d19ec863da0ed9059b2be70bec196c66dfa10ec0e49b338f7017258651bf95021035c595429bb0903248fe52a2b5b595dd7b4d945cc2340cdca536be389ee3f67886c5798f773fe8e0dac508c989659277a2180da4ca4ff07821058b8b251445d63d6b13ed1098a6417e39cac85197dbe31962ab9bd9f1f22a226d45366f6d0620fdb08c900d281af6110284b20085b414861d905d88f2e52739ee8cbb8022143259d3dd84691730aa2d52da441a8de0c6958068870022a41e9629ad3473fd3b8fdbe319dadb9b4924da994d2d716c7896fbe35152f78b48245d6b2da4507faf582be8eaf159b721cc837b05ae7debb1f79d08cb8b515edad942a22bc4b1c33eb3d34b1c797f06af90a72d16e2f96d9a74aa11dca8586b222d01af0fb60070f6c402d72f15d97f28c6f6d7027a5f5ce6c3233dc4e2ede496b278be4fff608cee8d3e1add806aeca51094cbb06397c1ecc328e746537c7e3ccdb5cb1136bf60635882d4d41c6ec6836ab37efa214f72208ed9f4d7cdd38ee310280542e38b1c43fb6de26b3672e1ec3cc99bcb246f66a938a3241ab3e91f7c861fbf77710b1e5e49915bae974203ba0e9e9c9cbc373d6d6d305a040a89c2a77f50b27d5782bbbf7acccf28349235dd16cf6dd374f7295e1de8a45c02d37499182b01cc0201a085d61a2144d8b2ac8fb6ed340e77240c4261890e04c250185262546d534a032154b59e0ad394e41c98182bf268ce6721ed9f064e0253356f6da2e24c1f030f783c15fe6da680af8021602bd051532ca9b8521488559f61aa86c29343578fbf0264a94c906c7d3409214c20043457a116ff6de6795578012889ff6b98fe016ea0ce1c203e47720000000049454e44ae426082 + + + +
diff --git a/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc new file mode 100644 index 00000000..b1905d30 --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.cc @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_custom_convolution_filter_configuration_widget.h" + +#include +#include + +#include + +#include "kis_filter.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_view.h" +#include "kis_types.h" +#include "kis_filter_configuration.h" +#include "kis_colorspace.h" +#include "kis_convolution_filter.h" +#include "kis_custom_convolution_filter_configuration_base_widget.h" +#include "kis_matrix_widget.h" + +KisCustomConvolutionFilterConfigurationWidget::KisCustomConvolutionFilterConfigurationWidget( KisFilter* /*nfilter*/, TQWidget * tqparent, const char * name) + : KisFilterConfigWidget ( tqparent, name ) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 2, 1); + Q_CHECK_PTR(widgetLayout); + +// TQPushButton *bnRefresh = new TQPushButton(i18n("Refresh Preview"), this, "bnrefresh"); +// Q_CHECK_PTR(bnRefresh); + +// TQSpacerItem *spacer = new TQSpacerItem(100, 30, TQSizePolicy::Expanding, TQSizePolicy::Minimum); +// Q_CHECK_PTR(spacer); + +// widgetLayout->addWidget(bnRefresh, 0, 0); +// widgetLayout->addItem(spacer, 0, 1); + + m_ccfcws = new KisCustomConvolutionFilterConfigurationBaseWidget((TQWidget*)this); + Q_CHECK_PTR(m_ccfcws); + + widgetLayout->addMultiCellWidget(m_ccfcws, 1, 1, 0, 1); + +// connect( bnRefresh, TQT_SIGNAL(clicked()), nfilter, TQT_SLOT(refreshPreview())); + connect( m_ccfcws->matrixWidget, TQT_SIGNAL(valueChanged()), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_ccfcws->spinBoxFactor, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_ccfcws->spinBoxOffset, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +void KisCustomConvolutionFilterConfigurationWidget::setConfiguration(KisFilterConfiguration * cfg) +{ + KisConvolutionConfiguration * config = dynamic_cast(cfg); + + if (config->matrix()->width != 3 || config->matrix()->height != 3) return; + + m_ccfcws->spinBoxOffset->setValue(config->matrix()->offset); + m_ccfcws->spinBoxFactor->setValue(config->matrix()->factor); + + m_ccfcws->matrixWidget->m11->setValue(config->matrix()->data[0]); + m_ccfcws->matrixWidget->m21->setValue(config->matrix()->data[1]); + m_ccfcws->matrixWidget->m31->setValue(config->matrix()->data[2]); + m_ccfcws->matrixWidget->m12->setValue(config->matrix()->data[3]); + m_ccfcws->matrixWidget->m22->setValue(config->matrix()->data[4]); + m_ccfcws->matrixWidget->m32->setValue(config->matrix()->data[5]); + m_ccfcws->matrixWidget->m31->setValue(config->matrix()->data[6]); + m_ccfcws->matrixWidget->m32->setValue(config->matrix()->data[7]); + m_ccfcws->matrixWidget->m33->setValue(config->matrix()->data[8]); +} + +#include "kis_custom_convolution_filter_configuration_widget.moc" diff --git a/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h new file mode 100644 index 00000000..b5819e39 --- /dev/null +++ b/chalk/plugins/filters/convolutionfilters/kis_custom_convolution_filter_configuration_widget.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CUSTOM_CONVOLUTION_FILTER_CONFIGURATION_WIDGET_H_ +#define _KIS_CUSTOM_CONVOLUTION_FILTER_CONFIGURATION_WIDGET_H_ + +#include "kis_filter_config_widget.h" + +class TQWidget; +class KisCustomConvolutionFilterConfigurationBaseWidget; +class KisMatrixWidget; +class KisFilter; + +class KisCustomConvolutionFilterConfigurationWidget : public KisFilterConfigWidget +{ + + Q_OBJECT + TQ_OBJECT + +public: + + KisCustomConvolutionFilterConfigurationWidget( KisFilter* nfilter, TQWidget * tqparent, const char * name); + inline KisCustomConvolutionFilterConfigurationBaseWidget* matrixWidget() { return m_ccfcws; }; + void setConfiguration(KisFilterConfiguration * config); + +private: + + KisCustomConvolutionFilterConfigurationBaseWidget* m_ccfcws; +}; + +#endif diff --git a/chalk/plugins/filters/cubismfilter/Makefile.am b/chalk/plugins/filters/cubismfilter/Makefile.am new file mode 100644 index 00000000..e281360e --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = chalkcubismfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkcubismfilter.la + +chalkcubismfilter_la_SOURCES = kis_cubism_filter_plugin.cc \ + kis_cubism_filter.cc \ + kis_polygon.cc + +noinst_HEADERS = kis_cubism_filter_plugin.h \ + kis_cubism_filter.h \ + kis_polygon.h + +chalkcubismfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkcubismfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkcubismfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/cubismfilter/chalkcubismfilter.desktop b/chalk/plugins/filters/cubismfilter/chalkcubismfilter.desktop new file mode 100644 index 00000000..fd8e7e2b --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/chalkcubismfilter.desktop @@ -0,0 +1,85 @@ +[Desktop Entry] +Name=Cubism Filter +Name[bg]=Кубичен филтър +Name[ca]=Filtre de cubisme +Name[cy]=Hidlen Giwbiaeth +Name[da]=Kubismefilter +Name[de]=Kubismus-Filter +Name[el]=Φίλτρο κυβισμού +Name[eo]=Kubisma filtrilo +Name[es]=Filtro de cubismo +Name[et]=Kubismifilter +Name[fa]=پالایۀ Cubism +Name[fr]=Filtre de cubisme +Name[fy]=Kubismefilter +Name[gl]=Filtro de Cubismo +Name[he]=מסנן קוביסטי +Name[hu]=Kubista szűrő +Name[is]=Teningasía +Name[it]=Filtro cubista +Name[ja]=キュビズムフィルタ +Name[km]=តម្រង​គូប +Name[lt]=Kubizmo filtras +Name[lv]=Kubisma filtrs +Name[nb]=Kubisme-filter +Name[nds]=Wörpel-Filter +Name[ne]=क्यूबिजम फिल्टर +Name[nl]=Kubismefilter +Name[pl]=Filtr kubistyczny +Name[pt]=Filtro de Cubismo +Name[pt_BR]=Filtro de Cubismo +Name[ru]=Кубизм +Name[se]=Kubisma-silli +Name[sk]=Filter kubizmus +Name[sl]=Filter Kubizem +Name[sr]=Кубистички филтер +Name[sr@Latn]=Kubistički filter +Name[sv]=Kubismfilter +Name[uk]=Фільтр кубізму +Name[uz]=Kubizm filteri +Name[uz@cyrillic]=Кубизм филтери +Name[zh_TW]=立體過濾器 +Comment=Cubism filter +Comment[bg]=Кубичен филтър +Comment[ca]=Filtre de cubisme +Comment[cy]=Hidlen Giwbiaeth +Comment[da]=Kubismefilter +Comment[de]=Kubismus-Filter +Comment[el]=Φίλτρο κυβισμού +Comment[eo]=Kubisma filtrilo +Comment[es]=Filtro de cubismo +Comment[et]=Kubismifilter +Comment[fa]=پالایۀ Cubism +Comment[fr]=Filtre de cubisme +Comment[fy]=Kubismefilter +Comment[gl]=Filtro de cubismo +Comment[he]=מסנן קוביסטי +Comment[hu]=Kubista szűrő +Comment[is]=Teningasía +Comment[it]=Filtro cubista +Comment[ja]=キュビズムフィルタ +Comment[km]=តម្រង​គូប +Comment[lt]=Kubizmo filtras +Comment[lv]=Kubisma filtrs +Comment[nb]=Kubisme-filter +Comment[nds]=Wörpel-Filter +Comment[ne]=क्यूबिजम फिल्टर +Comment[nl]=Kubismefilter +Comment[pl]=Filtr kubistyczny +Comment[pt]=Filtro de cubismo +Comment[pt_BR]=Filtro de cubismo +Comment[ru]=Кубизм +Comment[se]=Kubisma-silli +Comment[sk]=Filter kubizmus +Comment[sl]=Filter Kubizem +Comment[sr]=Кубистички филтер +Comment[sr@Latn]=Kubistički filter +Comment[sv]=Kubismfilter +Comment[uk]=Фільтр кубізму +Comment[uz]=Kubizm filteri +Comment[uz@cyrillic]=Кубизм филтери +Comment[zh_TW]=立體過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkcubismfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/cubismfilter/kis_cubism_filter.cc b/chalk/plugins/filters/cubismfilter/kis_cubism_filter.cc new file mode 100644 index 00000000..1cd1aa8d --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_cubism_filter.cc @@ -0,0 +1,453 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_cubism_filter.h" +#include "kis_polygon.h" +#include "kis_point.h" + +#define RANDOMNESS 5 +#define SUPERSAMPLE 4 +#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) +#define SQR(x) ((x) * (x)) + +KisCubismFilter::KisCubismFilter() : KisFilter(id(), "artistic", i18n("&Cubism...")) +{ +} + +bool KisCubismFilter::workWith(KisColorSpace* /*cs*/) +{ + return true; +} + + +void KisCubismFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, + KisFilterConfiguration* configuration, const TQRect& rect) +{ + Q_ASSERT(src); + Q_ASSERT(dst); + Q_ASSERT(configuration); + + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 tileSize = ((KisCubismFilterConfiguration*)configuration)->tileSize(); + TQ_UINT32 tileSaturation = ((KisCubismFilterConfiguration*)configuration)->tileSaturation(); + + KisColorSpace * cs = src->colorSpace(); + TQString id = cs->id().id(); + + if (id == "RGBA" || id == "GRAY" || id == "CMYK") { + cubism(src, dst, rect, tileSize, tileSaturation); + } + else { + if (src->image()) src->image()->lock(); + + KisPaintDeviceSP dev = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temporary"); + KisPainter gc(dev); + gc.bitBlt(0, 0, COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + + kdDebug() << src->colorSpace()->id().id() << endl; + cubism(dev, dev, TQRect(0, 0, rect.width(), rect.height()), tileSize, tileSaturation); + + gc.begin(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, dev, 0, 0, rect.width(), rect.height()); + gc.end(); + if (src->image()) src->image()->unlock(); + + kdDebug() << src->colorSpace()->id().id() << endl; + } +} + +void KisCubismFilter::randomizeIndices (TQ_INT32 count, TQ_INT32* indices) +{ + TQ_INT32 index1, index2; + TQ_INT32 tmp; + + //initialize random number generator with time + srand(static_cast(time(0))); + + for (TQ_INT32 i = 0; i < count * RANDOMNESS; i++) + { + index1 = randomIntNumber(0, count); + index2 = randomIntNumber(0, count); + tmp = indices[index1]; + indices[index1] = indices[index2]; + indices[index2] = tmp; + } +} + +TQ_INT32 KisCubismFilter::randomIntNumber(TQ_INT32 lowestNumber, TQ_INT32 highestNumber) +{ + if(lowestNumber > highestNumber) + { + TQ_INT32 temp = lowestNumber; + lowestNumber = highestNumber; + highestNumber = temp; + } + + return lowestNumber + (( highestNumber - lowestNumber ) * rand() )/ RAND_MAX; +} + +double KisCubismFilter::randomDoubleNumber(double lowestNumber, double highestNumber) +{ + if(lowestNumber > highestNumber) + { + double temp = lowestNumber; + lowestNumber = highestNumber; + highestNumber = temp; + } + + double range = highestNumber - lowestNumber; + return lowestNumber + range * rand() / (double)RAND_MAX; +} + +double KisCubismFilter::calcAlphaBlend (double* vec, double oneOverDist, double x, double y) +{ + + if ( oneOverDist==0 ) + return 1.0; + else + { + double r = (vec[0] * x + vec[1] * y) * oneOverDist; + if (r < 0.2) + r = 0.2; + else if (r > 1.0) + r = 1.0; + return r; + } +} + +void KisCubismFilter::convertSegment (TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2, TQ_INT32 offset, TQ_INT32* min, TQ_INT32* max, TQ_INT32 xmin, TQ_INT32 xmax) +{ + if (y1 > y2) + { + TQ_INT32 tmp = y2; y2 = y1; y1 = tmp; + tmp = x2; x2 = x1; x1 = tmp; + } + TQ_INT32 ydiff = (y2 - y1); + + if (ydiff) + { + double xinc = static_cast(x2 - x1) / static_cast(ydiff); + double xstart = x1 + 0.5 * xinc; + for (TQ_INT32 y = y1 ; y < y2; y++) + { + if(xstart >= xmin && xstart <= xmax) + { + if (xstart < min[y - offset]) + { + min[y-offset] = (int)xstart; + } + if (xstart > max[y - offset]) + { + max[y-offset] = (int)xstart; + } + xstart += xinc; + } + } + } +} + +#define USE_READABLE_BUT_SLOW_CODE + +void KisCubismFilter::fillPolyColor (KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPolygon* poly, const TQ_UINT8* col, TQ_UINT8* /*s*/, TQRect rect) +{ + TQ_INT32 val; + TQ_INT32 alpha; + TQ_UINT8 buf[4]; + TQ_INT32 x, y; + double xx, yy; + double vec[2]; + TQ_INT32 x1 = rect.left(), y1 = rect.top(), x2 = rect.right(), y2 = rect.bottom(); +// TQ_INT32 selWidth, selHeight; + TQ_INT32 *vals, *valsIter, *valsEnd; + TQ_INT32 b; + TQ_INT32 xs, ys, xe, ye; + + + TQ_INT32 sx = (TQ_INT32) (*poly)[0].x(); + TQ_INT32 sy = (TQ_INT32) (*poly)[0].y(); + TQ_INT32 ex = (TQ_INT32) (*poly)[1].x(); + TQ_INT32 ey = (TQ_INT32) (*poly)[1].y(); + + double dist = sqrt (SQR (ex - sx) + SQR (ey - sy)); + double oneOverDist = 0.0; + if (dist > 0.0) + { + double oneOverDist = 1/dist; + vec[0] = (ex - sx) * oneOverDist; + vec[1] = (ey - sy) * oneOverDist; + } + + TQ_INT32 pixelSize = src->pixelSize(); + //get the extents of the polygon + double dMinX, dMinY, dMaxX, dMaxY; + poly->extents (dMinX, dMinY, dMaxX, dMaxY); + TQ_INT32 minX = static_cast(dMinX); + TQ_INT32 minY = static_cast(dMinY); + TQ_INT32 maxX = static_cast(dMaxX); + TQ_INT32 maxY = static_cast(dMaxY); + TQ_INT32 sizeX = (maxX - minX) * SUPERSAMPLE; + TQ_INT32 sizeY = (maxY - minY) * SUPERSAMPLE; + + TQ_INT32 *minScanlines = new TQ_INT32[sizeY]; + TQ_INT32 *minScanlinesIter = minScanlines; + TQ_INT32 *maxScanlines = new TQ_INT32[sizeY]; + TQ_INT32 *maxScanlinesIter = maxScanlines; + + for (TQ_INT32 i = 0; i < sizeY; i++) + { + minScanlines[i] = maxX * SUPERSAMPLE; + maxScanlines[i] = minX * SUPERSAMPLE; + } + + if ( poly->numberOfPoints() ) + { + TQ_INT32 polyNpts = poly->numberOfPoints(); + + xs = static_cast((*poly)[polyNpts-1].x()); + ys = static_cast((*poly)[polyNpts-1].y()); + xe = static_cast((*poly)[0].x()); + ye = static_cast((*poly)[0].y()); + + xs *= SUPERSAMPLE; + ys *= SUPERSAMPLE; + xe *= SUPERSAMPLE; + ye *= SUPERSAMPLE; + + convertSegment (xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE); + + KisPolygon::iterator it; + + for ( it = poly->begin(); it != poly->end(); ) + { + xs = static_cast((*it).x()); + ys = static_cast((*it).y()); + ++it; + + if( it != poly->end() ) + { + xe = static_cast((*it).x()); + ye = static_cast((*it).y()); + + xs *= SUPERSAMPLE; + ys *= SUPERSAMPLE; + xe *= SUPERSAMPLE; + ye *= SUPERSAMPLE; + + convertSegment (xs, ys, xe, ye, minY * SUPERSAMPLE, minScanlines, maxScanlines, minX* SUPERSAMPLE, maxX* SUPERSAMPLE); + } + } + } + + vals = new TQ_INT32[sizeX]; +// x1 = minX; x2 = maxX; y1 = minY; y2 = maxY; + for (TQ_INT32 i = 0; i < sizeY; i++, minScanlinesIter++, maxScanlinesIter++) + { + if (! (i % SUPERSAMPLE)) + { + memset (vals, 0, sizeof( TQ_INT32 ) * sizeX); + } + + yy = static_cast(i) / static_cast(SUPERSAMPLE) + minY; + + for (TQ_INT32 j = *minScanlinesIter; j < *maxScanlinesIter; j++) + { + x = j - minX * SUPERSAMPLE; + vals[x] += 255; + } + + if (! ((i + 1) % SUPERSAMPLE)) + { + y = (i / SUPERSAMPLE) + minY; + if (y >= y1 && y <= y2) + { + for (TQ_INT32 j = 0; j < sizeX; j += SUPERSAMPLE) + { + x = (j / SUPERSAMPLE) + minX; + + if (x >= x1 && x <= x2) + { + for (val = 0, valsIter = &vals[j], valsEnd = &valsIter[SUPERSAMPLE]; valsIter < valsEnd; valsIter++) + { + val += *valsIter; + } + val /= SQR(SUPERSAMPLE); + + if (val > 0) + { + xx = static_cast(j) / static_cast(SUPERSAMPLE) + minX; + alpha = static_cast(val * calcAlphaBlend (vec, oneOverDist, xx - sx, yy - sy)); + +// KisRectIteratorPixel srcIt = src->createRectIterator(x,y,1,1, false); +// const TQ_UINT8* srcPixel = srcIt.oldRawData(); +// memcpy( buf, srcPixel, sizeof(TQ_UINT8) * pixelSize ); + src->readBytes(buf, x, y, 1, 1); + #ifndef USE_READABLE_BUT_SLOW_CODE + TQ_UINT8 *bufIter = buf; + const TQ_UINT8 *colIter = col; + TQ_UINT8 *bufEnd = buf+pixelSize; + + for(; bufIter < bufEnd; bufIter++, colIter++) + *bufIter = (static_cast(*colIter * alpha) + + (static_cast(*bufIter) + * (256 - alpha))) >> 8; + #else //original, pre-ECL code + for (b = 0; b < pixelSize; b++) + { + buf[b] = ((col[b] * alpha) + (buf[b] * (255 - alpha))) / 255; + } + #endif + + dst->writeBytes(buf, x, y, 1, 1); + } + } + } + } + } + } + delete[] vals; + delete[] minScanlines; + delete[] maxScanlines; +} + +void KisCubismFilter::cubism(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, TQ_UINT32 tileSize, TQ_UINT32 tileSaturation) +{ + Q_ASSERT(src); + Q_ASSERT(dst); + + //fill the destination image with the background color (black for now) + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + TQ_INT32 depth = src->colorSpace()->nColorChannels(); + while( ! dstIt.isDone() ) + { + for( TQ_INT32 i = 0; i < depth; i++) + { + dstIt.rawData()[i] = 0; + } + ++dstIt; + } + + //compute number of rows and columns + TQ_INT32 cols = ( rect.width() + tileSize - 1) / tileSize; + TQ_INT32 rows = ( rect.height() + tileSize - 1) / tileSize; + TQ_INT32 numTiles = (rows + 1) * (cols + 1); + + setProgressTotalSteps(numTiles); + setProgressStage(i18n("Applying cubism filter..."),0); + + TQ_INT32* randomIndices = new TQ_INT32[numTiles]; + for (TQ_INT32 i = 0; i < numTiles; i++) + { + randomIndices[i] = i; + } + randomizeIndices (numTiles, randomIndices); + + TQ_INT32 count = 0; + TQ_INT32 i, j, ix, iy; + double x, y, width, height, theta; + KisPolygon *poly = new KisPolygon(); + TQ_INT32 pixelSize = src->pixelSize(); + const TQ_UINT8 *srcPixel /*= new TQ_UINT8[ pixelSize ]*/; + TQ_UINT8 *dstPixel = 0; + while (count < numTiles) + { + i = randomIndices[count] / (cols + 1); + j = randomIndices[count] % (cols + 1); + x = j * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize/2.0) + rect.x(); + y = i * tileSize + (tileSize / 4.0) - randomDoubleNumber(0, tileSize/2.0) + rect.y(); + width = (tileSize + randomDoubleNumber(0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation; + height = (tileSize + randomDoubleNumber (0, tileSize / 4.0) - tileSize / 8.0) * tileSaturation; + theta = randomDoubleNumber(0, 2*M_PI); + poly->clear(); + poly->addPoint( -width / 2.0, -height / 2.0 ); + poly->addPoint( width / 2.0, -height / 2.0 ); + poly->addPoint( width / 2.0, height / 2.0 ); + poly->addPoint( -width / 2.0, height / 2.0 ); + poly->rotate( theta ); + poly->translate ( x, y ); + // bounds check on x, y + ix = (TQ_INT32) CLAMP (x, rect.x(), rect.x() + rect.width() - 1); + iy = (TQ_INT32) CLAMP (y, rect.y(), rect.y() + rect.height() - 1); + + //read the pixel at ix, iy + KisRectIteratorPixel srcIt = src->createRectIterator(ix,iy,1,1, false); + srcPixel = srcIt.oldRawData(); + if (srcPixel[pixelSize - 1]) + { + fillPolyColor (src, dst, poly, srcPixel, dstPixel, rect); + } + count++; + if ((count % 5) == 0) setProgress(count); + } + setProgressDone(); +} + +KisFilterConfigWidget * KisCubismFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 40, 10, i18n("Tile size"), "tileSize" ) ); + param.push_back( KisIntegerWidgetParam( 2, 40, 10, i18n("Tile saturation"), "tileSaturation" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisCubismFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisCubismFilterConfiguration( 10, 10); + } else { + return new KisCubismFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} diff --git a/chalk/plugins/filters/cubismfilter/kis_cubism_filter.h b/chalk/plugins/filters/cubismfilter/kis_cubism_filter.h new file mode 100644 index 00000000..f2624030 --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_cubism_filter.h @@ -0,0 +1,78 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CUBISM_FILTER_H_ +#define _KIS_CUBISM_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" +#include + +class KisPolygon; + +class KisCubismFilterConfiguration : public KisFilterConfiguration +{ +public: + KisCubismFilterConfiguration(TQ_UINT32 tileSize, TQ_UINT32 tileSaturation) + : KisFilterConfiguration( "cubism", 1 ) + , m_tileSize(tileSize) + , m_tileSaturation(tileSaturation) + { + setProperty("tileSize", tileSize); + setProperty("tileSaturation", tileSaturation); + }; +public: + inline TQ_UINT32 tileSize() { return getInt("tileSize"); }; + inline TQ_UINT32 tileSaturation() {return getInt("tileSaturation"); }; +private: + TQ_UINT32 m_tileSize; + TQ_UINT32 m_tileSaturation; +}; + +class KisCubismFilter : public KisFilter +{ +public: + KisCubismFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("cubism", i18n("Cubism")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisCubismFilterConfiguration(10,10)); return list; } + virtual bool workWith(KisColorSpace* cs); + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_RGBA8; }; +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration* configuration() { return new KisCubismFilterConfiguration( 10, 10); }; +private: + //this function takes an array of ordered indices i1,i2,i3,... and randomizes them i3,i1,i2,... + void randomizeIndices (TQ_INT32 count, TQ_INT32* indices); + TQ_INT32 randomIntNumber(TQ_INT32 lowestNumber, TQ_INT32 highestNumber); + double randomDoubleNumber(double lowestNumber, double highestNumber); + double calcAlphaBlend(double *vec, double oneOverDist, double x, double y); + void convertSegment(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2, TQ_INT32 offset, TQ_INT32* min, TQ_INT32* max, TQ_INT32 xmin, TQ_INT32 xmax); + void fillPolyColor(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisPolygon* poly, const TQ_UINT8* col, TQ_UINT8* dest, TQRect rect); + void cubism(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, TQ_UINT32 tileSize, TQ_UINT32 tileSaturation); + +}; + +#endif diff --git a/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc b/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc new file mode 100644 index 00000000..4e7dfa7d --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.cc @@ -0,0 +1,42 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_cubism_filter_plugin.h" +#include "kis_cubism_filter.h" + +typedef KGenericFactory KisCubismFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcubismfilter, KisCubismFilterPluginFactory( "chalk" ) ) + +KisCubismFilterPlugin::KisCubismFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) : KParts::Plugin(tqparent, name) +{ + setInstance(KisCubismFilterPluginFactory::instance()); + + if ( tqparent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(tqparent); + r->add(new KisCubismFilter()); + } +} + +KisCubismFilterPlugin::~KisCubismFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h b/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h new file mode 100644 index 00000000..b37e40c1 --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_cubism_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_CUBISM_FILTER_PLUGIN_H_ +#define _KIS_CUBISM_FILTER_PLUGIN_H_ + +#include + +class KisCubismFilterPlugin : public KParts::Plugin +{ +public: + KisCubismFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisCubismFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/cubismfilter/kis_polygon.cc b/chalk/plugins/filters/cubismfilter/kis_polygon.cc new file mode 100644 index 00000000..cd2d979f --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_polygon.cc @@ -0,0 +1,102 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#include "kis_polygon.h" + +void KisPolygon::addPoint(double x, double y) +{ + KisPoint point(x, y); + append(point); +} + +void KisPolygon::rotate(double theta) +{ + double ct, st, ox, oy; + + ct = cos( theta ); + st = sin( theta ); + + KisPointVector::iterator it; + for( it = begin(); it != end(); ++it ) + { + ox = (*it).x(); + oy = (*it).y(); + (*it).setX( ct * ox - st * oy ); + (*it).setY( st * ox + ct * oy ); + } +} + +void KisPolygon::translate(double tx, double ty) +{ + KisPointVector::iterator it; + + for( it = begin(); it != end(); ++it ) + { + (*it).setX( (*it).x() + tx ); + (*it).setY( (*it).y() + ty ); + } +} + +TQ_INT32 KisPolygon::extents (double& x1, double& y1, double& x2, double& y2) +{ + if ( empty() ) + { + return 0; + } + x1 = x2 = front().x(); + y1 = y2 = front().y(); + + KisPointVector::iterator it; + + for( it = begin(); it != end(); ++it ) + { + if ((*it).x() < x1) + { + x1 = (*it).x(); + } + if ((*it).x() > x2) + { + x2 = (*it).x(); + } + if ((*it).y() < y1) + { + y1 = (*it).y(); + } + if ((*it).y() > y2) + { + y2 = (*it).y(); + } + } + return 1; +} + +TQ_INT32 KisPolygon::numberOfPoints() +{ + return count(); +} + diff --git a/chalk/plugins/filters/cubismfilter/kis_polygon.h b/chalk/plugins/filters/cubismfilter/kis_polygon.h new file mode 100644 index 00000000..372ef18b --- /dev/null +++ b/chalk/plugins/filters/cubismfilter/kis_polygon.h @@ -0,0 +1,37 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_POLYGON_H_ +#define _KIS_POLYGON_H_ + +#include + +typedef TQValueVector KisPointVector; +class KisPolygon : public KisPointVector +{ + public: + void addPoint(double x, double y); + void translate(double tx, double ty); + void rotate(double theta); + TQ_INT32 extents(double &minX, double &minY, double &maxX, double &maxY); + TQ_INT32 numberOfPoints(); +}; + +#endif diff --git a/chalk/plugins/filters/embossfilter/Makefile.am b/chalk/plugins/filters/embossfilter/Makefile.am new file mode 100644 index 00000000..eaf403f4 --- /dev/null +++ b/chalk/plugins/filters/embossfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = chalkembossfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + -I$(srcdir)/../../../../lib/kofficeui \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkembossfilter.la + +chalkembossfilter_la_SOURCES = kis_emboss_filter_plugin.cc \ + kis_emboss_filter.cc + +noinst_HEADERS = kis_emboss_filter_plugin.h \ + kis_emboss_filter.h + +chalkembossfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkembossfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkembossfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/embossfilter/chalkembossfilter.desktop b/chalk/plugins/filters/embossfilter/chalkembossfilter.desktop new file mode 100644 index 00000000..af04bb1f --- /dev/null +++ b/chalk/plugins/filters/embossfilter/chalkembossfilter.desktop @@ -0,0 +1,71 @@ +[Desktop Entry] +Name=Emboss Filter +Name[bg]=Релефен филтър +Name[ca]=Filtre d'Emboss +Name[cy]=Hidlen Foglynnu +Name[da]=Relieffilter +Name[de]=Relief-Filter +Name[el]=Φίλτρο εμβάθυνσης +Name[eo]=Reliefiga filtrilo +Name[es]=Filtro de realce +Name[et]=Kohrutusfilter +Name[fa]=برجسته کردن پالایه +Name[fr]=Filtre gravure +Name[fy]=Reliëffilter +Name[gl]=Filtro de Gravado +Name[hu]=Emboss szűrő +Name[is]=Upphleypt sía +Name[it]=Filtro in rilievo +Name[ja]=エンボスフィルタ +Name[km]=តម្រង​ក្រឡោប +Name[nb]=Pregefilter +Name[nds]=Ingraven-Filter +Name[ne]=अलंकृत फिल्टर +Name[nl]=Reliëffilter +Name[pl]=Filtr wytłaczania +Name[pt]=Filtro de Gravação +Name[pt_BR]=Filtro de Relevo +Name[ru]=Рельеф +Name[sl]=Filter Izboči +Name[sr]=Рељефни филтер +Name[sr@Latn]=Reljefni filter +Name[sv]=Relieffilter +Name[uk]=Фільтр барельєфу +Name[zh_TW]=浮雕過濾器 +Comment=Emboss filter +Comment[bg]=Релефен филтър +Comment[ca]=Filtre d'Emboss +Comment[cy]=Hidlen foglynnu +Comment[da]=Relieffilter +Comment[de]=Relief-Filter +Comment[el]=Φίλτρο εμβάθυνσης +Comment[eo]=Reliefiga filtrilo +Comment[es]=Filtro de realce +Comment[et]=Kohrutusfilter +Comment[fa]=برجسته کردن پالایه +Comment[fr]=Filtre gravure +Comment[fy]=Reliëffilter +Comment[gl]=Filtro de gravado +Comment[hu]=Emboss szűrő +Comment[is]=Upphleypt sía +Comment[it]=Filtro in rilievo +Comment[ja]=エンボスフィルタ +Comment[km]=តម្រង​ក្រឡោប +Comment[nb]=Pregefilter +Comment[nds]=Ingraven-Filter +Comment[ne]=अलंकृत फिल्टर +Comment[nl]=Reliëffilter +Comment[pl]=Filtr wytłaczania +Comment[pt]=Filtro de gravação +Comment[pt_BR]=Filtro de relevo +Comment[ru]=Рельеф +Comment[sl]=Filter Izboči +Comment[sr]=Рељефни филтер +Comment[sr@Latn]=Reljefni filter +Comment[sv]=Relieffilter +Comment[uk]=Фільтр барельєфу +Comment[zh_TW]=浮雕過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkembossfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/embossfilter/kis_emboss_filter.cc b/chalk/plugins/filters/embossfilter/kis_emboss_filter.cc new file mode 100644 index 00000000..f15b5952 --- /dev/null +++ b/chalk/plugins/filters/embossfilter/kis_emboss_filter.cc @@ -0,0 +1,179 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * ported from digikam, Copyright 2004 by Gilles Caulier, + * Original Emboss algorithm copyrighted 2004 by + * Pieter Z. Voloshyn . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_emboss_filter.h" + +KisEmbossFilter::KisEmbossFilter() : KisFilter(id(), "emboss", i18n("&Emboss with Variable Depth...")) +{ +} + +void KisEmbossFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + Q_UNUSED(dst); + + + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 embossdepth = ((KisEmbossFilterConfiguration*)configuration)->depth(); + + //the actual filter function from digikam. It needs a pointer to a TQ_UINT8 array + //with the actual pixel data. + + Emboss(src, dst, rect, embossdepth); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to apply the Emboss effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * d => Emboss value + * + * Theory => This is an amazing effect. And the theory is very simple to + * understand. You get the diference between the colors and + * increase it. After this, get the gray tone + */ + +void KisEmbossFilter::Emboss(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, int d) +{ + float Depth = d / 10.0; + int R = 0, G = 0, B = 0; + uchar Gray = 0; + int Width = rect.width(); + int Height = rect.height(); + + setProgressTotalSteps(Height); + setProgressStage(i18n("Applying emboss filter..."),0); + + KisHLineIteratorPixel it = src->createHLineIterator(rect.x(), rect.y(), rect.width(), false); + KisHLineIteratorPixel dstIt = dst->createHLineIterator(rect.x(), rect.y(), rect.width(), true); + TQColor color1; + TQColor color2; + TQ_UINT8 opacity; + TQ_UINT8 opacity2; + + for (int y = 0 ; !cancelRequested() && (y < Height) ; ++y) + { + + for (int x = 0 ; !cancelRequested() && (x < Width) ; ++x, ++it, ++dstIt) + { + if (it.isSelected()) { + +// XXX: COLORSPACE_INDEPENDENCE + opacity = 0; + opacity2 = 0; + + src->colorSpace()->toTQColor(it.rawData(), &color1, &opacity); + + src->pixel(rect.x() + x + Lim_Max(x, 1, Width), rect.y() + y + Lim_Max(y, 1, Height), &color2, &opacity2); + + R = abs((int)((color1.red() - color2.red()) * Depth + (TQ_UINT8_MAX / 2))); + G = abs((int)((color1.green() - color2.green()) * Depth + (TQ_UINT8_MAX / 2))); + B = abs((int)((color1.blue() - color2.blue()) * Depth + (TQ_UINT8_MAX / 2))); + + Gray = CLAMP((R + G + B) / 3, 0, TQ_UINT8_MAX); + + dst->colorSpace()->fromTQColor(TQColor(Gray, Gray, Gray), opacity, dstIt.rawData()); + } + } + + it.nextRow(); + dstIt.nextRow(); + setProgress(y); + } + + setProgressDone(); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* This function limits the max and min values + * defined by the developer + * + * Now => Original value + * Up => Increments + * Max => Maximum value + * + * Theory => This function is used in some functions to limit the + * "for step". E.g. I have a picture with 309 pixels (width), and + * my "for step" is 5. All the code go alright until reachs the + * w = 305, because in the next step w will go to 310, but we want + * to analize all the pixels. So, this function will reduce the + * "for step", when necessary, until reach the last possible value + */ + +int KisEmbossFilter::Lim_Max (int Now, int Up, int Max) +{ + --Max; + while (Now > Max - Up) + --Up; + return (Up); +} + +KisFilterConfigWidget * KisEmbossFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 10, 300, 30, i18n("Depth"), "depth" ) ); + KisFilterConfigWidget * w = new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); + Q_CHECK_PTR(w); + return w; +} + +KisFilterConfiguration* KisEmbossFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisEmbossFilterConfiguration( 30 ); + } else { + return new KisEmbossFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/chalk/plugins/filters/embossfilter/kis_emboss_filter.h b/chalk/plugins/filters/embossfilter/kis_emboss_filter.h new file mode 100644 index 00000000..fe4410ed --- /dev/null +++ b/chalk/plugins/filters/embossfilter/kis_emboss_filter.h @@ -0,0 +1,62 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef _KIS_EMBOSS_FILTER_H_ +#define _KIS_EMBOSS_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisEmbossFilterConfiguration : public KisFilterConfiguration +{ +public: + KisEmbossFilterConfiguration(TQ_UINT32 depth) + : KisFilterConfiguration( "emboss", 1 ) + { + setProperty("depth", depth); + }; +public: + inline TQ_UINT32 depth() { return getInt("depth"); }; +}; + +class KisEmbossFilter : public KisFilter +{ +public: + KisEmbossFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("emboss", i18n("Emboss")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers() { return false; }; + + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisEmbossFilterConfiguration(100)); return list; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration* configuration() {return new KisEmbossFilterConfiguration( 30 );}; + +private: + void Emboss(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, int d); + inline int Lim_Max (int Now, int Up, int Max); +}; + +#endif diff --git a/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc b/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc new file mode 100644 index 00000000..4aec1db6 --- /dev/null +++ b/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.cc @@ -0,0 +1,40 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_emboss_filter_plugin.h" +#include "kis_emboss_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisEmbossFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkembossfilter, KisEmbossFilterPluginFactory( "chalk" ) ) + +KisEmbossFilterPlugin::KisEmbossFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) : KParts::Plugin(tqparent, name) +{ + setInstance(KisEmbossFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisEmbossFilter()); + } +} + +KisEmbossFilterPlugin::~KisEmbossFilterPlugin() +{ +} diff --git a/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.h b/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.h new file mode 100644 index 00000000..39803418 --- /dev/null +++ b/chalk/plugins/filters/embossfilter/kis_emboss_filter_plugin.h @@ -0,0 +1,32 @@ +/* This file is part of the KDE project + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_EMBOSS_FILTER_PLUGIN_H_ +#define _KIS_EMBOSS_FILTER_PLUGIN_H_ + +#include + +class KisEmbossFilterPlugin : public KParts::Plugin +{ +public: + KisEmbossFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisEmbossFilterPlugin(); +}; + +#endif + diff --git a/chalk/plugins/filters/example/Makefile.am b/chalk/plugins/filters/example/Makefile.am new file mode 100644 index 00000000..f2f39c3a --- /dev/null +++ b/chalk/plugins/filters/example/Makefile.am @@ -0,0 +1,22 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkexample.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkexample_la_SOURCES = example.cc + +kde_module_LTLIBRARIES = chalkexample.la +noinst_HEADERS = example.h + +chalkexample_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkexample_la_LIBADD = ../../../libchalkcommon.la + +chalkexample_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/example/chalkexample.desktop b/chalk/plugins/filters/example/chalkexample.desktop new file mode 100644 index 00000000..e9fc3447 --- /dev/null +++ b/chalk/plugins/filters/example/chalkexample.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Name=Invert Filter +Name[bg]=Инвертиращ филтър +Name[ca]=Inverteix filtre +Name[cy]=Hidlen Wrthdroi +Name[da]=Inverteringsfilter +Name[de]=Invertierungsfilter +Name[el]=Φίλτρο αντιστροφής +Name[eo]=Inversiga filtrilo +Name[es]=Filtro de inversión +Name[et]=Inverteerimisfilter +Name[fa]=پالایۀ وارونه +Name[fr]=Filtre d'inversion +Name[fy]=Omdraaifilter +Name[ga]=Scagaire Inbhéartaithe +Name[gl]=Filtro de Inversión +Name[hu]=Invertáló szűrő +Name[is]=Andhverf sía +Name[it]=File di inversione +Name[ja]=反転フィルタ +Name[km]=តម្រង​បញ្ច្រាស +Name[lt]=Invertavimo filtras +Name[nb]=Inverteringsfilter +Name[nds]=Ümdreih-Filter +Name[ne]=फिल्टर उल्टाउनुहोस् +Name[nl]=Inversefilter +Name[pl]=Filtr inwersji +Name[pt]=Filtro de Inversão +Name[pt_BR]=Filtro de Inversão +Name[ru]=Инвертирование +Name[se]=Inverterensilli +Name[sk]=Inverzný Filter +Name[sl]=Filter za obračanje +Name[sr]=Филтер за инверзију +Name[sr@Latn]=Filter za inverziju +Name[sv]=Inverteringsfilter +Name[uk]=Фільтр інвертування +Name[zh_TW]=倒轉過濾器 +Comment=Invert the colors of an image +Comment[bg]=Инвертиращ филтър +Comment[ca]=Inverteix els colors d'una imatge +Comment[cy]=Gwrthdroi lliwiau delwedd +Comment[da]=Invertér farverne i et billede +Comment[de]=Die Farben eines Bildes invertieren +Comment[el]=Αντιστροφή των χρωμάτων μίας εικόνας +Comment[en_GB]=Invert the colours of an image +Comment[eo]=Inversigi la kolorojn de bildo +Comment[es]=Invierte los colores de una imagen +Comment[et]=Inverteerib pildi värvid +Comment[fa]=وارونه کردن رنگهای یک تصویر +Comment[fr]=Inverse les couleurs de l'image +Comment[fy]=Draaid de kleuren fan in ôfbylding om +Comment[gl]=Inverte as cores dunha imaxe +Comment[hu]=Egy kép színeinek invertálása +Comment[is]=Snúðu litum myndarinnar +Comment[it]=Inverte i colori di un'immagine +Comment[ja]=画像の色を反転 +Comment[km]=បញ្ច្រាស​ពណ៌​រូបភាព +Comment[lt]=Invertuoja paveikslėlio spalvas +Comment[nb]=Snu om fargene i et bilde +Comment[nds]=De Klören vun en Bild ümdreihen +Comment[ne]=एउटा छविको रङहरू उल्टाउनुहोस् +Comment[nl]=Keert de kleuren van een afbeelding om +Comment[pl]=Odwraca kolory obrazka +Comment[pt]=Inverter as cores de uma imagem +Comment[pt_BR]=Inverter as cores de uma imagem +Comment[ru]=Инвертировать цвета изображения +Comment[se]=Invertere ivnniid govas +Comment[sk]=Invertovať farby obrázku +Comment[sl]=Preobrni barve v sliki +Comment[sr]=Инвертује боје на слици +Comment[sr@Latn]=Invertuje boje na slici +Comment[sv]=Invertera färgerna i en bild +Comment[uk]=Інвертація кольорів зображення +Comment[uz]=Rasmning ranglarini teskarisiga almashtirish +Comment[uz@cyrillic]=Расмнинг рангларини тескарисига алмаштириш +Comment[zh_TW]=倒轉圖片的色彩 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkexample +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/example/example.cc b/chalk/plugins/filters/example/example.cc new file mode 100644 index 00000000..2e2fbc7c --- /dev/null +++ b/chalk/plugins/filters/example/example.cc @@ -0,0 +1,95 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// #include + +#include "example.h" + +typedef KGenericFactory ChalkExampleFactory; +K_EXPORT_COMPONENT_FACTORY( chalkexample, ChalkExampleFactory( "chalk" ) ) + +ChalkExample::ChalkExample(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkExampleFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterInvert()); + } +} + +ChalkExample::~ChalkExample() +{ +} + +KisFilterInvert::KisFilterInvert() : KisFilter(id(), "adjust", i18n("&Invert")) +{ +} + +void KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 psize = cs->pixelSize(); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + if (src!=dst) + memcpy(dstIt.rawData(), srcIt.oldRawData(), psize); + + cs->invertColor( dstIt.rawData(), 1); + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/example/example.h b/chalk/plugins/filters/example/example.h new file mode 100644 index 00000000..df49d036 --- /dev/null +++ b/chalk/plugins/filters/example/example.h @@ -0,0 +1,47 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef EXAMPLE_H +#define EXAMPLE_H + +#include +#include "kis_filter.h" + +class ChalkExample : public KParts::Plugin +{ +public: + ChalkExample(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkExample(); +}; + +class KisFilterInvert : public KisFilter +{ +public: + KisFilterInvert(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("invert", i18n("Invert")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } +}; + +#endif diff --git a/chalk/plugins/filters/fastcolortransfer/Makefile.am b/chalk/plugins/filters/fastcolortransfer/Makefile.am new file mode 100644 index 00000000..f29b7a3b --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkfastcolortransfer.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkfastcolortransfer_la_SOURCES = wdgfastcolortransfer.ui fastcolortransfer.cc \ + kis_wdg_fastcolortransfer.cpp + +kde_module_LTLIBRARIES = chalkfastcolortransfer.la +noinst_HEADERS = fastcolortransfer.h kis_wdg_fastcolortransfer.h + +chalkfastcolortransfer_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficecore/.libs -lkofficecore +chalkfastcolortransfer_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO diff --git a/chalk/plugins/filters/fastcolortransfer/chalkfastcolortransfer.desktop b/chalk/plugins/filters/fastcolortransfer/chalkfastcolortransfer.desktop new file mode 100644 index 00000000..cc32f72b --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/chalkfastcolortransfer.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Comment=This plugins allow to transfer color from an image to an other image +Comment[bg]=Тази приставка позволява прехвърлянето на цвят от едно в друго изображение +Comment[ca]=Aquest endollats permeten de transferir el color d'una imatge a una altra +Comment[da]=Dette plugin gør det muligt at overføre en farve fra et billede til et andet billede +Comment[de]=Diese Module ermöglichen die Farbübertragung von einem Bild zu einem anderen +Comment[el]=Αυτό το πρόσθετο επιτρέπει τη μεταφορά χρώματος από μια εικόνα σε κάποια άλλη +Comment[es]=Este complemento le permite transferir colores de una imagen a otra +Comment[et]=See plugin võimaldab värvi ühelt pildilt teisele üle kanda +Comment[fa]=این وصله اجازۀ انتقال رنگ از یک تصویر به تصویر دیگر را می‌دهد +Comment[fr]=Ce module permet de transférer une couleur d'une image à une autre +Comment[fy]=Mei dizze plugin kinne jo kleur fan in ôfbylding nei in oare oersette +Comment[gl]=Estas extensión permiten transferir cor dunha imaxe a outra +Comment[hu]=Színek átvitele egyik képről a másikra +Comment[it]=Questo plugin permette di trasferire il colore da un'immagine a un'altra +Comment[ja]=このプラグインは他の画像から色を移植することを可能にします +Comment[km]=កម្មវិធី​ជំនួយ​នេះ​អនុញ្ញាត​ឲ្យ​ផ្ទេរ​ពណ៌​ពី​រូបភាព​មួយ​ទៅ​រូបភាព​មួយ​ផ្សេងទៀត​ +Comment[nb]=Med dette programtillegget kan farger overføres fra ett bilde til et annet +Comment[nds]=Mit dissen Moduul laat sik Klören vun een Bild na en anner överdregen +Comment[ne]=यो प्लगइनले एउटा छविबाट अर्को छविमा रङ स्थान्तरण गर्न अनुमति दिन्छ +Comment[nl]=Met deze plugin kunt u kleur van een afbeelding naar een andere overzetten +Comment[pl]=Ta wtyczka pozwala na przeniesienie koloru z jednego obrazka do drugiego +Comment[pt]=Este 'plugin' permite transferir a cor de uma imagem para outra +Comment[pt_BR]=Este plugin permite transferir a cor de uma imagem para outra +Comment[ru]=Перенос цвета из одного изображения в другое +Comment[sk]=Tieto moduly umožňujú presúvať farby medzi obrázkami +Comment[sl]=Ta vstavek omogoča prenos barve iz ene slike v drugo +Comment[sr]=Овај прикључак омогућава пренос боје са једне на другу слику +Comment[sr@Latn]=Ovaj priključak omogućava prenos boje sa jedne na drugu sliku +Comment[sv]=Insticksprogrammet gör det möjligt att överföra en färg från en bild till en annan bild +Comment[uk]=Перенесення кольору з одного зображення в інше +Comment[zh_TW]=這個外掛程式允許將一張圖片的顏色轉換為另一張圖片 +Icon= +Name=Color Transfer Filter +Name[bg]=Филтри за прехвърляне на цвят +Name[ca]=Filtre de transferència de color +Name[da]=Farveoverførselsfilter +Name[de]=Farbübertragungsfilter +Name[el]=Φίλτρο μεταφοράς χρώματος +Name[eo]=Kolortransiga filtrilo +Name[es]=Filtro de transferencia de color +Name[et]=Värviülekande filter +Name[fa]=پالایۀ انتقال رنگ +Name[fr]=Filtres de transfert de couleur +Name[fy]=Kleuroersetfilter +Name[gl]=Filtros de Transferencia de Cores +Name[hu]=Színátviteli szűrő +Name[it]=Filtro di trasferimento del colore +Name[ja]=色移植フィルタ +Name[km]=តម្រង​ផ្ទេរ​ពណ៌​ +Name[nb]=Fargeoverføringsfilter +Name[nds]=Klööröverdregenfilter +Name[ne]=रङ स्थान्तरण फिल्टर +Name[nl]=Kleuroverzetfilter +Name[pl]=Filtr przeniesienia koloru +Name[pt]=Filtro de Transferência de Cores +Name[pt_BR]=Filtros de Transferência de Cores +Name[ru]=Перенос цвета +Name[sk]=Filter na premenu farieb +Name[sl]=Filter za prenos barve +Name[sr]=Филтер за пренос боја +Name[sr@Latn]=Filter za prenos boja +Name[sv]=Färgöverföringsfilter +Name[uk]=Перенесення кольору +Name[zh_TW]=色彩轉換過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkfastcolortransfer +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.cc b/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.cc new file mode 100644 index 00000000..10ef044d --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.cc @@ -0,0 +1,206 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "fastcolortransfer.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_fastcolortransfer.h" +#include "wdgfastcolortransfer.h" + +typedef KGenericFactory ChalkFastColorTransferFactory; +K_EXPORT_COMPONENT_FACTORY( chalkfastcolortransfer, ChalkFastColorTransferFactory( "chalk" ) ) + + +FastColorTransferPlugin::FastColorTransferPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkFastColorTransferFactory::instance()); + + kdDebug(41006) << "Color Transfer Filter plugin. Class: " + << className() + << ", Parent: " + << tqparent -> className() + << "\n"; + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterFastColorTransfer()); + } +} + +FastColorTransferPlugin::~FastColorTransferPlugin() +{ +} + +KisFilterFastColorTransfer::KisFilterFastColorTransfer() : KisFilter(id(), "colors", i18n("&Color Transfer...")) +{ +} + + +KisFilterConfigWidget * KisFilterFastColorTransfer::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + return new KisWdgFastColorTransfer(this, tqparent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisFilterFastColorTransfer::configuration(TQWidget* w) +{ + KisWdgFastColorTransfer * wCTA = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wCTA) + { + config->setProperty("filename", wCTA->widget()->fileNameURLRequester->url() ); + } + return config; +} + +void KisFilterFastColorTransfer::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + kdDebug() << "Start transfering color" << endl; + TQVariant value; + TQString fileName; + if (config && config->getProperty("filename", value)) + { + fileName = value.toString(); + } else { + kdDebug() << "No file name for the reference image was specified." << endl; + return; + } + + KisPaintDeviceSP ref; + + KisDoc d; + d.import(fileName); + KisImageSP importedImage = d.currentImage(); + + if(importedImage) + { + ref = importedImage->projection(); + } + if(!ref) + { + kdDebug() << "No reference image was specified." << endl; + return; + } + + // Convert ref and src to LAB + KisColorSpace* labCS = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("LABA"),""); + if(!labCS) + { + kdDebug() << "The LAB colorspace is not available." << endl; + return; + } + + setProgressTotalSteps(5); + + KisColorSpace* oldCS = src->colorSpace(); + KisPaintDeviceSP srcLAB = new KisPaintDevice(*src.data()); + srcLAB->convertTo(labCS); + ref->convertTo(labCS); + + setProgress( 1 ); + + // Compute the means and sigmas of src + double meanL_src = 0., meanA_src = 0., meanB_src = 0.; + double sigmaL_src = 0., sigmaA_src = 0., sigmaB_src = 0.; + KisRectIteratorPixel srcLABIt = srcLAB->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false ); + while(!srcLABIt.isDone()) + { + const TQ_UINT16* data = reinterpret_cast(srcLABIt.oldRawData()); + TQ_UINT32 L = data[0]; + TQ_UINT32 A = data[1]; + TQ_UINT32 B = data[2]; + meanL_src += L; + meanA_src += A; + meanB_src += B; + sigmaL_src += L*L; + sigmaA_src += A*A; + sigmaB_src += B*B; + ++srcLABIt; + } + + setProgress( 3 ); + + double size = 1. / ( rect.width() * rect.height() ); + meanL_src *= size; + meanA_src *= size; + meanB_src *= size; + sigmaL_src *= size; + sigmaA_src *= size; + sigmaB_src *= size; + kdDebug() << size << " " << meanL_src << " " << meanA_src << " " << meanB_src << " " << sigmaL_src << " " << sigmaA_src << " " << sigmaB_src << endl; + // Compute the means and sigmas of src + double meanL_ref = 0., meanA_ref = 0., meanB_ref = 0.; + double sigmaL_ref = 0., sigmaA_ref = 0., sigmaB_ref = 0.; + KisRectIteratorPixel refIt = ref->createRectIterator(0, 0, importedImage->width(), importedImage->height(), false ); + while(!refIt.isDone()) + { + const TQ_UINT16* data = reinterpret_cast(refIt.oldRawData()); + TQ_UINT32 L = data[0]; + TQ_UINT32 A = data[1]; + TQ_UINT32 B = data[2]; + meanL_ref += L; + meanA_ref += A; + meanB_ref += B; + sigmaL_ref += L*L; + sigmaA_ref += A*A; + sigmaB_ref += B*B; + ++refIt; + } + + setProgress( 4 ); + + size = 1. / ( importedImage->width() * importedImage->height() ); + meanL_ref *= size; + meanA_ref *= size; + meanB_ref *= size; + sigmaL_ref *= size; + sigmaA_ref *= size; + sigmaB_ref *= size; + kdDebug() << size << " " << meanL_ref << " " << meanA_ref << " " << meanB_ref << " " << sigmaL_ref << " " << sigmaA_ref << " " << sigmaB_ref << endl; + + // Transfer colors + dst->convertTo(labCS); + { + double coefL = sqrt((sigmaL_ref - meanL_ref * meanL_ref) / (sigmaL_src - meanL_src * meanL_src)); + double coefA = sqrt((sigmaA_ref - meanA_ref * meanA_ref) / (sigmaA_src - meanA_src * meanA_src)); + double coefB = sqrt((sigmaB_ref - meanB_ref * meanB_ref) / (sigmaB_src - meanB_src * meanB_src)); + kdDebug() << coefL << " " << coefA << " " << coefB << endl; + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + while(!dstIt.isDone()) + { + TQ_UINT16* data = reinterpret_cast(dstIt.rawData()); + data[0] = (TQ_UINT16)CLAMP( ( (double)data[0] - meanL_src) * coefL + meanL_ref, 0., 65535.); + data[1] = (TQ_UINT16)CLAMP( ( (double)data[1] - meanA_src) * coefA + meanA_ref, 0., 65535.); + data[2] = (TQ_UINT16)CLAMP( ( (double)data[2] - meanB_src) * coefB + meanB_ref, 0., 65535.); + ++dstIt; + } + } + dst->convertTo(oldCS); + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.h b/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.h new file mode 100644 index 00000000..d8a3c898 --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/fastcolortransfer.h @@ -0,0 +1,55 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLORTRANSFER_H +#define COLORTRANSFER_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include +#include + +class FastColorTransferPlugin : public KParts::Plugin +{ + public: + FastColorTransferPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~FastColorTransferPlugin(); +}; + +class KisFilterFastColorTransfer : public KisFilter +{ + public: + KisFilterFastColorTransfer(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("colortransfer", i18n("Color Transfer")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp b/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp new file mode 100644 index 00000000..3c08cac3 --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_fastcolortransfer.h" + +#include + +#include + +#include "wdgfastcolortransfer.h" + +KisWdgFastColorTransfer::KisWdgFastColorTransfer(KisFilter* nfilter, TQWidget * tqparent, const char * name) : KisFilterConfigWidget ( tqparent, name ) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgFastColorTransfer(this); + widgetLayout -> addWidget(m_widget,0,0); + connect(m_widget->fileNameURLRequester, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SIGNAL(sigPleaseUpdatePreview())); +} + + +KisWdgFastColorTransfer::~KisWdgFastColorTransfer() +{ +} + +void KisWdgFastColorTransfer::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("filename", value)) + { + widget()->fileNameURLRequester->setURL( value.toString() ); + } + +} diff --git a/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h b/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h new file mode 100644 index 00000000..0a29aef5 --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/kis_wdg_fastcolortransfer.h @@ -0,0 +1,47 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WDG_COLORTRANSFER_H +#define KIS_WDG_COLORTRANSFER_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class KisFilter; +class WdgFastColorTransfer; + +/** + @author Cyrille Berger +*/ +class KisWdgFastColorTransfer : public KisFilterConfigWidget +{ + public: + KisWdgFastColorTransfer(KisFilter* nfilter, TQWidget * tqparent, const char * name); + ~KisWdgFastColorTransfer(); + virtual void setConfiguration(KisFilterConfiguration*); + inline WdgFastColorTransfer* widget() { return m_widget; } + private: + WdgFastColorTransfer* m_widget; +}; + +#endif diff --git a/chalk/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui b/chalk/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui new file mode 100644 index 00000000..a7184b4b --- /dev/null +++ b/chalk/plugins/filters/fastcolortransfer/wdgfastcolortransfer.ui @@ -0,0 +1,75 @@ + +WdgFastColorTransfer + + + WdgFastColorTransfer + + + + 0 + 0 + 236 + 112 + + + + + unnamed + + + 0 + + + + tqlayout1 + + + + unnamed + + + + label1 + + + Reference image: + + + + + fileNameURLRequester + + + Filename of the image whose tones and color you want to transfer to the current layer. + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 101 + + + + + + + + + + kurlrequester.h + klineedit.h + kpushbutton.h + + diff --git a/chalk/plugins/filters/halftone/kis_halftone.cpp b/chalk/plugins/filters/halftone/kis_halftone.cpp new file mode 100644 index 00000000..35e838ed --- /dev/null +++ b/chalk/plugins/filters/halftone/kis_halftone.cpp @@ -0,0 +1,190 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005-2006 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_halftone.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + typedef KGenericFactory ChalkHalftoneFactory; +K_EXPORT_COMPONENT_FACTORY( chalkhalftone, ChalkHalftoneFactory( "chalk" ) ) + + ChalkHalftone::ChalkHalftone(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkHalftoneFactory::instance()); + + kdDebug(41006) << "Halftone filter plugin. Class: " + << className() + << ", Parent: " + << tqparent->className() + << "\n"; + + + if ( tqparent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(tqparent); + r->add(new KisHalftoneReduction()); + } +} + +ChalkHalftone::~ChalkHalftone() +{ +} + + + +KisHalftoneReduction::KisHalftoneReduction() + : KisFilter(id(), "enhance", i18n("Halftone Reduction...")) +{ +} + + +KisHalftoneReduction::~KisHalftoneReduction() +{ +} + +KisFilterConfigWidget * KisHalftoneReduction::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 0, 100, BEST_WAVELET_FREQUENCY_VALUE, i18n("Frequency"), "frequency" ) ); + param.push_back( KisIntegerWidgetParam( 0, 100, 2, i18n("Half-size"), "halfsize" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisHalftoneReduction::configuration(TQWidget* nwidget ) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisHalftoneReductionConfiguration( BEST_WAVELET_FREQUENCY_VALUE, 2 ); + } else { + return new KisHalftoneReductionConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} + +void KisHalftoneReduction::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + + float frequency = 1.0; + int halfSize = 2; + + if(config !=0) + { + KisHalftoneReductionConfiguration* configWNRC = (KisHalftoneReductionConfiguration*)config; + frequency = configWNRC->getDouble("frequency"); + halfSize = configWNRC->getInt("halfsize"); + kdDebug(41005) << "frequency: " << frequency << endl; + } + + + TQ_INT32 depth = src->colorSpace()->nColorChannels(); + + int size; + int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); + for(size = 2; size < maxrectsize; size *= 2) ; + + KisMathToolbox* mathToolbox = KisMetaRegistry::instance()->mtRegistry()->get( src->colorSpace()->mathToolboxID() ); + setProgressTotalSteps(mathToolbox->fastWaveletTotalSteps(rect) * 2 + size*size*depth ); + connect(mathToolbox, TQT_SIGNAL(nextStep()), this, TQT_SLOT(incProgress())); + + + kdDebug(41005) << size << " " << maxrectsize << " " << rect.x() << " " << rect.y() << endl; + + kdDebug(41005) << halfSize << endl; + KisAutobrushShape* kas = new KisAutobrushCircleShape(2*halfSize+1, 2*halfSize+1 , halfSize, halfSize); + + TQImage tqmask; + kas->createBrush(&tqmask); + + KisKernelSP kernel = KisKernel::fromTQImage(tqmask); // TODO: for 1.6 reuse the chalk's core function for creating kernel : KisKernel::fromTQImage + tqmask.save("testtqmask.png", "PNG"); + + KisPaintDeviceSP interm = new KisPaintDevice(*src); + KisColorSpace * cs = src->colorSpace(); + + KisConvolutionPainter painter( interm ); + painter.beginTransaction("bouuh"); + painter.applyMatrix(kernel, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_REPEAT); + +// KisPaintDeviceSP interm2 = new KisPaintDevice(*interm); + + + kdDebug(41005) << "Transforming..." << endl; + setProgressStage( i18n("Fast wavelet transformation") ,progress()); + KisMathToolbox::KisWavelet* buff = 0; + KisMathToolbox::KisWavelet* wav = 0; + KisMathToolbox::KisWavelet* blurwav = 0; + try { + buff = mathToolbox->initWavelet(src, rect); + } catch(std::bad_alloc) + { + if(buff) delete buff; + return; + } + try { + wav = mathToolbox->fastWaveletTransformation(src, rect, buff); + blurwav = mathToolbox->fastWaveletTransformation(interm, rect, buff); + } catch(std::bad_alloc) + { + if(wav) delete wav; + return; + } + + kdDebug(41005) << "frequencying..." << endl; +// float* fin = wav->coeffs + wav->depth*wav->size*wav->size; +// setProgressStage( i18n("frequencying") ,progress()); +// float* it2 = wav->coeffs + wav->depth; + int sizecopy = (int)pow(2, frequency); + if(sizecopy > wav->size) sizecopy = wav->size; + for(int i = 0; i < sizecopy; i++) + { + float *itNotblured = wav->coeffs + wav->depth * wav->size * i; + float *itBlured = blurwav->coeffs + blurwav->depth * blurwav->size * i; + for(int j = 0; j< sizecopy; j++) + { + memcpy(itBlured, itNotblured, sizeof(float) * blurwav->depth); + itBlured += blurwav->depth; + itNotblured += wav->depth; + } + } + + kdDebug(41005) << "Untransforming..." << endl; + + setProgressStage( i18n("Fast wavelet untransformation") ,progress()); + mathToolbox->fastWaveletUntransformation( dst, rect, blurwav, buff); + + delete wav; + delete blurwav; + delete buff; + disconnect(mathToolbox, TQT_SIGNAL(nextStep()), this, TQT_SLOT(incProgress())); + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/halftone/kis_halftone.h b/chalk/plugins/filters/halftone/kis_halftone.h new file mode 100644 index 00000000..38842d31 --- /dev/null +++ b/chalk/plugins/filters/halftone/kis_halftone.h @@ -0,0 +1,79 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005-2006 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_HALFTONE_REDUCTION_H_ +#define KIS_HALFTONE_REDUCTION_H_ + +#include + +#include + +#define BEST_WAVELET_FREQUENCY_VALUE 2 + + +#include + +class ChalkHalftone : public KParts::Plugin +{ + public: + ChalkHalftone(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkHalftone(); +}; + + +class KisHalftoneReductionConfiguration + : public KisFilterConfiguration +{ +public: + KisHalftoneReductionConfiguration(double nt, int hs) + : KisFilterConfiguration( "halftone", 1 ) + { + setProperty("frequency", nt); + setProperty("halfsize", hs); + } + +}; + + +/** +@author Cyrille Berger +*/ +class KisHalftoneReduction : public KisFilter +{ +public: + KisHalftoneReduction(); + + ~KisHalftoneReduction(); + +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual KisFilterConfiguration * configuration(TQWidget* nwidget); + virtual KisFilterConfiguration * configuration() {return new KisHalftoneReductionConfiguration( BEST_WAVELET_FREQUENCY_VALUE, 2 );}; + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + + static inline KisID id() { return KisID("halftone", i18n("Halftone Reducer")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsThreading() { return false; }; + virtual bool supportsAdjustmentLayers() { return false; } + +}; + +#endif diff --git a/chalk/plugins/filters/imageenhancement/Makefile.am b/chalk/plugins/filters/imageenhancement/Makefile.am new file mode 100644 index 00000000..c6a884cd --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/Makefile.am @@ -0,0 +1,27 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkimageenhancement.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkimageenhancement_la_SOURCES = imageenhancement.cpp \ + kis_simple_noise_reducer.cpp kis_wavelet_noise_reduction.cpp + +kde_module_LTLIBRARIES = chalkimageenhancement.la + +chalkimageenhancement_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui + +noinst_HEADERS = imageenhancement.h kis_wavelet_noise_reduction.h + +chalkimageenhancement_la_LIBADD = ../../../libchalkcommon.la + +chalkimageenhencement_la_METASOURCES = AUTO + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/chalk/plugins/filters/imageenhancement/chalkimageenhancement.desktop b/chalk/plugins/filters/imageenhancement/chalkimageenhancement.desktop new file mode 100644 index 00000000..0067412c --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/chalkimageenhancement.desktop @@ -0,0 +1,80 @@ +[Desktop Entry] +Name=Enhancement Filters +Name[bg]=Филтри за подобрения +Name[ca]=Filtres de millora +Name[cy]=Hidlau Tecáu +Name[da]=Forbedringsfilter +Name[de]=Verbesserungsfilter +Name[el]=Φίλτρα βελτίωσης +Name[eo]=Emfaziga filtrilo +Name[es]=Filtros de realce +Name[et]=Parandusfiltrid +Name[fa]=پالایه‌های تقویت +Name[fr]=Filtres d'amélioration +Name[fy]=Korreksjefilters +Name[gl]=Filtros de Melloras +Name[hu]=Képjavító szűrők +Name[is]=Endurbótasíur +Name[it]=Filtri di miglioramento +Name[ja]=エンハンスメントフィルタ +Name[km]=តម្រង​ធ្វើ​ឲ្យ​ប្រសើរ +Name[nb]=Forbedringsfiltre +Name[nds]=Verbeternfilter +Name[ne]=अधिकतम फिल्टरहरू +Name[nl]=Correctiefilters +Name[pl]=Filtry poprawy jakości +Name[pt]=Filtros de Melhoramento +Name[pt_BR]=Filtros de Melhoramento +Name[ru]=Улучшение изображения +Name[se]=Buoridansillit +Name[sk]=Filtre vylepšení +Name[sl]=Filtri za izboljšanje +Name[sr]=Филтери за побољшање +Name[sr@Latn]=Filteri za poboljšanje +Name[sv]=Förbättringsfilter +Name[uk]=Фільтри покращання +Name[uz]=Yaxshilash filteri +Name[uz@cyrillic]=Яхшилаш филтери +Name[zh_CN]=增强过滤器 +Name[zh_TW]=增強過濾器 +Comment=Enhance the quality of an image +Comment[bg]=Подобряване на качеството на изображения +Comment[ca]=Millora la qualitat de la imatge +Comment[cy]=Tecâu ansawdd delwedd +Comment[da]=Forbedr kvaliteten af et billede +Comment[de]=Die Qualität eines Bildes verbessern +Comment[el]=Βελτίωση της ποιότητας μίας εικόνας +Comment[eo]=Plibonigi la kvaliton de bildo +Comment[es]=Realza la calidad de una imagen +Comment[et]=Parandavad pildi kvaliteeti +Comment[fa]=افزایش کیفیت یک تصویر +Comment[fr]=Améliore la qualité d'une image +Comment[fy]=De kwaliteit fan in ôfbylding ferbetterje +Comment[gl]=Mellora a calidade dunha imaxe +Comment[hu]=A képminőség feljavítására használható eszközök +Comment[is]=Til að auka gæði mynda +Comment[it]=Migliora la qualità di un'immagine +Comment[ja]=画質を高める +Comment[km]=បង្កើន​គុណភាព​រូបភាព +Comment[nb]=Forbedre kvaliteten på et bilde +Comment[nds]=De Gööd vun en Bild verbetern +Comment[ne]=एउटा छविको विशेषता बढाउनुहोस् +Comment[nl]=De kwaliteit van een afbeelding verbeteren +Comment[pl]=Filtry poprawiające jakość obrazka +Comment[pt]=Melhora a qualidade de uma imagem +Comment[pt_BR]=Melhora a qualidade de uma imagem +Comment[ru]=Улучшение качества изображения +Comment[se]=Buorit govvakvalitehta +Comment[sk]=Vylepšiť kvalitu obrázka +Comment[sl]=Izboljšaj kvaliteto slike +Comment[sr]=Побољшава квалитет слике +Comment[sr@Latn]=Poboljšava kvalitet slike +Comment[sv]=Förbättra kvaliteten hos en bild +Comment[uk]=Покращання якості зображення +Comment[uz]=Rasmning sifatini oshirish +Comment[uz@cyrillic]=Расмнинг сифатини ошириш +Comment[zh_TW]=增強圖片的品質 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkimageenhancement +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/imageenhancement/imageenhancement.cpp b/chalk/plugins/filters/imageenhancement/imageenhancement.cpp new file mode 100644 index 00000000..8108a3d6 --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/imageenhancement.cpp @@ -0,0 +1,73 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "imageenhancement.h" + +#include "kis_simple_noise_reducer.h" +#include "kis_wavelet_noise_reduction.h" + +typedef KGenericFactory ChalkImageEnhancementFactory; +K_EXPORT_COMPONENT_FACTORY( chalkimageenhancement, ChalkImageEnhancementFactory( "chalk" ) ) + + ChalkImageEnhancement::ChalkImageEnhancement(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkImageEnhancementFactory::instance()); + + kdDebug(41006) << "Image enhancement filter plugin. Class: " + << className() + << ", Parent: " + << tqparent->className() + << "\n"; + + + if ( tqparent->inherits("KisFilterRegistry") ) + { + KisFilterRegistry * r = dynamic_cast(tqparent); + r->add(new KisSimpleNoiseReducer()); + r->add(new KisWaveletNoiseReduction()); + } +} + +ChalkImageEnhancement::~ChalkImageEnhancement() +{ +} + diff --git a/chalk/plugins/filters/imageenhancement/imageenhancement.h b/chalk/plugins/filters/imageenhancement/imageenhancement.h new file mode 100644 index 00000000..b333e25f --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/imageenhancement.h @@ -0,0 +1,34 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef EXAMPLE_H +#define EXAMPLE_H + +#include + +class ChalkImageEnhancement : public KParts::Plugin +{ + public: + ChalkImageEnhancement(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkImageEnhancement(); +}; + +#endif diff --git a/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp b/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp new file mode 100644 index 00000000..0ff7a958 --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_simple_noise_reducer.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +KisSimpleNoiseReducer::KisSimpleNoiseReducer() + : KisFilter(id(), "enhance", i18n("&Gaussian Noise Reduction...")) +{ +} + + +KisSimpleNoiseReducer::~KisSimpleNoiseReducer() +{ +} + +KisFilterConfigWidget * KisSimpleNoiseReducer::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 0, 255, 50, i18n("Threshold"), "threshold" ) ); + param.push_back( KisIntegerWidgetParam( 0, 10, 1, i18n("Window size"), "windowsize") ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSimpleNoiseReducer::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisSimpleNoiseReducerConfiguration( 50, 1); + } else { + return new KisSimpleNoiseReducerConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} + +inline int ABS(int v) +{ + if(v < 0) return -v; + return v; +} + +void KisSimpleNoiseReducer::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + int threshold, windowsize; + if(config !=0) + { + KisSimpleNoiseReducerConfiguration* configSNRC = (KisSimpleNoiseReducerConfiguration*)config; + threshold = configSNRC->threshold(); + windowsize = configSNRC->windowsize(); + } else { + threshold = 50; + windowsize = 1; + } + + KisColorSpace* cs = src->colorSpace(); + + // Compute the blur tqmask + KisAutobrushShape* kas = new KisAutobrushCircleShape(2*windowsize+1, 2*windowsize+1, windowsize, windowsize); + + TQImage tqmask; + kas->createBrush(&tqmask); + + KisKernelSP kernel = KisKernel::fromTQImage(tqmask); + + KisPaintDeviceSP interm = new KisPaintDevice(*src); + KisConvolutionPainter painter( interm ); + + if (m_progressDisplay) + m_progressDisplay->setSubject( &painter, true, true ); + + painter.beginTransaction("bouuh"); + painter.applyMatrix(kernel, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_REPEAT); + + if (painter.cancelRequested()) { + cancel(); + } + + KisHLineIteratorPixel dstIt = dst->createHLineIterator(rect.x(), rect.y(), rect.width(), true ); + KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), rect.y(), rect.width(), false); + KisHLineIteratorPixel intermIt = interm->createHLineIterator(rect.x(), rect.y(), rect.width(), false); + + for( int j = 0; j < rect.height(); j++) + { + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + TQ_UINT8 diff = cs->difference(srcIt.oldRawData(), intermIt.rawData()); + if( diff > threshold) + { + cs->bitBlt( dstIt.rawData(), 0, cs, intermIt.rawData(), 0, 0, 0, 255, 1, 1, KisCompositeOp(COMPOSITE_COPY) ); + } + } + //incProgress(); + ++srcIt; + ++dstIt; + ++intermIt; + } + srcIt.nextRow(); + dstIt.nextRow(); + intermIt.nextRow(); + } + + setProgressDone(); // Must be called even if you don't really support progression +} + diff --git a/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.h b/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.h new file mode 100644 index 00000000..a233bb85 --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/kis_simple_noise_reducer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KISSIMPLENOISEREDUCER_H +#define KISSIMPLENOISEREDUCER_H + +#include +#include "kis_filter_config_widget.h" +/** +@author Cyrille Berger +*/ + +class KisSimpleNoiseReducerConfiguration + : public KisFilterConfiguration +{ + public: + KisSimpleNoiseReducerConfiguration(int nt, int ws) + : KisFilterConfiguration( "gaussiannoisereducer", 1 ) + { + setProperty("threshold", nt); + setProperty("windowsize", ws); + } + int threshold() { return getInt("threshold"); }; + int windowsize() { return getInt("windowsize"); }; +}; + +class KisSimpleNoiseReducer : public KisFilter +{ + public: + KisSimpleNoiseReducer(); + ~KisSimpleNoiseReducer(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual KisFilterConfiguration * configuration(TQWidget* nwidget); + virtual KisFilterConfiguration * configuration() { return new KisSimpleNoiseReducerConfiguration( 50, 1); }; + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + + static inline KisID id() { return KisID("gaussiannoisereducer", i18n("Gaussian Noise Reducer")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } +}; + +#endif diff --git a/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp b/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp new file mode 100644 index 00000000..021bf5c6 --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.cpp @@ -0,0 +1,130 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wavelet_noise_reduction.h" + +#include + +#include +#include +#include +#include +#include +#include + +KisWaveletNoiseReduction::KisWaveletNoiseReduction() + : KisFilter(id(), "enhance", i18n("&Wavelet Noise Reduction...")) +{ +} + + +KisWaveletNoiseReduction::~KisWaveletNoiseReduction() +{ +} + +KisFilterConfigWidget * KisWaveletNoiseReduction::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + vKisDoubleWidgetParam param; + param.push_back( KisDoubleWidgetParam( 0.0, 256.0, BEST_WAVELET_THRESHOLD_VALUE, i18n("Threshold"), "threshold" ) ); + return new KisMultiDoubleFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisWaveletNoiseReduction::configuration(TQWidget* nwidget ) +{ + KisMultiDoubleFilterWidget* widget = (KisMultiDoubleFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisWaveletNoiseReductionConfiguration( BEST_WAVELET_THRESHOLD_VALUE ); + } else { + return new KisWaveletNoiseReductionConfiguration( widget->valueAt( 0 ) ); + } +} + +void KisWaveletNoiseReduction::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + + float threshold = 1.0; + + if(config !=0) + { + KisWaveletNoiseReductionConfiguration* configWNRC = (KisWaveletNoiseReductionConfiguration*)config; + kdDebug() << "threshold: " << configWNRC->threshold() << endl; + threshold = configWNRC->threshold(); + } + + + TQ_INT32 depth = src->colorSpace()->nColorChannels(); + + int size; + int maxrectsize = (rect.height() < rect.width()) ? rect.width() : rect.height(); + for(size = 2; size < maxrectsize; size *= 2) ; + + KisMathToolbox* mathToolbox = KisMetaRegistry::instance()->mtRegistry()->get( src->colorSpace()->mathToolboxID() ); + setProgressTotalSteps(mathToolbox->fastWaveletTotalSteps(rect) * 2 + size*size*depth ); + connect(mathToolbox, TQT_SIGNAL(nextStep()), this, TQT_SLOT(incProgress())); + + + kdDebug(41005) << size << " " << maxrectsize << " " << rect.x() << " " << rect.y() << endl; + + kdDebug(41005) << "Transforming..." << endl; + setProgressStage( i18n("Fast wavelet transformation") ,progress()); + KisMathToolbox::KisWavelet* buff = 0; + KisMathToolbox::KisWavelet* wav = 0; + try { + buff = mathToolbox->initWavelet(src, rect); + } catch(std::bad_alloc) + { + if(buff) delete buff; + return; + } + try { + wav = mathToolbox->fastWaveletTransformation(src, rect, buff); + } catch(std::bad_alloc) + { + if(wav) delete wav; + return; + } + + kdDebug(41005) << "Thresholding..." << endl; + float* fin = wav->coeffs + wav->depth*wav->size*wav->size; + setProgressStage( i18n("Thresholding") ,progress()); + for(float* it = wav->coeffs + wav->depth; it < fin; it++) + { + if( *it > threshold) + { + *it -= threshold; + } else if( *it < -threshold ) { + *it += threshold; + } else { + *it = 0.; + } + incProgress(); + } + + kdDebug(41005) << "Untransforming..." << endl; + + setProgressStage( i18n("Fast wavelet untransformation") ,progress()); + mathToolbox->fastWaveletUntransformation( dst, rect, wav, buff); + + delete wav; + delete buff; + disconnect(mathToolbox, TQT_SIGNAL(nextStep()), this, TQT_SLOT(incProgress())); + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h b/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h new file mode 100644 index 00000000..85a96ec8 --- /dev/null +++ b/chalk/plugins/filters/imageenhancement/kis_wavelet_noise_reduction.h @@ -0,0 +1,68 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WAVELET_NOISE_REDUCTION_H +#define KIS_WAVELET_NOISE_REDUCTION_H + +#include + +#include + +#define BEST_WAVELET_THRESHOLD_VALUE 7.0 + +class KisWaveletNoiseReductionConfiguration + : public KisFilterConfiguration +{ +public: + KisWaveletNoiseReductionConfiguration(double nt) + : KisFilterConfiguration( "waveletnoisereducer", 1 ) + { + setProperty("threshold", nt); + } + + double threshold() { return getDouble("threshold"); }; +}; + + +/** +@author Cyrille Berger +*/ +class KisWaveletNoiseReduction : public KisFilter +{ +public: + KisWaveletNoiseReduction(); + + ~KisWaveletNoiseReduction(); + +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual KisFilterConfiguration * configuration(TQWidget* nwidget); + virtual KisFilterConfiguration * configuration() {return new KisWaveletNoiseReductionConfiguration( BEST_WAVELET_THRESHOLD_VALUE );}; + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + + static inline KisID id() { return KisID("waveletnoisereducer", i18n("Wavelet Noise Reducer")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsThreading() { return false; }; + virtual bool supportsAdjustmentLayers() { return false; } + +}; + +#endif diff --git a/chalk/plugins/filters/lenscorrectionfilter/Makefile.am b/chalk/plugins/filters/lenscorrectionfilter/Makefile.am new file mode 100644 index 00000000..c074bd65 --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalklenscorrectionfilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalklenscorrectionfilter_la_SOURCES = lenscorrectionfilter.cc \ + wdglenscorrectionoptions.ui kis_wdg_lens_correction.cpp + +kde_module_LTLIBRARIES = chalklenscorrectionfilter.la +noinst_HEADERS = lenscorrectionfilter.h + +chalklenscorrectionfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalklenscorrectionfilter_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO diff --git a/chalk/plugins/filters/lenscorrectionfilter/chalklenscorrectionfilter.desktop b/chalk/plugins/filters/lenscorrectionfilter/chalklenscorrectionfilter.desktop new file mode 100644 index 00000000..52bb0057 --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/chalklenscorrectionfilter.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Comment=Transform an image in a lenscorrection +Comment[bg]=Преобразуване на изображение в коригиране на лещи +Comment[ca]=Transforma una imatge en una lent correctora +Comment[da]=Transformér et billede med linsekorrektion +Comment[de]=Ein Bild mit einer Linsenkorrektur transformieren +Comment[el]=Μετασχηματισμός μιας εικόνας με διόρθωση οπτικών φακών +Comment[es]=Transforma una imagen en un corrección de lente +Comment[et]=Pildi teisendamine läätsekorrektsiooniga +Comment[fa]=تبدیل یک تصویر به صورت اصلاح عدسی +Comment[fy]=Transformearje in ôfbylding yn in lenskorreksje +Comment[gl]=Transforma unha imaxe nunha corrección de lente +Comment[hu]=Lencsekorrekció végrehajtása képen +Comment[it]=Trasforma un'immagine in una correzione lenticolare +Comment[ja]=レンズ補正によって画像を変形 +Comment[km]=ប្លែង​រូបភាព​ក្នុង​ការកែ​កែវ​ម៉ាស៊ីន​ថតរូប +Comment[nb]=Transformer et bilde med linsekorreksjon +Comment[nds]=En Bild mit Glööskorrektuur ümwanneln +Comment[ne]=लेन्ससुधारमा छवि रूपान्तरण गर्नुहोस् +Comment[nl]=Transformeer een afbeelding in een lenscorrectie +Comment[pl]=Usuwa efekt soczewki ze zdjęcia +Comment[pt]=Transformar uma imagem numa correcção de lentes +Comment[pt_BR]=Transforma uma imagem numa correção de lentes +Comment[ru]=Убрать искажение от линзы фотоаппарата +Comment[sk]=Transformovať obrázok pomocou korekcie šošovky +Comment[sl]=Preoblikuj sliko s popravljanjem lečenja +Comment[sr]=Трансформација слике за поправку сочива +Comment[sr@Latn]=Transformacija slike za popravku sočiva +Comment[sv]=Omvandla en bild med linskorrektion +Comment[uk]=Коректувати спотворення від лінзи фотоапарата +Comment[zh_TW]=在 lenscorrection 下轉換圖片 +Icon= +Name=LensCorrection Filter +Name[bg]=Филтри за коригиране на лещи +Name[ca]=Filtre de Lent correctora +Name[da]=Linekorrektionsfilter +Name[de]=Linsenkorrekturfilter +Name[el]=Φίλτρο οπτικών φακών +Name[eo]=LensKorekta filtrilo +Name[es]=Filtro de corrección de lente +Name[et]=Läätsekorrektsiooni filter +Name[fa]=پالایۀ اصلاح عدسی +Name[fy]=Lenskorreksjefilter +Name[gl]=Filtros de Corrección de Lente +Name[hu]=Lencsekorrekciós szűrő +Name[it]=Filtro di correzione lenticolare +Name[ja]=レンズ補正フィルタ +Name[km]=តម្រង​ការកែ​កែវ​ម៉ាស៊ីន​ថតរូប +Name[nb]=Linsekorreksjonsfilter +Name[nds]=Glööskorrektuurfilter +Name[ne]=लेन्ससुधार फिल्टर +Name[nl]=Lenscorrectiefilter +Name[pl]=Filtr korekcji efektu soczewki +Name[pt]=Filtro de Correcção de Lentes +Name[pt_BR]=Filtro de Correção de Lentes +Name[ru]=Убрать искажение линзы +Name[sk]=Filter korekcie šošovky +Name[sl]=Filter Popravljanje lečenja +Name[sr]=Филтер за поправку сочива +Name[sr@Latn]=Filter za popravku sočiva +Name[sv]=Linskorrektionsfilter +Name[uk]=Корекція спотворення лінзи +Name[uz]=Linzani toʻgʻrilash filteri +Name[uz@cyrillic]=Линзани тўғрилаш филтери +Name[zh_TW]=LensCorrection 過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalklenscorrectionfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp b/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp new file mode 100644 index 00000000..f33681a5 --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_lens_correction.h" + +#include + +#include + +#include "wdglenscorrectionoptions.h" + +KisWdgLensCorrection::KisWdgLensCorrection(KisFilter* /*nfilter*/, TQWidget* tqparent, const char* name) + : KisFilterConfigWidget(tqparent,name) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgLensCorrectionOptions(this); + widgetLayout -> addWidget(m_widget, 0, 0); + + connect( widget()->intXCenter, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intYCenter, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblCorrectionNearCenter, TQT_SIGNAL( valueChanged(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblCorrectionNearEdges, TQT_SIGNAL( valueChanged(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->dblBrightness, TQT_SIGNAL( valueChanged(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgLensCorrection::~KisWdgLensCorrection() +{ +} + +void KisWdgLensCorrection::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("xcenter", value)) + { + widget()->intXCenter->setValue( value.toUInt() ); + } + if (config->getProperty("ycenter", value)) + { + widget()->intYCenter->setValue( value.toUInt() ); + } + if (config->getProperty("correctionnearcenter", value)) + { + widget()->dblCorrectionNearCenter->setValue( value.toDouble() ); + } + if (config->getProperty("correctionnearedges", value)) + { + widget()->dblCorrectionNearEdges->setValue( value.toDouble() ); + } + if (config->getProperty("brightness", value)) + { + widget()->dblBrightness->setValue( value.toDouble() ); + } +} + + +#include "kis_wdg_lens_correction.moc" + diff --git a/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h b/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h new file mode 100644 index 00000000..193aa5aa --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/kis_wdg_lens_correction.h @@ -0,0 +1,44 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WDG_LENS_CORRECTION_H +#define KIS_WDG_LENS_CORRECTION_H + +#include + +class WdgLensCorrectionOptions; +class KisFilter; + +class KisWdgLensCorrection : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgLensCorrection(KisFilter* nfilter, TQWidget* tqparent = 0, const char* name = 0); + ~KisWdgLensCorrection(); + public: + inline WdgLensCorrectionOptions* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgLensCorrectionOptions* m_widget; +}; + +#endif + diff --git a/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc b/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc new file mode 100644 index 00000000..cd3627c5 --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.cc @@ -0,0 +1,152 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2006 Cyrille Berger + * + * Inspired by a similar plugin for the digikam project from: + * Copyright (c) 2005 Gilles Caulier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "lenscorrectionfilter.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_lens_correction.h" +#include "wdglenscorrectionoptions.h" + +typedef KGenericFactory ChalkLensCorrectionFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalklenscorrectionfilter, ChalkLensCorrectionFilterFactory( "chalk" ) ) + +ChalkLensCorrectionFilter::ChalkLensCorrectionFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkLensCorrectionFilterFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterLensCorrection()); + } +} + +ChalkLensCorrectionFilter::~ChalkLensCorrectionFilter() +{ +} + +KisFilterLensCorrection::KisFilterLensCorrection() : KisFilter(id(), "other", i18n("&Lens Correction...")) +{ +} + +KisFilterConfiguration* KisFilterLensCorrection::configuration(TQWidget* w) +{ + TQVariant value; + KisWdgLensCorrection* wN = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wN) + { + config->setProperty("xcenter", wN->widget()->intXCenter->value() ); + config->setProperty("ycenter", wN->widget()->intYCenter->value() ); + config->setProperty("correctionnearcenter", wN->widget()->dblCorrectionNearCenter->value() ); + config->setProperty("correctionnearedges", wN->widget()->dblCorrectionNearEdges->value() ); + config->setProperty("brightness", wN->widget()->dblBrightness->value() ); + } + return config; +} + +KisFilterConfigWidget * KisFilterLensCorrection::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + return new KisWdgLensCorrection((KisFilter*)this, (TQWidget*)tqparent, i18n("Configuration of lens correction filter").ascii()); +} + +void KisFilterLensCorrection::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rawrect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + TQRect layerrect = src->exactBounds(); + + TQRect workingrect = layerrect.intersect( rawrect ); + + setProgressTotalSteps(workingrect.width() * workingrect.height()); + + KisColorSpace* cs = dst->colorSpace(); + + TQVariant value; + double xcenter = (config && config->getProperty("xcenter", value)) ? value.toInt() : 50; + double ycenter = (config && config->getProperty("ycenter", value)) ? value.toInt() : 50; + double correctionnearcenter = (config && config->getProperty("correctionnearcenter", value)) ? value.toDouble() : 0.; + double correctionnearedges = (config && config->getProperty("correctionnearedges", value)) ? value.toDouble() : 0.; + double brightness = ( (config && config->getProperty("brightness", value)) ? value.toDouble() : 0. ); + + KisRectIteratorPixel dstIt = dst->createRectIterator(workingrect.x(), workingrect.y(), workingrect.width(), workingrect.height(), true ); + KisRandomSubAccessorPixel srcRSA = src->createRandomSubAccessor(); + + double normallise_radius_sq = 4.0 / (layerrect.width() * layerrect.width() + layerrect.height() * layerrect.height()); + xcenter = layerrect.x() + layerrect.width() * xcenter / 100.0; + ycenter = layerrect.y() + layerrect.height() * ycenter / 100.0; + double mult_sq = correctionnearcenter / 200.0; + double mult_qd = correctionnearedges / 200.0; + + TQ_UINT16 lab[4]; + + while(!dstIt.isDone()) + { + double off_x = dstIt.x() - xcenter; + double off_y = dstIt.y() - ycenter; + double radius_sq = ( (off_x * off_x) + (off_y * off_y) ) * normallise_radius_sq; + + double radius_mult = radius_sq * mult_sq + radius_sq * radius_sq * mult_qd; + double mag = radius_mult; + radius_mult += 1.0; + + double srcX = xcenter + radius_mult * off_x; + double srcY = ycenter + radius_mult * off_y; + + double brighten = 1.0 + mag * brightness; + + srcRSA.moveTo( KisPoint( srcX, srcY ) ); + srcRSA.sampledOldRawData( dstIt.rawData() ); + cs->toLabA16( dstIt.rawData(), (TQ_UINT8*)lab, 1); + lab[0] = CLAMP( lab[0] * static_cast( brighten ), 0, 65535); + cs->fromLabA16( (TQ_UINT8*)lab, dstIt.rawData(), 1); + + ++dstIt; + incProgress(); + } + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h b/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h new file mode 100644 index 00000000..f04012b6 --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/lenscorrectionfilter.h @@ -0,0 +1,53 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LENS_CORRECTIONFILTER_H +#define LENS_CORRECTIONFILTER_H + +#include +#include "kis_filter.h" + +class KisFilterConfigWidget; + +class ChalkLensCorrectionFilter : public KParts::Plugin +{ +public: + ChalkLensCorrectionFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkLensCorrectionFilter(); +}; + +class KisFilterLensCorrection : public KisFilter +{ + public: + KisFilterLensCorrection(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("lenscorrection", i18n("Lens Correction")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui b/chalk/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui new file mode 100644 index 00000000..d5ef416d --- /dev/null +++ b/chalk/plugins/filters/lenscorrectionfilter/wdglenscorrectionoptions.ui @@ -0,0 +1,229 @@ + +WdgLensCorrectionOptions + + + WdgLensCorrectionOptions + + + + 0 + 0 + 235 + 207 + + + + + unnamed + + + 0 + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 90 + + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 16 + 20 + + + + + + groupBox1 + + + Distortion Correction + + + + unnamed + + + + Center_3 + + + Y: + + + + + Center_2 + + + X: + + + + + intXCenter + + + 50 + + + 0 + + + 100 + + + + + intYCenter + + + 50 + + + 0 + + + 100 + + + + + spacer11 + + + Horizontal + + + Expanding + + + + 16 + 20 + + + + + + spacer12 + + + Horizontal + + + Expanding + + + + 51 + 20 + + + + + + textLabel1 + + + Near center: + + + + + textLabel2 + + + Near edges: + + + + + Center + + + Center: + + + + + dblCorrectionNearCenter + + + -100 + + + 100 + + + + + dblCorrectionNearEdges + + + -100 + + + 100 + + + + + + + textLabel2_2_2 + + + Brightness correction: + + + + + dblBrightness + + + -100 + + + 100 + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/levelfilter/Makefile.am b/chalk/plugins/filters/levelfilter/Makefile.am new file mode 100644 index 00000000..2f6fb459 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/Makefile.am @@ -0,0 +1,25 @@ +kde_services_DATA = chalklevelfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalklevelfilter_la_SOURCES = levelfilter.cc \ + wdg_level.ui \ + kis_level_filter.cc \ + kgradientslider.cc + +noinst_HEADERS = levelfilter.h \ + kis_level_filter.h \ + kgradientslider.h + +chalklevelfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalklevelfilter_la_LIBADD = ../../../libchalkcommon.la + +kde_module_LTLIBRARIES = chalklevelfilter.la + +chalklevelfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/levelfilter/chalklevelfilter.desktop b/chalk/plugins/filters/levelfilter/chalklevelfilter.desktop new file mode 100644 index 00000000..8426b08d --- /dev/null +++ b/chalk/plugins/filters/levelfilter/chalklevelfilter.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Name=Levels +Name[bg]=Нива +Name[br]=Liveoù +Name[ca]=Nivells +Name[da]=Niveauer +Name[de]=Stufen +Name[el]=Επίπεδα +Name[eo]=Niveloj +Name[es]=Niveles +Name[et]=Tasemed +Name[fa]=سطوح +Name[fy]=Nivo's +Name[hr]=Razine +Name[hu]=Szintek +Name[it]=Livelli +Name[ja]=レベル +Name[km]=កម្រិត +Name[lt]=Lygiai +Name[nb]=Nivåer +Name[nds]=Stopen +Name[ne]=स्तर +Name[nl]=Niveaus +Name[pl]=Poziomy +Name[pt]=Níveis +Name[pt_BR]=Níveis +Name[ru]=Уровни +Name[se]=Dásit +Name[sk]=Úrovne +Name[sl]=Ravni +Name[sr]=Нивои +Name[sr@Latn]=Nivoi +Name[sv]=Nivåer +Name[uk]=Рівні +Name[zh_TW]=等級 +Comment=Levels +Comment[bg]=Нива +Comment[br]=Liveoù +Comment[ca]=Nivells +Comment[da]=Niveauer +Comment[de]=Stufen +Comment[el]=Επίπεδα +Comment[eo]=Niveloj +Comment[es]=Niveles +Comment[et]=Tasemed +Comment[fa]=سطوح +Comment[fy]=Nivo's +Comment[hr]=Razine +Comment[hu]=Szintek +Comment[it]=Livelli +Comment[ja]=レベル +Comment[km]=កម្រិត +Comment[lt]=Lygiai +Comment[nb]=Nivåer +Comment[nds]=Stopen +Comment[ne]=स्तर +Comment[nl]=Niveaus +Comment[pl]=Poziomy +Comment[pt]=Níveis +Comment[pt_BR]=Níveis +Comment[ru]=Уровни +Comment[se]=Dásit +Comment[sk]=Úrovne +Comment[sl]=Ravni +Comment[sr]=Нивои +Comment[sr@Latn]=Nivoi +Comment[sv]=Nivåer +Comment[uk]=Рівні +Comment[zh_TW]=等級 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalklevelfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/levelfilter/kgradientslider.cc b/chalk/plugins/filters/levelfilter/kgradientslider.cc new file mode 100644 index 00000000..104ef375 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/kgradientslider.cc @@ -0,0 +1,338 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// C++ includes. + +#include +#include + +// TQt includes. + +#include +#include +#include +#include + +// Local includes. + +#include "kgradientslider.h" + +KGradientSlider::KGradientSlider(TQWidget *tqparent, const char *name, WFlags f) + : TQWidget(tqparent, name, f) +{ + m_dragging = false; + + setMouseTracking(true); + setPaletteBackgroundColor(TQt::NoBackground); + setMaximumSize(255, 28); + + m_blackcursor = 0; + m_whitecursor = 255; + m_gamma = 1.0; + m_gammaEnabled = false; + setFocusPolicy(TQ_StrongFocus); +} + +KGradientSlider::~KGradientSlider() +{ +} + +void KGradientSlider::paintEvent(TQPaintEvent *) +{ + int x, y; + int wWidth = width(); + int wHeight = height(); + + int gradientHeight = (wHeight / 3); + + // A TQPixmap is used for enable the double buffering. + /*if (!m_dragging) {*/ + TQPixmap pm(size()); + TQPainter p1; + p1.tqbegin(TQT_TQPAINTDEVICE(&pm), this); + + pm.fill(); + + // Draw first gradient + y = 0; + p1.setPen(TQPen::TQPen(TQColor(0,0,0),1, TQt::SolidLine)); + for( x=0; x<255; ++x ) + { + int gray = (255 * x) / wWidth; + p1.setPen(TQColor(gray, gray, gray)); + p1.drawLine(x, y, x, y + gradientHeight - 1); + } + + // Draw second gradient + y = (wHeight / 3); + if (m_blackcursor > 0) { + p1.fillRect(0, y, (int)m_blackcursor, gradientHeight, TQBrush(TQt::black)); + } + if (m_whitecursor < 255) { + p1.fillRect((int)m_whitecursor, y, 255, gradientHeight, TQBrush(TQt::white)); + } + for(x = (int)m_blackcursor; x < (int)m_whitecursor; ++x ) + { + double inten = (double)(x - m_blackcursor) / (double)(m_whitecursor - m_blackcursor); + inten = pow (inten, (1.0 / m_gamma)); + int gray = (int)(255 * inten); + p1.setPen(TQColor(gray, gray, gray)); + p1.drawLine(x, y, x, y + gradientHeight - 1); + } + + // Draw cursors + y = (2 * wHeight / 3); + TQPointArray *a = new TQPointArray(3); + p1.setPen(TQt::black); + + a->setPoint(0, m_blackcursor, y); + a->setPoint(1, m_blackcursor + 3, wHeight - 1); + a->setPoint(2, m_blackcursor - 3, wHeight - 1); + p1.setBrush(TQt::black); + p1.drawPolygon(*a); + + if (m_gammaEnabled) { + a->setPoint(0, m_gammacursor, y); + a->setPoint(1, m_gammacursor + 3, wHeight - 1); + a->setPoint(2, m_gammacursor - 3, wHeight - 1); + p1.setBrush(TQt::gray); + p1.drawPolygon(*a); + } + + a->setPoint(0, m_whitecursor, y); + a->setPoint(1, m_whitecursor + 3, wHeight - 1); + a->setPoint(2, m_whitecursor - 3, wHeight - 1); + p1.setBrush(TQt::white); + p1.drawPolygon(*a); + + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void KGradientSlider::mousePressEvent ( TQMouseEvent * e ) +{ + eCursor closest_cursor; + int distance; + + if (e->button() != Qt::LeftButton) + return; + + unsigned int x = e->pos().x(); + + distance = 1000; // just a big number + + if (abs((int)(x - m_blackcursor)) < distance) + { + distance = abs((int)(x - m_blackcursor)); + closest_cursor = BlackCursor; + } + + if (abs((int)(x - m_whitecursor)) < distance) + { + distance = abs((int)(x - m_whitecursor)); + closest_cursor = WhiteCursor; + } + + if (m_gammaEnabled && (abs((int)(x - m_gammacursor)) < distance)) + { + distance = abs((int)(x - m_gammacursor)); + closest_cursor = GammaCursor; + } + + if (distance > 20) + { + return; + } + + + m_dragging = true; + + // Determine cursor values and the leftmost and rightmost points. + + switch (closest_cursor) { + case BlackCursor: + m_blackcursor = x; + m_grab_cursor = closest_cursor; + m_leftmost = 0; + m_rightmost = m_whitecursor; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + break; + case WhiteCursor: + m_whitecursor = x; + m_grab_cursor = closest_cursor; + m_leftmost = m_blackcursor; + m_rightmost = 255; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + break; + case GammaCursor: + m_gammacursor = x; + m_grab_cursor = closest_cursor; + m_leftmost = m_blackcursor; + m_rightmost = m_whitecursor; + + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = (x - mid) / delta; + m_gamma = 1.0 / pow (10, tmp); + break; + } + tqrepaint(false); +} + +void KGradientSlider::mouseReleaseEvent ( TQMouseEvent * e ) +{ + if (e->button() != Qt::LeftButton) + return; + + m_dragging = false; + tqrepaint(false); + + switch (m_grab_cursor) { + case BlackCursor: + emit modifiedBlack(m_blackcursor); + break; + case WhiteCursor: + emit modifiedWhite(m_whitecursor); + break; + case GammaCursor: + emit modifiedGamma(m_gamma); + break; + } +} + +void KGradientSlider::mouseMoveEvent ( TQMouseEvent * e ) +{ + unsigned int x = abs(e->pos().x()); + + if (m_dragging == true) // Else, drag the selected point + { + if (x <= m_leftmost) + x = m_leftmost; + + if(x >= m_rightmost) + x = m_rightmost; + + /*if(x > 255) + x = 255; + + if(x < 0) + x = 0;*/ + + switch (m_grab_cursor) { + case BlackCursor: + if (m_blackcursor != x) + { + m_blackcursor = x; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + } + break; + case WhiteCursor: + if (m_whitecursor != x) + { + m_whitecursor = x; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + } + break; + case GammaCursor: + if (m_gammacursor != x) + { + m_gammacursor = x; + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = (x - mid) / delta; + m_gamma = 1.0 / pow (10, tmp); + } + break; + } + } + + tqrepaint(false); +} + +void KGradientSlider::leaveEvent( TQEvent * ) +{ +} + + +void KGradientSlider::enableGamma(bool b) +{ + m_gammaEnabled = b; + tqrepaint(false); +} + +double KGradientSlider::getGamma(void) +{ + return m_gamma; +} + +void KGradientSlider::modifyBlack(int v) { + if (v >= 0 && v <= (int)m_whitecursor) { + m_blackcursor = (unsigned int)v; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + tqrepaint(false); + } +} +void KGradientSlider::modifyWhite(int v) { + if (v >= (int)m_blackcursor && v <= 255) { + m_whitecursor = (unsigned int)v; + if (m_gammaEnabled) { + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + } + tqrepaint(false); + } +} +void KGradientSlider::modifyGamma(double v) { + m_gamma = v; + double delta = (double) (m_whitecursor - m_blackcursor) / 2.0; + double mid = (double)m_blackcursor + delta; + double tmp = log10 (1.0 / m_gamma); + m_gammacursor = (unsigned int)tqRound(mid + delta * tmp); + tqrepaint(false); +} + +#include "kgradientslider.moc" diff --git a/chalk/plugins/filters/levelfilter/kgradientslider.h b/chalk/plugins/filters/levelfilter/kgradientslider.h new file mode 100644 index 00000000..c8990c80 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/kgradientslider.h @@ -0,0 +1,85 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KGRADIENTSLIDER_H +#define KGRADIENTSLIDER_H + +// TQt includes. + +#include +#include +#include +#include + +class KGradientSlider : public TQWidget +{ +Q_OBJECT + TQ_OBJECT + + typedef enum { + BlackCursor, + GammaCursor, + WhiteCursor + } eCursor; + +public: + KGradientSlider(TQWidget *tqparent = 0, const char *name = 0, WFlags f = 0); + + virtual ~KGradientSlider(); + +public slots: + void modifyBlack(int); + void modifyWhite(int); + void modifyGamma(double); + +signals: + + void modifiedBlack(int); + void modifiedWhite(int); + void modifiedGamma(double); + +protected: + void paintEvent(TQPaintEvent *); + void mousePressEvent (TQMouseEvent * e); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + void leaveEvent ( TQEvent * ); + +public: + void enableGamma(bool b); + double getGamma(void); + +private: + unsigned int m_leftmost; + unsigned int m_rightmost; + eCursor m_grab_cursor; + unsigned int m_grab_index; + bool m_dragging; + + unsigned int m_blackcursor; + unsigned int m_whitecursor; + unsigned int m_gammacursor; + + bool m_gammaEnabled; + double m_gamma; +}; + + +#endif /* KGRADIENTSLIDER_H */ diff --git a/chalk/plugins/filters/levelfilter/kis_level_filter.cc b/chalk/plugins/filters/levelfilter/kis_level_filter.cc new file mode 100644 index 00000000..6b8dd6a0 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/kis_level_filter.cc @@ -0,0 +1,324 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "kis_filter_config_widget.h" +#include "kis_level_filter.h" +#include "wdg_level.h" +#include "kis_colorspace.h" +#include "kis_paint_device.h" +#include "kis_iterators_pixel.h" +#include "kis_iterator.h" +#include "kis_histogram.h" +#include "kis_basic_histogram_producers.h" +#include "kis_painter.h" +#include "kgradientslider.h" + +KisLevelFilterConfiguration::KisLevelFilterConfiguration() + : KisFilterConfiguration( "levels", 1 ) +{ + whitevalue = 255; + blackvalue = 0; + gammavalue = 1.0; + + outwhitevalue = 0xFFFF; + outblackvalue = 0; + + m_adjustment = 0; +} + +KisLevelFilterConfiguration::~KisLevelFilterConfiguration() +{ + delete m_adjustment; +} + +void KisLevelFilterConfiguration::fromXML( const TQString& s ) +{ + KisFilterConfiguration::fromXML(s); + blackvalue = getInt( "blackvalue" ); + whitevalue = getInt( "whitevalue" ); + gammavalue = getDouble( "gammavalue" ); + outblackvalue = getInt( "outblackvalue" ); + outwhitevalue = getInt( "outwhitevalue" ); +} + +TQString KisLevelFilterConfiguration::toString() +{ + m_properties.clear(); + setProperty("blackvalue", blackvalue); + setProperty("whitevalue", whitevalue); + setProperty("gammavalue", gammavalue); + setProperty("outblackvalue", outblackvalue); + setProperty("outwhitevalue", outwhitevalue); + + return KisFilterConfiguration::toString(); +} + +KisLevelFilter::KisLevelFilter() + : KisFilter( id(), "adjust", i18n("&Levels")) +{ + +} + +KisFilterConfigWidget * KisLevelFilter::createConfigurationWidget(TQWidget *tqparent, KisPaintDeviceSP dev) +{ + return new KisLevelConfigWidget(tqparent, dev); +} + +KisFilterConfiguration* KisLevelFilter::configuration(TQWidget *nwidget) +{ + KisLevelConfigWidget* widget = (KisLevelConfigWidget*)nwidget; + + if ( widget == 0 ) + { + return new KisLevelFilterConfiguration(); + } else { + return widget->config(); + } +} + +std::list KisLevelFilter::listOfExamplesConfiguration(KisPaintDeviceSP /*dev*/) +{ + //XXX should really come up with a list of configurations + std::list list; + list.insert(list.begin(), new KisLevelFilterConfiguration( )); + return list; +} + +bool KisLevelFilter::workWith(KisColorSpace* cs) +{ + return (cs->getProfile() != 0); +} + + +void KisLevelFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + + if (!config) { + kdWarning() << "No configuration object for level filter\n"; + return; + } + + KisLevelFilterConfiguration* configBC = (KisLevelFilterConfiguration*) config; + Q_ASSERT(config); + + if (src!=dst) { + KisPainter gc(dst); + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + gc.end(); + } + + if (configBC->m_adjustment == 0) { + TQ_UINT16 transfer[256]; + for (int i = 0; i < 256; i++) { + if (i <= configBC->blackvalue) + transfer[i] = configBC->outblackvalue; + else if (i < configBC->whitevalue) + { + double a = (double)(i - configBC->blackvalue) / (double)(configBC->whitevalue - configBC->blackvalue); + a = (double)(configBC->outwhitevalue - configBC->outblackvalue) * pow (a, (1.0 / configBC->gammavalue)); + transfer[i] = int(configBC->outblackvalue + a); + } + else + transfer[i] = configBC->outwhitevalue; + } + configBC->m_adjustment = src->colorSpace()->createBrightnessContrastAdjustment(transfer); + } + + KisRectIteratorPixel iter = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + setProgressTotalSteps(rect.width() * rect.height()); + TQ_INT32 pixelsProcessed = 0; + + while( ! iter.isDone() && !cancelRequested()) + { + TQ_UINT32 npix=0, maxpix = iter.nConseqPixels(); + TQ_UINT8 selectedness = iter.selectedness(); + // The idea here is to handle stretches of completely selected and completely unselected pixels. + // Partially selected pixels are handled one pixel at a time. + switch(selectedness) + { + case MIN_SELECTED: + while(iter.selectedness()==MIN_SELECTED && maxpix) + { + --maxpix; + ++iter; + ++npix; + } + pixelsProcessed += npix; + break; + + case MAX_SELECTED: + { + TQ_UINT8 *firstPixel = iter.rawData(); + while(iter.selectedness()==MAX_SELECTED && maxpix) + { + --maxpix; + if (maxpix != 0) + ++iter; + ++npix; + } + // adjust + src->colorSpace()->applyAdjustment(firstPixel, firstPixel, configBC->m_adjustment, npix); + pixelsProcessed += npix; + ++iter; + break; + } + + default: + // adjust, but since it's partially selected we also only partially adjust + src->colorSpace()->applyAdjustment(iter.oldRawData(), iter.rawData(), configBC->m_adjustment, 1); + const TQ_UINT8 *pixels[2] = {iter.oldRawData(), iter.rawData()}; + TQ_UINT8 weights[2] = {MAX_SELECTED - selectedness, selectedness}; + src->colorSpace()->mixColors(pixels, weights, 2, iter.rawData()); + ++iter; + pixelsProcessed++; + break; + } + setProgress(pixelsProcessed); + } + + setProgressDone(); +} + +KisLevelConfigWidget::KisLevelConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name, WFlags f) + : KisFilterConfigWidget(tqparent, name, f) +{ + m_page = new WdgLevel(this); + histogram = NULL; + + m_page->ingradient->enableGamma(true); + m_page->blackspin->setValue(0); + m_page->whitespin->setValue(255); + m_page->gammaspin->setNum(1.0); + m_page->ingradient->modifyGamma(1.0); + m_page->outblackspin->setValue(0); + m_page->outwhitespin->setValue(255); + + TQHBoxLayout * l = new TQHBoxLayout(this); + Q_CHECK_PTR(l); + l->addWidget(m_page, 0, TQt::AlignTop); + + connect( m_page->blackspin, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->whitespin, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->ingradient, TQT_SIGNAL(modifiedGamma(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + + connect( m_page->blackspin, TQT_SIGNAL(valueChanged(int)), m_page->ingradient, TQT_SLOT(modifyBlack(int))); + connect( m_page->whitespin, TQT_SIGNAL(valueChanged(int)), m_page->ingradient, TQT_SLOT(modifyWhite(int))); + //connect( m_page->whitespin, TQT_SIGNAL(valueChanged(int)), m_page->ingradient, TQT_SLOT(modifyGamma())); + + connect( m_page->ingradient, TQT_SIGNAL(modifiedBlack(int)), m_page->blackspin, TQT_SLOT(setValue(int))); + connect( m_page->ingradient, TQT_SIGNAL(modifiedWhite(int)), m_page->whitespin, TQT_SLOT(setValue(int))); + connect( m_page->ingradient, TQT_SIGNAL(modifiedGamma(double)), m_page->gammaspin, TQT_SLOT(setNum(double))); + + + connect( m_page->outblackspin, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( m_page->outwhitespin, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + + connect( m_page->outblackspin, TQT_SIGNAL(valueChanged(int)), m_page->outgradient, TQT_SLOT(modifyBlack(int))); + connect( m_page->outwhitespin, TQT_SIGNAL(valueChanged(int)), m_page->outgradient, TQT_SLOT(modifyWhite(int))); + + connect( m_page->outgradient, TQT_SIGNAL(modifiedBlack(int)), m_page->outblackspin, TQT_SLOT(setValue(int))); + connect( m_page->outgradient, TQT_SIGNAL(modifiedWhite(int)), m_page->outwhitespin, TQT_SLOT(setValue(int))); + + connect( (TQObject*)(m_page->chkLogarithmic), TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(drawHistogram(bool))); + + KisHistogramProducerSP producer = new KisGenericLabHistogramProducer(); + histogram = new KisHistogram(dev, producer, LINEAR); + m_histlog = false; + drawHistogram(); + +} + +KisLevelConfigWidget::~KisLevelConfigWidget() +{ + delete histogram; +} + +void KisLevelConfigWidget::drawHistogram(bool logarithmic) +{ + int height = 256; + + if (m_histlog != logarithmic) { + // Update the histogram + if (logarithmic) + histogram->setHistogramType(LOGARITHMIC); + else + histogram->setHistogramType(LINEAR); + m_histlog = logarithmic; + } + + TQPixmap pix(256, height); + pix.fill(); + TQPainter p(&pix); + p.setPen(TQPen::TQPen(TQt::gray,1, TQt::SolidLine)); + + double highest = (double)histogram->calculations().getHighest(); + TQ_INT32 bins = histogram->producer()->numberOfBins(); + + if (histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( int i=0; igetValue(i) * factor)); + } + } else { + double factor = (double)height / (double)log(highest); + for( int i = 0; i < bins; ++i ) { + p.drawLine(i, height, i, height - int(log((double)histogram->getValue(i)) * factor)); + } + } + + m_page->histview->setPixmap(pix); +} + +KisLevelFilterConfiguration * KisLevelConfigWidget::config() +{ + KisLevelFilterConfiguration * cfg = new KisLevelFilterConfiguration(); + + cfg->blackvalue = m_page->blackspin->value(); + cfg->whitevalue = m_page->whitespin->value(); + cfg->gammavalue = m_page->ingradient->getGamma(); + + cfg->outblackvalue = m_page->outblackspin->value() * 255; + cfg->outwhitevalue = m_page->outwhitespin->value() * 255; + + return cfg; +} + +void KisLevelConfigWidget::setConfiguration( KisFilterConfiguration * config ) +{ + KisLevelFilterConfiguration * cfg = dynamic_cast(config); + m_page->blackspin->setValue(cfg->blackvalue); + m_page->whitespin->setValue(cfg->whitevalue); + m_page->ingradient->modifyGamma(cfg->gammavalue); + + m_page->outblackspin->setValue(cfg->outblackvalue / 255); + m_page->outwhitespin->setValue(cfg->outwhitevalue / 255); +} + diff --git a/chalk/plugins/filters/levelfilter/kis_level_filter.h b/chalk/plugins/filters/levelfilter/kis_level_filter.h new file mode 100644 index 00000000..8f3d3591 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/kis_level_filter.h @@ -0,0 +1,94 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_LEVEL_FILTER_H_ +#define _KIS_LEVEL_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class WdgLevel; +class TQWidget; +class KisColorAdjustment; +class KisHistogram; + +class KisLevelFilterConfiguration : public KisFilterConfiguration { + +public: + + KisLevelFilterConfiguration(); + virtual ~KisLevelFilterConfiguration(); + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + TQ_UINT8 blackvalue, whitevalue; + double gammavalue; + TQ_UINT16 outblackvalue, outwhitevalue; + KisColorAdjustment * m_adjustment; +}; + +/** + * This class affect Intensity Y of the image + */ +class KisLevelFilter : public KisFilter +{ + +public: + + KisLevelFilter(); + +public: + + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget *); + virtual KisFilterConfiguration * configuration() { return new KisLevelFilterConfiguration(); }; + virtual void process(KisPaintDeviceSP, KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("levels", i18n("Levels")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP dev); + + virtual ColorSpaceIndependence colorSpaceIndependence() { return TO_LAB16; }; + virtual bool workWith(KisColorSpace* cs); +}; + + +class KisLevelConfigWidget : public KisFilterConfigWidget { +Q_OBJECT + TQ_OBJECT +public: + KisLevelConfigWidget(TQWidget * tqparent, KisPaintDeviceSP dev, const char * name = 0, WFlags f = 0 ); + virtual ~KisLevelConfigWidget(); + + KisLevelFilterConfiguration * config(); + void setConfiguration( KisFilterConfiguration * config ); + WdgLevel * m_page; + +protected slots: + void drawHistogram(bool logarithmic = false); + +protected: + KisHistogram *histogram; + bool m_histlog; +}; + +#endif diff --git a/chalk/plugins/filters/levelfilter/levelfilter.cc b/chalk/plugins/filters/levelfilter/levelfilter.cc new file mode 100644 index 00000000..669775fb --- /dev/null +++ b/chalk/plugins/filters/levelfilter/levelfilter.cc @@ -0,0 +1,67 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "levelfilter.h" +#include "kis_level_filter.h" + +typedef KGenericFactory LevelFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalklevelfilter, LevelFilterFactory( "chalk" ) ) + +LevelFilter::LevelFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(LevelFilterFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisLevelFilter()); + } +} + +LevelFilter::~LevelFilter() +{ +} diff --git a/chalk/plugins/filters/levelfilter/levelfilter.h b/chalk/plugins/filters/levelfilter/levelfilter.h new file mode 100644 index 00000000..69627ff7 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/levelfilter.h @@ -0,0 +1,35 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Frederic Coiffier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef LEVEL_H +#define LEVEL_H + +#include + +class KisColorSpace; +class KisColorAdjustment; + +class LevelFilter : public KParts::Plugin +{ + public: + LevelFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~LevelFilter(); +}; + +#endif diff --git a/chalk/plugins/filters/levelfilter/wdg_level.ui b/chalk/plugins/filters/levelfilter/wdg_level.ui new file mode 100644 index 00000000..0db94640 --- /dev/null +++ b/chalk/plugins/filters/levelfilter/wdg_level.ui @@ -0,0 +1,331 @@ + +WdgLevel + + + WdgLevel + + + + 0 + 0 + 269 + 479 + + + + + 3 + 3 + 0 + 0 + + + + + 0 + 0 + + + + + 32767 + 32767 + + + + Levels + + + + unnamed + + + 0 + + + + chkLogarithmic + + + Logarithmic + + + + + textLabel2 + + + <b>Input levels</b> + + + + + tqlayout7 + + + + unnamed + + + + histview + + + + 256 + 256 + + + + + 256 + 256 + + + + true + + + + + tqlayout5 + + + + unnamed + + + + ingradient + + + + 256 + 20 + + + + + + tqlayout5 + + + + unnamed + + + + blackspin + + + PlusMinus + + + 255 + + + + + spacer5 + + + Horizontal + + + MinimumExpanding + + + + 25 + 20 + + + + + + gammaspin + + + 1.0 + + + AlignCenter + + + + + spacer6 + + + Horizontal + + + MinimumExpanding + + + + 25 + 20 + + + + + + whitespin + + + PlusMinus + + + 255 + + + + + + + + + textLabel3 + + + <b>Output levels</b> + + + + + tqlayout6 + + + + unnamed + + + + outgradient + + + + 256 + 20 + + + + + + tqlayout2 + + + + unnamed + + + + outblackspin + + + PlusMinus + + + 255 + + + + + spacer3 + + + Horizontal + + + MinimumExpanding + + + + 50 + 20 + + + + + + outwhitespin + + + PlusMinus + + + 255 + + + + + + + + + + + spacer5_2 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + spacer6_2 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + KGradientSlider +
kgradientslider.h
+ + -1 + -1 + + 0 + + 0 + 0 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + kgradientslider.h + kgradientslider.h + +
diff --git a/chalk/plugins/filters/noisefilter/Makefile.am b/chalk/plugins/filters/noisefilter/Makefile.am new file mode 100644 index 00000000..c3db54d0 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalknoisefilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalknoisefilter_la_SOURCES = noisefilter.cc wdgnoiseoptions.ui \ + kis_wdg_noise.cpp + +kde_module_LTLIBRARIES = chalknoisefilter.la +noinst_HEADERS = noisefilter.h kis_wdg_noise.h + +chalknoisefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalknoisefilter_la_LIBADD = ../../../libchalkcommon.la + +chalknoisefilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/noisefilter/chalknoisefilter.desktop b/chalk/plugins/filters/noisefilter/chalknoisefilter.desktop new file mode 100644 index 00000000..6ff1e2f1 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/chalknoisefilter.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Name=Noise Filter +Name[bg]=Шумов филтър +Name[ca]=Filtre de soroll +Name[da]=Støjfilter +Name[de]=Rauschfilter +Name[el]=Φίλτρο θορύβου +Name[eo]=Brufiltrilo +Name[es]=Filtro de ruido +Name[et]=Mürafilter +Name[fa]=پالایۀ نوفه +Name[fr]=Filtre de bruit +Name[fy]=Rûsfilter +Name[ga]=Scagaire Torainn +Name[gl]=Filtro de Ruído +Name[hu]=Zajszűrő +Name[it]=Filtro dei disturbi +Name[ja]=ノイズフィルタ +Name[km]=តម្រង​ភាព​មិន​ច្បាស់ +Name[lt]=Triukšmo filtras +Name[lv]=Trokšņu filtrs +Name[nb]=Støyfilter +Name[nds]=Ruusfilter +Name[ne]=ध्वनि फिल्टर +Name[nl]=Ruisfilter +Name[pl]=Filtr dodania szumu +Name[pt]=Filtro de Ruído +Name[pt_BR]=Filtro de Ruído +Name[ru]=Шум +Name[se]=Gádjasilli +Name[sk]=Filter zrnenie +Name[sl]=Filter za šum +Name[sr]=Филтер за шум +Name[sr@Latn]=Filter za šum +Name[sv]=Brusfilter +Name[uk]=Фільтр шуму +Name[uz]=Shovqin filteri +Name[uz@cyrillic]=Шовқин филтери +Name[zh_TW]=雜訊過濾器 +Comment=Add noise to an image +Comment[bg]=Добавяне на шум към изображение +Comment[ca]=Afegeix soroll a una imatge +Comment[da]=Tilføj støj til et billede +Comment[de]=Einem Bild Rauschen hinzufügen +Comment[el]=Προσθήκη θορύβου σε μια εικόνα +Comment[eo]=Aldoni bruon (entropion) al bildo +Comment[es]=Añadir ruido a una imagen +Comment[et]=Müra lisamine pildile +Comment[fa]=افزودن نوفه به یک تصویر +Comment[fr]=Ajouter du bruit à une image +Comment[fy]=Rûs oan in ôfbylding taheakje +Comment[gl]=Engade ruído a unha imaxe +Comment[hu]=Zaj hozzáadása képhez +Comment[it]=Aggiungi un disturbo all'immagine +Comment[ja]=画像にノイズを加える +Comment[km]=បន្ថែម​ភាព​មិន​ច្បាស់​ទៅ​រូបភាព +Comment[lv]=Pievieno attēlam troksni +Comment[nb]=Legg til støy i et bilde +Comment[nds]=En Bild Rusen tofögen +Comment[ne]=एउटा छविमा ध्वनि थप्नुहोस् +Comment[nl]=Voeg ruis toe aan een afbeelding +Comment[pl]=Dodaje szum do obrazka +Comment[pt]=Adiciona ruído a uma imagem +Comment[pt_BR]=Adiciona ruído a uma imagem +Comment[ru]=Добавление шума в изображение +Comment[se]=Lasit gája govvii +Comment[sk]=Pridať do obrázku zrnenie +Comment[sl]=Dodaj šum k sliki +Comment[sr]=Додај шум на слику +Comment[sr@Latn]=Dodaj šum na sliku +Comment[sv]=Lägg till brus i en bild +Comment[uk]=Додавання шуму в зображення +Comment[zh_TW]=在圖片中增加雜訊 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalknoisefilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/noisefilter/kis_wdg_noise.cpp b/chalk/plugins/filters/noisefilter/kis_wdg_noise.cpp new file mode 100644 index 00000000..060418f3 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/kis_wdg_noise.cpp @@ -0,0 +1,59 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_noise.h" + +#include + +#include + +#include "wdgnoiseoptions.h" + +KisWdgNoise::KisWdgNoise(KisFilter* /*nfilter*/, TQWidget* tqparent, const char* name) + : KisFilterConfigWidget(tqparent,name) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgNoiseOptions(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intLevel, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intOpacity, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgNoise::~KisWdgNoise() +{ +} + +void KisWdgNoise::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("level", value)) + { + widget()->intLevel->setValue( value.toUInt() ); + } + if (config->getProperty("opacity", value)) + { + widget()->intOpacity->setValue( value.toUInt() ); + } +} + + +#include "kis_wdg_noise.moc" + diff --git a/chalk/plugins/filters/noisefilter/kis_wdg_noise.h b/chalk/plugins/filters/noisefilter/kis_wdg_noise.h new file mode 100644 index 00000000..ca42ebd2 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/kis_wdg_noise.h @@ -0,0 +1,44 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WDG_NOISE_H +#define KIS_WDG_NOISE_H + +#include + +class WdgNoiseOptions; +class KisFilter; + +class KisWdgNoise : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgNoise(KisFilter* nfilter, TQWidget* tqparent = 0, const char* name = 0); + ~KisWdgNoise(); + public: + inline WdgNoiseOptions* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgNoiseOptions* m_widget; +}; + +#endif + diff --git a/chalk/plugins/filters/noisefilter/noisefilter.cc b/chalk/plugins/filters/noisefilter/noisefilter.cc new file mode 100644 index 00000000..af593703 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/noisefilter.cc @@ -0,0 +1,128 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "noisefilter.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_noise.h" +#include "wdgnoiseoptions.h" + +typedef KGenericFactory ChalkNoiseFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalknoisefilter, ChalkNoiseFilterFactory( "chalk" ) ) + +ChalkNoiseFilter::ChalkNoiseFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkNoiseFilterFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterNoise()); + } +} + +ChalkNoiseFilter::~ChalkNoiseFilter() +{ +} + +KisFilterNoise::KisFilterNoise() : KisFilter(id(), "other", i18n("&Random Noise...")) +{ +} + +KisFilterConfiguration* KisFilterNoise::configuration(TQWidget* w) +{ + KisWdgNoise* wN = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wN) + { + config->setProperty("level", wN->widget()->intLevel->value() ); + config->setProperty("opacity", wN->widget()->intOpacity->value() ); + } + return config; +} + +KisFilterConfigWidget * KisFilterNoise::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev) +{ + return new KisWdgNoise((KisFilter*)this, (TQWidget*)tqparent, i18n("Configuration of noise filter").ascii()); +} + +void KisFilterNoise::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 psize = cs->pixelSize(); + + TQVariant value; + int level = (config && config->getProperty("level", value)) ? value.toInt() : 50; + int opacity = (config && config->getProperty("opacity", value)) ? value.toInt() : 100; + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + + TQ_UINT8* interm = new TQ_UINT8[ cs->pixelSize() ]; + TQ_UINT32 threshold = (RAND_MAX / 100) * (100 - level); + + TQ_UINT8 weights[2]; + weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; + const TQ_UINT8* pixels[2]; + pixels[0] = interm; + while(!srcIt.isDone()) + { + if(rand() > threshold) + { + TQColor c = tqRgb((double)rand()/RAND_MAX * 255,(double)rand()/RAND_MAX * 255,(double)rand()/RAND_MAX * 255); + cs->fromTQColor( c, interm, 0 ); + pixels[1] = srcIt.oldRawData(); + cs->mixColors( pixels, weights, 2, dstIt.rawData() ); + } + ++srcIt; + ++dstIt; + incProgress(); + } + + delete interm; + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/noisefilter/noisefilter.h b/chalk/plugins/filters/noisefilter/noisefilter.h new file mode 100644 index 00000000..b73c761f --- /dev/null +++ b/chalk/plugins/filters/noisefilter/noisefilter.h @@ -0,0 +1,52 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef NOISEFILTER_H +#define NOISEFILTER_H + +#include +#include "kis_filter.h" + +class KisFilterConfigWidget; + +class ChalkNoiseFilter : public KParts::Plugin +{ +public: + ChalkNoiseFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkNoiseFilter(); +}; + +class KisFilterNoise : public KisFilter +{ + public: + KisFilterNoise(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("noise", i18n("Noise")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/noisefilter/wdgnoiseoptions.ui b/chalk/plugins/filters/noisefilter/wdgnoiseoptions.ui new file mode 100644 index 00000000..969d4153 --- /dev/null +++ b/chalk/plugins/filters/noisefilter/wdgnoiseoptions.ui @@ -0,0 +1,111 @@ + +WdgNoiseOptions + + + WdgNoiseOptions + + + + 0 + 0 + 174 + 63 + + + + + unnamed + + + 0 + + + + textLabel2 + + + Opacity: + + + + + textLabel1 + + + Level: + + + + + intOpacity + + + 100 + + + 0 + + + 100 + + + + + intLevel + + + 50 + + + 0 + + + 100 + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 21 + + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/oilpaintfilter/Makefile.am b/chalk/plugins/filters/oilpaintfilter/Makefile.am new file mode 100644 index 00000000..d67aab54 --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = chalkoilpaintfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I../../../ui/ \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkoilpaintfilter.la + +chalkoilpaintfilter_la_SOURCES = kis_oilpaint_filter_plugin.cc \ + kis_oilpaint_filter.cc + +noinst_HEADERS = kis_oilpaint_filter_plugin.h \ + kis_oilpaint_filter.h + +chalkoilpaintfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkoilpaintfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkoilpaintfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/oilpaintfilter/chalkoilpaintfilter.desktop b/chalk/plugins/filters/oilpaintfilter/chalkoilpaintfilter.desktop new file mode 100644 index 00000000..ae6682f6 --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/chalkoilpaintfilter.desktop @@ -0,0 +1,77 @@ +[Desktop Entry] +Name=Oilpaint Filter +Name[bg]=Филтър маслена боя +Name[ca]=Filtre de pintura a l'oli +Name[cy]=Hidlen Baent Olew +Name[da]=Oliemalerifilter +Name[de]=Ölgemälde-Filter +Name[el]=Φίλτρο ελαιογραφίας +Name[eo]=Olefarba filtrilo +Name[es]=Filtro de pintura al óleo +Name[et]=Õlimaalifilter +Name[fa]=پالایۀ رنگ روغن +Name[fi]=Öljymaalaussuodin +Name[fr]=Filtre de peinture à l'huile +Name[fy]=Oaljefervefilter +Name[gl]=Filtro de Pintura ao Óleo +Name[he]=מסנן צבעי שמן +Name[hu]=Olajfestmény szűrő +Name[is]=Olíumálunarsía +Name[it]=Filtro di pittura a olio +Name[ja]=油絵フィルタ +Name[km]=តម្រង​គំនូរ​ពណ៌​ប្រេង +Name[nb]=Oljemalingsfilter +Name[nds]=Öölbild-Filter +Name[ne]=ओइलपेन्ट फिल्टर +Name[nl]=Olieverffilter +Name[pl]=Filtr farb olejnych +Name[pt]=Filtro de Pintura a Óleo +Name[pt_BR]=Filtro de Pintura a Óleo +Name[ru]=Масляная краска +Name[sk]=Filter olejomaľba +Name[sl]=Filter Oljne barve +Name[sr]=Филтер за уље на платну +Name[sr@Latn]=Filter za ulje na platnu +Name[sv]=Oljemålningsfilter +Name[uk]=Фільтр олійних фарб +Name[zh_TW]=油畫過濾器 +Comment=Oilpaint filter +Comment[bg]=Филтър маслена боя +Comment[ca]=Filtre de pintura a l'oli +Comment[cy]=Hidlen baent olew +Comment[da]=Oliemalerifilter +Comment[de]=Ölgemälde-Filter +Comment[el]=Φίλτρο ελαιογραφίας +Comment[eo]=Olefarba filtrilo +Comment[es]=Filtro de pintura al óleo +Comment[et]=Õlimaalifilter +Comment[fa]=پالایۀ رنگ روغن +Comment[fi]=Öljymaalaussuodin +Comment[fr]=Filtre peinture à l'huile +Comment[fy]=Oaljefervefilter +Comment[gl]=Filtro de pintura ao óleo +Comment[he]=מסנן צבעי שמן +Comment[hu]=Olajfestmény szűrő +Comment[is]=Olíumálunarsía +Comment[it]=Filtro di pittura a olio +Comment[ja]=油絵フィルタ +Comment[km]=តម្រង​គំនូរ​ពណ៌​ប្រេង +Comment[nb]=Oljemalingsfilter +Comment[nds]=Öölbild-Filter +Comment[ne]=ओइलपेन्ट फिल्टर +Comment[nl]=Olieverffilter +Comment[pl]=Filtr farb olejnych +Comment[pt]=Filtro de pintura a óleo +Comment[pt_BR]=Filtro de pintura a óleo +Comment[ru]=Масляная краска +Comment[sk]=Filter olejomaľba +Comment[sl]=Filter Oljna barva +Comment[sr]=Филтер за уље на платну +Comment[sr@Latn]=Filter za ulje na platnu +Comment[sv]=Oljemålningsfilter +Comment[uk]=Фільтр олійних фарб +Comment[zh_TW]=油畫過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkoilpaintfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc new file mode 100644 index 00000000..fc96b991 --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.cc @@ -0,0 +1,256 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * ported from digikam, Copyright 2004 by Gilles Caulier, + * Original Oilpaint algorithm copyrighted 2004 by + * Pieter Z. Voloshyn . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_oilpaint_filter.h" + +KisOilPaintFilter::KisOilPaintFilter() : KisFilter(id(), "artistic", i18n("&Oilpaint...")) +{ +} + +void KisOilPaintFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + + if (!configuration) { + kdWarning() << "No configuration object for oilpaint filter\n"; + return; + } + + Q_UNUSED(dst); + + TQ_INT32 x = rect.x(), y = rect.y(); + TQ_INT32 width = rect.width(); + TQ_INT32 height = rect.height(); + + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 brushSize = ((KisOilPaintFilterConfiguration*)configuration)->brushSize(); + TQ_UINT32 smooth = ((KisOilPaintFilterConfiguration*)configuration)->smooth(); + + + OilPaint(src, dst, x, y, width, height, brushSize, smooth); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to apply the OilPaint effect. + * + * data => The image data in RGBA mode. + * w => Width of image. + * h => Height of image. + * BrushSize => Brush size. + * Smoothness => Smooth value. + * + * Theory => Using MostFrequentColor function we take the main color in + * a matrix and simply write at the original position. + */ + +void KisOilPaintFilter::OilPaint(KisPaintDeviceSP src, KisPaintDeviceSP dst, int x, int y, int w, int h, int BrushSize, int Smoothness) +{ + setProgressTotalSteps(h); + setProgressStage(i18n("Applying oilpaint filter..."),0); + + TQRect bounds(x, y, w, h); + + for (TQ_INT32 yOffset = 0; yOffset < h; yOffset++) { + + KisHLineIteratorPixel it = src->createHLineIterator(x, y + yOffset, w, false); + KisHLineIteratorPixel dstIt = dst->createHLineIterator(x, y + yOffset, w, true); + + while (!it.isDone() && !cancelRequested()) { + + if (it.isSelected()) { + + uint color = MostFrequentColor(src, bounds, it.x(), it.y(), BrushSize, Smoothness); + dst->colorSpace()->fromTQColor(TQColor(tqRed(color), tqGreen(color), tqBlue(color)), tqAlpha(color), dstIt.rawData()); + } + + ++it; + ++dstIt; + } + + setProgress(yOffset); + } + + setProgressDone(); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to determine the most frequent color in a matrix + * + * Bits => Bits array + * Width => Image width + * Height => Image height + * X => Position horizontal + * Y => Position vertical + * Radius => Is the radius of the matrix to be analized + * Intensity => Intensity to calcule + * + * Theory => This function creates a matrix with the analized pixel in + * the center of this matrix and find the most frequenty color + */ + +uint KisOilPaintFilter::MostFrequentColor (KisPaintDeviceSP src, const TQRect& bounds, int X, int Y, int Radius, int Intensity) +{ + uint color; + uint I; + + double Scale = Intensity / 255.0; + + // Alloc some arrays to be used + uchar *IntensityCount = new uchar[(Intensity + 1) * sizeof (uchar)]; + uint *AverageColorR = new uint[(Intensity + 1) * sizeof (uint)]; + uint *AverageColorG = new uint[(Intensity + 1) * sizeof (uint)]; + uint *AverageColorB = new uint[(Intensity + 1) * sizeof (uint)]; + + // Erase the array + memset(IntensityCount, 0, (Intensity + 1) * sizeof (uchar)); + + /*for (i = 0; i <= Intensity; ++i) + IntensityCount[i] = 0;*/ + + KisRectIteratorPixel it = src->createRectIterator(X - Radius, Y - Radius, (2 * Radius) + 1, (2 * Radius) + 1, false); + + while (!it.isDone()) { + + if (bounds.tqcontains(it.x(), it.y())) { + +// XXX: COLORSPACE_INDEPENDENCE + + TQColor c; + src->colorSpace()->toTQColor(it.rawData(), &c); + + // Swapping red and blue here is done because that gives the same + // output as digikam, even though it might be interpreted as a bug + // in both applications. + int b = c.red(); + int g = c.green(); + int r = c.blue(); + + I = (uint)(GetIntensity (r, g, b) * Scale); + IntensityCount[I]++; + + if (IntensityCount[I] == 1) + { + AverageColorR[I] = r; + AverageColorG[I] = g; + AverageColorB[I] = b; + } + else + { + AverageColorR[I] += r; + AverageColorG[I] += g; + AverageColorB[I] += b; + } + } + + ++it; + } + + I = 0; + int MaxInstance = 0; + + for (int i = 0 ; i <= Intensity ; ++i) + { + if (IntensityCount[i] > MaxInstance) + { + I = i; + MaxInstance = IntensityCount[i]; + } + } + + int R, G, B; + if (MaxInstance != 0) { + R = AverageColorR[I] / MaxInstance; + G = AverageColorG[I] / MaxInstance; + B = AverageColorB[I] / MaxInstance; + } else { + R = 0; + G = 0; + B = 0; + } + + // Swap red and blue back to get the correct colour. + color = tqRgb (B, G, R); + + delete [] IntensityCount; // free all the arrays + delete [] AverageColorR; + delete [] AverageColorG; + delete [] AverageColorB; + + return (color); // return the most frequenty color +} + + +KisFilterConfigWidget * KisOilPaintFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 1, 5, 1, i18n("Brush size"), "brushSize" ) ); + param.push_back( KisIntegerWidgetParam( 10, 255, 30, i18n("Smooth"), "smooth" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisOilPaintFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisOilPaintFilterConfiguration( 1, 30); + } else { + return new KisOilPaintFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} + +std::list KisOilPaintFilter::listOfExamplesConfiguration(KisPaintDeviceSP ) +{ + std::list list; + list.insert(list.begin(), new KisOilPaintFilterConfiguration( 1, 30)); + return list; +} + diff --git a/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h new file mode 100644 index 00000000..fbc07a63 --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter.h @@ -0,0 +1,69 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_OILPAINT_FILTER_H_ +#define _KIS_OILPAINT_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisOilPaintFilterConfiguration : public KisFilterConfiguration +{ + +public: + + KisOilPaintFilterConfiguration(TQ_UINT32 brushSize, TQ_UINT32 smooth) + : KisFilterConfiguration( "oilpaint", 1 ) + { + setProperty("brushSize", brushSize); + setProperty("smooth", smooth); + }; +public: + + inline TQ_UINT32 brushSize() { return getInt("brushSize"); }; + inline TQ_UINT32 smooth() {return getInt("smooth"); }; + +}; + + +class KisOilPaintFilter : public KisFilter +{ +public: + KisOilPaintFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("oilpaint", i18n("Oilpaint")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP dev); + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return new KisOilPaintFilterConfiguration( 1, 30); }; +private: + void OilPaint(KisPaintDeviceSP src, KisPaintDeviceSP dst, int x, int y, int w, int h, int BrushSize, int Smoothness); + uint MostFrequentColor(KisPaintDeviceSP, const TQRect& bounds, int X, int Y, int Radius, int Intensity); + // Function to calcule the color intensity and return the luminance (Y) + // component of YIQ color model. + inline uint GetIntensity(uint Red, uint Green, uint Blue) { return ((uint)(Red * 0.3 + Green * 0.59 + Blue * 0.11)); } +}; + +#endif diff --git a/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc new file mode 100644 index 00000000..7167b04d --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.cc @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_oilpaint_filter_plugin.h" +#include "kis_oilpaint_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisOilPaintFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkoilpaintfilter, KisOilPaintFilterPluginFactory( "chalk" ) ) + +KisOilPaintFilterPlugin::KisOilPaintFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) : KParts::Plugin(tqparent, name) +{ + setInstance(KisOilPaintFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisOilPaintFilter()); + } + +} + +KisOilPaintFilterPlugin::~KisOilPaintFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h new file mode 100644 index 00000000..1f780918 --- /dev/null +++ b/chalk/plugins/filters/oilpaintfilter/kis_oilpaint_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_OILPAINT_FILTER_PLUGIN_H_ +#define _KIS_OILPAINT_FILTER_PLUGIN_H_ + +#include + +class KisOilPaintFilterPlugin : public KParts::Plugin +{ +public: + KisOilPaintFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisOilPaintFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/pixelizefilter/Makefile.am b/chalk/plugins/filters/pixelizefilter/Makefile.am new file mode 100644 index 00000000..9a8771a6 --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = chalkpixelizefilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + -I$(srcdir)/../../../../lib/kofficeui \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkpixelizefilter.la + +chalkpixelizefilter_la_SOURCES = kis_pixelize_filter_plugin.cc \ + kis_pixelize_filter.cc + +noinst_HEADERS = kis_pixelize_filter_plugin.h \ + kis_pixelize_filter.h + +chalkpixelizefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkpixelizefilter_la_LIBADD = ../../../libchalkcommon.la + +chalkpixelizefilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/pixelizefilter/chalkpixelizefilter.desktop b/chalk/plugins/filters/pixelizefilter/chalkpixelizefilter.desktop new file mode 100644 index 00000000..a7a2e88f --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/chalkpixelizefilter.desktop @@ -0,0 +1,83 @@ +[Desktop Entry] +Name=Pixelize Filter +Name[bg]=Филтър Pixelize +Name[ca]=Filtre de pixelació +Name[cy]=Hidlen bicseleiddio +Name[da]=Billedpunktfilter +Name[de]=Pixelize-Filter +Name[el]=Φίλτρο δημιουργίας εικονοστοιχείων +Name[en_GB]=Pixelise Filter +Name[eo]=Rastrumiga filtrilo +Name[es]=Filtro de pixelación +Name[et]=Mosaiigi filter +Name[fa]=پالایۀ Pixelize +Name[fr]=Filtre pixélisation +Name[fy]=Byldpuntfilter +Name[ga]=Scagaire Picteilínithe +Name[gl]=Filtro de Pixelización +Name[he]=מסנן מפוקסל +Name[hu]=Pixelesítő szűrő +Name[is]=Punktasía +Name[it]=Filtro di pixellizzazione +Name[ja]=ピクセル化フィルタ +Name[km]=តម្រង​ធ្វើ​ភីកសែល +Name[nb]=Pikseleringsfilter +Name[nds]=Pixelfilter +Name[ne]=फिल्टर पिक्सेलाइज गर्नुहोस् +Name[nl]=Pixelfilter +Name[pl]=Filtr pikselizacji +Name[pt]=Filtro de Pixelização +Name[pt_BR]=Filtro de Pixelização +Name[ru]=Пикселизация +Name[sk]=Filter pixelizovať +Name[sl]=Filter Spremeni v pike +Name[sr]=Филтер за пикселизацију +Name[sr@Latn]=Filter za pikselizaciju +Name[sv]=Bildpunktsfilter +Name[uk]=Фільтр пікселювання +Name[uz]=Piksellashtirish filteri +Name[uz@cyrillic]=Пикселлаштириш филтери +Name[zh_TW]=像素化過濾器 +Comment=Pixelize filter +Comment[bg]=Филтър Pixelize +Comment[ca]=Filtre de pixelació +Comment[cy]=Hidlen bicseleiddio +Comment[da]=Billedpunktfilter +Comment[de]=Pixelize-Filter +Comment[el]=Φίλτρο δημιουργίας εικονοστοιχείων +Comment[en_GB]=Pixelise filter +Comment[eo]=Rastrumiga filtrilo +Comment[es]=Filtro de pixelación +Comment[et]=Mosaiigi filter +Comment[fa]=پالایۀ Pixelize +Comment[fr]=Filtre pixélisation +Comment[fy]=Byldpuntfilter +Comment[ga]=Scagaire picteilínithe +Comment[gl]=Filtro de pixelización +Comment[he]=מסנן מפוקסל +Comment[hu]=Pixelesítő szűrő +Comment[is]=Punktasía +Comment[it]=Filtro di pixellizzazione +Comment[ja]=ピクセル化フィルタ +Comment[km]=តម្រង​ធ្វើ​ភីកសែល +Comment[nb]=Pikseleringsfilter +Comment[nds]=Pixelfilter +Comment[ne]=फिल्टर पिक्सेलाइज गर्नुहोस् +Comment[nl]=Pixelfilter +Comment[pl]=Filtr pikselizacji +Comment[pt]=Filtro de pixelização +Comment[pt_BR]=Filtro de pixelização +Comment[ru]=Пикселизация +Comment[sk]=Filter pixelizovať +Comment[sl]=Filter Spremeni v pike +Comment[sr]=Филтер за пикселизацију +Comment[sr@Latn]=Filter za pikselizaciju +Comment[sv]=Bildpunktsfilter +Comment[uk]=Фільтр пікселювання +Comment[uz]=Piksellashtirish filteri +Comment[uz@cyrillic]=Пикселлаштириш филтери +Comment[zh_TW]=像素化過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkpixelizefilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.cc b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.cc new file mode 100644 index 00000000..267b159b --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.cc @@ -0,0 +1,188 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_pixelize_filter.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +KisPixelizeFilter::KisPixelizeFilter() : KisFilter(id(), "artistic", i18n("&Pixelize...")) +{ +} + +void KisPixelizeFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + Q_ASSERT( src ); + Q_ASSERT( dst ); + Q_ASSERT( configuration ); + Q_ASSERT( rect.isValid() ); + + TQ_INT32 x = rect.x(), y = rect.y(); + TQ_INT32 width = rect.width(); + TQ_INT32 height = rect.height(); + + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 pixelWidth = ((KisPixelizeFilterConfiguration*)configuration)->pixelWidth(); + TQ_UINT32 pixelHeight = ((KisPixelizeFilterConfiguration*)configuration)->pixelHeight(); + + pixelize(src, dst, x, y, width, height, pixelWidth, pixelHeight); +} + +void KisPixelizeFilter::pixelize(KisPaintDeviceSP src, KisPaintDeviceSP dst, int startx, int starty, int width, int height, int pixelWidth, int pixelHeight) +{ + Q_ASSERT(src); + Q_ASSERT(dst); + + if (!src) return; + if (!dst) return; + + TQ_INT32 pixelSize = src->pixelSize(); + TQMemArray average( pixelSize ); + + TQ_INT32 count; + + //calculate the total number of pixels + TQ_INT32 numX=0; + TQ_INT32 numY=0; + + for (TQ_INT32 x = startx; x < startx + width; x += pixelWidth - (x % pixelWidth)) + { + numX++; + } + for (TQ_INT32 y = starty; y < starty + height; y += pixelHeight - (y % pixelHeight)) + { + numY++; + } + + setProgressTotalSteps( numX * numY ); + setProgressStage(i18n("Applying pixelize filter..."),0); + + TQ_INT32 numberOfPixelsProcessed = 0; + + for (TQ_INT32 y = starty; y < starty + height; y += pixelHeight - (y % pixelHeight)) + { + TQ_INT32 h = pixelHeight - (y % pixelHeight); + h = MIN(h, starty + height - y); + + for (TQ_INT32 x = startx; x < startx + width; x += pixelWidth - (x % pixelWidth)) + { + TQ_INT32 w = pixelWidth - (x % pixelWidth); + w = MIN(w, startx + width - x); + + for (TQ_INT32 i = 0; i < pixelSize; i++) + { + average[i] = 0; + } + count = 0; + + //read + KisRectIteratorPixel srcIt = src->createRectIterator(x, y, w, h, false); + while( ! srcIt.isDone() ) { + if(srcIt.isSelected()) + { + for (TQ_INT32 i = 0; i < pixelSize; i++) + { + average[i] += srcIt.oldRawData()[i]; + } + count++; + } + ++srcIt; + } + + //average + if (count > 0) + { + for (TQ_INT32 i = 0; i < pixelSize; i++) + average[i] /= count; + } + //write + srcIt = src->createRectIterator(x, y, w, h, false); + KisRectIteratorPixel dstIt = dst->createRectIterator(x, y, w, h, true ); + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + for( int i = 0; i < pixelSize; i++) + { + dstIt.rawData()[i] = average[i]; + } + } + ++srcIt; + ++dstIt; + } + numberOfPixelsProcessed++; + setProgress(numberOfPixelsProcessed); + } + } + + setProgressDone(); +} + +KisFilterConfigWidget * KisPixelizeFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 40, 10, i18n("Pixel width"), "pixelWidth" ) ); + param.push_back( KisIntegerWidgetParam( 2, 40, 10, i18n("Pixel height"), "pixelHeight" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisPixelizeFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisPixelizeFilterConfiguration( 10, 10); + } else { + return new KisPixelizeFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} + +KisFilterConfiguration * KisPixelizeFilter::configuration() +{ + return new KisPixelizeFilterConfiguration(10, 10); +} diff --git a/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.h b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.h new file mode 100644 index 00000000..c7d8bb31 --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter.h @@ -0,0 +1,61 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_PIXELIZE_FILTER_H_ +#define _KIS_PIXELIZE_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisPixelizeFilterConfiguration : public KisFilterConfiguration +{ +public: + KisPixelizeFilterConfiguration(TQ_UINT32 pixelWidth, TQ_UINT32 pixelHeight) + : KisFilterConfiguration( "pixelize", 1 ) + { + setProperty("pixelWidth", pixelWidth); + setProperty("pixelHeight", pixelHeight); + }; +public: + inline TQ_UINT32 pixelWidth() { return getInt("pixelWidth"); }; + inline TQ_UINT32 pixelHeight() {return getInt("pixelHeight"); }; +}; + +class KisPixelizeFilter : public KisFilter +{ +public: + KisPixelizeFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("pixelize", i18n("Pixelize")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisPixelizeFilterConfiguration(10,10)); return list; } +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration * configuration(); +private: + void pixelize(KisPaintDeviceSP src, KisPaintDeviceSP dst, int x, int y, int w, int h, int pixelWidth, int pixelHeight); +}; + +#endif diff --git a/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc new file mode 100644 index 00000000..93309146 --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.cc @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_pixelize_filter_plugin.h" +#include "kis_pixelize_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisPixelizeFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkpixelizefilter, KisPixelizeFilterPluginFactory( "chalk" ) ) + +KisPixelizeFilterPlugin::KisPixelizeFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(KisPixelizeFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisPixelizeFilter()); + } +} + +KisPixelizeFilterPlugin::~KisPixelizeFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h new file mode 100644 index 00000000..25d8a62f --- /dev/null +++ b/chalk/plugins/filters/pixelizefilter/kis_pixelize_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_PIXELIZE_FILTER_PLUGIN_H_ +#define _KIS_PIXELIZE_FILTER_PLUGIN_H_ + +#include + +class KisPixelizeFilterPlugin : public KParts::Plugin +{ +public: + KisPixelizeFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisPixelizeFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/raindropsfilter/Makefile.am b/chalk/plugins/filters/raindropsfilter/Makefile.am new file mode 100644 index 00000000..d4e5632d --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/Makefile.am @@ -0,0 +1,24 @@ +kde_services_DATA = chalkraindropsfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../chalkcolor/color_strategy \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkraindropsfilter.la + +chalkraindropsfilter_la_SOURCES = kis_raindrops_filter_plugin.cc \ + kis_raindrops_filter.cc + +noinst_HEADERS = kis_raindrops_filter_plugin.h \ + kis_raindrops_filter.h + +chalkraindropsfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkraindropsfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkraindropsfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/raindropsfilter/chalkraindropsfilter.desktop b/chalk/plugins/filters/raindropsfilter/chalkraindropsfilter.desktop new file mode 100644 index 00000000..13b90349 --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/chalkraindropsfilter.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Name=Raindrops Filter +Name[bg]=Филтър за дъждовни капки +Name[ca]=Filtre de gotes de pluja +Name[cy]=Hidlen Ddiferion Glaw +Name[da]=Regndråbefilter +Name[de]=Regentropfen-Filter +Name[el]=Φίλτρο σταγόνων βροχής +Name[eo]=Pluvguta filtrilo +Name[es]=Filtro de gotas de lluvia +Name[et]=Vihmapiiskade filter +Name[fa]=پالایۀ قطرات باران +Name[fi]=Vesipisarasuodin +Name[fr]=Filtre gouttes de pluie +Name[fy]=Reindruppenfilter +Name[gl]=Filtro de Pingas de Chuvia +Name[hu]=Esőcsepp szűrő +Name[is]=Regndropasía +Name[it]=Filtro a gocce di pioggia +Name[ja]=雨滴フィルタ +Name[km]=តម្រង​តំណក់ទឹកភ្លៀង +Name[nb]=Regndråpefilter +Name[nds]=Regendrüppen-Filter +Name[ne]=वर्षाथोपा फिल्टर +Name[nl]=Regendruppelfilter +Name[pl]=Filtr symulujący krople deszczu +Name[pt]=Filtro de Pingos de Chuva +Name[pt_BR]=Filtro de Pingos de Chuva +Name[ru]=Дождевые капли +Name[se]=Arvečalbmesilli +Name[sk]=Filter dažďové kvapky +Name[sl]=Filter Dežne kapljice +Name[sr]=Филтер за кишне капи +Name[sr@Latn]=Filter za kišne kapi +Name[sv]=Regndroppsfilter +Name[uk]=Фільтр дощових крапель +Name[uz]=Yomgʻir tomchilari filteri +Name[uz@cyrillic]=Ёмғир томчилари филтери +Name[zh_TW]=雨滴過濾器 +Comment=Raindrops filter +Comment[bg]=Филтър за дъждовни капки +Comment[ca]=Filtre de gotes de pluja +Comment[cy]=Hidlen ddiferion glaw +Comment[da]=Regndråbefilter +Comment[de]=Regentropfen-Filter +Comment[el]=Φίλτρο σταγόνων βροχής +Comment[eo]=Pluvguta filtrilo +Comment[es]=Filtro de gotas de lluvia +Comment[et]=Vihmapiiskade filter +Comment[fa]=پالایۀ قطرات باران +Comment[fi]=Vesipisarasuodin +Comment[fr]=Filtre gouttes de pluie +Comment[fy]=Reindruppenfilter +Comment[gl]=Filtro de pingas de chuvia +Comment[hu]=Esőcsepp szűrő +Comment[is]=Regndropasía +Comment[it]=Filtro a gocce di pioggia +Comment[ja]=雨滴フィルタ +Comment[km]=តម្រង​តំណក់​ទឹកភ្លៀង +Comment[nb]=Regndråpefilter +Comment[nds]=Regendrüppen-Filter +Comment[ne]=वर्षाथोपा फिल्टर +Comment[nl]=Regendruppelfilter +Comment[pl]=Filtr symulujący krople deszczu +Comment[pt]=Filtro de pingos de chuva +Comment[pt_BR]=Filtro de pingos de chuva +Comment[ru]=Дождевые капли +Comment[se]=Arvečalbmesilli +Comment[sk]=Filter dažďové kvapky +Comment[sl]=Filter Dežne kapljice +Comment[sr]=Филтер за кишне капи +Comment[sr@Latn]=Filter za kišne kapi +Comment[sv]=Regndroppsfilter +Comment[uk]=Фільтр дощових крапель +Comment[uz]=Yomgʻir tomchilari filteri +Comment[uz@cyrillic]=Ёмғир томчилари филтери +Comment[zh_TW]=雨滴過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkraindropsfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.cc b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.cc new file mode 100644 index 00000000..c208bb52 --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.cc @@ -0,0 +1,439 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Michael Thaler + * + * ported from digikam, Copyright 2004 by Gilles Caulier, + * Original RainDrops algorithm copyrighted 2004 by + * Pieter Z. Voloshyn . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_raindrops_filter.h" + +KisRainDropsFilter::KisRainDropsFilter() : KisFilter(id(), "artistic", i18n("&Raindrops...")) +{ +} + +void KisRainDropsFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + + Q_UNUSED(dst); + + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 dropSize = ((KisRainDropsFilterConfiguration*)configuration)->dropSize(); + TQ_UINT32 number = ((KisRainDropsFilterConfiguration*)configuration)->number(); + TQ_UINT32 fishEyes = ((KisRainDropsFilterConfiguration*)configuration)->fishEyes(); + + + rainDrops(src, dst, rect, dropSize, number, fishEyes); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to apply the RainDrops effect (inspired from Jason Waltman code) + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * DropSize => Raindrop size + * Amount => Maximum number of raindrops + * Coeff => FishEye coefficient + * + * Theory => This functions does several math's functions and the engine + * is simple to undestand, but a little hard to implement. A + * control will indicate if there is or not a raindrop in that + * area, if not, a fisheye effect with a random size (max=DropSize) + * will be applied, after this, a shadow will be applied too. + * and after this, a blur function will finish the effect. + */ + +void KisRainDropsFilter::rainDrops(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, int DropSize, int Amount, int Coeff) +{ + setProgressTotalSteps(Amount); + setProgressStage(i18n("Applying oilpaint filter..."),0); + + if (Coeff <= 0) Coeff = 1; + + if (Coeff > 100) Coeff = 100; + + int Width = rect.width(); + int Height = rect.height(); + + bool** BoolMatrix = CreateBoolArray (Width, Height); + + int i, j, k, l, m, n; // loop variables + int Bright; // Bright value for shadows and highlights + int x, y; // center coordinates + int Counter = 0; // Counter (duh !) + int NewSize; // Size of current raindrop + int halfSize; // Half of the current raindrop + int Radius; // Maximum radius for raindrop + int BlurRadius; // Blur Radius + int BlurPixels; + + double r, a; // polar coordinates + double OldRadius; // Radius before processing + double NewCoeff = (double)Coeff * 0.01; // FishEye Coefficients + double s; + double R, G, B; + + bool FindAnother = false; // To search for good coordinates + + KisColorSpace * cs = src->colorSpace(); + + TQDateTime dt = TQDateTime::tqcurrentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + + srand ((uint) dt.secsTo(Y2000)); + + // Init booleen Matrix. + + for (i = 0 ; !cancelRequested() && (i < Width) ; ++i) + { + for (j = 0 ; !cancelRequested() && (j < Height) ; ++j) + { + BoolMatrix[i][j] = false; + } + } + KisRandomAccessorPixel oldIt = src->createRandomAccessor(0,0,false); + KisRandomAccessorPixel dstIt = dst->createRandomAccessor(0,0,true); + + for (int NumBlurs = 0 ; !cancelRequested() && (NumBlurs <= Amount) ; ++NumBlurs) + { + NewSize = (int)(rand() * ((double)(DropSize - 5) / RAND_MAX) + 5); + halfSize = NewSize / 2; + Radius = halfSize; + s = Radius / log (NewCoeff * Radius + 1); + + Counter = 0; + + do + { + FindAnother = false; + y = (int)(rand() * ((double)( Width - 1) / RAND_MAX)); + x = (int)(rand() * ((double)(Height - 1) / RAND_MAX)); + + if (BoolMatrix[y][x]) + FindAnother = true; + else + for (i = x - halfSize ; !cancelRequested() && (i <= x + halfSize) ; i++) + for (j = y - halfSize ; !cancelRequested() && (j <= y + halfSize) ; j++) + if ((i >= 0) && (i < Height) && (j >= 0) && (j < Width)) + if (BoolMatrix[j][i]) + FindAnother = true; + + Counter++; + } + while (!cancelRequested() && (FindAnother && (Counter < 10000)) ); + + if (Counter >= 10000) + { + NumBlurs = Amount; + break; + } + + for (i = -1 * halfSize ; !cancelRequested() && (i < NewSize - halfSize) ; i++) + { + for (j = -1 * halfSize ; !cancelRequested() && (j < NewSize - halfSize) ; j++) + { + r = sqrt (i * i + j * j); + a = atan2 (i, j); + + if (r <= Radius) + { + OldRadius = r; + r = (exp (r / s) - 1) / NewCoeff; + + k = x + (int)(r * sin (a)); + l = y + (int)(r * cos (a)); + + m = x + i; + n = y + j; + + if ((k >= 0) && (k < Height) && (l >= 0) && (l < Width)) + { + if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) + { + Bright = 0; + + if (OldRadius >= 0.9 * Radius) + { + if ((a <= 0) && (a > -2.25)) + Bright = -80; + else if ((a <= -2.25) && (a > -2.5)) + Bright = -40; + else if ((a <= 0.25) && (a > 0)) + Bright = -40; + } + + else if (OldRadius >= 0.8 * Radius) + { + if ((a <= -0.75) && (a > -1.50)) + Bright = -40; + else if ((a <= 0.10) && (a > -0.75)) + Bright = -30; + else if ((a <= -1.50) && (a > -2.35)) + Bright = -30; + } + + else if (OldRadius >= 0.7 * Radius) + { + if ((a <= -0.10) && (a > -2.0)) + Bright = -20; + else if ((a <= 2.50) && (a > 1.90)) + Bright = 60; + } + + else if (OldRadius >= 0.6 * Radius) + { + if ((a <= -0.50) && (a > -1.75)) + Bright = -20; + else if ((a <= 0) && (a > -0.25)) + Bright = 20; + else if ((a <= -2.0) && (a > -2.25)) + Bright = 20; + } + + else if (OldRadius >= 0.5 * Radius) + { + if ((a <= -0.25) && (a > -0.50)) + Bright = 30; + else if ((a <= -1.75 ) && (a > -2.0)) + Bright = 30; + } + + else if (OldRadius >= 0.4 * Radius) + { + if ((a <= -0.5) && (a > -1.75)) + Bright = 40; + } + + else if (OldRadius >= 0.3 * Radius) + { + if ((a <= 0) && (a > -2.25)) + Bright = 30; + } + + else if (OldRadius >= 0.2 * Radius) + { + if ((a <= -0.5) && (a > -1.75)) + Bright = 20; + } + + BoolMatrix[n][m] = true; + + TQColor originalColor; + oldIt.moveTo(rect.x() + l, rect.y() + k); + cs->toTQColor(oldIt.oldRawData(), &originalColor); + + int newRed = CLAMP(originalColor.red() + Bright, 0, TQ_UINT8_MAX); + int newGreen = CLAMP(originalColor.green() + Bright, 0, TQ_UINT8_MAX); + int newBlue = CLAMP(originalColor.blue() + Bright, 0, TQ_UINT8_MAX); + + TQColor newColor; + newColor.setRgb(newRed, newGreen, newBlue); + + dstIt.moveTo(rect.x() + n, rect.y() + m); + cs->fromTQColor(newColor, dstIt.rawData()); + } + } + } + } + } + + BlurRadius = NewSize / 25 + 1; + + for (i = -1 * halfSize - BlurRadius ; !cancelRequested() && (i < NewSize - halfSize + BlurRadius) ; i++) + { + for (j = -1 * halfSize - BlurRadius ; !cancelRequested() && (j < NewSize - halfSize + BlurRadius) ; j++) + { + r = sqrt (i * i + j * j); + + if (r <= Radius * 1.1) + { + R = G = B = 0; + BlurPixels = 0; + + for (k = -1 * BlurRadius; k < BlurRadius + 1; k++) + for (l = -1 * BlurRadius; l < BlurRadius + 1; l++) + { + m = x + i + k; + n = y + j + l; + + if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) + { + TQColor color; + dstIt.moveTo(rect.x() + n, rect.y() + m); + + cs->toTQColor(dstIt.rawData(), &color); + + R += color.red(); + G += color.green(); + B += color.blue(); + BlurPixels++; + } + } + + m = x + i; + n = y + j; + + if ((m >= 0) && (m < Height) && (n >= 0) && (n < Width)) + { + TQColor color; + + color.setRgb((int)(R / BlurPixels), (int)(G / BlurPixels), (int)(B / BlurPixels)); + dstIt.moveTo(rect.x() + n, rect.y() + m); + + cs->fromTQColor(color, dstIt.rawData()); + } + } + } + } + + setProgress(NumBlurs); + } + +/* KisRectIteratorPixel srcIt2 = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + KisRectIteratorPixel dstIt2 = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true); + + while (!srcIt2.isDone()) { + + if (!srcIt2.isSelected()) { + memcpy(dstIt2.rawData(), srcIt2.oldRawData(), src->pixelSize()); + } + ++srcIt2; + } +*/ + FreeBoolArray (BoolMatrix, Width); + + setProgressDone(); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* Function to free a dinamic boolean array + * + * lpbArray => Dynamic boolean array + * Columns => The array bidimension value + * + * Theory => An easy to undestand 'for' statement + */ +void KisRainDropsFilter::FreeBoolArray (bool** lpbArray, uint Columns) +{ + for (uint i = 0; i < Columns; ++i) + free (lpbArray[i]); + + free (lpbArray); +} + +/* Function to create a bidimentional dinamic boolean array + * + * Columns => Number of columns + * Rows => Number of rows + * + * Theory => Using 'for' statement, we can alloc multiple dinamic arrays + * To create more dimentions, just add some 'for's, ok? + */ +bool** KisRainDropsFilter::CreateBoolArray (uint Columns, uint Rows) +{ + bool** lpbArray = NULL; + lpbArray = (bool**) malloc (Columns * sizeof (bool*)); + + if (lpbArray == NULL) + return (NULL); + + for (uint i = 0; i < Columns; ++i) + { + lpbArray[i] = (bool*) malloc (Rows * sizeof (bool)); + if (lpbArray[i] == NULL) + { + FreeBoolArray (lpbArray, Columns); + return (NULL); + } + } + + return (lpbArray); +} + +// This method have been ported from Pieter Z. Voloshyn algorithm code. + +/* This function limits the RGB values + * + * ColorValue => Here, is an RGB value to be analized + * + * Theory => A color is represented in RGB value (e.g. 0xFFFFFF is + * white color). But R, G and B values has 256 values to be used + * so, this function analize the value and limits to this range + */ + +uchar KisRainDropsFilter::LimitValues (int ColorValue) +{ + if (ColorValue > 255) // MAX = 255 + ColorValue = 255; + if (ColorValue < 0) // MIN = 0 + ColorValue = 0; + return ((uchar) ColorValue); +} + +KisFilterConfigWidget * KisRainDropsFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 1, 200, 80, i18n("Drop size"), "dropsize" ) ); + param.push_back( KisIntegerWidgetParam( 1, 500, 80, i18n("Number"), "number" ) ); + param.push_back( KisIntegerWidgetParam( 1, 100, 30, i18n("Fish eyes"), "fishEyes" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisRainDropsFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisRainDropsFilterConfiguration( 30, 80, 20); + } else { + return new KisRainDropsFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ), widget->valueAt( 2 ) ); + } +} diff --git a/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.h b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.h new file mode 100644 index 00000000..0d797d7d --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter.h @@ -0,0 +1,67 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_RAINDROPS_FILTER_H_ +#define _KIS_RAINDROPS_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisRainDropsFilterConfiguration : public KisFilterConfiguration +{ +public: + KisRainDropsFilterConfiguration(TQ_UINT32 dropSize, TQ_UINT32 number, TQ_UINT32 fishEyes) + : KisFilterConfiguration( "raindrops", 1 ) + { + setProperty("dropsize", dropSize); + setProperty("number", number); + setProperty("fishEyes", fishEyes); + }; +public: + inline TQ_UINT32 dropSize() { return getInt("dropsize"); }; + inline TQ_UINT32 number() {return getInt("number"); }; + inline TQ_UINT32 fishEyes() {return getInt("fishEyes"); }; + +}; + +class KisRainDropsFilter : public KisFilter +{ +public: + KisRainDropsFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("raindrops", i18n("Raindrops")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisRainDropsFilterConfiguration( 30, 80, 20)); return list; } + +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +private: + void rainDrops(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, int DropSize, int Amount, int Coeff); + bool** CreateBoolArray (uint Columns, uint Rows); + void FreeBoolArray (bool** lpbArray, uint Columns); + uchar LimitValues (int ColorValue); +}; + +#endif diff --git a/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc new file mode 100644 index 00000000..593311d5 --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.cc @@ -0,0 +1,44 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_raindrops_filter_plugin.h" +#include "kis_raindrops_filter.h" + + +typedef KGenericFactory KisRainDropsFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkraindropsfilter, KisRainDropsFilterPluginFactory( "chalk" ) ) + +KisRainDropsFilterPlugin::KisRainDropsFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) : KParts::Plugin(tqparent, name) +{ + setInstance(KisRainDropsFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisRainDropsFilter()); + } +} + +KisRainDropsFilterPlugin::~KisRainDropsFilterPlugin() +{ +} diff --git a/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h new file mode 100644 index 00000000..ca4e05d3 --- /dev/null +++ b/chalk/plugins/filters/raindropsfilter/kis_raindrops_filter_plugin.h @@ -0,0 +1,33 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_RAINDROPS_FILTER_PLUGIN_H_ +#define _KIS_RAINDROPS_FILTER_PLUGIN_H_ + +#include + +class KisRainDropsFilterPlugin : public KParts::Plugin +{ +public: + KisRainDropsFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisRainDropsFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/randompickfilter/Makefile.am b/chalk/plugins/filters/randompickfilter/Makefile.am new file mode 100644 index 00000000..0757704c --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkrandompickfilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkrandompickfilter_la_SOURCES = randompickfilter.cc wdgrandompickoptions.ui \ + kis_wdg_random_pick.cpp + +kde_module_LTLIBRARIES = chalkrandompickfilter.la +noinst_HEADERS = randompickfilter.h + +chalkrandompickfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkrandompickfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkrandompickfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/randompickfilter/chalkrandompickfilter.desktop b/chalk/plugins/filters/randompickfilter/chalkrandompickfilter.desktop new file mode 100644 index 00000000..b7bb807a --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/chalkrandompickfilter.desktop @@ -0,0 +1,65 @@ +[Desktop Entry] +Comment=Random pick to an image +Comment[bg]=Случайно избиране на изображение +Comment[ca]=Agafa aleatòriament una imatge +Comment[da]=Udfør tilfældigt valg i et billede +Comment[de]=Zufallsauswahl zu einem Bild +Comment[el]=Τυχαία ανύψωση σε μια εικόνα +Comment[es]=Elección aleatoria de una imagen +Comment[et]=Juhuslik valik pildil +Comment[fa]=برداشتن تصادفی برای یک تصویر +Comment[fy]=Samar in kar foar in ôfbylding +Comment[gl]=Toma aleatoria para unha imaxe +Comment[hu]=Véletlenszerű képszűrő +Comment[it]=Scegli casualmente un'immagine +Comment[km]=រើស​ដោយ​ចៃដន្យ​ទៅ​រូបភាព +Comment[nb]=Tilfeldig plukk til et bilde +Comment[nds]=Tofällig Bildutwahl +Comment[ne]=एउटा छविमा अनियन्त्रित तरिकाले टिप्नुहोस् +Comment[nl]=Willekeurige keuze voor een afbeelding +Comment[pl]=Losowy wybór fragmentu obrazka +Comment[pt]=Extrai aleatoriamente para uma imagem +Comment[pt_BR]=Extrai aleatoriamente para uma imagem +Comment[ru]=Меняет местами некоторые точки в случайном порядке +Comment[sk]=Random pick do obrázku +Comment[sl]=Uzberi sliko naključno +Comment[sr]=Насумичан избор са слике +Comment[sr@Latn]=Nasumičan izbor sa slike +Comment[sv]=Utför slumpmässigt urval i en bild +Comment[uk]=Міняє місцями деякі точки зображення +Comment[zh_TW]=隨機挑選圖片 +Icon= +Name=Random pick Filter +Name[bg]=Филтър за случайно избиране +Name[ca]=Aplica un filtre aleatòriament +Name[da]=Tilfældigt udvalgsfilter +Name[de]=Zufallsauswahlfilter +Name[el]=Φίλτρο τυχαίας ανύψωσης +Name[es]=Filtro de elección aleatoria +Name[et]=Juhusliku valiku filter +Name[fa]=پالایۀ برداشتن تصادفی +Name[fy]=Samar-kar-filter +Name[gl]=Filtro de toma aleatoria +Name[hu]=Véletlenszerű szűrő +Name[it]=Filtro di scelta casuale +Name[ja]=ランダムピックフィルタ +Name[km]=តម្រង​រើស​ដោយ​ចៃដន្យ +Name[nb]=Tilfeldig plukk-filter +Name[nds]=Filter för tofällig Bildutwahl +Name[ne]=फिल्टर अनियन्त्रित तरिकाले टिप्नुहोस् +Name[nl]=Willekeurige-keuze-filter +Name[pl]=Filtr losowego wyboru +Name[pt]=Filtro de Extracção Aleatória +Name[pt_BR]=Filtro de Extração Aleatória +Name[ru]=Случайный выбор +Name[sk]=Random pick filter +Name[sl]=Filter za naključno izbiro +Name[sr]=Филтер за насумичан избор +Name[sr@Latn]=Filter za nasumičan izbor +Name[sv]=Slumpmässigt urvalsfilter +Name[uk]=Випадковий вибір +Name[zh_TW]=隨機挑選過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkrandompickfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp b/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp new file mode 100644 index 00000000..044f9613 --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.cpp @@ -0,0 +1,64 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_random_pick.h" + +#include + +#include + +#include "wdgrandompickoptions.h" + +KisWdgRandomPick::KisWdgRandomPick(KisFilter* /*nfilter*/, TQWidget* tqparent, const char* name) + : KisFilterConfigWidget(tqparent,name) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgRandomPickOptions(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intLevel, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intWindowSize, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intOpacity, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgRandomPick::~KisWdgRandomPick() +{ +} + +void KisWdgRandomPick::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("level", value)) + { + widget()->intLevel->setValue( value.toUInt() ); + } + if (config->getProperty("windowsize", value)) + { + widget()->intWindowSize->setValue( value.toUInt() ); + } + if (config->getProperty("opacity", value)) + { + widget()->intOpacity->setValue( value.toUInt() ); + } +} + + +#include "kis_wdg_random_pick.moc" + diff --git a/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.h b/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.h new file mode 100644 index 00000000..54b46e20 --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/kis_wdg_random_pick.h @@ -0,0 +1,44 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WDG_RANDOMPICK_H +#define KIS_WDG_RANDOMPICK_H + +#include + +class WdgRandomPickOptions; +class KisFilter; + +class KisWdgRandomPick : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgRandomPick(KisFilter* nfilter, TQWidget* tqparent = 0, const char* name = 0); + ~KisWdgRandomPick(); + public: + inline WdgRandomPickOptions* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgRandomPickOptions* m_widget; +}; + +#endif + diff --git a/chalk/plugins/filters/randompickfilter/randompickfilter.cc b/chalk/plugins/filters/randompickfilter/randompickfilter.cc new file mode 100644 index 00000000..3a645590 --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/randompickfilter.cc @@ -0,0 +1,131 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "randompickfilter.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_random_pick.h" +#include "wdgrandompickoptions.h" + +typedef KGenericFactory ChalkRandomPickFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalkrandompickfilter, ChalkRandomPickFilterFactory( "chalk" ) ) + +ChalkRandomPickFilter::ChalkRandomPickFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkRandomPickFilterFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterRandomPick()); + } +} + +ChalkRandomPickFilter::~ChalkRandomPickFilter() +{ +} + +KisFilterRandomPick::KisFilterRandomPick() : KisFilter(id(), "other", i18n("&Random Pick...")) +{ +} + +KisFilterConfiguration* KisFilterRandomPick::configuration(TQWidget* w) +{ + KisWdgRandomPick* wN = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wN) + { + config->setProperty("level", wN->widget()->intLevel->value() ); + config->setProperty("windowsize", wN->widget()->intWindowSize->value() ); + config->setProperty("opacity", wN->widget()->intOpacity->value() ); + } + return config; +} + +KisFilterConfigWidget * KisFilterRandomPick::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev) +{ + return new KisWdgRandomPick((KisFilter*)this, (TQWidget*)tqparent, i18n("Configuration of random pick filter").ascii()); +} + +void KisFilterRandomPick::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.height() * rect.width()); + + KisColorSpace * cs = src->colorSpace(); + TQ_INT32 psize = cs->pixelSize(); + + TQVariant value; + int level = (config && config->getProperty("level", value)) ? value.toInt() : 50; + double windowsize = (config && config->getProperty("windowsize", value)) ? value.toInt() / 2. : 2.5; + int opacity = (config && config->getProperty("opacity", value)) ? value.toInt() : 100; + + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + KisRandomAccessorPixel srcRA = src->createRandomAccessor(0, 0, false); + + TQ_UINT32 threshold = (RAND_MAX / 100) * (100 - level); + + TQ_UINT8 weights[2]; + weights[0] = (255 * opacity) / 100; weights[1] = 255 - weights[0]; + const TQ_UINT8* pixels[2]; + while(!srcIt.isDone()) + { + if(rand() > threshold) + { + int x = srcIt.x() + 2.5 * rand() / RAND_MAX; + int y = srcIt.y() + 2.5 * rand() / RAND_MAX; + srcRA.moveTo( x, y); + pixels[0] = srcRA.oldRawData(); + pixels[1] = srcIt.oldRawData(); + cs->mixColors( pixels, weights, 2, dstIt.rawData() ); + } + ++srcIt; + ++dstIt; + incProgress(); + } + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/randompickfilter/randompickfilter.h b/chalk/plugins/filters/randompickfilter/randompickfilter.h new file mode 100644 index 00000000..4b50c215 --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/randompickfilter.h @@ -0,0 +1,52 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef RANDOMPICKFILTER_H +#define RANDOMPICKFILTER_H + +#include +#include "kis_filter.h" + +class KisFilterConfigWidget; + +class ChalkRandomPickFilter : public KParts::Plugin +{ +public: + ChalkRandomPickFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkRandomPickFilter(); +}; + +class KisFilterRandomPick : public KisFilter +{ + public: + KisFilterRandomPick(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("randompick", i18n("Random Pick")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/randompickfilter/wdgrandompickoptions.ui b/chalk/plugins/filters/randompickfilter/wdgrandompickoptions.ui new file mode 100644 index 00000000..5bdae980 --- /dev/null +++ b/chalk/plugins/filters/randompickfilter/wdgrandompickoptions.ui @@ -0,0 +1,135 @@ + +WdgRandomPickOptions + + + WdgRandomPickOptions + + + + 0 + 0 + 242 + 93 + + + + + unnamed + + + 0 + + + + textLabel1 + + + Level: + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + textLabel2 + + + Opacity: + + + + + intOpacity + + + 100 + + + 0 + + + 100 + + + + + intLevel + + + 50 + + + 0 + + + 100 + + + + + textLabel1_2 + + + Size of the window: + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 16 + 20 + + + + + + intWindowSize + + + 5 + + + 3 + + + 100 + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/roundcorners/Makefile.am b/chalk/plugins/filters/roundcorners/Makefile.am new file mode 100644 index 00000000..1e884560 --- /dev/null +++ b/chalk/plugins/filters/roundcorners/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = chalkroundcornersfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkroundcornersfilter.la + +chalkroundcornersfilter_la_SOURCES = kis_round_corners_filter_plugin.cc \ + kis_round_corners_filter.cc + +noinst_HEADERS = kis_round_corners_filter_plugin.h \ + kis_round_corners_filter.h + +chalkroundcornersfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkroundcornersfilter_la_LIBADD = ../../../libchalkcommon.la + +chalkroundcornersfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/roundcorners/chalkroundcornersfilter.desktop b/chalk/plugins/filters/roundcorners/chalkroundcornersfilter.desktop new file mode 100644 index 00000000..c3b6e182 --- /dev/null +++ b/chalk/plugins/filters/roundcorners/chalkroundcornersfilter.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Sobel Filter +Name[bg]=Филтър Sobel +Name[ca]=Filtre Sobel +Name[cy]=Hidlen Sobel +Name[da]=Sobelfilter +Name[de]=Sobel-Filter +Name[el]=Φίλτρο άκρων Sobel +Name[es]=Filtro Sobel +Name[et]=Sobeli filter +Name[fa]=پالایۀ Sobel +Name[fr]=Filtre de Sobel +Name[fy]=Sobelfilter +Name[ga]=Scagaire Sobel +Name[gl]=Filtro Sobel +Name[hu]=Sobel-eszköz +Name[is]=Sobel sía +Name[it]=Filtro Sobel +Name[ja]=ソーベルフィルタ +Name[km]=តម្រង​ស៊ូបែល​ +Name[nds]=Sobelfilter +Name[ne]=सोबेल फिल्टर +Name[nl]=Sobelfilter +Name[pl]=Filtr Sobela +Name[pt]=Filtro Sobel +Name[pt_BR]=Filtro Sobel +Name[ru]=Собел +Name[se]=Sobelsilli +Name[sk]=Sobel filter +Name[sl]=Filter Sobel +Name[sr]=Собелов филтер +Name[sr@Latn]=Sobelov filter +Name[sv]=Sobelfilter +Name[uk]=Фільтр Собеля +Name[zh_TW]=Sobel 過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkroundcornersfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/roundcorners/kis_round_corners_filter.cc b/chalk/plugins/filters/roundcorners/kis_round_corners_filter.cc new file mode 100644 index 00000000..3b8177d4 --- /dev/null +++ b/chalk/plugins/filters/roundcorners/kis_round_corners_filter.cc @@ -0,0 +1,158 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_round_corners_filter.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +KisRoundCornersFilter::KisRoundCornersFilter() : KisFilter(id(), "map", i18n("&Round Corners...")) +{ +} + +void KisRoundCornersFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + //read the filter configuration values from the KisFilterConfiguration object + TQ_INT32 radius = (TQ_INT32)((KisRoundCornersFilterConfiguration*)configuration)->radius(); + TQ_UINT32 pixelSize = src->pixelSize(); + + setProgressTotalSteps( rect.height() ); + setProgressStage(i18n("Applying pixelize filter..."),0); + + for (TQ_INT32 y = rect.y(); y < rect.height(); y++) + { + TQ_INT32 x = rect.x(); + TQ_INT32 x0 = rect.x(); + TQ_INT32 y0 = rect.x(); + TQ_INT32 width = rect.width(); + TQ_INT32 height = rect.height(); + KisHLineIteratorPixel dstIt = dst->createHLineIterator(x, y, width, true ); + KisHLineIteratorPixel srcIt = src->createHLineIterator(x, y, width, false); + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + for( unsigned int i = 0; i < pixelSize; i++) + { + if ( i < pixelSize - 1 ) + { + dstIt.rawData()[i] = srcIt.oldRawData()[i]; + } + else + { + if( x <= radius && y <= radius) + { + double dx = radius - x; + double dy = radius - y; + double dradius = static_cast(radius); + if ( dx >= sqrt( dradius*dradius - dy*dy ) ) + { + dstIt.rawData()[i] = 0; + } + } + else if( x >= x0 + width - radius && y <= radius) + { + double dx = x + radius - x0 - width; + double dy = radius - y; + double dradius = static_cast(radius); + if ( dx >= sqrt( dradius*dradius - dy*dy ) ) + { + dstIt.rawData()[i] = 0; + } + } + else if( x <= radius && y >= y0 + height - radius) + { + double dx = radius - x; + double dy = y + radius - y0 - height; + double dradius = static_cast(radius); + if ( dx >= sqrt( dradius*dradius - dy*dy ) ) + { + dstIt.rawData()[i] = 0; + } + } + else if( x >= x0 + width - radius && y >= y0 + height - radius) + { + + double dx = x + radius - x0 - width; + double dy = y + radius - y0 - height; + double dradius = static_cast(radius); + if ( dx >= sqrt( dradius*dradius - dy*dy ) ) + { + dstIt.rawData()[i] = 0; + } + } + } + } + } + ++srcIt; + ++dstIt; + ++x; + } + setProgress(y); + } + setProgressDone(); +} + +KisFilterConfigWidget * KisRoundCornersFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 100, 30, i18n("Radius"), "radius" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisRoundCornersFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisRoundCornersFilterConfiguration( 30 ); + } else { + return new KisRoundCornersFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/chalk/plugins/filters/roundcorners/kis_round_corners_filter.h b/chalk/plugins/filters/roundcorners/kis_round_corners_filter.h new file mode 100644 index 00000000..ec5fb9fb --- /dev/null +++ b/chalk/plugins/filters/roundcorners/kis_round_corners_filter.h @@ -0,0 +1,58 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_ROUND_CORNERS_FILTER_H_ +#define _KIS_ROUND_CORNERS_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisRoundCornersFilterConfiguration : public KisFilterConfiguration +{ +public: + KisRoundCornersFilterConfiguration(TQ_INT32 radius) + : KisFilterConfiguration( "roundcorners", 1 ) + { + setProperty("radius", radius); + }; +public: + inline TQ_INT32 radius() { return getInt("radius"); }; +}; + +class KisRoundCornersFilter : public KisFilter +{ +public: + KisRoundCornersFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("roundcorners", i18n("Round Corners")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers () { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisRoundCornersFilterConfiguration(30)); return list; } +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return new KisRoundCornersFilterConfiguration( 30 ); }; +private: +}; + +#endif diff --git a/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc b/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc new file mode 100644 index 00000000..f53acf46 --- /dev/null +++ b/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.cc @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_round_corners_filter_plugin.h" +#include "kis_round_corners_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisRoundCornersFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkroundcornersfilter, KisRoundCornersFilterPluginFactory( "chalk" ) ) + +KisRoundCornersFilterPlugin::KisRoundCornersFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(KisRoundCornersFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisRoundCornersFilter()); + } +} + +KisRoundCornersFilterPlugin::~KisRoundCornersFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h b/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h new file mode 100644 index 00000000..e55239e4 --- /dev/null +++ b/chalk/plugins/filters/roundcorners/kis_round_corners_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_ROUND_CORNERS_FILTER_PLUGIN_H_ +#define _KIS_ROUND_CORNERS_FILTER_PLUGIN_H_ + +#include + +class KisRoundCornersFilterPlugin : public KParts::Plugin +{ +public: + KisRoundCornersFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisRoundCornersFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/smalltilesfilter/Makefile.am b/chalk/plugins/filters/smalltilesfilter/Makefile.am new file mode 100644 index 00000000..87a17332 --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = chalksmalltilesfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +kde_module_LTLIBRARIES = chalksmalltilesfilter.la + +chalksmalltilesfilter_la_SOURCES = kis_small_tiles_filter_plugin.cc \ + kis_small_tiles_filter.cc + +noinst_HEADERS = kis_small_tiles_filter_plugin.h \ + kis_small_tiles_filter.h + +chalksmalltilesfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalksmalltilesfilter_la_LIBADD = ../../../libchalkcommon.la + +chalksmalltilesfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/smalltilesfilter/chalksmalltilesfilter.desktop b/chalk/plugins/filters/smalltilesfilter/chalksmalltilesfilter.desktop new file mode 100644 index 00000000..ae9bcc2f --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/chalksmalltilesfilter.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Small Tiles Filter +Name[bg]=Филтър "малки плочки" +Name[br]=Sil teoloù bihan +Name[ca]=Filtre de petites rajoles +Name[cy]=Hidlen Deiliau Bychain +Name[da]=Småflisefilter +Name[de]=Kleine-Quadrate-Filter +Name[el]=Φίλτρο μικρών παραθέσεων +Name[es]=Filtro de azulejos pequeños +Name[et]=Väikeste klotside filter +Name[fa]=پالایۀ کاشیهای کوچک +Name[fr]=Filtre mosaïque +Name[fy]=Lytse-tegelfilter +Name[gl]=Filtro de Pequenos Mosaicos +Name[hu]=Aprómozaik szűrő +Name[is]=Smá flísasía +Name[it]=Filtro per piccoli riquadri +Name[ja]=小タイルフィルタ +Name[km]=តម្រង​ក្រឡា​ក្បឿង​តូច +Name[nb]=Små fliser-filter +Name[nds]=Lüttkachel-Filter +Name[ne]=सानो टाइल फिल्टर +Name[nl]=Kleine tegeltjes +Name[pl]=Filtr małych kafelków +Name[pt]=Filtro de Pequenos Padrões +Name[pt_BR]=Filtro de Pequenos Padrões +Name[ru]=Маленькая черепица +Name[sk]=Filter malé dlaždice +Name[sl]=Filter Majhni kvadrati +Name[sr]=Филтер малих плоча +Name[sr@Latn]=Filter malih ploča +Name[sv]=Smårutorsfilter +Name[uk]=Фільтр маленьких плиток +Name[zh_TW]=小塊拼貼過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalksmalltilesfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc new file mode 100644 index 00000000..6c621e47 --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.cc @@ -0,0 +1,187 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_integer_filter_widget.h" +#include "kis_small_tiles_filter.h" + + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +void KisSmallTilesFilterConfiguration::fromXML(const TQString & s) +{ + KisFilterConfiguration::fromXML(s); + m_numberOfTiles = getInt("numberOfTiles"); +} + +TQString KisSmallTilesFilterConfiguration::toString() +{ + m_properties.clear(); + setProperty("numberOfTiles()", m_numberOfTiles); + + return KisFilterConfiguration::toString(); +} + +KisSmallTilesFilter::KisSmallTilesFilter() : KisFilter(id(), "map", i18n("&Small Tiles...")) +{ +} + +void KisSmallTilesFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + //read the filter configuration values from the KisFilterConfiguration object + TQ_UINT32 numberOfTiles = ((KisSmallTilesFilterConfiguration*)configuration)->numberOfTiles(); + + createSmallTiles(src, dst, rect, numberOfTiles); +} + +void KisSmallTilesFilter::createSmallTiles(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, TQ_UINT32 numberOfTiles) +{ + if (!src) return; + if (!dst) return; + + TQRect srcRect = src->exactBounds(); + + int w = static_cast(srcRect.width() / numberOfTiles); + int h = static_cast(srcRect.height() / numberOfTiles); + + KisPaintDeviceSP tile = 0; + if (src->hasSelection()) { + KisPaintDeviceSP tmp = new KisPaintDevice(src->colorSpace(), "selected bit"); + KisPainter gc(tmp); + gc.bltSelection(0, 0, COMPOSITE_COPY, src, OPACITY_OPAQUE, rect.x(), rect.y(), rect.width(), rect.height()); + tile = src->createThumbnailDevice(srcRect.width() / numberOfTiles, srcRect.height() / numberOfTiles); + } + else { + tile = src->createThumbnailDevice(srcRect.width() / numberOfTiles, srcRect.height() / numberOfTiles); + } + if (tile == 0) return; + + KisPaintDeviceSP scratch = new KisPaintDevice(src->colorSpace()); + + KisPainter gc(scratch); + + setProgressTotalSteps(numberOfTiles); + + for (uint y = 0; y < numberOfTiles; ++y) { + for (uint x = 0; x < numberOfTiles; ++x) { + // XXX make composite op and opacity configurable + gc.bitBlt( w * x, h * y, COMPOSITE_COPY, tile, 0, 0, w, h); + setProgress(y); + } + } + gc.end(); + + gc.begin(dst); + if (src->hasSelection()) { + gc.bltSelection(rect.x(), rect.y(), COMPOSITE_OVER, scratch, src->selection(), OPACITY_OPAQUE, 0, 0, rect.width(), rect.height() ); + } + else { + gc.bitBlt(rect.x(), rect.y(), COMPOSITE_OVER, scratch, OPACITY_OPAQUE, 0, 0, rect.width(), rect.height() ); + } + setProgressDone(); + gc.end(); + + //KisPainter gc(tmp); + //gc.bitBlt(rect.x(), rect.y(), COMPOSITE_COPY, src, rect.x(), rect.y(), rect.width(), rect.height()); + //gc.end(); + + //KisScaleWorker worker(tmp, 1.0 / static_cast(numberOfTiles), 1.0 / static_cast(numberOfTiles), new KisMitchellFilterStrategy() ); + //worker.run(); + +// TQRect tmpRect = tmp->exactBounds(); +// +// for( TQ_UINT32 i=0; i < numberOfTiles; i++ ) +// { +// for( TQ_UINT32 j=0; j < numberOfTiles; j++ ) +// { +// for( TQ_INT32 row = tmpRect.y(); row < tmpRect.height(); row++ ) +// { +// KisHLineIteratorPixel tmpIt = tmp->createHLineIterator(tmpRect.x(), row, tmpRect.width() , false); +// KisHLineIteratorPixel dstIt = dst->createHLineIterator( tmpRect.x() + i * tmpRect.width(), row + j * tmpRect.height(), tmpRect.width() , true); +// +// while( ! tmpIt.isDone() ) +// { +// if(tmpIt.isSelected()) +// { +// for( int i = 0; i < depth; i++) +// { +// dstIt.rawData()[i] = tmpIt.oldRawData()[i]; +// } +// } +// ++tmpIt; +// ++dstIt; +// } +// } +// } +// } + + setProgressDone(); +} + +KisFilterConfigWidget * KisSmallTilesFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 2, 5, 1, i18n("Number of tiles"), "smalltiles" ) ); + return new KisMultiIntegerFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSmallTilesFilter::configuration(TQWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisSmallTilesFilterConfiguration( 2 ); + } else { + return new KisSmallTilesFilterConfiguration( widget->valueAt( 0 ) ); + } +} diff --git a/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h new file mode 100644 index 00000000..8d82eda2 --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter.h @@ -0,0 +1,70 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_SMALL_TILES_FILTER_H_ +#define _KIS_SMALL_TILES_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisSmallTilesFilterConfiguration : public KisFilterConfiguration +{ +public: + KisSmallTilesFilterConfiguration(TQ_UINT32 numberOfTiles) + : KisFilterConfiguration( "smalltiles", 1 ) + , m_numberOfTiles(numberOfTiles) {}; + + + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + inline TQ_UINT32 numberOfTiles() { return m_numberOfTiles; }; + +private: + TQ_UINT32 m_numberOfTiles; +}; + +class KisSmallTilesFilter : public KisFilter +{ + +public: + KisSmallTilesFilter(); + +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("smalltiles", i18n("Small Tiles")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisSmallTilesFilterConfiguration(2)); return list; } + +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration * configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return new KisSmallTilesFilterConfiguration( 2 ); }; + +private: + void createSmallTiles(KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect, TQ_UINT32 numberOfTiles); +}; + +#endif diff --git a/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc new file mode 100644 index 00000000..5283980c --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.cc @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_small_tiles_filter_plugin.h" +#include "kis_small_tiles_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisSmallTilesFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalksmalltilesfilter, KisSmallTilesFilterPluginFactory( "chalk" ) ) + +KisSmallTilesFilterPlugin::KisSmallTilesFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(KisSmallTilesFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisSmallTilesFilter()); + } +} + +KisSmallTilesFilterPlugin::~KisSmallTilesFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h new file mode 100644 index 00000000..601568f2 --- /dev/null +++ b/chalk/plugins/filters/smalltilesfilter/kis_small_tiles_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_SMALL_TILES_FILTER_PLUGIN_H_ +#define _KIS_SMALL_TILES_FILTER_PLUGIN_H_ + +#include + +class KisSmallTilesFilterPlugin : public KParts::Plugin +{ +public: + KisSmallTilesFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisSmallTilesFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/sobelfilter/Makefile.am b/chalk/plugins/filters/sobelfilter/Makefile.am new file mode 100644 index 00000000..c7853223 --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/Makefile.am @@ -0,0 +1,23 @@ +kde_services_DATA = chalksobelfilter.desktop + +INCLUDES = \ + -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalksobelfilter.la + +chalksobelfilter_la_SOURCES = kis_sobel_filter_plugin.cc \ + kis_sobel_filter.cc + +noinst_HEADERS = kis_sobel_filter_plugin.h \ + kis_sobel_filter.h + +chalksobelfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalksobelfilter_la_LIBADD = ../../../libchalkcommon.la + +chalksobelfilter_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/sobelfilter/chalksobelfilter.desktop b/chalk/plugins/filters/sobelfilter/chalksobelfilter.desktop new file mode 100644 index 00000000..46ecd68f --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/chalksobelfilter.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Sobel Filter +Name[bg]=Филтър Sobel +Name[ca]=Filtre Sobel +Name[cy]=Hidlen Sobel +Name[da]=Sobelfilter +Name[de]=Sobel-Filter +Name[el]=Φίλτρο άκρων Sobel +Name[es]=Filtro Sobel +Name[et]=Sobeli filter +Name[fa]=پالایۀ Sobel +Name[fr]=Filtre de Sobel +Name[fy]=Sobelfilter +Name[ga]=Scagaire Sobel +Name[gl]=Filtro Sobel +Name[hu]=Sobel-eszköz +Name[is]=Sobel sía +Name[it]=Filtro Sobel +Name[ja]=ソーベルフィルタ +Name[km]=តម្រង​ស៊ូបែល​ +Name[nds]=Sobelfilter +Name[ne]=सोबेल फिल्टर +Name[nl]=Sobelfilter +Name[pl]=Filtr Sobela +Name[pt]=Filtro Sobel +Name[pt_BR]=Filtro Sobel +Name[ru]=Собел +Name[se]=Sobelsilli +Name[sk]=Sobel filter +Name[sl]=Filter Sobel +Name[sr]=Собелов филтер +Name[sr@Latn]=Sobelov filter +Name[sv]=Sobelfilter +Name[uk]=Фільтр Собеля +Name[zh_TW]=Sobel 過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalksobelfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/sobelfilter/kis_sobel_filter.cc b/chalk/plugins/filters/sobelfilter/kis_sobel_filter.cc new file mode 100644 index 00000000..9a2f5604 --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/kis_sobel_filter.cc @@ -0,0 +1,217 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_multi_bool_filter_widget.h" +#include "kis_sobel_filter.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +void KisSobelFilterConfiguration::fromXML(const TQString & s) +{ + KisFilterConfiguration::fromXML(s); + m_doHorizontally = getBool( "doHorizontally" ); + m_doVertically = getBool( "doVertically" ); + m_keepSign = getBool( "makeOpaque" ); +} + +TQString KisSobelFilterConfiguration::toString() +{ + m_properties.clear(); + setProperty("doHorizontally", m_doHorizontally); + setProperty("doVertically", m_doVertically); + setProperty("keepSign", m_keepSign); + setProperty("makeOpaque", m_makeOpaque); + + return KisFilterConfiguration::toString(); +} + +KisSobelFilter::KisSobelFilter() : KisFilter(id(), "edge", i18n("&Sobel...")) +{ +} + +void KisSobelFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + //read the filter configuration values from the KisFilterConfiguration object + bool doHorizontally = ((KisSobelFilterConfiguration*)configuration)->doHorizontally(); + bool doVertically = ((KisSobelFilterConfiguration*)configuration)->doVertically(); + bool keepSign = ((KisSobelFilterConfiguration*)configuration)->keepSign(); + bool makeOpaque = ((KisSobelFilterConfiguration*)configuration)->makeOpaque(); + + //pixelize(src, dst, x, y, width, height, pixelWidth, pixelHeight); + sobel(rect, src, dst, doHorizontally, doVertically, keepSign, makeOpaque); +} + +void KisSobelFilter::prepareRow (KisPaintDeviceSP src, TQ_UINT8* data, TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 w, TQ_UINT32 h) +{ + if (y > h -1) y = h -1; + TQ_UINT32 pixelSize = src->pixelSize(); + + src->readBytes( data, x, y, w, 1 ); + + for (TQ_UINT32 b = 0; b < pixelSize; b++) { + int offset = pixelSize - b; + data[-offset] = data[b]; + data[w * pixelSize + b] = data[(w - 1) * pixelSize + b]; + } +} + +#define RMS(a, b) (sqrt ((a) * (a) + (b) * (b))) +#define ROUND(x) ((int) ((x) + 0.5)) + +void KisSobelFilter::sobel(const TQRect & rc, KisPaintDeviceSP src, KisPaintDeviceSP dst, bool doHorizontal, bool doVertical, bool keepSign, bool makeOpaque) +{ + TQRect rect = rc; //src->exactBounds(); + TQ_UINT32 x = rect.x(); + TQ_UINT32 y = rect.y(); + TQ_UINT32 width = rect.width(); + TQ_UINT32 height = rect.height(); + TQ_UINT32 pixelSize = src->pixelSize(); + + setProgressTotalSteps( height ); + setProgressStage(i18n("Applying sobel filter..."),0); + + /* allocate row buffers */ + TQ_UINT8* prevRow = new TQ_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(prevRow); + TQ_UINT8* curRow = new TQ_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(curRow); + TQ_UINT8* nextRow = new TQ_UINT8[ (width + 2) * pixelSize]; + Q_CHECK_PTR(nextRow); + TQ_UINT8* dest = new TQ_UINT8[ width * pixelSize]; + Q_CHECK_PTR(dest); + + TQ_UINT8* pr = prevRow + pixelSize; + TQ_UINT8* cr = curRow + pixelSize; + TQ_UINT8* nr = nextRow + pixelSize; + + prepareRow (src, pr, x, y - 1, width, height); + prepareRow (src, cr, x, y, width, height); + + TQ_UINT32 counter =0; + TQ_UINT8* d; + TQ_UINT8* tmp; + TQ_INT32 gradient, horGradient, verGradient; + // loop through the rows, applying the sobel convolution + for (TQ_UINT32 row = 0; row < height; row++) + { + + // prepare the next row + prepareRow (src, nr, x, row + 1, width, height); + d = dest; + + for (TQ_UINT32 col = 0; col < width * pixelSize; col++) + { + int positive = col + pixelSize; + int negative = col - pixelSize; + horGradient = (doHorizontal ? + ((pr[negative] + 2 * pr[col] + pr[positive]) - + (nr[negative] + 2 * nr[col] + nr[positive])) + : 0); + + verGradient = (doVertical ? + ((pr[negative] + 2 * cr[negative] + nr[negative]) - + (pr[positive] + 2 * cr[positive] + nr[positive])) + : 0); + gradient = (TQ_INT32)((doVertical && doHorizontal) ? + (ROUND (RMS (horGradient, verGradient)) / 5.66) // always >0 + : (keepSign ? (127 + (ROUND ((horGradient + verGradient) / 8.0))) + : (ROUND (TQABS (horGradient + verGradient) / 4.0)))); + + *d++ = gradient; + if (gradient > 10) counter ++; + } + + // shuffle the row pointers + tmp = pr; + pr = cr; + cr = nr; + nr = tmp; + + //store the dest + dst->writeBytes(dest, x, row, width, 1); + + if ( makeOpaque ) + { + KisHLineIteratorPixel dstIt = dst->createHLineIterator(x, row, width, true); + while( ! dstIt.isDone() ) + { + dstIt.rawData()[pixelSize-1]=255; //XXXX: is the alpha channel always 8 bit? Otherwise this is wrong! + ++dstIt; + } + } + setProgress(row); + } + setProgressDone(); + + delete[] prevRow; + delete[] curRow; + delete[] nextRow; + delete[] dest; +} + + +KisFilterConfigWidget * KisSobelFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP) +{ + vKisBoolWidgetParam param; + param.push_back( KisBoolWidgetParam( true, i18n("Sobel horizontally"), "doHorizontally" ) ); + param.push_back( KisBoolWidgetParam( true, i18n("Sobel vertically"), "doVertically" ) ); + param.push_back( KisBoolWidgetParam( true, i18n("Keep sign of result"), "keepSign" ) ); + param.push_back( KisBoolWidgetParam( true, i18n("Make image opaque"), "makeOpaque" ) ); + return new KisMultiBoolFilterWidget(tqparent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisSobelFilter::configuration(TQWidget* nwidget) +{ + KisMultiBoolFilterWidget* widget = (KisMultiBoolFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisSobelFilterConfiguration( true, true, true, true); + } else { + return new KisSobelFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ), widget->valueAt( 2 ), widget->valueAt( 3 ) ); + } +} diff --git a/chalk/plugins/filters/sobelfilter/kis_sobel_filter.h b/chalk/plugins/filters/sobelfilter/kis_sobel_filter.h new file mode 100644 index 00000000..757757bc --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/kis_sobel_filter.h @@ -0,0 +1,75 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_SOBEL_FILTER_H_ +#define _KIS_SOBEL_FILTER_H_ + +#include "kis_filter.h" +#include "kis_filter_config_widget.h" + +class KisSobelFilterConfiguration : public KisFilterConfiguration +{ +public: + KisSobelFilterConfiguration(bool doHorizontally, bool doVertically, bool keepSign, bool makeOpaque) + : KisFilterConfiguration( "sobel", 1 ) + , m_doHorizontally(doHorizontally) + , m_doVertically(doVertically) + , m_keepSign(keepSign) + , m_makeOpaque(makeOpaque) + {}; + + virtual void fromXML( const TQString& ); + virtual TQString toString(); + +public: + inline bool doHorizontally() { return m_doHorizontally; }; + inline bool doVertically() {return m_doVertically; }; + inline bool keepSign() {return m_keepSign; }; + inline bool makeOpaque() {return m_makeOpaque; }; + +private: + bool m_doHorizontally; + bool m_doVertically; + bool m_keepSign; + bool m_makeOpaque; +}; + +class KisSobelFilter : public KisFilter +{ +public: + KisSobelFilter(); +public: + virtual void process(KisPaintDeviceSP,KisPaintDeviceSP, KisFilterConfiguration* , const TQRect&); + static inline KisID id() { return KisID("sobel", i18n("Sobel")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return true; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual std::list listOfExamplesConfiguration(KisPaintDeviceSP ) + { std::list list; list.insert(list.begin(), new KisSobelFilterConfiguration(true,true,true,true)); return list; } +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); + virtual KisFilterConfiguration * configuration() { return new KisSobelFilterConfiguration( true, true, true, true); }; +private: + void prepareRow (KisPaintDeviceSP src, TQ_UINT8* data, TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 w, TQ_UINT32 h); + void sobel(const TQRect & rc, KisPaintDeviceSP src, KisPaintDeviceSP dst, bool doHorizontal, bool doVertical, bool keepSign, bool makeOpaque); +}; + +#endif diff --git a/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc b/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc new file mode 100644 index 00000000..e0ef8c80 --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.cc @@ -0,0 +1,43 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include "kis_sobel_filter_plugin.h" +#include "kis_sobel_filter.h" +#include "kis_global.h" + +typedef KGenericFactory KisSobelFilterPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalksobelfilter, KisSobelFilterPluginFactory( "chalk" ) ) + +KisSobelFilterPlugin::KisSobelFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(KisSobelFilterPluginFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisSobelFilter()); + } +} + +KisSobelFilterPlugin::~KisSobelFilterPlugin() +{ +} + diff --git a/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h b/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h new file mode 100644 index 00000000..87564cfe --- /dev/null +++ b/chalk/plugins/filters/sobelfilter/kis_sobel_filter_plugin.h @@ -0,0 +1,32 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_SOBEL_FILTER_PLUGIN_H_ +#define _KIS_SOBEL_FILTER_PLUGIN_H_ + +#include + +class KisSobelFilterPlugin : public KParts::Plugin +{ +public: + KisSobelFilterPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisSobelFilterPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/threadtest/Makefile.am b/chalk/plugins/filters/threadtest/Makefile.am new file mode 100644 index 00000000..7846c3c0 --- /dev/null +++ b/chalk/plugins/filters/threadtest/Makefile.am @@ -0,0 +1,18 @@ +kde_services_DATA = chalkthreadtest.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$(srcdir)/../../../../lib/kofficecore \ + $(all_includes) + +chalkthreadtest_la_SOURCES = threadtest.cc + +kde_module_LTLIBRARIES = chalkthreadtest.la +noinst_HEADERS = threadtest.h + +chalkthreadtest_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkthreadtest_la_LIBADD = ../../../libchalkcommon.la + +chalkthreadtest_la_METASOURCES = AUTO diff --git a/chalk/plugins/filters/threadtest/chalkthreadtest.desktop b/chalk/plugins/filters/threadtest/chalkthreadtest.desktop new file mode 100644 index 00000000..658964a1 --- /dev/null +++ b/chalk/plugins/filters/threadtest/chalkthreadtest.desktop @@ -0,0 +1,38 @@ +[Desktop Entry] +Name=Invert Filter with Threads +Name[bg]=Инвертиращ филтър с нишки +Name[ca]=Inverteix filtre amb fils +Name[cy]=Gwrthdroi Hidlen efo Edeifion +Name[da]=Inverteringsfilter med tråde +Name[de]=Invertierungsfilter mit Threads +Name[el]=Φίλτρο αντιστροφής με νήματα +Name[es]=Invertir filtro con hilos +Name[et]=Lõimedega inverteerimise filter +Name[fa]=وارونه کردن پالایه با رشته‌ها +Name[fr]=Filtre d'inversion avec fils +Name[fy]=Filter mei trieden omdraaie +Name[ga]=Inbhéartaigh Scagaire le Snáitheanna +Name[gl]=Filtro de Inversión Multifío +Name[hu]=Invertáló szűrő szálakkal +Name[is]=Snúa síu með þráðum +Name[it]=File di inversione con trama +Name[km]=បញ្ច្រាស​តម្រង​ជាមួយ​សរសៃ +Name[nb]=Inverteringsfilter med tråder +Name[nds]=Ümdreihfilter mit Sträng +Name[ne]=धागोसँग फिल्टर उल्टाउनुहोस् +Name[nl]=Filter met threads omkeren +Name[pl]=Filtr inwersji z wątkami +Name[pt]=Filtro de Inversão Multitarefa +Name[pt_BR]=Filtro de Inversão Multitarefa +Name[ru]=Инвертирование +Name[sk]=Filter inverzie s vláknami +Name[sl]=Filter za obračanje z nitmi +Name[sr]=Филтер за инверзију са нитима +Name[sr@Latn]=Filter za inverziju sa nitima +Name[sv]=Inverteringsfilter med trådar +Name[uk]=Інвертування +Name[zh_TW]=有 Thread 的反轉過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkthreadtest +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/threadtest/threadtest.cc b/chalk/plugins/filters/threadtest/threadtest.cc new file mode 100644 index 00000000..f96a1616 --- /dev/null +++ b/chalk/plugins/filters/threadtest/threadtest.cc @@ -0,0 +1,140 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2004 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// #include + +#include "threadtest.h" + +typedef KGenericFactory ChalkThreadTestFactory; +K_EXPORT_COMPONENT_FACTORY( chalkthreadtest, ChalkThreadTestFactory( "chalk" ) ) + +ChalkThreadTest::ChalkThreadTest(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkThreadTestFactory::instance()); + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * r = dynamic_cast(tqparent); + r->add(new KisFilterInvert()); + } +} + +ChalkThreadTest::~ChalkThreadTest() +{ +} + +class InversionThread : public TQThread +{ + +public: + + InversionThread(const TQString & name, KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect& rect) + : TQThread() + , m_name(name) + , m_src(src) + , m_dst(dst) + , m_rect(rect) + { + kdDebug() << "Thread created " << m_name << ", " << TQThread::currentThread() << ", " << m_rect << "\n"; + }; + + void run() + { + kdDebug() << "Thread started:" << m_name << ", " << TQThread::currentThread() << "\n"; + + KisRectIteratorPixel dstIt = m_dst->createRectIterator(m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height(), true ); + KisRectIteratorPixel srcIt = m_src->createRectIterator(m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height(), false); + TQ_INT32 depth = m_src -> colorSpace() -> nColorChannels(); + + kdDebug() << "Thread " << m_name << " starts loop \n"; + + while( ! srcIt.isDone() ) { + if ( srcIt.isSelected() ) { + for( int i = 0; i < depth; i++) { + dstIt.rawData()[i] = TQ_UINT8_MAX - srcIt.oldRawData()[i]; + } + } + ++srcIt; + ++dstIt; + } + kdDebug() << "Thread " << m_name << " finished \n"; + }; + +private: + TQString m_name; + KisPaintDeviceSP m_src; + KisPaintDeviceSP m_dst; + TQRect m_rect; + +}; + +KisFilterInvert::KisFilterInvert() : KisFilter(id(), "colors", i18n("Invert with &Threads")) +{ +} + +void KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const TQRect& rect) +{ + kdDebug() << "Going to invert " << rect << "\n"; + int h2 = rect.height() / 2; + int w2 = rect.width() / 2; + + setProgressTotalSteps(4); + InversionThread t1("t1", src, dst, TQRect(0, 0, w2, h2)); + InversionThread t2("t2", src, dst, TQRect(w2, 0, w2, h2)); + InversionThread t3("t3", src, dst, TQRect(0, h2, w2, h2)); + InversionThread t4("t4", src, dst, TQRect(w2, h2, w2, h2)); + + t1.start(); + t2.start(); + t3.start(); + t4.start(); + t1.wait(); + setProgress(1); + t2.wait(); + setProgress(2); + t3.wait(); + setProgress(3); + t4.wait(); + setProgress(4); + + setProgressDone(); +} diff --git a/chalk/plugins/filters/threadtest/threadtest.h b/chalk/plugins/filters/threadtest/threadtest.h new file mode 100644 index 00000000..26c61a58 --- /dev/null +++ b/chalk/plugins/filters/threadtest/threadtest.h @@ -0,0 +1,46 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef THREADTEST_H +#define THREADTESt_H + +#include +#include "kis_filter.h" + +class ChalkThreadTest : public KParts::Plugin +{ +public: + ChalkThreadTest(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkThreadTest(); +}; + +class KisFilterInvert : public KisFilter +{ +public: + KisFilterInvert(); +public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("invertthread", i18n("Invert with Threads")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } +}; + +#endif diff --git a/chalk/plugins/filters/unsharp/Makefile.am b/chalk/plugins/filters/unsharp/Makefile.am new file mode 100644 index 00000000..fb34c63e --- /dev/null +++ b/chalk/plugins/filters/unsharp/Makefile.am @@ -0,0 +1,20 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkunsharpfilter.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkunsharpfilter_la_SOURCES = wdgunsharp.ui kis_wdg_unsharp.cc unsharp.cc kis_unsharp_filter.cc + +kde_module_LTLIBRARIES = chalkunsharpfilter.la + +chalkunsharpfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkunsharpfilter_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO diff --git a/chalk/plugins/filters/unsharp/chalkunsharpfilter.desktop b/chalk/plugins/filters/unsharp/chalkunsharpfilter.desktop new file mode 100644 index 00000000..cbf7edcf --- /dev/null +++ b/chalk/plugins/filters/unsharp/chalkunsharpfilter.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Icon= +Name=Image enhancement Filters (Extension) +Name[bg]=Филтри за подобрения (разширения) +Name[ca]=Filtres de millora d'imatge (Extensió) +Name[da]=Billedforbedringsfiltre (Udvidelse) +Name[de]=Verbesserungsfilter (Erweiterung) +Name[el]=Φίλτρα βελτίωσης εικόνας (Επέκταση) +Name[es]=Filtros de realce de imagen (Extensión) +Name[et]=Parandusfiltrid (laiendus) +Name[fa]=پالایه‌های تقویت تصویر )پسوند( +Name[fr]=Filtres d'amélioration d'images (extension) +Name[fy]=Ofbyldingsfilters (útwreiding) +Name[gl]=Filtros de Mellora da Imaxe (Extensións) +Name[hu]=Képjavító szűrők (kiterjesztés) +Name[it]=Filtri di miglioramento delle immagini (estensione) +Name[ja]=画像エンハンスメントフィルタ (拡張) +Name[km]=តម្រង​ធ្វើ​ឲ្យ​រូបភាព​ប្រសើរ (ផ្នែក​បន្ថែម) +Name[nb]=Bildeforbedringsfiltre (Utvidelse) +Name[nds]=Verbeternfilter (Verwiedern) +Name[ne]=छवि अधिकता फिल्टरहरू (अपवाद) +Name[nl]=Afbeeldingsfilters (extensie) +Name[pl]=Filtry poprawy jakości (rozszerzenie) +Name[pt]=Filtros de Melhoramento de Imagem (Extensão) +Name[pt_BR]=Filtros de Melhoramento de Imagem (Extensão) +Name[ru]=Улучшение изображения (расширение) +Name[se]=Govvabuoridansillit (viiddádus) +Name[sk]=Filtre vylepšenia obrázkov (rozšírenie) +Name[sl]=Filtri za izboljšanje slike (razširitev) +Name[sr]=Филтери за побољшање слика (проширење) +Name[sr@Latn]=Filteri za poboljšanje slika (proširenje) +Name[sv]=Bildförbättringsfilter (utökning) +Name[uk]=Фільтри покращання зображення (розширення) +Name[uz]=Rasmning sifatini oshirish filterlari (kengaytma) +Name[uz@cyrillic]=Расмнинг сифатини ошириш филтерлари (кенгайтма) +Name[zh_TW]=增強過濾器(延伸) +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkunsharpfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/unsharp/kis_unsharp_filter.cc b/chalk/plugins/filters/unsharp/kis_unsharp_filter.cc new file mode 100644 index 00000000..d9539920 --- /dev/null +++ b/chalk/plugins/filters/unsharp/kis_unsharp_filter.cc @@ -0,0 +1,152 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_unsharp_filter.h" + +#include +#include + +#include +#include +#include + + +#include "kis_wdg_unsharp.h" +#include "wdgunsharp.h" + +KisKernelSP kernelFromTQImage(const TQImage& img) +{ + KisKernelSP k = new KisKernel; + k->width = img.width(); + k->height = img.height(); + k->offset = 0; + uint count = k->width * k->height; + k->data = new TQ_INT32[count]; + TQ_INT32* itData = k->data; + TQ_UINT8* itImg = (TQ_UINT8*)img.bits(); + k->factor = 0; + for(uint i = 0; i < count; ++i , ++itData, itImg+=4) + { + *itData = 255 - ( *itImg + *(itImg+1) + *(itImg+2) ) / 3; + k->factor += *itData; + } + return k; +} + + +KisUnsharpFilter::KisUnsharpFilter() : KisFilter(id(), "enhance", i18n("&Unsharp Mask...")) +{ +} + +KisFilterConfigWidget * KisUnsharpFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP ) +{ + return new KisWdgUnsharp(this, tqparent, "configuration of color to alpha"); +} + +KisFilterConfiguration* KisUnsharpFilter::configuration(TQWidget* w) +{ + KisWdgUnsharp * wCTA = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wCTA) + { + config->setProperty("halfSize", wCTA->widget()->intHalfSize->value() ); + config->setProperty("amount", wCTA->widget()->doubleAmount->value() ); + config->setProperty("threshold", wCTA->widget()->intThreshold->value() ); + } + return config; + return 0; +} + +void KisUnsharpFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + if(!config) config = new KisFilterConfiguration(id().id(), 1); + + TQVariant value; + uint halfSize = (config->getProperty("halfSize", value)) ? value.toUInt() : 4; + uint size = 2 * halfSize + 1; + double amount = (config->getProperty("amount", value)) ? value.toDouble() : 0.5; + uint threshold = (config->getProperty("threshold", value)) ? value.toUInt() : 10; + + kdDebug() << " brush size = " << size << " " << halfSize << endl; + KisAutobrushShape* kas = new KisAutobrushCircleShape(size, size , halfSize, halfSize); + + TQImage tqmask; + kas->createBrush(&tqmask); + + KisKernelSP kernel = kernelFromTQImage(tqmask); // TODO: for 1.6 reuse the chalk's core function for creating kernel : KisKernel::fromTQImage + + KisPaintDeviceSP interm = new KisPaintDevice(*src); + KisColorSpace * cs = src->colorSpace(); + + KisConvolutionPainter painter( interm ); + painter.beginTransaction("bouuh"); + painter.applyMatrix(kernel, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_REPEAT); + + if (painter.cancelRequested()) { + cancel(); + } + + KisHLineIteratorPixel dstIt = dst->createHLineIterator(rect.x(), rect.y(), rect.width(), true ); + KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), rect.y(), rect.width(), false); + KisHLineIteratorPixel intermIt = interm->createHLineIterator(rect.x(), rect.y(), rect.width(), false); + + TQ_UINT8 *colors[2]; + + int pixelsProcessed = 0; + TQ_INT32 weights[2]; +/* weights[0] = 128; + TQ_INT32 factor = (TQ_UINT32) 128 / amount; + weights[1] = (factor - 128);*/ + TQ_INT32 factor = 128; + weights[0] = factor * ( 1. + amount); + weights[1] = -factor * amount; + kdDebug() << (int) weights[0] << " " << (int)weights[1] << " " << factor << endl; + for( int j = 0; j < rect.height(); j++) + { + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + TQ_UINT8 diff = cs->difference(srcIt.oldRawData(), intermIt.rawData()); + if( diff > threshold) + { + colors[0] = srcIt.rawData(); + colors[1] = intermIt.rawData(); + cs->convolveColors(colors, weights, KisChannelInfo::FLAG_COLOR, dstIt.rawData(), factor, 0, 2 ); + } + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + ++intermIt; + } + srcIt.nextRow(); + dstIt.nextRow(); + intermIt.nextRow(); + } + + + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/unsharp/kis_unsharp_filter.h b/chalk/plugins/filters/unsharp/kis_unsharp_filter.h new file mode 100644 index 00000000..0f25f318 --- /dev/null +++ b/chalk/plugins/filters/unsharp/kis_unsharp_filter.h @@ -0,0 +1,47 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_BLUR_FILTER_H +#define KIS_BLUR_FILTER_H + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include "kis_filter.h" + +class KisUnsharpFilter : public KisFilter +{ + public: + KisUnsharpFilter(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + static inline KisID id() { return KisID("unsharptqmask", i18n("Unsharp Mask")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/unsharp/kis_wdg_unsharp.cc b/chalk/plugins/filters/unsharp/kis_wdg_unsharp.cc new file mode 100644 index 00000000..4a59a224 --- /dev/null +++ b/chalk/plugins/filters/unsharp/kis_wdg_unsharp.cc @@ -0,0 +1,52 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_unsharp.h" + +#include +#include + +#include +#include + +#include + +#include "wdgunsharp.h" + +KisWdgUnsharp::KisWdgUnsharp( KisFilter* , TQWidget * tqparent, const char * name) : KisFilterConfigWidget ( tqparent, name ) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgUnsharp(this); + widgetLayout -> addWidget(m_widget,0,0); + + connect( widget()->intHalfSize, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->doubleAmount, TQT_SIGNAL( valueChanged(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intThreshold, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +void KisWdgUnsharp::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + widget()->intHalfSize->setValue( (config->getProperty("halfSize", value)) ? value.toUInt() : 4 ); + widget()->doubleAmount->setValue( (config->getProperty("amount", value)) ? value.toDouble() : 0.1 ); + widget()->intThreshold->setValue( (config->getProperty("threshold", value)) ? value.toUInt() : 20 ); +} + +#include "kis_wdg_unsharp.moc" diff --git a/chalk/plugins/filters/unsharp/kis_wdg_unsharp.h b/chalk/plugins/filters/unsharp/kis_wdg_unsharp.h new file mode 100644 index 00000000..52ffb584 --- /dev/null +++ b/chalk/plugins/filters/unsharp/kis_wdg_unsharp.h @@ -0,0 +1,45 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_WDG_UNSHARP_H_ +#define _KIS_WDG_UNSHARP_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class KisFilter; +class WdgUnsharp; + +class KisWdgUnsharp : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgUnsharp( KisFilter* nfilter, TQWidget * tqparent, const char * name); + inline WdgUnsharp* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgUnsharp* m_widget; +}; + +#endif diff --git a/chalk/plugins/filters/unsharp/unsharp.cc b/chalk/plugins/filters/unsharp/unsharp.cc new file mode 100644 index 00000000..60516f42 --- /dev/null +++ b/chalk/plugins/filters/unsharp/unsharp.cc @@ -0,0 +1,50 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "unsharp.h" + +#include + +#include "kis_unsharp_filter.h" + +typedef KGenericFactory UnsharpPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkunsharpfilter, UnsharpPluginFactory( "chalk" ) ) + +UnsharpPlugin::UnsharpPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(UnsharpPluginFactory::instance()); + + + kdDebug(41006) << "Extensions Image enhancement Filters plugin. Class: " + << className() + << ", Parent: " + << tqparent -> className() + << "\n"; + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisUnsharpFilter()); + } +} + +UnsharpPlugin::~UnsharpPlugin() +{ +} diff --git a/chalk/plugins/filters/unsharp/unsharp.h b/chalk/plugins/filters/unsharp/unsharp.h new file mode 100644 index 00000000..59a92694 --- /dev/null +++ b/chalk/plugins/filters/unsharp/unsharp.h @@ -0,0 +1,37 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _UNSHARP_PLUGIN_H_ +#define _UNSHARP_PLUGIN_H_ + +// TODO: remove that +#define LCMS_HEADER +// TODO: remove it ! + +#include + +class UnsharpPlugin : public KParts::Plugin +{ +public: + UnsharpPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~UnsharpPlugin(); +}; + +#endif diff --git a/chalk/plugins/filters/unsharp/wdgunsharp.ui b/chalk/plugins/filters/unsharp/wdgunsharp.ui new file mode 100644 index 00000000..376ed16e --- /dev/null +++ b/chalk/plugins/filters/unsharp/wdgunsharp.ui @@ -0,0 +1,138 @@ + +WdgUnsharp + + + WdgUnsharp + + + + 0 + 0 + 181 + 81 + + + + + unnamed + + + 0 + + + 0 + + + + intHalfSize + + + 4 + + + 1 + + + 1000 + + + + + textLabel1 + + + Half-size: + + + + + doubleAmount + + + 0.5 + + + 5 + + + 2 + + + + + textLabel2 + + + Threshold: + + + + + textLabel3 + + + Amount: + + + + + spacer5 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + intThreshold + + + 10 + + + 0 + + + 255 + + + + + spacer6 + + + Vertical + + + Expanding + + + + 20 + 21 + + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/filters/wavefilter/Makefile.am b/chalk/plugins/filters/wavefilter/Makefile.am new file mode 100644 index 00000000..0e4aacf9 --- /dev/null +++ b/chalk/plugins/filters/wavefilter/Makefile.am @@ -0,0 +1,23 @@ +chalkrcdir = $(kde_datadir)/chalk/chalkplugins + +kde_services_DATA = chalkwavefilter.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkwavefilter_la_SOURCES = wavefilter.cc wdgwaveoptions.ui \ + kis_wdg_wave.cpp + +kde_module_LTLIBRARIES = chalkwavefilter.la +noinst_HEADERS = wavefilter.h kis_wdg_wave.h + +chalkwavefilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkwavefilter_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO diff --git a/chalk/plugins/filters/wavefilter/chalkwavefilter.desktop b/chalk/plugins/filters/wavefilter/chalkwavefilter.desktop new file mode 100644 index 00000000..4a08b628 --- /dev/null +++ b/chalk/plugins/filters/wavefilter/chalkwavefilter.desktop @@ -0,0 +1,72 @@ +[Desktop Entry] +Comment=Transform an image in a wave +Comment[bg]=Превръщане на изображение във вълна +Comment[ca]=Transforma una imatge en una ona +Comment[da]=Tranbsformér et billede med en bølge +Comment[de]=Ein Bild in eine Welle transformieren +Comment[el]=Μετασχηματισμός μιας εικόνας με κυματομορφή +Comment[es]=Transformar una imagen en una onda +Comment[et]=Pildi teisendamine lainefiltris +Comment[fa]=تبدیل یک تصویر به صورت یک موج +Comment[fr]=Transformer une image en une vague +Comment[fy]=Transformearje in ôfbylding yn in golf +Comment[gl]=Transforma unha imaxe nunha onda +Comment[hu]=Kép hullámosítása +Comment[it]=Trasforma un'immagine in un'onda +Comment[ja]=画像を波で変形 +Comment[km]=ប្លែង​រូបភាព​ក្នុង​រលក +Comment[nb]=Transformer et bilde i en bølge +Comment[nds]=En Bild na en Bülg ümwanneln +Comment[ne]=तरङमा छवि रूपान्तरण गर्नुहोस् +Comment[nl]=Transformeer een afbeelding in een golf +Comment[pl]=Przekształca obrazek w falę +Comment[pt]=Transforma uma imagem numa onda +Comment[pt_BR]=Transforma uma imagem numa onda +Comment[ru]=Искажает изображение волнами +Comment[sk]=Transformovať obrázok pomocou vlny +Comment[sl]=Pretvorba slike v val +Comment[sr]=Трансформише слику у таласу +Comment[sr@Latn]=Transformiše sliku u talasu +Comment[sv]=Omvandla en bild med en våg +Comment[uk]=Спотворення зображення хвилями +Comment[zh_TW]=在 wave 中轉換圖片 +Icon= +Name=Wave Filter +Name[bg]=Вълнови филтър +Name[ca]=Filtre d'ona +Name[da]=Bølgefilter +Name[de]=Wellenfilter +Name[el]=Φίλτρο κυμματομορφής +Name[eo]=Ondofiltrilo +Name[es]=Filtro de onda +Name[et]=Lainefilter +Name[fa]=پالایۀ موج +Name[fr]=Filtre vague +Name[fy]=Golf-filter +Name[gl]=Filtro de Onda +Name[hu]=Hullámszűrő +Name[it]=Filtro onda +Name[ja]=波フィルタ +Name[km]=តម្រង​រលក +Name[nb]=Bølgefilter +Name[nds]=Bülgenfilter +Name[ne]=तरङ फिल्टर +Name[nl]=Golffilter +Name[pl]=Filtr fali +Name[pt]=Filtro de Onda +Name[pt_BR]=Filtro de Onda +Name[ru]=Волны +Name[se]=Bárrosilli +Name[sk]=Filter vlna +Name[sl]=Filter za valove +Name[sr]=Филтер за таласе +Name[sr@Latn]=Filter za talase +Name[sv]=Vågfilter +Name[uk]=Хвилі +Name[uz]=Toʻlqin filteri +Name[uz@cyrillic]=Тўлқин филтери +Name[zh_TW]=Wave 過濾器 +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkwavefilter +X-Chalk-Version=2 diff --git a/chalk/plugins/filters/wavefilter/kis_wdg_wave.cpp b/chalk/plugins/filters/wavefilter/kis_wdg_wave.cpp new file mode 100644 index 00000000..374fc6c8 --- /dev/null +++ b/chalk/plugins/filters/wavefilter/kis_wdg_wave.cpp @@ -0,0 +1,90 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_wdg_wave.h" + +#include + +#include +#include + +#include "wdgwaveoptions.h" + +KisWdgWave::KisWdgWave(KisFilter* /*nfilter*/, TQWidget* tqparent, const char* name) + : KisFilterConfigWidget(tqparent,name) +{ + TQGridLayout *widgetLayout = new TQGridLayout(this, 1, 1); + m_widget = new WdgWaveOptions(this); + widgetLayout -> addWidget(m_widget, 0, 0); + + connect( widget()->intHWavelength, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intHShift, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intHAmplitude, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbHShape, TQT_SIGNAL( activated(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVWavelength, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVShift, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->intVAmplitude, TQT_SIGNAL( valueChanged(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); + connect( widget()->cbVShape, TQT_SIGNAL( activated(int)), TQT_SIGNAL(sigPleaseUpdatePreview())); +} + +KisWdgWave::~KisWdgWave() +{ +} + +void KisWdgWave::setConfiguration(KisFilterConfiguration* config) +{ + TQVariant value; + if (config->getProperty("horizontalwavelength", value)) + { + widget()->intHWavelength->setValue( value.toUInt() ); + } + if (config->getProperty("horizontalshift", value)) + { + widget()->intHShift->setValue( value.toUInt() ); + } + if (config->getProperty("horizontalamplitude", value)) + { + widget()->intHAmplitude->setValue( value.toUInt() ); + } + if (config->getProperty("horizontaltqshape", value)) + { + widget()->cbHShape->setCurrentItem( value.toUInt() ); + } + if (config->getProperty("verticalwavelength", value)) + { + widget()->intVWavelength->setValue( value.toUInt() ); + } + if (config->getProperty("verticalshift", value)) + { + widget()->intVShift->setValue( value.toUInt() ); + } + if (config->getProperty("verticalamplitude", value)) + { + widget()->intVAmplitude->setValue( value.toUInt() ); + } + if (config->getProperty("verticaltqshape", value)) + { + widget()->cbVShape->setCurrentItem( value.toUInt() ); + } +} + + +#include "kis_wdg_wave.moc" + diff --git a/chalk/plugins/filters/wavefilter/kis_wdg_wave.h b/chalk/plugins/filters/wavefilter/kis_wdg_wave.h new file mode 100644 index 00000000..6f9b0744 --- /dev/null +++ b/chalk/plugins/filters/wavefilter/kis_wdg_wave.h @@ -0,0 +1,44 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WDG_WAVE_H +#define KIS_WDG_WAVE_H + +#include + +class WdgWaveOptions; +class KisFilter; + +class KisWdgWave : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT + public: + KisWdgWave(KisFilter* nfilter, TQWidget* tqparent = 0, const char* name = 0); + ~KisWdgWave(); + public: + inline WdgWaveOptions* widget() { return m_widget; }; + virtual void setConfiguration(KisFilterConfiguration*); + private: + WdgWaveOptions* m_widget; +}; + +#endif + diff --git a/chalk/plugins/filters/wavefilter/wavefilter.cc b/chalk/plugins/filters/wavefilter/wavefilter.cc new file mode 100644 index 00000000..1d78bafc --- /dev/null +++ b/chalk/plugins/filters/wavefilter/wavefilter.cc @@ -0,0 +1,169 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "wavefilter.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_wave.h" +#include "wdgwaveoptions.h" + +typedef KGenericFactory ChalkWaveFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwavefilter, ChalkWaveFilterFactory( "chalk" ) ) + +class KisWaveCurve { + public: + virtual double valueAt(int x, int y) =0; +}; + +class KisSinusoidalWaveCurve : public KisWaveCurve { + public: + KisSinusoidalWaveCurve(int amplitude, int wavelenght, int shift) : m_amplitude(amplitude), m_wavelength(wavelenght), m_shift(shift) + { + } + virtual double valueAt(int x, int y) + { + return y + m_amplitude * cos( (double) ( m_shift + x) / m_wavelength ); + } + private: + int m_amplitude, m_wavelength, m_shift; +}; + +class KisTriangleWaveCurve : public KisWaveCurve { + public: + KisTriangleWaveCurve(int amplitude, int wavelenght, int shift) : m_amplitude(amplitude), m_wavelength(wavelenght), m_shift(shift) + { + } + virtual double valueAt(int x, int y) + { + return y + m_amplitude * pow( -1, (m_shift + x) / m_wavelength ) * (0.5 - (double)( (m_shift + x) % m_wavelength ) / m_wavelength ); + } + private: + int m_amplitude, m_wavelength, m_shift; +}; + + + +ChalkWaveFilter::ChalkWaveFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkWaveFilterFactory::instance()); + + + if (tqparent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast(tqparent); + manager->add(new KisFilterWave()); + } +} + +ChalkWaveFilter::~ChalkWaveFilter() +{ +} + +KisFilterWave::KisFilterWave() : KisFilter(id(), "other", i18n("&Wave...")) +{ +} + +KisFilterConfiguration* KisFilterWave::configuration(TQWidget* w) +{ + KisWdgWave* wN = dynamic_cast(w); + KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 1); + if(wN) + { + config->setProperty("horizontalwavelength", wN->widget()->intHWavelength->value() ); + config->setProperty("horizontalshift", wN->widget()->intHShift->value() ); + config->setProperty("horizontalamplitude", wN->widget()->intHAmplitude->value() ); + config->setProperty("horizontaltqshape", wN->widget()->cbHShape->currentItem() ); + config->setProperty("verticalwavelength", wN->widget()->intVWavelength->value() ); + config->setProperty("verticalshift", wN->widget()->intVShift->value() ); + config->setProperty("verticalamplitude", wN->widget()->intVAmplitude->value() ); + config->setProperty("verticaltqshape", wN->widget()->cbVShape->currentItem() ); + } + return config; +} + +KisFilterConfigWidget * KisFilterWave::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP /*dev*/) +{ + return new KisWdgWave((KisFilter*)this, (TQWidget*)tqparent, i18n("Configuration of wave filter").ascii()); +} + +void KisFilterWave::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* config, const TQRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + setProgressTotalSteps(rect.width() * rect.height()); + + TQVariant value; + int horizontalwavelength = (config && config->getProperty("horizontalwavelength", value)) ? value.toInt() : 50; + int horizontalshift = (config && config->getProperty("horizontalshift", value)) ? value.toInt() : 50; + int horizontalamplitude = (config && config->getProperty("horizontalamplitude", value)) ? value.toInt() : 4; + int horizontaltqshape = (config && config->getProperty("horizontaltqshape", value)) ? value.toInt() : 0; + int verticalwavelength = (config && config->getProperty("verticalwavelength", value)) ? value.toInt() : 50; + int verticalshift = (config && config->getProperty("verticalshift", value)) ? value.toInt() : 50; + int verticalamplitude = (config && config->getProperty("verticalamplitude", value)) ? value.toInt() : 4; + int verticaltqshape = (config && config->getProperty("verticaltqshape", value)) ? value.toInt() : 0; + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + KisWaveCurve* verticalcurve; + if(verticaltqshape == 1) + verticalcurve = new KisTriangleWaveCurve(verticalamplitude, verticalwavelength, verticalshift); + else + verticalcurve = new KisSinusoidalWaveCurve(verticalamplitude, verticalwavelength, verticalshift); + KisWaveCurve* horizontalcurve; + if(horizontaltqshape == 1) + horizontalcurve = new KisTriangleWaveCurve(horizontalamplitude, horizontalwavelength, horizontalshift); + else + horizontalcurve = new KisSinusoidalWaveCurve(horizontalamplitude, horizontalwavelength, horizontalshift); + KisRandomSubAccessorPixel srcRSA = src->createRandomSubAccessor(); + while(!dstIt.isDone()) + { + double xv = horizontalcurve->valueAt( dstIt.y(), dstIt.x() ); + double yv = verticalcurve->valueAt( dstIt.x(), dstIt.y() ); + srcRSA.moveTo( KisPoint( xv, yv ) ); + srcRSA.sampledOldRawData(dstIt.rawData()); + ++dstIt; + incProgress(); + } + delete horizontalcurve; + delete verticalcurve; + setProgressDone(); // Must be called even if you don't really support progression +} diff --git a/chalk/plugins/filters/wavefilter/wavefilter.h b/chalk/plugins/filters/wavefilter/wavefilter.h new file mode 100644 index 00000000..3397ab0b --- /dev/null +++ b/chalk/plugins/filters/wavefilter/wavefilter.h @@ -0,0 +1,53 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WAVEFILTER_H +#define WAVEFILTER_H + +#include +#include "kis_filter.h" + +class KisFilterConfigWidget; + +class ChalkWaveFilter : public KParts::Plugin +{ +public: + ChalkWaveFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkWaveFilter(); +}; + +class KisFilterWave : public KisFilter +{ + public: + KisFilterWave(); + public: + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const TQRect&); + virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; }; + static inline KisID id() { return KisID("wave", i18n("Wave")); }; + virtual bool supportsPainting() { return true; } + virtual bool supportsPreview() { return true; } + virtual bool supportsIncrementalPainting() { return false; } + virtual bool supportsAdjustmentLayers() { return false; } + public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*); +}; + +#endif diff --git a/chalk/plugins/filters/wavefilter/wdgwaveoptions.ui b/chalk/plugins/filters/wavefilter/wdgwaveoptions.ui new file mode 100644 index 00000000..10fff389 --- /dev/null +++ b/chalk/plugins/filters/wavefilter/wdgwaveoptions.ui @@ -0,0 +1,281 @@ + +WdgWaveOptions + + + WdgWaveOptions + + + + 0 + 0 + 223 + 303 + + + + + unnamed + + + 0 + + + + spacer2 + + + Horizontal + + + Expanding + + + + 60 + 20 + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 60 + + + + + + groupBox1 + + + Horizontal Wave + + + + unnamed + + + + textLabel1 + + + Wavelength: + + + + + intHWavelength + + + 50 + + + 1 + + + 1000000 + + + + + textLabel2 + + + Shift: + + + + + intHShift + + + 0 + + + 0 + + + 1000000 + + + + + textLabel2_2 + + + Amplitude: + + + + + intHAmplitude + + + 20 + + + 0 + + + 1000000 + + + + + + Sinusoidale + + + + + Triangle + + + + cbHShape + + + + + textLabel1_2 + + + Shape: + + + + + + + Vertical_wave + + + Vertical Wave + + + + unnamed + + + + textLabel1_3 + + + Wavelength: + + + + + intVWavelength + + + 50 + + + 1 + + + 1000000 + + + + + textLabel2_3 + + + Shift: + + + + + intVShift + + + 0 + + + 0 + + + 1000000 + + + + + textLabel2_2_2 + + + Amplitude: + + + + + intVAmplitude + + + 20 + + + 0 + + + 1000000 + + + + + + Sinusoidale + + + + + Triangle + + + + cbVShape + + + + + textLabel1_2_2 + + + Shape: + + + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + kcombobox.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + kcombobox.h + + diff --git a/chalk/plugins/paintops/Makefile.am b/chalk/plugins/paintops/Makefile.am new file mode 100644 index 00000000..328f0162 --- /dev/null +++ b/chalk/plugins/paintops/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = \ + defaultpaintops diff --git a/chalk/plugins/paintops/defaultpaintops/Makefile.am b/chalk/plugins/paintops/defaultpaintops/Makefile.am new file mode 100644 index 00000000..120368c6 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/Makefile.am @@ -0,0 +1,39 @@ +chalkimagesdir = $(prefix)/share/apps/chalk/images + +chalkimages_DATA = \ + airbrush.png \ + paintbrush.png \ + eraser.png \ + pencil.png + + +kde_services_DATA = chalkdefaultpaintops.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + + +chalkdefaultpaintops_la_SOURCES = \ + defaultpaintops_plugin.cc \ + kis_airbrushop.cc \ + kis_brushop.cc \ + kis_duplicateop.cc \ + kis_eraseop.cc \ + kis_penop.cc \ + kis_dlgbrushcurvecontrol.ui \ + kis_smudgeop.cc + +noinst_HEADERS = defaultpaintops_plugin.h kis_airbrushop.h kis_brushop.h \ + kis_duplicateop.h kis_eraseop.h kis_penop.h kis_smudgeop.h + +kde_module_LTLIBRARIES = chalkdefaultpaintops.la + +chalkdefaultpaintops_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkdefaultpaintops_la_LIBADD = ../../../libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +chalkdefaultpaintops_la_METASOURCES = AUTO diff --git a/chalk/plugins/paintops/defaultpaintops/README b/chalk/plugins/paintops/defaultpaintops/README new file mode 100644 index 00000000..47b07ce7 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/README @@ -0,0 +1,3 @@ +Default implementations of the paintop interface. These may +some day become plugins. New paintops should be created as +plugins. diff --git a/chalk/plugins/paintops/defaultpaintops/airbrush.png b/chalk/plugins/paintops/defaultpaintops/airbrush.png new file mode 100644 index 00000000..36c1d707 Binary files /dev/null and b/chalk/plugins/paintops/defaultpaintops/airbrush.png differ diff --git a/chalk/plugins/paintops/defaultpaintops/chalkdefaultpaintops.desktop b/chalk/plugins/paintops/defaultpaintops/chalkdefaultpaintops.desktop new file mode 100644 index 00000000..e1c940b2 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/chalkdefaultpaintops.desktop @@ -0,0 +1,93 @@ +[Desktop Entry] +Name=Default Paint Operations +Name[bg]=Операции за рисуване по подразбиране +Name[ca]=Operacions de pintura per defecte +Name[cy]=Gweithrediadau Paent Rhagosodol +Name[da]=Standard maleoperationer +Name[de]=Standard Maloperation +Name[el]=Προκαθορισμένες λειτουργίες ζωγραφικής +Name[eo]=Aprioraj pentrooperacioj +Name[es]=Operaciones de pintura predefinidas +Name[et]=Vaikimisi joonistamistoimingud +Name[eu]=Margotze-eragiketa lehenetsiak +Name[fa]=عملیات رنگ‌آمیزی پیش‌فرض +Name[fi]=Oletusväritystoimenpiteet +Name[fr]=Opérations de dessin par défaut +Name[fy]=Standertskilderaksjes +Name[ga]=Oibríochtaí Réamhshocraithe Péinteála +Name[gl]=Operacións de Pintura Predefinidas +Name[he]=פעולות הצביעה המוגדרות כברירת מחדל +Name[hu]=Alapértelmezett festési műveletek +Name[is]=Sjálfgefnar málunaraðgerðir +Name[it]=Operazioni predefinite di disegno +Name[ja]=標準の描画操作 +Name[km]=ប្រតិបត្តិការ​គូរ​លំនាំដើម +Name[ms]=Operasi Cat Piawai +Name[nb]=Standard maleteknikker +Name[nds]=Standard-Maalakschonen +Name[ne]=पूर्वनिर्धारित पेन्ट सञ्चालन +Name[nl]=Standaardschilderoperaties +Name[nn]=Standard måleoperasjonar +Name[pl]=Domyślne operacje na obrazkach +Name[pt]=Operações de Pintura Predefinidas +Name[pt_BR]=Operações de pintura padrão +Name[ru]=Стандартные инструменты рисования +Name[se]=Standárda málendoaimmat +Name[sk]=Štandardné operácie kreslenia +Name[sl]=Privzete operacije za slikanje +Name[sr]=Подразумеване сликарске операције +Name[sr@Latn]=Podrazumevane slikarske operacije +Name[sv]=Förvalda målningsåtgärder +Name[uk]=Типові дії малювання +Name[uz]=Andoza chizish amallari +Name[uz@cyrillic]=Андоза чизиш амаллари +Name[zh_CN]=默认绘图操作 +Name[zh_TW]=預設繪圖操作 +Comment=Default paint operations +Comment[bg]=Операции за рисуване по подразбиране +Comment[ca]=Operacions de pintura per defecte +Comment[cy]=Gweithrediadau paent rhagosodol +Comment[da]=Standard maleoperationer +Comment[de]=Standard Maloperation +Comment[el]=Προκαθορισμένες λειτουργίες ζωγραφικής +Comment[eo]=Aprioraj pentrooperacioj +Comment[es]=Operaciones de pintado predefinidas +Comment[et]=Vaikimisi joonistamistoimingud +Comment[eu]=Margotze-eragiketa lehenetsiak +Comment[fa]=عملیات رنگ‌آمیزی پیش‌فرض +Comment[fi]=Oletusväritystoimenpiteet +Comment[fr]=Opérations de dessin par défaut +Comment[fy]=Standertskilderaksjes +Comment[ga]=Oibríochtaí réamhshocraithe péinteála +Comment[gl]=Operacións de pintura predefinidas +Comment[he]=פעולות הצביעה המוגדרות כברירת מחדל +Comment[hu]=Alapértelmezett festési műveletek +Comment[is]=Sjálfgefnar málunaraðgerðir +Comment[it]=Operazioni predefinite di disegno +Comment[ja]=標準の描画操作 +Comment[km]=ប្រតិបត្តិកា​គូរ​លំនាំ​ដើម​ +Comment[ms]=Operasi cat piawai +Comment[nb]=Standard maleteknikker +Comment[nds]=Standard-Maalakschonen +Comment[ne]=पूर्वनिर्धारित पेन्ट सञ्चालन +Comment[nl]=Standaardschilderoperaties +Comment[nn]=Standard måleoperasjonar +Comment[pl]=Domyślne operacje na obrazkach +Comment[pt]=Operações de pintura predefinidas +Comment[pt_BR]=Operações de pintura padrão +Comment[ru]=Инструменты рисования по умолчанию +Comment[se]=Standárda málendoaimmat +Comment[sk]=Štandardné operácie kreslenia +Comment[sl]=Privzete operacije za slikanje +Comment[sr]=Подразумеване сликарске операције +Comment[sr@Latn]=Podrazumevane slikarske operacije +Comment[sv]=Förvalda målningsåtgärder +Comment[uk]=Типові дії малювання +Comment[uz]=Andoza chizish amallari +Comment[uz@cyrillic]=Андоза чизиш амаллари +Comment[zh_CN]=默认绘图操作 +Comment[zh_TW]=預設繪圖操作 +ServiceTypes=Chalk/Paintop +Type=Service +X-KDE-Library=chalkdefaultpaintops +X-Chalk-Version=2 diff --git a/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc b/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc new file mode 100644 index 00000000..5a267f57 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.cc @@ -0,0 +1,70 @@ +/* + * defaultpaintops_plugin.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_airbrushop.h" +#include "kis_brushop.h" +#include "kis_duplicateop.h" +#include "kis_eraseop.h" +#include "kis_smudgeop.h" +#include "kis_penop.h" +#include "kis_global.h" +#include "kis_paintop_registry.h" + +#include "defaultpaintops_plugin.h" + +typedef KGenericFactory DefaultPaintOpsPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkdefaultpaintops, DefaultPaintOpsPluginFactory( "chalkcore" ) ) + + +DefaultPaintOpsPlugin::DefaultPaintOpsPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(DefaultPaintOpsPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisPaintOpRegistry") ) + { + KisPaintOpRegistry * r = dynamic_cast(tqparent); + // Add hard-coded paint ops. Plugin paintops will add + // themselves in the plugin initialization code. + r->add ( new KisAirbrushOpFactory ); + r->add ( new KisBrushOpFactory ); + r->add ( new KisDuplicateOpFactory ); + r->add ( new KisEraseOpFactory ); + r->add ( new KisPenOpFactory ); + r->add ( new KisSmudgeOpFactory ); + } + +} + +DefaultPaintOpsPlugin::~DefaultPaintOpsPlugin() +{ +} + +#include "defaultpaintops_plugin.moc" diff --git a/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h b/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h new file mode 100644 index 00000000..d7afb9d0 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/defaultpaintops_plugin.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DEFAULT_PAINTOPS_PLUGIN_H_ +#define DEFAULT_PAINTOPS_PLUGIN_H_ + +#include + +/** + * A plugin wrapper that adds the paintop factories to the paintop registry. + */ +class DefaultPaintOpsPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + DefaultPaintOpsPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~DefaultPaintOpsPlugin(); +}; + +#endif // DEFAULT_PAINTOPSGRAY_PLUGIN_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/eraser.png b/chalk/plugins/paintops/defaultpaintops/eraser.png new file mode 100644 index 00000000..c5461aba Binary files /dev/null and b/chalk/plugins/paintops/defaultpaintops/eraser.png differ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.cc b/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.cc new file mode 100644 index 00000000..85bef3f6 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_vec.h" +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_layer.h" +#include "kis_selection.h" +#include "kis_airbrushop.h" + +KisPaintOp * KisAirbrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisAirbrushOp(painter); + Q_CHECK_PTR(op); + return op; +} + + +KisAirbrushOp::KisAirbrushOp(KisPainter * painter) + : super(painter) +{ +} + +KisAirbrushOp::~KisAirbrushOp() +{ +} + +void KisAirbrushOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ +// See: http://www.sysf.physto.se/~klere/airbrush/ for information +// about _real_ airbrushes. +// +// Most graphics apps -- especially the simple ones like Kolourpaint +// and the previous version of this routine in Chalk took a brush +// tqshape -- often a simple ellipse -- and filled that tqshape with a +// random 'spray' of single pixels. +// +// Other, more advanced graphics apps, like the Gimp or Photoshop, +// take the brush tqshape and paint just as with the brush paint op, +// only making the initial dab more transparent, and perhaps adding +// extra transparence near the edges. Then, using a timer, when the +// cursor stays in place, dab upon dab is positioned in the same +// place, which makes the result less and less transparent. +// +// What I want to do here is create an airbrush that approaches a real +// one. It won't use brush tqshapes, instead going for the old-fashioned +// circle. Depending upon pressure, both the size of the dab and the +// rate of paint deposition is determined. The edges of the dab are +// more transparent than the center, with perhaps even some fully +// transparent pixels between the near-transparent pixels. +// +// By pressing some to-be-determined key at the same time as pressing +// mouse-down, one edge of the dab is made straight, to simulate +// working with a shield. +// +// Tilt may be used to make the gradients more realistic, but I don't +// have a tablet that supports tilt. +// +// Anyway, it's exactly twenty years ago that I have held a real +// airbrush, for the first and up to now the last time... +// + + if (!m_painter) return; + + KisPaintDeviceSP device = m_painter->device(); + + // For now: use the current brush tqshape -- it beats calculating + // ellipes and cones, and it shows the working of the timer. + if (!device) return; + + KisBrush * brush = m_painter->brush(); + if (! brush->canPaintFor(info) ) + return; + KisPaintDeviceSP dab = m_painter->dab(); + + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), info, xFraction, yFraction); + } + else { + KisAlphaMaskSP tqmask = brush->tqmask(info, xFraction, yFraction); + dab = computeDab(tqmask); + } + + m_painter->setDab(dab); // Cache dab for future paints in the painter. + m_painter->setPressure(info.pressure); // Cache pressure in the current painter. + + TQRect dabRect = TQRect(0, 0, brush->tqmaskWidth(info), brush->tqmaskHeight(info)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), m_painter->opacity(), sx, sy, sw, sh); + } + + m_painter->addDirtyRect(dstRect); +} diff --git a/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.h b/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.h new file mode 100644 index 00000000..805664d7 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_airbrushop.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_AIRBRUSHOP_H_ +#define KIS_AIRBRUSHOP_H_ + +#include "kis_paintop.h" + +class KisPoint; +class KisPainter; + +class KisAirbrushOpFactory : public KisPaintOpFactory { + +public: + KisAirbrushOpFactory() {} + virtual ~KisAirbrushOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("airbrush", i18n("Pixel Airbrush")); } + virtual TQString pixmap() { return "airbrush.png"; } +}; + + + +class KisAirbrushOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisAirbrushOp(KisPainter * painter); + virtual ~KisAirbrushOp(); + + // We want to spray even when the pointer doesn't move. + virtual bool incremental() { return true; } + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +}; + +#endif // KIS_AIRBRUSHOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_brushop.cc b/chalk/plugins/paintops/defaultpaintops/kis_brushop.cc new file mode 100644 index 00000000..360fa66e --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_brushop.cc @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "kcurve.h" +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_layer.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_input_device.h" +#include "kis_selection.h" +#include "kis_brushop.h" + +#include "kis_dlgbrushcurvecontrol.h" + +KisPaintOp * KisBrushOpFactory::createOp(const KisPaintOpSettings *settings, KisPainter * painter) +{ + const KisBrushOpSettings *brushopSettings = dynamic_cast(settings); + Q_ASSERT(settings == 0 || brushopSettings != 0); + + KisPaintOp * op = new KisBrushOp(brushopSettings, painter); + Q_CHECK_PTR(op); + return op; +} + +KisBrushOpSettings::KisBrushOpSettings(TQWidget *tqparent) + : super(tqparent) +{ + m_optionsWidget = new TQWidget(tqparent, "brush option widget"); + TQHBoxLayout * l = new TQHBoxLayout(m_optionsWidget); + l->setAutoAdd(true); + m_pressureVariation = new TQLabel(i18n("Pressure variation: "), m_optionsWidget); + m_size = new TQCheckBox(i18n("Size"), m_optionsWidget); + m_size->setChecked(true); + m_opacity = new TQCheckBox(i18n("Opacity"), m_optionsWidget); + m_darken = new TQCheckBox(i18n("Darken"), m_optionsWidget); + m_curveControl = new WdgBrushCurveControl(m_optionsWidget); + TQToolButton* moreButton = new TQToolButton(TQt::UpArrow, m_optionsWidget); + moreButton->tqsetSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); + moreButton->setMinimumSize(TQSize(24,24)); // Bah, I had hoped the above line would make this unneeded + connect(moreButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotCustomCurves())); + + m_customSize = false; + m_customOpacity = false; + m_customDarken = false; + // the curves will get filled in when the slot gets accepted +} + +void KisBrushOpSettings::slotCustomCurves() { + if (m_curveControl->exec() == TQDialog::Accepted) { + m_customSize = m_curveControl->sizeCheckbox->isChecked(); + m_customOpacity = m_curveControl->opacityCheckbox->isChecked(); + m_customDarken = m_curveControl->darkenCheckbox->isChecked(); + + if (m_customSize) { + transferCurve(m_curveControl->sizeCurve, m_sizeCurve); + } + if (m_customOpacity) { + transferCurve(m_curveControl->opacityCurve, m_opacityCurve); + } + if (m_customDarken) { + transferCurve(m_curveControl->darkenCurve, m_darkenCurve); + } + } +} + +void KisBrushOpSettings::transferCurve(KCurve* curve, double* target) { + double value; + for (int i = 0; i < 256; i++) { + value = curve->getCurveValue( i / 255.0); + if (value < PRESSURE_MIN) + target[i] = PRESSURE_MIN; + else if (value > PRESSURE_MAX) + target[i] = PRESSURE_MAX; + else + target[i] = value; + } +} + + +bool KisBrushOpSettings::varySize() const +{ + return m_size->isChecked(); +} + +bool KisBrushOpSettings::varyOpacity() const +{ + return m_opacity->isChecked(); +} + +bool KisBrushOpSettings::varyDarken() const +{ + return m_darken->isChecked(); +} + +KisPaintOpSettings* KisBrushOpFactory::settings(TQWidget * tqparent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return 0; + } else { + return new KisBrushOpSettings(tqparent); + } +} + +KisBrushOp::KisBrushOp(const KisBrushOpSettings *settings, KisPainter *painter) + : super(painter) + , m_pressureSize(true) + , m_pressureOpacity(false) + , m_pressureDarken(false) + , m_customSize(false) + , m_customOpacity(false) + , m_customDarken(false) +{ + if (settings != 0) { + m_pressureSize = settings->varySize(); + painter->setVaryBrushSpacingWithPressureWhenDrawingALine( m_pressureSize ); + + m_pressureOpacity = settings->varyOpacity(); + m_pressureDarken = settings->varyDarken(); + m_customSize = settings->customSize(); + m_customOpacity = settings->customOpacity(); + m_customDarken = settings->customDarken(); + if (m_customSize) { + memcpy(m_sizeCurve, settings->sizeCurve(), 256 * sizeof(double)); + } + if (m_customOpacity) { + memcpy(m_opacityCurve, settings->opacityCurve(), 256 * sizeof(double)); + } + if (m_customDarken) { + memcpy(m_darkenCurve, settings->darkenCurve(), 256 * sizeof(double)); + } + } +} + +KisBrushOp::~KisBrushOp() +{ + m_painter->setVaryBrushSpacingWithPressureWhenDrawingALine( true ); +} + +void KisBrushOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + KisPaintInformation adjustedInfo(info); + if (!m_pressureSize) + adjustedInfo.pressure = PRESSURE_DEFAULT; + else if (m_customSize) + adjustedInfo.pressure = scaleToCurve(adjustedInfo.pressure, m_sizeCurve); + + // Painting should be implemented according to the following algorithm: + // retrieve brush + // if brush == tqmask + // retrieve tqmask + // else if brush == image + // retrieve image + // subsample (tqmask | image) for position -- pos should be double! + // apply filters to tqmask (colour | gradient | pattern | etc. + // composite filtered tqmask into temporary layer + // composite temporary layer into target layer + // @see: doc/brush.txt + + if (!m_painter->device()) return; + + KisBrush *brush = m_painter->brush(); + + Q_ASSERT(brush); + if (!brush) return; + if (! brush->canPaintFor(adjustedInfo) ) + return; + + KisPaintDeviceSP device = m_painter->device(); + + KisPoint hotSpot = brush->hotSpot(adjustedInfo); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisPaintDeviceSP dab = 0; + + TQ_UINT8 origOpacity = m_painter->opacity(); + KisColor origColor = m_painter->paintColor(); + + if (m_pressureOpacity) { + if (!m_customOpacity) + m_painter->setOpacity((TQ_INT8)(origOpacity * info.pressure)); + else + m_painter->setOpacity((TQ_INT8)(origOpacity * scaleToCurve(info.pressure, m_opacityCurve))); + } + + if (m_pressureDarken) { + KisColor darkened = origColor; + // Darken docs aren't really clear about what exactly the amount param can have as value... + TQ_UINT32 darkenAmount; + if (!m_customDarken) + darkenAmount = (TQ_INT32)(255 - 75 * info.pressure); + else + darkenAmount = (TQ_INT32)(255 - 75 * scaleToCurve(info.pressure, m_darkenCurve)); + + darkened.colorSpace()->darken(origColor.data(), darkened.data(), + darkenAmount, false, 0.0, 1); + m_painter->setPaintColor(darkened); + } + + if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), adjustedInfo, xFraction, yFraction); + } + else { + KisAlphaMaskSP tqmask = brush->tqmask(adjustedInfo, xFraction, yFraction); + dab = computeDab(tqmask); + } + + m_painter->setPressure(adjustedInfo.pressure); + + TQRect dabRect = TQRect(0, 0, brush->tqmaskWidth(adjustedInfo), + brush->tqmaskHeight(adjustedInfo)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), m_painter->opacity(), sx, sy, sw, sh); + } + m_painter->addDirtyRect(dstRect); + + m_painter->setOpacity(origOpacity); + m_painter->setPaintColor(origColor); +} + +#include "kis_brushop.moc" diff --git a/chalk/plugins/paintops/defaultpaintops/kis_brushop.h b/chalk/plugins/paintops/defaultpaintops/kis_brushop.h new file mode 100644 index 00000000..6475b3d7 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_brushop.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_BRUSHOP_H_ +#define KIS_BRUSHOP_H_ + +#include "kis_paintop.h" + +class TQWidget; +class TQCheckBox; +class TQLabel; +class KisPoint; +class KisPainter; +class KCurve; +class WdgBrushCurveControl; + +class KisBrushOpFactory : public KisPaintOpFactory { + +public: + KisBrushOpFactory() {} + virtual ~KisBrushOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("paintbrush", i18n("Pixel Brush")); } + virtual TQString pixmap() { return "paintbrush.png"; } + virtual KisPaintOpSettings *settings(TQWidget * tqparent, const KisInputDevice& inputDevice); +}; + +class KisBrushOpSettings : public TQObject, public KisPaintOpSettings { + Q_OBJECT + TQ_OBJECT + typedef KisPaintOpSettings super; +public: + KisBrushOpSettings(TQWidget *tqparent); + + bool varySize() const; + bool varyOpacity() const; + bool varyDarken() const; + + bool customSize() const { return m_customSize; } + bool customOpacity() const { return m_customOpacity; } + bool customDarken() const { return m_customDarken; } + const double* sizeCurve() const { return m_sizeCurve; } + const double* opacityCurve() const { return m_opacityCurve; } + const double* darkenCurve() const { return m_darkenCurve; } + + virtual TQWidget *widget() const { return m_optionsWidget; } +private slots: + void slotCustomCurves(); +private: + void transferCurve(KCurve* curve, double* target); + TQWidget *m_optionsWidget; + TQLabel * m_pressureVariation; + TQCheckBox * m_size; + TQCheckBox * m_opacity; + TQCheckBox * m_darken; + WdgBrushCurveControl* m_curveControl; + + bool m_customSize; + bool m_customOpacity; + bool m_customDarken; + double m_sizeCurve[256]; + double m_opacityCurve[256]; + double m_darkenCurve[256]; +}; + +class KisBrushOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisBrushOp(const KisBrushOpSettings *settings, KisPainter * painter); + virtual ~KisBrushOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +private: + inline double scaleToCurve(double pressure, double* curve) const { + int offset = CLAMP(int(255.0 * pressure), 0, 255); + return curve[offset]; + } + bool m_pressureSize; + bool m_pressureOpacity; + bool m_pressureDarken; + bool m_customSize; + bool m_customOpacity; + bool m_customDarken; + double m_sizeCurve[256]; + double m_opacityCurve[256]; + double m_darkenCurve[256]; +}; + +#endif // KIS_BRUSHOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_convolveop.cc b/chalk/plugins/paintops/defaultpaintops/kis_convolveop.cc new file mode 100644 index 00000000..72bf9e66 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_convolveop.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_layer.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_selection.h" +#include "kis_convolveop.h" + + +KisPaintOp * KisConvolveOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisConvolveOp(painter); + Q_CHECK_PTR(op); + return op; +} + + +KisConvolveOp::KisConvolveOp(KisPainter * painter) + : super(painter) +{ +} + +KisConvolveOp::~KisConvolveOp() +{ +} + +void KisConvolveOp::paintAt(const KisPoint &/*pos*/, const KisPaintInformation& /*info*/) +{ + // XXX: use convolve painter here. + +} diff --git a/chalk/plugins/paintops/defaultpaintops/kis_convolveop.h b/chalk/plugins/paintops/defaultpaintops/kis_convolveop.h new file mode 100644 index 00000000..d5dc3764 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_convolveop.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CONVOLVEOP_H_ +#define KIS_CONVOLVEOP_H_ + +#include "kis_paintop.h" + +class KisPoint; +class KisPainter; + + +class KisConvolveOpFactory : public KisPaintOpFactory { + +public: + KisConvolveOpFactory() {} + virtual ~KisConvolveOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("convolve", i18n("Convolve")); } +}; + + +class KisConvolveOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisConvolveOp(KisPainter * painter); + virtual ~KisConvolveOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +}; + +#endif // KIS_CONVOLVEOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui b/chalk/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui new file mode 100644 index 00000000..f6021ecc --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_dlgbrushcurvecontrol.ui @@ -0,0 +1,271 @@ + +WdgBrushCurveControl + + + WdgBrushCurveControl + + + + 0 + 0 + 477 + 430 + + + + Custom Curves + + + true + + + + unnamed + + + + tabWidget + + + + Widget8 + + + Size Curve + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + sizeCheckbox + + + Use custom curve + + + + + sizeCurve + + + + 7 + 7 + 0 + 0 + + + + + + + + + + Widget9 + + + Opacity Curve + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + opacityCheckbox + + + Use custom curve + + + + + opacityCurve + + + + 7 + 7 + 0 + 0 + + + + + + + + + + TabPage + + + Darken Curve + + + + unnamed + + + + tqlayout5 + + + + unnamed + + + + darkenCheckbox + + + Use custom curve + + + + + darkenCurve + + + + 7 + 7 + 0 + 0 + + + + + + + + + + + Layout1 + + + + unnamed + + + 0 + + + 6 + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + &Cancel + + + + + + true + + + + + + + + + KCurve +
kcurve.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + buttonOk + clicked() + WdgBrushCurveControl + accept() + + + buttonCancel + clicked() + WdgBrushCurveControl + reject() + + + + + kcurve.h + kcurve.h + kcurve.h + +
diff --git a/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.cc b/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.cc new file mode 100644 index 00000000..139ed51d --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.cc @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_duplicateop.h" + +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_layer.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_paintop.h" +#include "kis_iterators_pixel.h" +#include "kis_selection.h" +#include "kis_perspective_grid.h" +#include "kis_random_sub_accessor.h" + +KisPaintOp * KisDuplicateOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisDuplicateOp(painter); + Q_CHECK_PTR(op); + return op; +} + + +KisDuplicateOp::KisDuplicateOp(KisPainter * painter) + : super(painter) + , m_target(0) + , m_srcdev(0) +{ +} + +KisDuplicateOp::~KisDuplicateOp() +{ +} + +double KisDuplicateOp::minimizeEnergy(const double* m, double* sol, int w, int h) +{ + int rowstride = 3*w; + double err = 0; + memcpy(sol, m, 3* sizeof(double) * w); + m+=rowstride; + sol+=rowstride; + for ( int i = 1; i < h - 1; i++) + { + memcpy(sol, m, 3* sizeof(double)); + m+=3; sol+=3; + for ( int j = 3; j < rowstride-3; j++) + { + double tmp = *sol; + *sol = ( ( *(m - 3 ) + *(m + 3) + *(m - rowstride ) + *(m + rowstride )) + 2 * *m ) /6; + double diff = *sol - tmp; + err += diff*diff; + m ++; sol ++; + } + memcpy(sol, m, 3* sizeof(double)); + m+=3; sol+=3; +} + memcpy(sol, m, 3* sizeof(double) * w); + return err; +} + + +void KisDuplicateOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + if (!m_painter) return; + + bool heal = m_painter->duplicateHealing(); +// int healradius = m_painter->duplicateHealingRadius(); + + KisPaintDeviceSP device = m_painter->device(); + if (m_source) device = m_source; + if (!device) return; + + KisBrush * brush = m_painter->brush(); + if (!brush) return; + if (! brush->canPaintFor(info) ) + return; + + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + xFraction = yFraction = 0.0; + + KisPaintDeviceSP dab = 0; + + if (brush->brushType() == IMAGE || + brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), info, xFraction, yFraction); + dab->convertTo(KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + else { + KisAlphaMaskSP tqmask = brush->tqmask(info, xFraction, yFraction); + dab = computeDab(tqmask, KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + + m_painter->setPressure(info.pressure); + + KisPoint srcPointF = pt - m_painter->duplicateOffset(); + TQPoint srcPoint = TQPoint(x - static_cast(m_painter->duplicateOffset().x()), + y - static_cast(m_painter->duplicateOffset().y())); + + + TQ_INT32 sw = dab->extent().width(); + TQ_INT32 sh = dab->extent().height(); + + if (srcPoint.x() < 0 ) + srcPoint.setX(0); + + if( srcPoint.y() < 0) + srcPoint.setY(0); + if( !(m_srcdev && m_srcdev->colorSpace() != device->colorSpace()) ) + { + m_srcdev = new KisPaintDevice(device->colorSpace(), "duplicate source dev"); + m_target = new KisPaintDevice(device->colorSpace(), "duplicate target dev"); + } + Q_CHECK_PTR(m_srcdev); + + // Perspective correction ? + KisPainter copyPainter(m_srcdev); + if(m_painter->duplicatePerspectiveCorrection()) + { + double startM[3][3]; + double endM[3][3]; + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + startM[i][j] = 0.; + endM[i][j] = 0.; + } + startM[i][i] = 1.; + endM[i][i] = 1.; + } + // First look for the grid corresponding to the start point + KisSubPerspectiveGrid* subGridStart = *device->image()->perspectiveGrid()->begin();//device->image()->perspectiveGrid()->gridAt(KisPoint(srcPoint.x() +hotSpot.x(),srcPoint.y() +hotSpot.y())); + TQRect r = TQRect(0,0, device->image()->width(), device->image()->height()); + +#if 1 + if(subGridStart) + { +// kdDebug() << "fgrid" << endl; +// kdDebug() << *subGridStart->topLeft() << " " << *subGridStart->topRight() << " " << *subGridStart->bottomLeft() << " " << *subGridStart->bottomRight() << endl; + double* b = KisPerspectiveMath::computeMatrixTransfoFromPerspective( r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { +// kdDebug() << "sol[" << 3*i+j << "]=" << b[3*i+j] << endl; + startM[i][j] = b[3*i+j]; + } + } + + } +#endif +#if 1 + // Second look for the grid corresponding to the end point + KisSubPerspectiveGrid* subGridEnd = *device->image()->perspectiveGrid()->begin();// device->image()->perspectiveGrid()->gridAt(pos); + if(subGridEnd) + { +// kdDebug() << "second grid" << endl; + double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { +// kdDebug() << "sol[" << 3*i+j << "]=" << b[3*i+j] << endl; + endM[i][j] = b[3*i+j]; + } + } + } +#endif +// kdDebug()<< " oouuuuh" << srcPointF << KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, srcPointF ) ) << KisPerspectiveMath::matProd(endM, KisPerspectiveMath::matProd(startM, srcPointF ) ); + + // Compute the translation in the perspective transformation space: + KisPoint positionStartPaintingT = KisPerspectiveMath::matProd(endM, m_painter->duplicateStart() ); + KisPoint duplicateStartPoisitionT = KisPerspectiveMath::matProd(endM, m_painter->duplicateStart() - m_painter->duplicateOffset() ); + KisPoint translat = duplicateStartPoisitionT - positionStartPaintingT; + KisRectIteratorPixel dstIt = m_srcdev->createRectIterator(0, 0, sw, sh, true); + KisRandomSubAccessorPixel srcAcc = device->createRandomSubAccessor(); + //Action + while(!dstIt.isDone()) + { + if(dstIt.isSelected()) + { + KisPoint p = KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, KisPoint(dstIt.x() + x, dstIt.y() + y) ) + translat ); + srcAcc.moveTo( p ); + srcAcc.sampledOldRawData( dstIt.rawData() ); + } + ++dstIt; + } + + + } else { + // Or, copy the source data on the temporary device: + copyPainter.bitBlt(0, 0, COMPOSITE_COPY, device, srcPoint.x(), srcPoint.y(), sw, sh); + copyPainter.end(); + } + + // heal ? + + if(heal) + { + TQ_UINT16 dataDevice[4]; + TQ_UINT16 dataSrcDev[4]; + TQMemArray matrix ( 3 * sw * sh ); + // First divide + KisColorSpace* deviceCs = device->colorSpace(); + KisHLineIteratorPixel deviceIt = device->createHLineIterator(x, y, sw, false ); + KisHLineIteratorPixel srcDevIt = m_srcdev->createHLineIterator(0, 0, sw, true ); + double* matrixIt = &matrix[0]; + for(int j = 0; j < sh; j++) + { + for(int i= 0; !srcDevIt.isDone(); i++) + { + deviceCs->toLabA16(deviceIt.rawData(), (TQ_UINT8*)dataDevice, 1); + deviceCs->toLabA16(srcDevIt.rawData(), (TQ_UINT8*)dataSrcDev, 1); + // Division + for( int k = 0; k < 3; k++) + { + matrixIt[k] = dataDevice[k] / (double)TQMAX(dataSrcDev [k], 1); + } + ++deviceIt; + ++srcDevIt; + matrixIt +=3; + } + deviceIt.nextRow(); + srcDevIt.nextRow(); + } + // Minimize energy + { + int iter = 0; + double err; + TQMemArray solution ( 3 * sw * sh ); + do { + err = minimizeEnergy(&matrix[0], &solution[0],sw,sh); + memcpy (&matrix[0], &solution[0], sw * sh * 3 * sizeof(double)); + iter++; + } while( err < 0.00001 && iter < 100); + } + + // Finaly multiply + deviceIt = device->createHLineIterator(x, y, sw, false ); + srcDevIt = m_srcdev->createHLineIterator(0, 0, sw, true ); + matrixIt = &matrix[0]; + for(int j = 0; j < sh; j++) + { + for(int i= 0; !srcDevIt.isDone(); i++) + { + deviceCs->toLabA16(deviceIt.rawData(), (TQ_UINT8*)dataDevice, 1); + deviceCs->toLabA16(srcDevIt.rawData(), (TQ_UINT8*)dataSrcDev, 1); + // Multiplication + for( int k = 0; k < 3; k++) + { + dataSrcDev[k] = (int)CLAMP( matrixIt[k] * TQMAX( dataSrcDev[k], 1), 0, 65535 ); + } + deviceCs->fromLabA16((TQ_UINT8*)dataSrcDev, srcDevIt.rawData(), 1); + ++deviceIt; + ++srcDevIt; + matrixIt +=3; + } + deviceIt.nextRow(); + srcDevIt.nextRow(); + } + } + + + // Add the dab as selection to the srcdev +// KisPainter copySelection(srcdev->selection().data()); +// copySelection.bitBlt(0, 0, COMPOSITE_OVER, dab, 0, 0, sw, sh); +// copySelection.end(); + + // copy the srcdev onto a new device, after applying the dab selection + copyPainter.begin(m_target); + + copyPainter.bltMask(0, 0, COMPOSITE_OVER, m_srcdev, dab, + OPACITY_OPAQUE, 0, 0, sw, sh); + copyPainter.end(); + + TQRect dabRect = TQRect(0, 0, brush->tqmaskWidth(info), brush->tqmaskHeight(info)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + sw = dstRect.width(); + sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), m_target, + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), m_target, m_painter->opacity(), sx, sy, sw, sh); + } + + + m_painter->addDirtyRect(dstRect); +} diff --git a/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.h b/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.h new file mode 100644 index 00000000..965e0dc9 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_duplicateop.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_DUPLICATEOP_H_ +#define KIS_DUPLICATEOP_H_ + +#include "kis_paintop.h" + +class KisPoint; +class KisPainter; + +class KisDuplicateOpFactory : public KisPaintOpFactory { + +public: + KisDuplicateOpFactory() {} + virtual ~KisDuplicateOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("duplicate", i18n("Duplicate")); } + virtual bool userVisible(KisColorSpace *) { return false; } + +}; + +class KisDuplicateOp : public KisPaintOp { + + typedef KisPaintOp super; + + + public: + + KisDuplicateOp(KisPainter * painter); + virtual ~KisDuplicateOp(); + + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + private: + double minimizeEnergy(const double* m, double* sol, int w, int h); + private: + KisPaintDeviceSP m_target, m_srcdev; + +}; + +#endif // KIS_DUPLICATEOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_eraseop.cc b/chalk/plugins/paintops/defaultpaintops/kis_eraseop.cc new file mode 100644 index 00000000..13045139 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_eraseop.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_layer.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_iterators_pixel.h" +#include "kis_colorspace.h" +#include "kis_selection.h" +#include "kis_eraseop.h" + +KisPaintOp * KisEraseOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisEraseOp(painter); + Q_CHECK_PTR(op); + return op; +} + + +KisEraseOp::KisEraseOp(KisPainter * painter) + : super(painter) +{ +} + +KisEraseOp::~KisEraseOp() +{ +} + +void KisEraseOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ +// Erasing is traditionally in paint applications one of two things: +// either it is painting in the 'background' color, or it is replacing +// all pixels with transparent (black?) pixels. +// +// That's what this paint op does for now; however, anyone who has +// ever worked with paper and soft pencils knows that a sharp piece of +// eraser rubber is a pretty useful too for making sharp to fuzzy lines +// in the graphite layer, or equally useful: for smudging skin tones. +// +// A smudge tool for Chalk is in the making, but when working with +// a tablet, the eraser tip should be at least as functional as a rubber eraser. +// That means that only after repeated or forceful application should all the +// 'paint' or 'graphite' be removed from the surface -- a kind of pressure +// sensitive, incremental smudge. +// +// And there should be an option to not have the eraser work on certain +// kinds of material. Layers are just a hack for this; putting your ink work +// in one layer and your pencil in another is not the same as really working +// with the combination. + + if (!m_painter) return; + + KisPaintDeviceSP device = m_painter->device(); + if (!device) return; + + KisBrush *brush = m_painter->brush(); + if (! brush->canPaintFor(info) ) + return; + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + TQ_INT32 destX; + double xFraction; + TQ_INT32 destY; + double yFraction; + + splitCoordinate(pt.x(), &destX, &xFraction); + splitCoordinate(pt.y(), &destY, &yFraction); + + KisAlphaMaskSP tqmask = brush->tqmask(info, xFraction, yFraction); + + KisPaintDeviceSP dab = new KisPaintDevice(device->colorSpace(), "erase op dab"); + Q_CHECK_PTR(dab); + + TQ_INT32 tqmaskWidth = tqmask->width(); + TQ_INT32 tqmaskHeight = tqmask->height(); + + TQRect dstRect; + + KisRectIteratorPixel it = dab->createRectIterator(0, 0, tqmaskWidth, tqmaskHeight, true); + KisColorSpace* cs = dab->colorSpace(); + while (!it.isDone()) { + cs->setAlpha(it.rawData(), TQ_UINT8_MAX - tqmask->alphaAt(it.x(), it.y()), 1); + ++it; + } + + TQRect dabRect = TQRect(0, 0, tqmaskWidth, tqmaskHeight); + dstRect = TQRect(destX, destY, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - destX; + TQ_INT32 sy = dstRect.y() - destY; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), COMPOSITE_ERASE, dab.data(), + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), COMPOSITE_ERASE, dab.data(), m_painter->opacity(), sx, sy, sw, sh); + } + + m_painter->addDirtyRect(dstRect); +} + diff --git a/chalk/plugins/paintops/defaultpaintops/kis_eraseop.h b/chalk/plugins/paintops/defaultpaintops/kis_eraseop.h new file mode 100644 index 00000000..8c88a122 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_eraseop.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_ERASEOP_H_ +#define KIS_ERASEOP_H_ + +#include "kis_paintop.h" + +class KisPoint; +class KisPainter; + +class KisEraseOpFactory : public KisPaintOpFactory { + +public: + KisEraseOpFactory() {} + virtual ~KisEraseOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("eraser", i18n("Pixel Eraser")); } + virtual TQString pixmap() { return "eraser.png"; } +}; + + +class KisEraseOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisEraseOp(KisPainter * painter); + virtual ~KisEraseOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +}; + +#endif // KIS_ERASEOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_penop.cc b/chalk/plugins/paintops/defaultpaintops/kis_penop.cc new file mode 100644 index 00000000..0fcbca02 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_penop.cc @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "klocale.h" +#include "kis_layer.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_iterator.h" +#include "kis_selection.h" +#include "kis_iterators_pixel.h" + +#include "kis_penop.h" + + +KisPaintOp * KisPenOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisPenOp(painter); + Q_CHECK_PTR(op); + return op; +} + + +KisPenOp::KisPenOp(KisPainter * painter) + : super(painter) +{ +} + +KisPenOp::~KisPenOp() +{ +} + +void KisPenOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + if (!m_painter) return; + KisPaintDeviceSP device = m_painter->device(); + if (!device) return; + KisBrush * brush = m_painter->brush(); + if (!brush) return; + if (! brush->canPaintFor(info) ) + return; + + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + TQ_INT32 x = pt.roundX(); + TQ_INT32 y = pt.roundY(); + + KisPaintDeviceSP dab = 0; + if (brush->brushType() == IMAGE || + brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), info); + } + else { + // Compute tqmask without sub-pixel positioning + KisAlphaMaskSP tqmask = brush->tqmask(info); + dab = computeDab(tqmask); + } + + m_painter->setPressure(info.pressure); + TQRect dabRect = TQRect(0, 0, brush->tqmaskWidth(info), brush->tqmaskHeight(info)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + KisColorSpace * cs = dab->colorSpace(); + + // Set all alpha > opaque/2 to opaque, the rest to transparent. + // XXX: Using 4/10 as the 1x1 circle brush paints nothing with 0.5. + + KisRectIteratorPixel pixelIt = dab->createRectIterator(dabRect.x(), dabRect.y(), dabRect.width(), dabRect.height(), true); + + while (!pixelIt.isDone()) { + TQ_UINT8 alpha = cs->getAlpha(pixelIt.rawData()); + + if (alpha < (4 * OPACITY_OPAQUE) / 10) { + cs->setAlpha(pixelIt.rawData(), OPACITY_TRANSPARENT, 1); + } else { + cs->setAlpha(pixelIt.rawData(), OPACITY_OPAQUE, 1); + } + + ++pixelIt; + } + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), dab.data(), m_painter->opacity(), sx, sy, sw, sh); + } + + m_painter->addDirtyRect(dstRect); +} diff --git a/chalk/plugins/paintops/defaultpaintops/kis_penop.h b/chalk/plugins/paintops/defaultpaintops/kis_penop.h new file mode 100644 index 00000000..ac03a501 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_penop.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PENOP_H_ +#define KIS_PENOP_H_ + +#include +#include +#include "kis_paintop.h" + +class KisPoint; +class KisPainter; + +class KisPenOpFactory : public KisPaintOpFactory { + +public: + KisPenOpFactory() {} + virtual ~KisPenOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id(){ return KisID("pen", i18n("Pixel Pencil")); } + virtual TQString pixmap() { return "pencil.png"; } +}; + + +class KisPenOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisPenOp(KisPainter * painter); + virtual ~KisPenOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + +}; + +#endif // KIS_PENOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.cc b/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.cc new file mode 100644 index 00000000..2e50bebb --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.cc @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_smudgeop.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_colorspace_factory_registry.h" +#include "kcurve.h" +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_layer.h" +#include "kis_meta_registry.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" +#include "kis_input_device.h" +#include "kis_selection.h" + +#include "kis_dlgbrushcurvecontrol.h" + +KisPaintOp * KisSmudgeOpFactory::createOp(const KisPaintOpSettings *settings, KisPainter * painter) +{ + const KisSmudgeOpSettings *brushopSettings = dynamic_cast(settings); + Q_ASSERT(settings == 0 || brushopSettings != 0); + + KisPaintOp * op = new KisSmudgeOp(brushopSettings, painter); + Q_CHECK_PTR(op); + return op; +} + +KisSmudgeOpSettings::KisSmudgeOpSettings(TQWidget *tqparent, bool isTablet) + : super(tqparent) +{ + m_optionsWidget = new TQWidget(tqparent, "brush option widget"); + TQHBoxLayout * l = new TQHBoxLayout(m_optionsWidget); + l->setAutoAdd(true); + m_rateLabel = new TQLabel(i18n("Rate: "), m_optionsWidget); + m_rateSlider = new TQSlider(0,100,1, 50, Qt::Horizontal, m_optionsWidget); + if(isTablet) + { + m_pressureVariation = new TQLabel(i18n("Pressure variation: "), m_optionsWidget); + m_size = new TQCheckBox(i18n("Size"), m_optionsWidget); + m_size->setChecked(true); + m_opacity = new TQCheckBox(i18n("Opacity"), m_optionsWidget); + m_rate = new TQCheckBox(i18n("Rate"), m_optionsWidget); + m_curveControl = new WdgBrushCurveControl(m_optionsWidget); + // We abuse the darken curve here for rate + m_curveControl->tabWidget->setTabLabel(m_curveControl->tabWidget->page(2), i18n("Rate")); + m_curveControl->tabWidget->setTabToolTip(m_curveControl->tabWidget->page(2), + i18n("Modifies the rate. Bottom is 0% of the rate top is 100% of the original rate.")); + TQToolButton* moreButton = new TQToolButton(TQt::UpArrow, m_optionsWidget); + moreButton->tqsetSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); + moreButton->setMinimumSize(TQSize(24,24)); // Bah, I had hoped the above line would make this unneeded + connect(moreButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotCustomCurves())); + } else { + m_pressureVariation = 0; + m_size = 0; + m_rate = 0; + m_opacity = 0; + m_curveControl = 0; + } + + m_customRate = false; + m_customSize = false; + m_customOpacity = false; + // the curves will get filled in when the slot gets accepted +} + +void KisSmudgeOpSettings::slotCustomCurves() { + if (m_curveControl->exec() == TQDialog::Accepted) { + m_customRate = m_curveControl->darkenCheckbox->isChecked(); + m_customSize = m_curveControl->sizeCheckbox->isChecked(); + m_customOpacity = m_curveControl->opacityCheckbox->isChecked(); + + if (m_customRate) { + transferCurve(m_curveControl->darkenCurve, m_rateCurve); + } + if (m_customSize) { + transferCurve(m_curveControl->sizeCurve, m_sizeCurve); + } + if (m_customOpacity) { + transferCurve(m_curveControl->opacityCurve, m_opacityCurve); + } + } +} + +void KisSmudgeOpSettings::transferCurve(KCurve* curve, double* target) { + double value; + for (int i = 0; i < 256; i++) { + value = curve->getCurveValue( i / 255.0); + if (value < PRESSURE_MIN) + target[i] = PRESSURE_MIN; + else if (value > PRESSURE_MAX) + target[i] = PRESSURE_MAX; + else + target[i] = value; + } +} + +int KisSmudgeOpSettings::rate() const +{ + return m_rateSlider->value(); +} + +bool KisSmudgeOpSettings::varyRate() const +{ + return m_rate ? m_rate->isChecked() : false; +} + +bool KisSmudgeOpSettings::varySize() const +{ + return m_size ? m_size->isChecked() : true; +} + +bool KisSmudgeOpSettings::varyOpacity() const +{ + return m_opacity ? m_opacity->isChecked() : false; +} + +KisPaintOpSettings* KisSmudgeOpFactory::settings(TQWidget * tqparent, const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::mouse()) { + // No options for mouse, only tablet devices + return new KisSmudgeOpSettings(tqparent, false); + } else { + return new KisSmudgeOpSettings(tqparent, true); + } +} + +KisSmudgeOp::KisSmudgeOp(const KisSmudgeOpSettings *settings, KisPainter *painter) + : super(painter) + , m_firstRun(true) + , m_rate(50) + , m_pressureSize(true) + , m_pressureRate(false) + , m_pressureOpacity(false) + , m_customRate(false) + , m_customSize(false) + , m_customOpacity(false) + , m_target(0) + , m_srcdev(0) +{ + if (settings != 0) { + m_rate = settings->rate(); + m_pressureRate = settings->varyRate(); + m_pressureSize = settings->varySize(); + m_pressureOpacity = settings->varyOpacity(); + m_customRate = settings->customRate(); + m_customSize = settings->customSize(); + m_customOpacity = settings->customOpacity(); + if (m_customSize) { + memcpy(m_sizeCurve, settings->sizeCurve(), 256 * sizeof(double)); + } + if (m_customOpacity) { + memcpy(m_opacityCurve, settings->opacityCurve(), 256 * sizeof(double)); + } + if (m_customRate) { + memcpy(m_rateCurve, settings->rateCurve(), 256 * sizeof(double)); + } + } + KisPaintDeviceSP device = m_painter->device(); + m_srcdev = new KisPaintDevice(device->colorSpace(), "duplicate source dev"); + m_target = new KisPaintDevice(device->colorSpace(), "duplicate target dev"); +} + +KisSmudgeOp::~KisSmudgeOp() +{ +} + +void KisSmudgeOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + KisPaintInformation adjustedInfo(info); + if (!m_pressureSize) + adjustedInfo.pressure = PRESSURE_DEFAULT; + else if (m_customSize) + adjustedInfo.pressure = scaleToCurve(adjustedInfo.pressure, m_sizeCurve); + + // Painting should be implemented according to the following algorithm: + // retrieve brush + // if brush == tqmask + // retrieve tqmask + // else if brush == image + // retrieve image + // subsample (tqmask | image) for position -- pos should be double! + // apply filters to tqmask (colour | gradient | pattern | etc. + // composite filtered tqmask into temporary layer + // composite temporary layer into target layer + // @see: doc/brush.txt + + if (!m_painter->device()) return; + + KisBrush *brush = m_painter->brush(); + + Q_ASSERT(brush); + if (!brush) return; + if (! brush->canPaintFor(adjustedInfo) ) + return; + + KisPaintDeviceSP device = m_painter->device(); + + KisPoint hotSpot = brush->hotSpot(adjustedInfo); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisPaintDeviceSP dab = 0; + + TQ_UINT8 origOpacity = m_painter->opacity(); + + if (m_pressureOpacity) { + if (!m_customOpacity) + m_painter->setOpacity((TQ_INT8)(origOpacity * info.pressure)); + else + m_painter->setOpacity((TQ_INT8)(origOpacity * scaleToCurve(info.pressure, m_opacityCurve))); + } + + if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) { + dab = brush->image(device->colorSpace(), adjustedInfo, xFraction, yFraction); + dab->convertTo(KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + else { + KisAlphaMaskSP tqmask = brush->tqmask(adjustedInfo, xFraction, yFraction); + dab = computeDab(tqmask, KisMetaRegistry::instance()->csRegistry()->getAlpha8()); + } + + + m_painter->setPressure(adjustedInfo.pressure); + + TQRect dabRect = TQRect(0, 0, brush->tqmaskWidth(adjustedInfo), + brush->tqmaskHeight(adjustedInfo)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + TQ_INT32 sw = dab->extent().width(); + TQ_INT32 sh = dab->extent().height(); + + KisPainter copyPainter(m_srcdev); + int opacity = OPACITY_OPAQUE; + if(!m_firstRun) + { + opacity = rate(); + if (m_pressureRate) { + if (m_customRate) { + opacity = CLAMP((TQ_UINT8)(double(opacity) * scaleToCurve(info.pressure, m_rateCurve)), OPACITY_TRANSPARENT, OPACITY_OPAQUE); + } else { + opacity = CLAMP((TQ_UINT8)(double(opacity) * info.pressure), OPACITY_TRANSPARENT, OPACITY_OPAQUE); + } + } + opacity = OPACITY_OPAQUE - opacity; + } else { + m_firstRun = false; + } + copyPainter.bitBlt(0, 0, COMPOSITE_OVER, device, opacity, pt.x(), pt.y(), sw, sh); + copyPainter.end(); + + m_target = new KisPaintDevice(device->colorSpace(), "duplicate target dev"); + + copyPainter.begin(m_target); + + copyPainter.bltMask(0, 0, COMPOSITE_OVER, m_srcdev, dab, + OPACITY_OPAQUE, 0, 0, sw, sh); + copyPainter.end(); + + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + sw = dstRect.width(); + sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), m_target, + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), m_target, m_painter->opacity(), sx, sy, sw, sh); + } + + m_painter->addDirtyRect(dstRect); + + m_painter->setOpacity(origOpacity); + +} + +#include "kis_smudgeop.moc" diff --git a/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.h b/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.h new file mode 100644 index 00000000..d9c8872d --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/kis_smudgeop.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SMUDGEOP_H_ +#define KIS_SMUDGEOP_H_ + +#include "kis_paintop.h" +#include + +class TQWidget; +class TQCheckBox; +class TQLabel; +class TQSlider; +class KisPoint; +class KisPainter; +class KCurve; +class WdgBrushCurveControl; + +class KisSmudgeOpFactory : public KisPaintOpFactory { + +public: + KisSmudgeOpFactory() {} + virtual ~KisSmudgeOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("smudge", i18n("Smudge Brush")); } + virtual TQString pixmap() { return "paintbrush.png"; } + virtual KisPaintOpSettings *settings(TQWidget * tqparent, const KisInputDevice& inputDevice); +}; + +class KisSmudgeOpSettings : public TQObject, public KisPaintOpSettings { + Q_OBJECT + TQ_OBJECT + typedef KisPaintOpSettings super; +public: + KisSmudgeOpSettings(TQWidget *tqparent, bool isTablet); + + int rate() const; + bool varyRate() const; + bool varySize() const; + bool varyOpacity() const; + + bool customRate() const { return m_customRate; } + bool customSize() const { return m_customSize; } + bool customOpacity() const { return m_customOpacity; } + const double* rateCurve() const { return m_rateCurve; } + const double* sizeCurve() const { return m_sizeCurve; } + const double* opacityCurve() const { return m_opacityCurve; } + + virtual TQWidget *widget() const { return m_optionsWidget; } +private slots: + void slotCustomCurves(); +private: + void transferCurve(KCurve* curve, double* target); + TQWidget *m_optionsWidget; + TQLabel* m_rateLabel; + TQSlider* m_rateSlider; + TQLabel * m_pressureVariation; + TQCheckBox * m_rate; + TQCheckBox * m_size; + TQCheckBox * m_opacity; + WdgBrushCurveControl* m_curveControl; + + bool m_customSize; + bool m_customRate; + bool m_customOpacity; + double m_rateCurve[256]; + double m_sizeCurve[256]; + double m_opacityCurve[256]; +}; + +class KisSmudgeOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisSmudgeOp(const KisSmudgeOpSettings *settings, KisPainter * painter); + virtual ~KisSmudgeOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); + + int rate() { return (m_rate * 255) / 100; } +private: + KisPaintDeviceSP m_target, m_srcdev; + inline double scaleToCurve(double pressure, double* curve) const { + int offset = CLAMP(int(255.0 * pressure), 0, 255); + return curve[offset]; + } + bool m_firstRun; + int m_rate; + bool m_pressureRate; + bool m_pressureSize; + bool m_pressureOpacity; + bool m_customRate; + bool m_customSize; + bool m_customOpacity; + double m_rateCurve[256]; + double m_sizeCurve[256]; + double m_opacityCurve[256]; +}; + +#endif // KIS_BRUSHOP_H_ diff --git a/chalk/plugins/paintops/defaultpaintops/paintbrush.png b/chalk/plugins/paintops/defaultpaintops/paintbrush.png new file mode 100644 index 00000000..accc0411 Binary files /dev/null and b/chalk/plugins/paintops/defaultpaintops/paintbrush.png differ diff --git a/chalk/plugins/paintops/defaultpaintops/pencil.png b/chalk/plugins/paintops/defaultpaintops/pencil.png new file mode 100644 index 00000000..08a2f4cf Binary files /dev/null and b/chalk/plugins/paintops/defaultpaintops/pencil.png differ diff --git a/chalk/plugins/paintops/defaultpaintops/src/README b/chalk/plugins/paintops/defaultpaintops/src/README new file mode 100644 index 00000000..769ced65 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/src/README @@ -0,0 +1,2 @@ +These svg images are the basis of the paintop pixmaps; they were taken from +the OpenClipArt repository and are in the public domain. diff --git a/chalk/plugins/paintops/defaultpaintops/src/pencil_01.svg b/chalk/plugins/paintops/defaultpaintops/src/pencil_01.svg new file mode 100644 index 00000000..40319104 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/src/pencil_01.svg @@ -0,0 +1,637 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pencil + + + + + office + + + + + Karol Szczerba + + + + + Karol Szczerba + + + + + Karol Szczerba + + + + image/svg+xml + + + + + en + + + + + + + + + diff --git a/chalk/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg b/chalk/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg new file mode 100644 index 00000000..4b29bb9a --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/src/pencil_jonathan_dietrich_01.svg @@ -0,0 +1,434 @@ + + + + + + + + Pencil + HASH(0x885a0cc) + + + pencil + + + + + Jonathan Dietrich + + + + + Jonathan Dietrich + + + + + Jonathan Dietrich + + + HASH(0x846b07c) + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg b/chalk/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg new file mode 100644 index 00000000..b79fcd57 --- /dev/null +++ b/chalk/plugins/paintops/defaultpaintops/src/pennello_mauro_olivo_01.svg @@ -0,0 +1,616 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pennello + Created with The Inkscape + + + + office + + + + + Mauro Olivo + + + + + Mauro Olivo + + + + + Mauro Olivo + + + + image/svg+xml + + + + + en + + + + + + + + + diff --git a/chalk/plugins/tools/Makefile.am b/chalk/plugins/tools/Makefile.am new file mode 100644 index 00000000..eb40c4e9 --- /dev/null +++ b/chalk/plugins/tools/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = defaulttools selectiontools tool_crop tool_curves tool_filter \ + tool_polygon tool_polyline tool_selectsimilar tool_star tool_transform \ + tool_perspectivegrid tool_perspectivetransform diff --git a/chalk/plugins/tools/defaulttools/Makefile.am b/chalk/plugins/tools/defaulttools/Makefile.am new file mode 100644 index 00000000..b8998604 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/Makefile.am @@ -0,0 +1,83 @@ +kde_services_DATA = chalkdefaulttools.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkdefaulttools_la_SOURCES = \ + default_tools.cc \ + kis_tool_colorpicker.cc \ + kis_tool_move.cc \ + kis_tool_zoom.cc \ + kis_tool_brush.cc \ + kis_tool_line.cc \ + kis_tool_duplicate.cc \ + kis_tool_fill.cc \ + kis_tool_rectangle.cc \ + kis_tool_ellipse.cc \ + kis_tool_pan.cc \ + kis_tool_text.cc \ + kis_tool_gradient.cc \ + wdgcolorpicker.ui + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalkdefaulttools.la + +noinst_HEADERS = \ + default_tools.h \ + kis_tool_fill.h \ + kis_tool_brush.h \ + kis_tool_gradient.h \ + kis_tool_rectangle.h \ + kis_tool_colorpicker.h \ + kis_tool_line.h \ + kis_tool_text.h \ + kis_tool_duplicate.h \ + kis_tool_move.h \ + kis_tool_zoom.h \ + kis_tool_ellipse.h \ + kis_tool_pan.h + + +chalkdefaulttools_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkdefaulttools_la_LIBADD = ../../../libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +chalkdefaulttools_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_rectangle_cursor.png \ + tool_ellipse_cursor.png \ + tool_line_cursor.png \ + tool_freehand_cursor.png \ + tool_duplicate_cursor.png \ + tool_fill_cursor.png \ + tool_color_fill.png \ + tool_text_cursor.png \ + tool_gradient_cursor.png \ + tool_gradient.png \ + tool_line.png \ + tool_rectangle.png \ + tool_ellipse.png \ + tool_pan.png \ + tool_freehand.png \ + tool_text.png \ + openhand_cursor.xpm \ + closedhand_cursor.xpm \ + tool_zoom_plus_cursor.png \ + tool_zoom_minus_cursor.png \ + tool_move.png \ + tool_colorpicker.png \ + tool_duplicate.png \ + tool_zoom.png + + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/defaulttools/chalkdefaulttools.desktop b/chalk/plugins/tools/defaulttools/chalkdefaulttools.desktop new file mode 100644 index 00000000..6472d637 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/chalkdefaulttools.desktop @@ -0,0 +1,56 @@ +[Desktop Entry] +Name=Default Tools +Name[bg]=Инструменти по подразбиране +Name[br]=Ostilhoù dre ziouer +Name[ca]=Eines per defecte +Name[cy]=Offer Rhagosodol +Name[da]=Standardværktøjer +Name[de]=Standardwerkzeuge +Name[el]=Προκαθορισμένα εργαλεία +Name[eo]=Aprioraj Iloj +Name[es]=Herramientas predefinidas +Name[et]=Vaiketööriistad +Name[eu]=Tresna lehenetsiak +Name[fa]=ابزارهای پیش‌فرض +Name[fi]=Oletustyökalut +Name[fr]=Outils par défaut +Name[fy]=Standert ark +Name[ga]=Uirlisí Réamhshocraithe +Name[gl]=Ferramentas Predefinidas +Name[he]=כלים המוגדרים כברירת מחדל +Name[hi]=डिफ़ॉल्ट औज़ार +Name[hr]=Zadani alati +Name[hu]=Alapértelmezett eszközök +Name[is]=Sjálfgefin tól +Name[it]=Strumenti predefiniti +Name[ja]=標準ツール +Name[km]=ឧបករណ៍​លំនាំដើម +Name[lt]=Numatyti įrankiai +Name[lv]=Noklusējuma rīks +Name[ms]=Alat Piawai +Name[nb]=Standardverktøy +Name[nds]=Standardwarktüüch +Name[ne]=पूर्वनिर्धारित उपकरणहरू +Name[nl]=Standaardgereedschappen +Name[nn]=Standardverktøy +Name[pl]=Domyślne narzędzia +Name[pt]=Ferramentas Predefinidas +Name[pt_BR]=Ferramentas Padrão +Name[ru]=Стандартный инструментарий +Name[se]=Standárdreaiddut +Name[sk]=Štandardné nástroje +Name[sl]=Privzeta orodja +Name[sr]=Подразумевани алати +Name[sr@Latn]=Podrazumevani alati +Name[sv]=Standardverktyg +Name[ta]=முன்னிருப்பு கருவிகள் +Name[tr]=Öntanımlı Araçlar +Name[uk]=Типові інструменти +Name[uz]=Andoza vositalar +Name[uz@cyrillic]=Андоза воситалар +Name[zh_CN]=默认工具 +Name[zh_TW]=預設工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalkdefaulttools +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/defaulttools/closedhand_cursor.xpm b/chalk/plugins/tools/defaulttools/closedhand_cursor.xpm new file mode 100644 index 00000000..b3d98f85 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/closedhand_cursor.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char *closedhand_cursor[]={ +"22 22 3 1", +". c None", +"# c #000000", +"a c #ffffff", +"......................", +"......................", +"......................", +"......................", +".......##.##.##.......", +"......#aa#aa#aa###....", +"......#aa#aa#aa#aa#...", +"......#aa#aa#aa#aa#...", +".....##aaaaaaaa#aa#...", +"....#a#aaaaaaaaaaa#...", +"....#a#aaaaaaaaaaa#...", +"....#a#aaaaaaaaaaa#...", +"....#aaaaaaaaaaaaa#...", +".....#aaaaaaaaaaaa#...", +".....#aaaaaaaaaaa#....", +"......#aaaaaaaaaa#....", +"......#aaaaaaaaaa#....", +".......#aaaaaaaa#.....", +".......#aaaaaaaa#.....", +".......##########.....", +"......................", +"......................"}; diff --git a/chalk/plugins/tools/defaulttools/default_tools.cc b/chalk/plugins/tools/defaulttools/default_tools.cc new file mode 100644 index 00000000..61d06e98 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/default_tools.cc @@ -0,0 +1,88 @@ +/* + * default_tools.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "default_tools.h" + +#include "kis_tool_fill.h" +#include "kis_tool_brush.h" +#include "kis_tool_freehand.h" +#include "kis_tool_gradient.h" +#include "kis_tool_rectangle.h" +#include "kis_tool_colorpicker.h" +#include "kis_tool_line.h" +#include "kis_tool_text.h" +#include "kis_tool_duplicate.h" +#include "kis_tool_move.h" +#include "kis_tool_zoom.h" +#include "kis_tool_ellipse.h" +#include "kis_tool_pan.h" + + +typedef KGenericFactory DefaultToolsFactory; +K_EXPORT_COMPONENT_FACTORY( chalkdefaulttools, DefaultToolsFactory( "chalk" ) ) + + +DefaultTools::DefaultTools(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(DefaultToolsFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + + r->add(new KisToolFillFactory()); + r->add(new KisToolGradientFactory()); + r->add(new KisToolBrushFactory()); + r->add(new KisToolColorPickerFactory()); + r->add(new KisToolLineFactory()); + r->add(new KisToolTextFactory()); + r->add(new KisToolDuplicateFactory()); + r->add(new KisToolMoveFactory()); + r->add(new KisToolZoomFactory()); + r->add(new KisToolEllipseFactory()); + r->add(new KisToolRectangleFactory()); + r->add(new KisToolPanFactory()); + + } +} + +DefaultTools::~DefaultTools() +{ +} + +#include "default_tools.moc" diff --git a/chalk/plugins/tools/defaulttools/default_tools.h b/chalk/plugins/tools/defaulttools/default_tools.h new file mode 100644 index 00000000..c50a9147 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/default_tools.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DEFAULT_TOOLS_H_ +#define DEFAULT_TOOLS_H_ + +#include + +/** + * A module wrapper around Chalk's default tools. + * Despite the fact that new tools are created for every new view, + * it is not possible to make tools standard parts of the type of the + * imagesize plugin, because we need to create a new set of tools for every + * pointer device (mouse, stylus, eraser, puck, etc.). So this plugin is + * a module which is loaded once into Chalk. For every tool there is a factory + * class that is registered with the tool registry, and that is used to create + * new instances of the tools. + */ +class DefaultTools : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + DefaultTools(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~DefaultTools(); + +}; + +#endif // DEFAULT_TOOLS_H_ diff --git a/chalk/plugins/tools/defaulttools/kis_tool_brush.cc b/chalk/plugins/tools/defaulttools/kis_tool_brush.cc new file mode 100644 index 00000000..373e0a07 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_brush.cc @@ -0,0 +1,167 @@ +/* + * kis_tool_brush.cc - part of Chalk + * + * Copyright (c) 2003-2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_config.h" +#include "kis_brush.h" +#include "kis_paintop.h" +#include "kis_paintop_registry.h" +#include "kis_cmb_composite.h" +#include "kis_cursor.h" +#include "kis_painter.h" +#include "kis_tool_brush.h" +#include "kis_canvas_subject.h" +#include "kis_boundary.h" +#include "kis_move_event.h" +#include "kis_canvas.h" +#include "kis_layer.h" + +KisToolBrush::KisToolBrush() + : super(i18n("Brush")) +{ + setName("tool_brush"); + setCursor(KisCursor::load("tool_freehand_cursor.png", 5, 5)); + m_rate = 100; // Conveniently hardcoded for now + m_timer = new TQTimer(this); + Q_CHECK_PTR(m_timer); + + connect(m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(timeoutPaint())); + +} + +KisToolBrush::~KisToolBrush() +{ + delete m_timer; + m_timer = 0; +} + +void KisToolBrush::timeoutPaint() +{ + if (currentImage() && painter()) { + painter()->paintAt(m_prevPos, m_prevPressure, m_prevXTilt, m_prevYTilt); + currentImage()->activeLayer()->setDirty(painter()->dirtyRect()); + } +} + + +void KisToolBrush::update(KisCanvasSubject *subject) +{ + super::update(subject); +} + +void KisToolBrush::initPaint(KisEvent *e) +{ + super::initPaint(e); + + if (!m_painter) { + kdWarning() << "Didn't create a painter! Something is wrong!\n"; + return; + } + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), m_painter); + if (!op) return; + + m_subject->canvasController()->kiscanvas()->update(); // remove the outline + + painter()->setPaintOp(op); // And now the painter owns the op and will destroy it. + + if (op->incremental()) { + m_timer->start( m_rate ); + } +} + + +void KisToolBrush::endPaint() +{ + m_timer->stop(); + super::endPaint(); +} + + +void KisToolBrush::setup(KActionCollection *collection) +{ + + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Brush"), + "tool_freehand", TQt::Key_B, this, + TQT_SLOT(activate()), collection, + name()); + m_action->setToolTip(i18n("Draw freehand")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolBrush::move(KisMoveEvent *e) { + KisToolFreehand::move(e); + KisConfig cfg; + if (m_mode != PAINT && cfg.cursorStyle() == CURSOR_STYLE_OUTLINE) + paintOutline(e->pos()); +} + +void KisToolBrush::leave(TQEvent */*e*/) { + m_subject->canvasController()->kiscanvas()->update(); // remove the outline +} + + +void KisToolBrush::slotSetPaintingMode( int mode ) +{ + if (mode == TQButton::On) { + // Direct painting + m_paintIncremental = true; + } + else { + m_paintIncremental = false; + } +} + + +TQWidget* KisToolBrush::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + m_chkDirect = new TQCheckBox(i18n("Paint direct"), widget, "chkDirect"); + m_chkDirect->setChecked(true); + connect(m_chkDirect, TQT_SIGNAL(stateChanged(int)), this, TQT_SLOT(slotSetPaintingMode(int))); + + m_optionLayout = new TQGridLayout(widget, 3, 2, 0, 6); + Q_CHECK_PTR(m_optionLayout); + + super::addOptionWidgetLayout(m_optionLayout); + m_optionLayout->addWidget(m_chkDirect, 0, 0); + + return widget; +} + +#include "kis_tool_brush.moc" + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_brush.h b/chalk/plugins/tools/defaulttools/kis_tool_brush.h new file mode 100644 index 00000000..a23e8d12 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_brush.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2003-2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_BRUSH_H_ +#define KIS_TOOL_BRUSH_H_ + + +#include "kis_tool_freehand.h" + +#include "kis_tool_factory.h" +#include "koffice_export.h" + +class TQTimer; +class KisPoint; +class TQHBoxLayout; +class TQPainter; +class TQRect; +class TQCheckBox; +class TQGridLayout; + +class KRITACORE_EXPORT KisToolBrush : public KisToolFreehand { + Q_OBJECT + TQ_OBJECT + typedef KisToolFreehand super; + +public: + KisToolBrush(); + virtual ~KisToolBrush(); + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 0; } + TQWidget* createOptionWidget(TQWidget* tqparent); + +protected: + + virtual void initPaint(KisEvent *e); + virtual void endPaint(); + virtual void move(KisMoveEvent *e); + virtual void leave(TQEvent *e); + +private slots: + + void timeoutPaint(); + void slotSetPaintingMode( int mode ); + +private: + + TQ_INT32 m_rate; + TQTimer * m_timer; + TQGridLayout* m_optionLayout; + TQCheckBox * m_chkDirect; +}; + +class KisToolBrushFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolBrushFactory() : super() {}; + virtual ~KisToolBrushFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolBrush(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("brush", i18n("Brush Tool")); } +}; + + +#endif // KIS_TOOL_BRUSH_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.cc b/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.cc new file mode 100644 index 00000000..32dbcf9d --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.cc @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_layer.h" +#include "kis_cursor.h" +#include "kis_canvas_subject.h" +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_tool_colorpicker.h" +#include "kis_tool_colorpicker.moc" +#include "kis_button_press_event.h" +#include "kis_canvas_subject.h" +#include "kis_iterators_pixel.h" +#include "kis_color.h" +#include "kis_resourceserver.h" +#include "kis_palette.h" +#include "wdgcolorpicker.h" + +namespace { + // The location of the sample all visible layers in the combobox + const int SAMPLE_MERGED = 0; +} + +KisToolColorPicker::KisToolColorPicker() + : super (i18n("Color Picker")) +{ + setName("tool_colorpicker"); + setCursor(KisCursor::pickerCursor()); + m_optionsWidget = 0; + m_subject = 0; + m_radius = 1; + m_addPalette = false; + m_updateColor = true; + m_normaliseValues = false; + m_pickedColor = KisColor(); +} + +KisToolColorPicker::~KisToolColorPicker() +{ +} + +void KisToolColorPicker::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolColorPicker::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject) { + if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) + return; + + KisImageSP img; + + if (!m_subject || !(img = m_subject->currentImg())) + return; + + KisPaintDeviceSP dev = img->activeDevice(); + + if (!dev) return; + + bool sampleMerged = m_optionsWidget->cmbSources->currentItem() == SAMPLE_MERGED; + if (!sampleMerged) { + if (!img->activeLayer()) + { + KMessageBox::information(0, i18n("Cannot pick a color as no layer is active.")); + return; + } + if (!img->activeLayer()-> visible()) { + KMessageBox::information(0, i18n("Cannot pick a color as the active layer is not visible.")); + return; + } + } + + TQPoint pos = TQPoint(e->pos().floorX(), e->pos().floorY()); + + if (!img->bounds().tqcontains(pos)) { + return; + } + + if (sampleMerged) { + dev = img->mergedImage(); + } + + if (m_radius == 1) { + m_pickedColor = dev->colorAt (pos.x(), pos.y()); + } else { + // radius 2 ==> 9 pixels, 3 => 9 pixels, etc + static int counts[] = { 0, 1, 9, 25, 45, 69, 109, 145, 193, 249 }; + + KisColorSpace* cs = dev->colorSpace(); + int pixelSize = cs->pixelSize(); + + TQ_UINT8* data = new TQ_UINT8[pixelSize]; + TQ_UINT8** pixels = new TQ_UINT8*[counts[m_radius]]; + TQ_UINT8* weights = new TQ_UINT8[counts[m_radius]]; + + int i = 0; + // dummy init + KisHLineIteratorPixel iter = dev->createHLineIterator(0, 0, 1, false);; + for (int y = - m_radius; y <= m_radius; y++) { + for (int x = - m_radius; x <= m_radius; x++) { + if (x*x + y*y < m_radius * m_radius) { + iter = dev->createHLineIterator(pos.x() + x, pos.y() + y, 1, false); + + pixels[i] = new TQ_UINT8[pixelSize]; + memcpy(pixels[i], iter.rawData(), pixelSize); + + if (x == 0 && y == 0) { + // Because the sum of the weights must be 255, + // we cheat a bit, and weigh the center pixel differently in order + // to sum to 255 in total + // It's -(counts -1), because we'll add the center one implicitly + // through that calculation + weights[i] = 255 - (counts[m_radius]-1) * (255 / counts[m_radius]); + } else { + weights[i] = 255 / counts[m_radius]; + } + i++; + } + } + } + // Weird, I can't do that directly :/ + const TQ_UINT8** cpixels = const_cast(pixels); + cs->mixColors(cpixels, weights, counts[m_radius], data); + m_pickedColor = KisColor(data, cs); + + for (i = 0; i < counts[m_radius]; i++) + delete[] pixels[i]; + delete[] pixels; + delete[] data; + } + + displayPickedColor(); + + if (m_updateColor) { + if (e->button() == Qt::LeftButton) + m_subject->setFGColor(m_pickedColor); + else + m_subject->setBGColor(m_pickedColor); + } + + if (m_addPalette) { + // Convert to RGB to add to palette, we ought to have our own format :( + KisPaletteEntry ent; + ent.color = m_pickedColor.toTQColor(); + // We don't ask for a name, too intrusive here + + KisPalette* palette = m_palettes.at(m_optionsWidget-> cmbPalette->currentItem()); + palette->add(ent); + + if (!palette->save()) { + KMessageBox::error(0, i18n("Cannot write to palette file %1. Maybe it is read-only.").tqarg(palette->filename()), i18n("Palette")); + } + } + } +} + +void KisToolColorPicker::displayPickedColor() +{ + if (m_pickedColor.data() && m_optionsWidget) { + + TQValueVector channels = m_pickedColor.colorSpace()->channels(); + m_optionsWidget->listViewChannels->clear(); + + for (int i = channels.count() - 1; i >= 0 ; --i) { + TQString channelValueText; + + if (m_normaliseValues) { + channelValueText = i18n("%1%").tqarg(m_pickedColor.colorSpace()->normalisedChannelValueText(m_pickedColor.data(), i)); + } else { + channelValueText = m_pickedColor.colorSpace()->channelValueText(m_pickedColor.data(), i); + } + + m_optionsWidget->listViewChannels->insertItem(new TQListViewItem(m_optionsWidget->listViewChannels, + channels[i]->name(), + channelValueText)); + } + } +} + +void KisToolColorPicker::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Color Picker"), "tool_colorpicker", TQt::Key_P, this, TQT_SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Color picker")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQWidget* KisToolColorPicker::createOptionWidget(TQWidget* tqparent) +{ + m_optionsWidget = new ColorPickerOptionsWidget(tqparent); + + m_optionsWidget->cbUpdateCurrentColour->setChecked(m_updateColor); + + m_optionsWidget->cmbSources->setCurrentItem(0); + + m_optionsWidget->cbNormaliseValues->setChecked(m_normaliseValues); + m_optionsWidget->cbPalette->setChecked(m_addPalette); + m_optionsWidget->radius->setValue(m_radius); + + m_optionsWidget->listViewChannels->setSorting(-1); + + connect(m_optionsWidget->cbUpdateCurrentColour, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetUpdateColor(bool))); + connect(m_optionsWidget->cbNormaliseValues, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetNormaliseValues(bool))); + connect(m_optionsWidget->cbPalette, TQT_SIGNAL(toggled(bool)), + TQT_SLOT(slotSetAddPalette(bool))); + connect(m_optionsWidget->radius, TQT_SIGNAL(valueChanged(int)), + TQT_SLOT(slotChangeRadius(int))); + + KisResourceServerBase* srv = KisResourceServerRegistry::instance()->get("PaletteServer"); + + if (!srv) { + return m_optionsWidget; + } + + TQValueList palettes = srv->resources(); + + for(uint i = 0; i < palettes.count(); i++) { + KisPalette* palette = dynamic_cast(*palettes.at(i)); + if (palette) { + m_optionsWidget->cmbPalette->insertItem(palette->name()); + m_palettes.append(palette); + } + } + + connect(srv, TQT_SIGNAL(resourceAdded(KisResource*)), this, TQT_SLOT(slotAddPalette(KisResource*))); + + return m_optionsWidget; +} + +TQWidget* KisToolColorPicker::optionWidget() +{ + return m_optionsWidget; +} + +void KisToolColorPicker::slotSetUpdateColor(bool state) +{ + m_updateColor = state; +} + + +void KisToolColorPicker::slotSetNormaliseValues(bool state) +{ + m_normaliseValues = state; + displayPickedColor(); +} + +void KisToolColorPicker::slotSetAddPalette(bool state) { + m_addPalette = state; +} + +void KisToolColorPicker::slotChangeRadius(int value) { + m_radius = value; +} + +void KisToolColorPicker::slotAddPalette(KisResource* resource) { + KisPalette* palette = dynamic_cast(resource); + if (palette) { + m_optionsWidget-> cmbPalette->insertItem(palette->name()); + m_palettes.append(palette); + } +} + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.h b/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.h new file mode 100644 index 00000000..ab59ef17 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_colorpicker.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_COLOR_PICKER_H_ +#define KIS_TOOL_COLOR_PICKER_H_ + +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" +#include "tqvaluevector.h" + +class ColorPickerOptionsWidget; +class KisResource; +class KisPalette; + +class KisToolColorPicker : public KisToolNonPaint { + + Q_OBJECT + TQ_OBJECT + typedef KisToolNonPaint super; + +public: + KisToolColorPicker(); + virtual ~KisToolColorPicker(); + +public: + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual void buttonPress(KisButtonPressEvent *e); + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual TQ_UINT32 priority() { return 3; } + +public slots: + void slotSetUpdateColor(bool); + void slotSetNormaliseValues(bool); + void slotSetAddPalette(bool); + void slotChangeRadius(int); + void slotAddPalette(KisResource* resource); + +private: + void displayPickedColor(); + + bool m_updateColor; + bool m_addPalette; + bool m_normaliseValues; + int m_radius; + KisColor m_pickedColor; + + ColorPickerOptionsWidget *m_optionsWidget; + KisCanvasSubject *m_subject; + TQValueVector m_palettes; +}; + +class KisToolColorPickerFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolColorPickerFactory() : super() {}; + virtual ~KisToolColorPickerFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolColorPicker(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("colorpicker", i18n("Color Picker")); } +}; + + +#endif // KIS_TOOL_COLOR_PICKER_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_duplicate.cc b/chalk/plugins/tools/defaulttools/kis_tool_duplicate.cc new file mode 100644 index 00000000..9619c6ae --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_duplicate.cc @@ -0,0 +1,255 @@ +/* + * kis_tool_duplicate.cc - part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_brush.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_tool_duplicate.h" +#include "kis_painter.h" +#include "kis_vec.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop.h" +#include "kis_paintop_registry.h" +#include "kis_canvas_subject.h" +#include "kis_perspective_grid.h" + +#include "kis_canvas_painter.h" +#include "kis_boundary_painter.h" + +KisToolDuplicate::KisToolDuplicate() + : super(i18n("Duplicate Brush")), m_isOffsetNotUptodate(true), m_position(TQPoint(-1,-1)) +{ + setName("tool_duplicate"); + m_subject = 0; + setCursor(KisCursor::load("tool_duplicate_cursor.png", 5, 5)); +} + +KisToolDuplicate::~KisToolDuplicate() +{ +} + +void KisToolDuplicate::activate() +{ + m_position = TQPoint(-1,-1); + super::activate(); + if( m_subject->currentImg()->perspectiveGrid()->countSubGrids() != 1 ) + { + m_perspectiveCorrection->setEnabled( false ); + m_perspectiveCorrection->setChecked( false ); + } else { + m_perspectiveCorrection->setEnabled( true ); + } +} + +void KisToolDuplicate::buttonPress(KisButtonPressEvent *e) +{ + if (e->state() == ShiftButton) { + m_position = e->pos(); + m_isOffsetNotUptodate = true; + } else { + if (m_position != TQPoint(-1, -1)) { + super::buttonPress(e); + } + } +} + + +void KisToolDuplicate::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Duplicate Brush"), + "tool_duplicate", TQt::Key_C, this, + TQT_SLOT(activate()), collection, + name()); + m_action->setToolTip(i18n("Duplicate parts of the image. Shift-click to select the point to duplicate from to begin.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolDuplicate::initPaint(KisEvent *e) +{ + if( m_position != TQPoint(-1,-1)) + { + if(m_isOffsetNotUptodate) + { + m_offset = e->pos() - m_position; + m_isOffsetNotUptodate = false; + } + m_paintIncremental = false; + super::initPaint(e); + painter()->setDuplicateOffset( m_offset ); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("duplicate", 0, painter()); + if (op && m_source) { + op->setSource(m_source); + painter()->setPaintOp(op); + } + m_positionStartPainting = e->pos(); + painter()->setDuplicateStart( e->pos() ); + } +} + +void KisToolDuplicate::move(KisMoveEvent *e) +{ + + // Paint the outline where we will (or are) copying from + if( m_position == TQPoint(-1,-1) ) + return; + + TQPoint srcPos; + if (m_mode == PAINT) { + // if we are in perspective correction mode, update the offset when moving + if(m_perspectiveCorrection->isChecked()) + { + double startM[3][3]; + double endM[3][3]; + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + startM[i][j] = 0.; + endM[i][j] = 0.; + } + startM[i][i] = 1.; + endM[i][i] = 1.; + } + + // First look for the grid corresponding to the start point + KisSubPerspectiveGrid* subGridStart = *m_subject->currentImg()->perspectiveGrid()->begin();//device->image()->perspectiveGrid()->gridAt(KisPoint(srcPoint.x() +hotSpot.x(),srcPoint.y() +hotSpot.y())); + TQRect r = TQRect(0,0, m_subject->currentImg()->width(), m_subject->currentImg()->height()); + + if(subGridStart) + { + double* b = KisPerspectiveMath::computeMatrixTransfoFromPerspective( r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + startM[i][j] = b[3*i+j]; + } + } + + } + // Second look for the grid corresponding to the end point + KisSubPerspectiveGrid* subGridEnd = *m_subject->currentImg()->perspectiveGrid()->begin();// device->image()->perspectiveGrid()->gridAt(pos); + if(subGridEnd) + { + double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + endM[i][j] = b[3*i+j]; + } + } + } + // Compute the translation in the perspective transformation space: + KisPoint translat; + { + KisPoint positionStartPaintingT = KisPerspectiveMath::matProd(endM, m_positionStartPainting); + KisPoint currentPositionT = KisPerspectiveMath::matProd(endM, e->pos() ); + KisPoint duplicateStartPoisitionT = KisPerspectiveMath::matProd(endM, m_positionStartPainting - m_offset); + KisPoint duplicateRealPosition = KisPerspectiveMath::matProd(startM, duplicateStartPoisitionT + (currentPositionT - positionStartPaintingT) ); + KisPoint p = e->pos() - duplicateRealPosition; + srcPos = p.floorTQPoint(); + } + + }else { + srcPos = painter()->duplicateOffset().floorTQPoint(); + } + } else { + if(m_isOffsetNotUptodate) + srcPos = e->pos().floorTQPoint() - m_position.floorTQPoint(); + else + srcPos = m_offset.floorTQPoint(); + } + + TQ_INT32 x; + TQ_INT32 y; + + // like KisPaintOp::splitCoordinate + x = (TQ_INT32)((e->x() < 0) ? e->x() - 1 : e->x()); + y = (TQ_INT32)((e->y() < 0) ? e->y() - 1 : e->y()); + srcPos = TQPoint(x - srcPos.x(), y - srcPos.y()); + + paintOutline(srcPos); + super::move(e); +} + +void KisToolDuplicate::paintAt(const KisPoint &pos, + const double pressure, + const double xtilt, + const double ytilt) +{ + if( m_position != TQPoint(-1,-1)) + { + if(m_isOffsetNotUptodate) + { + m_offset = pos - m_position; + m_isOffsetNotUptodate = false; + } + painter()->setDuplicateHealing( m_healing->isChecked() ); + painter()->setDuplicateHealingRadius( m_healingRadius->value() ); + painter()->setDuplicatePerspectiveCorrection( m_perspectiveCorrection->isChecked() ); + painter()->paintAt( pos, pressure, xtilt, ytilt); + } +} + +TQString KisToolDuplicate::quickHelp() const { + return i18n("To start, shift-click on the place you want to duplicate from. Then you can start painting. An indication of where you are copying from will be displayed while drawing and moving the mouse."); +} + +TQWidget* KisToolDuplicate::createOptionWidget(TQWidget* tqparent) +{ + TQWidget* widget = KisToolPaint::createOptionWidget(tqparent); + m_healing = new TQCheckBox(widget); + m_healing->setChecked( false); + addOptionWidgetOption(m_healing, new TQLabel(i18n("Healing"), widget )); + m_healingRadius = new KIntNumInput(widget); + + KisBrush *brush = m_subject->currentBrush(); + int healingradius = 20; + if( brush ) + { + healingradius = 2 * TQMAX(brush->width(),brush->height()); + } + + m_healingRadius->setValue( healingradius ); + addOptionWidgetOption(m_healingRadius, new TQLabel(i18n("Healing radius"), widget )); + m_perspectiveCorrection = new TQCheckBox(widget); + addOptionWidgetOption(m_perspectiveCorrection, new TQLabel(i18n("Correct the perspective"), widget )); + return widget; +} + +#include "kis_tool_duplicate.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_duplicate.h b/chalk/plugins/tools/defaulttools/kis_tool_duplicate.h new file mode 100644 index 00000000..8a298318 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_duplicate.h @@ -0,0 +1,92 @@ +/* + * kis_tool_duplicate.h - part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_DUPLICATE_H__ +#define __KIS_TOOL_DUPLICATE_H__ + +#include "kis_tool_freehand.h" +#include "kis_tool_factory.h" + +class KisEvent; +class KisButtonPressEvent; + +class TQCheckBox; +class KIntNumInput; + +class KisToolDuplicate : public KisToolFreehand { + + typedef KisToolFreehand super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolDuplicate(); + virtual ~KisToolDuplicate(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual TQ_UINT32 priority() { return 0; } + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + + virtual void paintAt(const KisPoint &pos, + const double pressure, + const double xTilt, + const double yTilt); + + virtual TQString quickHelp() const; + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + +protected slots: + virtual void activate(); + +protected: + virtual void initPaint(KisEvent *e); + + // Tool starting duplicate + KisPoint m_offset; // This member give the offset from the click position to the point where we take the duplication + bool m_isOffsetNotUptodate; // Tells if the offset is update + KisPoint m_position; // Give the position of the last alt-click + KisPoint m_positionStartPainting; + TQCheckBox* m_healing; + KIntNumInput* m_healingRadius; + TQCheckBox* m_perspectiveCorrection; +}; + + +class KisToolDuplicateFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolDuplicateFactory() : super() {}; + virtual ~KisToolDuplicateFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolDuplicate(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("duplicate", i18n("Duplicate Tool")); } +}; + + + +#endif //__KIS_TOOL_DUPLICATE_H__ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_ellipse.cc b/chalk/plugins/tools/defaulttools/kis_tool_ellipse.cc new file mode 100644 index 00000000..65593c23 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_ellipse.cc @@ -0,0 +1,186 @@ +/* + * kis_tool_ellipse.cc - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include "kis_painter.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_tool_ellipse.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_undo_adapter.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" + +KisToolEllipse::KisToolEllipse() + : super(i18n ("Ellipse")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_ellipse"); + setCursor(KisCursor::load("tool_ellipse_cursor.png", 6, 6)); +} + +KisToolEllipse::~KisToolEllipse() +{ +} + +void KisToolEllipse::update (KisCanvasSubject *subject) +{ + super::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg (); +} + +void KisToolEllipse::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage && event->button() == Qt::LeftButton) { + m_dragging = true; + m_dragStart = m_dragCenter = m_dragEnd = event->pos(); + draw(m_dragStart, m_dragEnd); + } +} + +void KisToolEllipse::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + // move (alt) or resize ellipse + if (event->state() & TQt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + KisPoint diag = event->pos() - (event->state() & TQt::ControlButton + ? m_dragCenter : m_dragStart); + // circle? + if (event->state() & TQt::ShiftButton) { + double size = TQMAX(fabs(diag.x()), fabs(diag.y())); + double w = diag.x() < 0 ? -size : size; + double h = diag.y() < 0 ? -size : size; + diag = KisPoint(w, h); + } + + // resize around center point? + if (event->state() & TQt::ControlButton) { + m_dragStart = m_dragCenter - diag; + m_dragEnd = m_dragCenter + diag; + } else { + m_dragEnd = m_dragStart + diag; + } + } + // draw new lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragCenter = KisPoint((m_dragStart.x() + m_dragEnd.x()) / 2, + (m_dragStart.y() + m_dragEnd.y()) / 2); + } +} + +void KisToolEllipse::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject || !m_currentImage) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragging = false; + + if (m_dragStart == m_dragEnd) + return; + + if (!m_currentImage) + return; + + if (!m_currentImage->activeDevice()) + return; + + KisPaintDeviceSP device = m_currentImage->activeDevice (); + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n ("Ellipse")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBackgroundColor(m_subject->bgColor()); + painter.setFillStyle(fillStyle()); + painter.setBrush(m_subject->currentBrush()); + painter.setPattern(m_subject->currentPattern()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + + painter.paintEllipse(m_dragStart, m_dragEnd, PRESSURE_DEFAULT/*event->pressure()*/, event->xTilt(), event->yTilt()); + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + KisUndoAdapter *adapter = m_currentImage->undoAdapter(); + if (adapter) { + adapter->addCommand(painter.endTransaction()); + } + } +} + +void KisToolEllipse::draw(const KisPoint& start, const KisPoint& end ) +{ + if (!m_subject || !m_currentImage) + return; + + KisCanvasController *controller = m_subject->canvasController (); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter p (canvas); + + p.setRasterOp (TQt::NotROP); + p.drawEllipse (TQRect (controller->windowToView (start).floorTQPoint(), controller->windowToView (end).floorTQPoint())); + p.end (); +} + +void KisToolEllipse::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F7)); + m_action = new KRadioAction(i18n("&Ellipse"), + "tool_ellipse", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Draw an ellipse")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_ellipse.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_ellipse.h b/chalk/plugins/tools/defaulttools/kis_tool_ellipse.h new file mode 100644 index 00000000..4f79fbd6 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_ellipse.h @@ -0,0 +1,91 @@ +/* + * kis_tool_ellipse.h - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_ELLIPSE_H__ +#define __KIS_TOOL_ELLIPSE_H__ + +#include "kis_tool_shape.h" + +class KisCanvas; +class KisPainter; +class KisRect; + +class KisToolEllipse : public KisToolShape { + + typedef KisToolShape super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolEllipse(); + virtual ~KisToolEllipse(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 3; } + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + +protected: + virtual void draw(const KisPoint& start, const KisPoint& stop); + +protected: + KisPoint m_dragCenter; + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; + KisImageSP m_currentImage; +}; + + +#include "kis_tool_factory.h" + +class KisToolEllipseFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolEllipseFactory() : super() {}; + virtual ~KisToolEllipseFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolEllipse(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("ellipse", i18n("Ellipse Tool")); } +}; + + +#endif //__KIS_TOOL_ELLIPSE_H__ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_fill.cc b/chalk/plugins/tools/defaulttools/kis_tool_fill.cc new file mode 100644 index 00000000..1e2b82c5 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_fill.cc @@ -0,0 +1,233 @@ +/* + * kis_tool_fill.cc - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "knuminput.h" + +#include "kis_layer.h" +#include "kis_cursor.h" +#include "kis_painter.h" +#include "kis_tool_brush.h" +#include "kis_cmb_composite.h" +#include "kis_tool_fill.h" +#include "kis_colorspace.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_pattern.h" +#include "kis_fill_painter.h" +#include "kis_progress_display_interface.h" +#include "kis_undo_adapter.h" +#include "kis_canvas_subject.h" +#include "kis_selection.h" + +KisToolFill::KisToolFill() + : super(i18n("Fill")), m_wasPressed(false) +{ + setName("tool_fill"); + m_subject = 0; + m_oldColor = 0; + m_threshold = 15; + m_usePattern = false; + m_unmerged = false; + m_fillOnlySelection = false; + + setCursor(KisCursor::load("tool_fill_cursor.png", 6, 6)); +} + +void KisToolFill::update(KisCanvasSubject *subject) +{ + m_subject = subject; + m_currentImage = subject->currentImg(); + + super::update(m_subject); +} + +KisToolFill::~KisToolFill() +{ +} + +bool KisToolFill::flood(int startX, int startY) +{ + KisPaintDeviceSP device = m_currentImage->activeDevice(); + if (!device) return false; + + if (m_fillOnlySelection) { + TQRect rc = device->selection()->selectedRect(); + KisPaintDeviceSP filled = new KisPaintDevice(device->colorSpace(), "filled"); + KisFillPainter painter(filled); + if (m_usePattern) + painter.fillRect(rc.x(), rc.y(), rc.width(), rc.height(), + m_subject->currentPattern()); + else + painter.fillRect(rc.x(), rc.y(), rc.width(), rc.height(), + m_subject->fgColor(), m_opacity); + painter.end(); + KisPainter painter2(device); + if (m_currentImage->undo()) painter2.beginTransaction(i18n("Fill")); + painter2.bltSelection(rc.x(), rc.y() , m_compositeOp, filled, m_opacity, + rc.x(), rc.y(), rc.width(), rc.height()); + + device->setDirty(filled->extent()); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter2.endTransaction()); + } + return true; + } + + KisFillPainter painter(device); + if (m_currentImage->undo()) painter.beginTransaction(i18n("Flood Fill")); + painter.setPaintColor(m_subject->fgColor()); + painter.setOpacity(m_opacity); + painter.setFillThreshold(m_threshold); + painter.setCompositeOp(m_compositeOp); + painter.setPattern(m_subject->currentPattern()); + painter.setSampleMerged(!m_unmerged); + painter.setCareForSelection(true); + + KisProgressDisplayInterface *progress = m_subject->progressDisplay(); + if (progress) { + progress->setSubject(&painter, true, true); + } + + if (m_usePattern) + painter.fillPattern(startX, startY); + else + painter.fillColor(startX, startY); + + device->setDirty(painter.dirtyRect()); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + + return true; +} + +void KisToolFill::buttonPress(KisButtonPressEvent *e) +{ + m_startPos = e->pos(); + m_wasPressed = true; +} + +void KisToolFill::buttonRelease(KisButtonReleaseEvent *e) +{ + if (!m_subject) return; + if (!m_currentImage || !m_currentImage->activeDevice()) return; + if (e->button() != Qt::LeftButton) return; + if(!m_wasPressed) return; + m_wasPressed = false; + int x, y; + x = m_startPos.floorX(); + y = m_startPos.floorY(); + if (!m_currentImage->bounds().tqcontains(x, y)) { + return; + } + flood(x, y); + notifyModified(); +} + +TQWidget* KisToolFill::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + + m_lbThreshold = new TQLabel(i18n("Threshold: "), widget); + m_slThreshold = new KIntNumInput( widget, "int_widget"); + m_slThreshold->setRange( 1, 100); + m_slThreshold->setSteps( 3, 3); + m_slThreshold->setValue(m_threshold); + connect(m_slThreshold, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetThreshold(int))); + + m_checkUsePattern = new TQCheckBox(i18n("Use pattern"), widget); + m_checkUsePattern->setChecked(m_usePattern); + connect(m_checkUsePattern, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetUsePattern(bool))); + + m_checkSampleMerged = new TQCheckBox(i18n("Limit to current layer"), widget); + m_checkSampleMerged->setChecked(m_unmerged); + connect(m_checkSampleMerged, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetSampleMerged(bool))); + + m_checkFillSelection = new TQCheckBox(i18n("Fill entire selection"), widget); + m_checkFillSelection->setChecked(m_fillOnlySelection); + connect(m_checkFillSelection, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetFillSelection(bool))); + + addOptionWidgetOption(m_slThreshold, m_lbThreshold); + + addOptionWidgetOption(m_checkFillSelection); + addOptionWidgetOption(m_checkSampleMerged); + addOptionWidgetOption(m_checkUsePattern); + + return widget; +} + +void KisToolFill::slotSetThreshold(int threshold) +{ + m_threshold = threshold; +} + +void KisToolFill::slotSetUsePattern(bool state) +{ + m_usePattern = state; +} + +void KisToolFill::slotSetSampleMerged(bool state) +{ + m_unmerged = state; +} + +void KisToolFill::slotSetFillSelection(bool state) +{ + m_fillOnlySelection = state; + m_slThreshold->setEnabled(!state); + m_checkSampleMerged->setEnabled(!state); +} + +void KisToolFill::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Fill"), + "tool_color_fill", + TQt::Key_F, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Contiguous fill")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_fill.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_fill.h b/chalk/plugins/tools/defaulttools/kis_tool_fill.h new file mode 100644 index 00000000..61087243 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_fill.h @@ -0,0 +1,109 @@ +/* + * kis_tool_fill.h - part of Krayon^Chalk + * + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __filltool_h__ +#define __filltool_h__ + +#include + +#include "kis_point.h" +#include "kis_tool_paint.h" + +class KisPainter; +class TQWidget; +class TQLabel; +class TQCheckBox; +class KIntNumInput; +class KActionCollection; + +class KisToolFill : public KisToolPaint { + + typedef KisToolPaint super; + Q_OBJECT + TQ_OBJECT + +public: + + KisToolFill(); + virtual ~KisToolFill(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual TQ_UINT32 priority() { return 0; } + + virtual void update(KisCanvasSubject *subject); + + virtual void buttonPress(KisButtonPressEvent*); + virtual void buttonRelease(KisButtonReleaseEvent*); + + bool flood(int startX, int startY); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + +public slots: + virtual void slotSetThreshold(int); + virtual void slotSetUsePattern(bool); + virtual void slotSetSampleMerged(bool); + virtual void slotSetFillSelection(bool); + +private: + KisPoint m_startPos; + int m_threshold; + TQ_INT32 m_depth; + KisLayerSP m_lay; + TQ_UINT8* m_oldColor, *m_color; + KisPainter *m_painter; + KisCanvasSubject *m_subject; + KisImageSP m_currentImage; + bool *m_map, m_unmerged, m_usePattern, m_fillOnlySelection; + KisSelectionSP m_selection; + + TQLabel *m_lbThreshold; + KIntNumInput *m_slThreshold; + TQCheckBox *m_checkUsePattern; + TQCheckBox *m_checkSampleMerged; + TQCheckBox *m_checkFillSelection; + bool m_wasPressed; // use for preventing bug:133148 +}; + + +#include "kis_tool_factory.h" + +class KisToolFillFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolFillFactory() : super() {}; + virtual ~KisToolFillFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisToolFill * t = new KisToolFill(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("fill", i18n("Fill Tool")); } + +}; + + + + +#endif //__filltool_h__ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_gradient.cc b/chalk/plugins/tools/defaulttools/kis_tool_gradient.cc new file mode 100644 index 00000000..4eb685a5 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_gradient.cc @@ -0,0 +1,309 @@ +/* + * kis_tool_gradient.cc - part of Chalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2003 Boudewijn Rempt + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_canvas_subject.h" +#include "kis_cmb_composite.h" +#include "kis_cursor.h" +#include "kis_double_widget.h" +#include "kis_gradient_painter.h" +#include "kis_move_event.h" +#include "kis_painter.h" +#include "kis_progress_display_interface.h" +#include "kis_tool_gradient.h" +#include "kis_undo_adapter.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +KisToolGradient::KisToolGradient() + : super(i18n("Gradient")), + m_dragging( false ) +{ + setName("tool_gradient"); + setCursor(KisCursor::load("tool_gradient_cursor.png", 6, 6)); + + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); + + m_reverse = false; + m_tqshape = KisGradientPainter::GradientShapeLinear; + m_repeat = KisGradientPainter::GradientRepeatNone; + m_antiAliasThreshold = 0.2; +} + +KisToolGradient::~KisToolGradient() +{ +} + +void KisToolGradient::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolGradient::paint(KisCanvasPainter& gc) +{ + if (m_dragging) + paintLine(gc); +} + +void KisToolGradient::paint(KisCanvasPainter& gc, const TQRect&) +{ + if (m_dragging) + paintLine(gc); +} + +void KisToolGradient::buttonPress(KisButtonPressEvent *e) +{ + if (!m_subject || !m_subject->currentImg()) { + return; + } + + if (e->button() == Qt::LeftButton) { + m_dragging = true; + m_startPos = e->pos(); + m_endPos = e->pos(); + } +} + +void KisToolGradient::move(KisMoveEvent *e) +{ + if (m_dragging) { + if (m_startPos != m_endPos) { + paintLine(); + } + + if ((e->state() & TQt::ShiftButton) == TQt::ShiftButton) { + m_endPos = straightLine(e->pos()); + } + else { + m_endPos = e->pos(); + } + + paintLine(); + } +} + +void KisToolGradient::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_dragging && e->button() == Qt::LeftButton) { + + KisCanvasController *controller = m_subject->canvasController(); + KisImageSP img = m_subject->currentImg(); + + m_dragging = false; + + if (m_startPos == m_endPos) { + controller->updateCanvas(); + m_dragging = false; + return; + } + + if ((e->state() & TQt::ShiftButton) == TQt::ShiftButton) { + m_endPos = straightLine(e->pos()); + } + else { + m_endPos = e->pos(); + } + + KisPaintDeviceSP device; + + if (img && (device = img->activeDevice())) { + + KisGradientPainter painter(device); + + if (img->undo()) painter.beginTransaction(i18n("Gradient")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setGradient(*(m_subject->currentGradient())); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + + KisProgressDisplayInterface *progress = m_subject->progressDisplay(); + + if (progress) { + progress->setSubject(&painter, true, true); + } + + bool painted = painter.paintGradient(m_startPos, m_endPos, m_tqshape, m_repeat, m_antiAliasThreshold, m_reverse, 0, 0, m_subject->currentImg()->width(), m_subject->currentImg()->height()); + + if (painted) { + // does whole thing at moment + device->setDirty(painter.dirtyRect()); + + notifyModified(); + + if (img->undo()) { + img->undoAdapter()->addCommand(painter.endTransaction()); + } + } + + /* remove remains of the line drawn while moving */ + if (controller->kiscanvas()) { + controller->kiscanvas()->update(); + } + + } + } +} + +KisPoint KisToolGradient::straightLine(KisPoint point) +{ + KisPoint comparison = point - m_startPos; + KisPoint result; + + if ( fabs(comparison.x()) > fabs(comparison.y())) { + result.setX(point.x()); + result.setY(m_startPos.y()); + } else { + result.setX( m_startPos.x() ); + result.setY( point.y() ); + } + + return result; +} + +void KisToolGradient::paintLine() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + paintLine(gc); + } +} + +void KisToolGradient::paintLine(KisCanvasPainter& gc) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + + KisPoint start = controller->windowToView(m_startPos); + KisPoint end = controller->windowToView(m_endPos); + + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::SolidLine); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawLine(start.floorTQPoint(), end.floorTQPoint()); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +TQWidget* KisToolGradient::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + Q_CHECK_PTR(widget); + + m_lbShape = new TQLabel(i18n("Shape:"), widget); + m_lbRepeat = new TQLabel(i18n("Repeat:"), widget); + + m_ckReverse = new TQCheckBox(i18n("Reverse"), widget, "reverse_check"); + connect(m_ckReverse, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetReverse(bool))); + + m_cmbShape = new TQComboBox(false, widget, "tqshape_combo"); + connect(m_cmbShape, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetShape(int))); + m_cmbShape->insertItem(i18n("Linear")); + m_cmbShape->insertItem(i18n("Bi-Linear")); + m_cmbShape->insertItem(i18n("Radial")); + m_cmbShape->insertItem(i18n("Square")); + m_cmbShape->insertItem(i18n("Conical")); + m_cmbShape->insertItem(i18n("Conical Symmetric")); + + m_cmbRepeat = new TQComboBox(false, widget, "repeat_combo"); + connect(m_cmbRepeat, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetRepeat(int))); + m_cmbRepeat->insertItem(i18n("None")); + m_cmbRepeat->insertItem(i18n("Forwards")); + m_cmbRepeat->insertItem(i18n("Alternating")); + + addOptionWidgetOption(m_cmbShape, m_lbShape); + + addOptionWidgetOption(m_cmbRepeat, m_lbRepeat); + + addOptionWidgetOption(m_ckReverse); + + m_lbAntiAliasThreshold = new TQLabel(i18n("Anti-alias threshold:"), widget); + + m_slAntiAliasThreshold = new KDoubleNumInput(widget, "threshold_slider"); + m_slAntiAliasThreshold->setRange( 0, 1); + m_slAntiAliasThreshold->setValue(m_antiAliasThreshold); + connect(m_slAntiAliasThreshold, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotSetAntiAliasThreshold(double))); + + addOptionWidgetOption(m_slAntiAliasThreshold, m_lbAntiAliasThreshold); + + return widget; +} + +void KisToolGradient::slotSetShape(int tqshape) +{ + m_tqshape = static_cast(tqshape); +} + +void KisToolGradient::slotSetRepeat(int repeat) +{ + m_repeat = static_cast(repeat); +} + +void KisToolGradient::slotSetReverse(bool state) +{ + m_reverse = state; +} + +void KisToolGradient::slotSetAntiAliasThreshold(double value) +{ + m_antiAliasThreshold = value; +} + +void KisToolGradient::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Gradient"), + "tool_gradient", TQt::Key_G, this, + TQT_SLOT(activate()), collection, + name()); + m_action->setToolTip(i18n("Draw a gradient")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_gradient.moc" + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_gradient.h b/chalk/plugins/tools/defaulttools/kis_tool_gradient.h new file mode 100644 index 00000000..59d78ad3 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_gradient.h @@ -0,0 +1,124 @@ +/* + * kis_tool_line.h - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_GRADIENT_H_ +#define KIS_TOOL_GRADIENT_H_ + +#include "kis_tool_paint.h" + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_gradient_painter.h" +#include "kis_tool_factory.h" + +class KIntNumInput; +class KDoubleNumInput; + +class KisCmbComposite; +class KisPainter; + +class TQLabel; +class TQPoint; +class TQWidget; +class TQCheckBox; + + + +class KisToolGradient : public KisToolPaint { + + Q_OBJECT + TQ_OBJECT + typedef KisToolPaint super; + +public: + KisToolGradient(); + virtual ~KisToolGradient(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual TQ_UINT32 priority() { return 1; } + + virtual void update(KisCanvasSubject *subject); + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + + TQWidget* createOptionWidget(TQWidget* tqparent); + +public slots: + void slotSetShape(int); + void slotSetRepeat(int); + void slotSetReverse(bool); + void slotSetAntiAliasThreshold(double); + +private: + void paintLine(); + void paintLine(KisCanvasPainter& gc); + + KisPoint straightLine(KisPoint point); + + bool m_dragging; + + KisPoint m_startPos; + KisPoint m_endPos; + + KisCanvasSubject *m_subject; + + KisGradientPainter::enumGradientShape m_tqshape; + KisGradientPainter::enumGradientRepeat m_repeat; + + bool m_reverse; + double m_antiAliasThreshold; + + TQLabel *m_lbShape; + TQLabel *m_lbRepeat; + TQCheckBox *m_ckReverse; + TQComboBox *m_cmbShape; + TQComboBox *m_cmbRepeat; + TQLabel *m_lbAntiAliasThreshold; + KDoubleNumInput *m_slAntiAliasThreshold; +}; + +class KisToolGradientFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolGradientFactory() : super() {}; + virtual ~KisToolGradientFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolGradient(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("gradient", i18n("Gradient Tool")); } +}; + + + +#endif //KIS_TOOL_GRADIENT_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_line.cc b/chalk/plugins/tools/defaulttools/kis_tool_line.cc new file mode 100644 index 00000000..243052cf --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_line.cc @@ -0,0 +1,254 @@ +/* + * kis_tool_line.cc - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2003 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_cursor.h" +#include "kis_painter.h" +#include "kis_tool_line.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_canvas_subject.h" +#include "kis_undo_adapter.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_layer.h" + +KisToolLine::KisToolLine() + : super(i18n("Line")), + m_dragging( false ) +{ + setName("tool_line"); + setCursor(KisCursor::load("tool_line_cursor.png", 6, 6)); + + m_painter = 0; + m_currentImage = 0; + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); +} + +KisToolLine::~KisToolLine() +{ +} + +void KisToolLine::update(KisCanvasSubject *subject) +{ + m_subject = subject; + m_currentImage = subject->currentImg(); + + super::update(m_subject); +} + + +void KisToolLine::paint(KisCanvasPainter& gc) +{ + if (m_dragging) + paintLine(gc, TQRect()); +} + +void KisToolLine::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + if (m_dragging) + paintLine(gc, rc); +} + +void KisToolLine::buttonPress(KisButtonPressEvent *e) +{ + if (!m_subject || !m_currentImage) return; + + if (!m_subject->currentBrush()) return; + + if (e->button() == Qt::LeftButton) { + m_dragging = true; + //KisCanvasController *controller = m_subject->canvasController(); + m_startPos = e->pos(); //controller->windowToView(e->pos()); + m_endPos = e->pos(); //controller->windowToView(e->pos()); + } +} + +void KisToolLine::move(KisMoveEvent *e) +{ + if (m_dragging) { + if (m_startPos != m_endPos) + paintLine(); + //KisCanvasController *controller = m_subject->canvasController(); + + if (e->state() & TQt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else if (e->state() & TQt::ShiftButton) + m_endPos = straightLine(e->pos()); + else + m_endPos = e->pos();//controller->windowToView(e->pos()); + paintLine(); + } +} + +void KisToolLine::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_dragging && e->button() == Qt::LeftButton) { + m_dragging = false; + KisCanvasController *controller = m_subject->canvasController(); + KisImageSP img = m_subject->currentImg(); + + if (m_startPos == m_endPos) { + controller->updateCanvas(); + m_dragging = false; + return; + } + + if ((e->state() & TQt::ShiftButton) == TQt::ShiftButton) { + m_endPos = straightLine(e->pos()); + } + else { + m_endPos = e->pos(); + } + + KisPaintDeviceSP device; + if (m_currentImage && + (device = m_currentImage->activeDevice()) && + m_subject && + m_subject->currentBrush()) + { + delete m_painter; + m_painter = new KisPainter( device ); + Q_CHECK_PTR(m_painter); + + if (m_currentImage->undo()) m_painter->beginTransaction(i18n("Line")); + + m_painter->setPaintColor(m_subject->fgColor()); + m_painter->setBrush(m_subject->currentBrush()); + m_painter->setOpacity(m_opacity); + m_painter->setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), m_painter); + m_painter->setPaintOp(op); // Painter takes ownership + m_painter->paintLine(m_startPos, PRESSURE_DEFAULT, 0, 0, m_endPos, PRESSURE_DEFAULT, 0, 0); + device->setDirty( m_painter->dirtyRect() ); + notifyModified(); + + /* remove remains of the line drawn while moving */ + if (controller->kiscanvas()) { + controller->kiscanvas()->update(); + } + + if (m_currentImage->undo() && m_painter) { + m_currentImage->undoAdapter()->addCommand(m_painter->endTransaction()); + } + delete m_painter; + m_painter = 0; + } else { + if (m_painter) + controller->updateCanvas(m_painter->dirtyRect()); // Removes the last remaining line. + } + } + +} + +KisPoint KisToolLine::straightLine(KisPoint point) +{ + KisPoint comparison = point - m_startPos; + KisPoint result; + + if ( fabs(comparison.x()) > fabs(comparison.y())) { + result.setX(point.x()); + result.setY(m_startPos.y()); + } else { + result.setX( m_startPos.x() ); + result.setY( point.y() ); + } + + return result; +} + +void KisToolLine::paintLine() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintLine(gc, rc); + } +} + +void KisToolLine::paintLine(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::SolidLine); + KisPoint start; + KisPoint end; + +// Q_ASSERT(controller); + start = controller->windowToView(m_startPos); + end = controller->windowToView(m_endPos); +// start.setX(start.x() - controller->horzValue()); +// start.setY(start.y() - controller->vertValue()); +// end.setX(end.x() - controller->horzValue()); +// end.setY(end.y() - controller->vertValue()); +// end.setX((end.x() - start.x())); +// end.setY((end.y() - start.y())); +// start *= m_subject->zoomFactor(); +// end *= m_subject->zoomFactor(); + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawLine(start.floorTQPoint(), end.floorTQPoint()); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolLine::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Line"), + "tool_line", TQt::Key_L, this, + TQT_SLOT(activate()), collection, + name()); + m_action->setToolTip(i18n("Draw a line")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQString KisToolLine::quickHelp() const { + return i18n("Alt+Drag will move the origin of the currently displayed line around, Shift+Drag will force you to draw straight lines"); +} + +#include "kis_tool_line.moc" + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_line.h b/chalk/plugins/tools/defaulttools/kis_tool_line.h new file mode 100644 index 00000000..4ce0ff38 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_line.h @@ -0,0 +1,100 @@ +/* + * kis_tool_line.h - part of Krayon + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_LINE_H_ +#define KIS_TOOL_LINE_H_ + +#include "kis_tool_paint.h" + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_tool_factory.h" + +class KisBrush; +class KisPainter; + +class TQPoint; +class TQWidget; + + +class KisToolLine : public KisToolPaint { + + Q_OBJECT + TQ_OBJECT + typedef KisToolPaint super; + + public: + KisToolLine(); + virtual ~KisToolLine(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 1; } + virtual void update(KisCanvasSubject *subject); + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + + virtual TQString quickHelp() const; + + private: + void paintLine(); + void paintLine(KisCanvasPainter& gc, const TQRect& rc); + + KisPoint straightLine(KisPoint point); + + + bool m_dragging; + + KisPoint m_startPos; + KisPoint m_endPos; + + KisCanvasSubject *m_subject; + KisImageSP m_currentImage; + KisPainter *m_painter; +}; + + +class KisToolLineFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolLineFactory() : super() {}; + virtual ~KisToolLineFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolLine(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("line", i18n("Line Tool")); } +}; + + + + +#endif //KIS_TOOL_LINE_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_move.cc b/chalk/plugins/tools/defaulttools/kis_tool_move.cc new file mode 100644 index 00000000..7c8733c9 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_move.cc @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1999 Matthias Elter + * 1999 Michael Koch + * 2002 Patrick Julien + * 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_tool_move.h" +#include "kis_tool_move.moc" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_selection.h" +#include "kis_selection_manager.h" +#include "kis_layer.h" + +KisToolMove::KisToolMove() + : super(i18n("Move Tool")) + , m_subject( 0 ) + , m_keyEvent( 0 ) +{ + setName("tool_move"); + + setCursor(KisCursor::moveCursor()); + m_repeatTimer = new TQTimer(this); + connect( m_repeatTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( slotMove() ) ); +} + +KisToolMove::~KisToolMove() +{ +} + +void KisToolMove::update(KisCanvasSubject *subject) +{ + m_subject = subject; + m_strategy.reset(subject); + super::update(subject); +} + +void KisToolMove::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton) { + TQPoint pos = e->pos().floorTQPoint(); + KisImageSP img = m_subject->currentImg(); + KisLayerSP dev; + + if (!img || !(dev = img->activeLayer())) + return; + + m_strategy.startDrag(pos); + } +} + +void KisToolMove::move(KisMoveEvent *e) +{ + if (m_subject && e->state() == Qt::LeftButton) { + TQPoint pos = e->pos().floorTQPoint(); + if((e->state() & TQt::AltButton) || (e->state() & TQt::ControlButton)) { + if(fabs(pos.x() - m_dragStart.x()) > fabs(pos.y() - m_dragStart.y())) + pos.setY(m_dragStart.y()); + else + pos.setX(m_dragStart.x()); + } + m_strategy.drag(pos); + } +} + +void KisToolMove::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton) { + m_strategy.endDrag(e->pos().floorTQPoint()); + } +} + +void KisToolMove::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Move"), + "tool_move", + TQt::SHIFT+TQt::Key_V, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Move")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + + +void KisToolMove::keyPress( TQKeyEvent *e ) +{ + m_keyEvent = e; + + if (m_subject) { + + KisImageSP img = m_subject->currentImg(); + KisLayerSP dev; + + if (!img || !(dev = img->activeLayer())) + return; + + m_dragStart = TQPoint( 0, 0 ); + m_strategy.startDrag( m_dragStart ); + m_steps = 1; + m_repeatTimer->start(200); + + } +} + +void KisToolMove::keyRelease(TQKeyEvent *) +{ + m_repeatTimer->stop(); + + if ( m_subject && m_keyEvent) { + + if ( m_keyEvent->key() == TQt::Key_Left ) { + m_strategy.endDrag(TQPoint( -m_steps, 0 )); + } + else if ( m_keyEvent->key() == TQt::Key_Right ) { + m_strategy.endDrag(TQPoint(m_steps, 0) ); + } + else if ( m_keyEvent->key() == TQt::Key_Up ) { + m_strategy.endDrag(TQPoint(0, -m_steps) ); + } + else if ( m_keyEvent->key() == TQt::Key_Down ) { + m_strategy.endDrag(TQPoint(0, m_steps) ); + } + } + m_steps = 0; + m_keyEvent = 0; + +} + +void KisToolMove::slotMove() +{ + if (m_subject && m_keyEvent) { + + if ( m_keyEvent->key() == TQt::Key_Left ) { + m_strategy.drag(TQPoint(-m_steps, 0) ); + } + else if ( m_keyEvent->key() == TQt::Key_Right ) { + m_strategy.drag(TQPoint(m_steps, 0) ); + } + else if ( m_keyEvent->key() == TQt::Key_Up ) { + m_strategy.drag(TQPoint(0, -m_steps) ); + } + else if ( m_keyEvent->key() == TQt::Key_Down ) { + m_strategy.drag(TQPoint(0, m_steps) ); + } + + ++m_steps; + } + +} diff --git a/chalk/plugins/tools/defaulttools/kis_tool_move.h b/chalk/plugins/tools/defaulttools/kis_tool_move.h new file mode 100644 index 00000000..274cc3c7 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_move.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1999 Matthias Elter + * 1999 Michael Koch + * 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_MOVE_H_ +#define KIS_TOOL_MOVE_H_ + +#include + +#include "kis_strategy_move.h" +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" + +class TQTimer; + +class KisToolMove : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolMove(); + virtual ~KisToolMove(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual TQ_UINT32 priority() { return 2; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void keyPress(TQKeyEvent *e); + virtual void keyRelease(TQKeyEvent *e); + +private slots: + + void slotMove(); + +private: + + KisCanvasSubject *m_subject; + KisStrategyMove m_strategy; + TQPoint m_dragStart; + TQTimer * m_repeatTimer; + TQKeyEvent * m_keyEvent; + int m_steps; +}; + + +class KisToolMoveFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolMoveFactory() : super() {}; + virtual ~KisToolMoveFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolMove(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("move", i18n("Move Tool")); } +}; + + + +#endif // KIS_TOOL_MOVE_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_pan.cc b/chalk/plugins/tools/defaulttools/kis_tool_pan.cc new file mode 100644 index 00000000..f7a92dcb --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_pan.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_tool_pan.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" + +KisToolPan::KisToolPan() + : super(i18n("Pan Tool")) +{ + setName("tool_pan"); + m_subject = 0; + m_dragging = false; + m_openHandCursor = KisCursor::openHandCursor(); + m_closedHandCursor = KisCursor::closedHandCursor(); + setCursor(m_openHandCursor); +} + +KisToolPan::~KisToolPan() +{ +} + +void KisToolPan::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolPan::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && !m_dragging && e->button() == Qt::LeftButton) { + KisCanvasController *controller = m_subject->canvasController(); + + m_origScrollX = controller->horzValue(); + m_origScrollY = controller->vertValue(); + m_dragPos = controller->windowToView(e->pos()); + m_dragging = true; + setCursor(m_closedHandCursor); + } +} + +void KisToolPan::move(KisMoveEvent *e) +{ + if (m_subject && m_dragging) { + KisCanvasController *controller = m_subject->canvasController(); + + KisPoint currPos = controller->windowToView(e->pos()); + KisPoint delta = currPos - m_dragPos; + controller->scrollTo(m_origScrollX - delta.floorX(), m_origScrollY - delta.floorY()); + } +} + +void KisToolPan::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_dragging && e->button() == Qt::LeftButton) { + setCursor(m_openHandCursor); + m_dragging = false; + } +} + +void KisToolPan::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Pan"), "tool_pan", TQt::SHIFT+TQt::Key_H, this, TQT_SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Pan")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_pan.moc" + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_pan.h b/chalk/plugins/tools/defaulttools/kis_tool_pan.h new file mode 100644 index 00000000..36ed9dcc --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_pan.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_PAN_H_ +#define KIS_TOOL_PAN_H_ + +#include "kis_point.h" +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" +#include + +class KisCanvasSubject; +class KisPoint; + +class KRITATOOL_EXPORT KisToolPan : public KisToolNonPaint +{ + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolPan(); + virtual ~KisToolPan(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_VIEW; } + virtual TQ_UINT32 priority() { return 1; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual bool wantsAutoScroll() const { return false; } + +private: + KisCanvasSubject *m_subject; + KisPoint m_dragPos; + TQ_INT32 m_origScrollX; + TQ_INT32 m_origScrollY; + bool m_dragging; + TQCursor m_openHandCursor; + TQCursor m_closedHandCursor; +}; + +class KisToolPanFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolPanFactory() : super() {}; + virtual ~KisToolPanFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolPan(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("pan", i18n("Pan Tool")); } +}; + + +#endif // KIS_TOOL_PAN_H_ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_rectangle.cc b/chalk/plugins/tools/defaulttools/kis_tool_rectangle.cc new file mode 100644 index 00000000..b8387d78 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_rectangle.cc @@ -0,0 +1,187 @@ +/* + * kis_tool_rectangle.cc - part of Chalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_move_event.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_tool_rectangle.h" +#include "kis_undo_adapter.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_layer.h" + +KisToolRectangle::KisToolRectangle() + : super(i18n ("Rectangle")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_rectangle"); + setCursor(KisCursor::load("tool_rectangle_cursor.png", 6, 6)); +} + +KisToolRectangle::~KisToolRectangle() +{ +} + +void KisToolRectangle::update (KisCanvasSubject *subject) +{ + super::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg (); +} + +void KisToolRectangle::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage && event->button() == Qt::LeftButton) { + m_dragging = true; + m_dragStart = m_dragCenter = m_dragEnd = event->pos(); + draw(m_dragStart, m_dragEnd); + } +} + +void KisToolRectangle::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + // move (alt) or resize rectangle + if (event->state() & TQt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + KisPoint diag = event->pos() - (event->state() & TQt::ControlButton + ? m_dragCenter : m_dragStart); + // square? + if (event->state() & TQt::ShiftButton) { + double size = TQMAX(fabs(diag.x()), fabs(diag.y())); + double w = diag.x() < 0 ? -size : size; + double h = diag.y() < 0 ? -size : size; + diag = KisPoint(w, h); + } + + // resize around center point? + if (event->state() & TQt::ControlButton) { + m_dragStart = m_dragCenter - diag; + m_dragEnd = m_dragCenter + diag; + } else { + m_dragEnd = m_dragStart + diag; + } + } + // draw new lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragCenter = KisPoint((m_dragStart.x() + m_dragEnd.x()) / 2, + (m_dragStart.y() + m_dragEnd.y()) / 2); + } +} + +void KisToolRectangle::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject) + return; + + if (!m_currentImage) + return; + + KisPaintDeviceSP device = m_currentImage->activeDevice (); + if (!device) return; + + if (m_dragging && event->button() == Qt::LeftButton) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragging = false; + + if (m_dragStart == m_dragEnd) + return; + + if (!m_currentImage) + return; + + + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n ("Rectangle")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBackgroundColor(m_subject->bgColor()); + painter.setFillStyle(fillStyle()); + painter.setBrush(m_subject->currentBrush()); + painter.setPattern(m_subject->currentPattern()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); + + painter.paintRect(m_dragStart, m_dragEnd, PRESSURE_DEFAULT/*event->pressure()*/, event->xTilt(), event->yTilt()); + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + } +} + +void KisToolRectangle::draw(const KisPoint& start, const KisPoint& end ) +{ + if (!m_subject) + return; + + KisCanvasController *controller = m_subject->canvasController (); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter p (canvas); + + p.setRasterOp (TQt::NotROP); + p.drawRect (TQRect (controller->windowToView (start).floorTQPoint(), controller->windowToView (end).floorTQPoint())); + p.end (); +} + +void KisToolRectangle::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Rectangle"), + "tool_rectangle", + TQt::Key_F6, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Draw a rectangle")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_rectangle.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_rectangle.h b/chalk/plugins/tools/defaulttools/kis_tool_rectangle.h new file mode 100644 index 00000000..d9f898a9 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_rectangle.h @@ -0,0 +1,96 @@ +/* + * kis_tool_rectangle.h - part of KImageShop^WKrayon^WChalk + * + * Copyright (c) 1999 Michael Koch + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_RECTANGLE_H__ +#define __KIS_TOOL_RECTANGLE_H__ + +#include + +#include "kis_tool_shape.h" +#include "kis_types.h" +#include "kis_tool_factory.h" +#include "kis_point.h" + +class TQPainter; +class KisPainter; + +class KisToolRectangle : public KisToolShape { + + typedef KisToolShape super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolRectangle(); + virtual ~KisToolRectangle(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 2; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + +protected: + virtual void draw(const KisPoint&, const KisPoint&); + +protected: + int m_lineThickness; + + KisPoint m_dragCenter; + KisPoint m_dragStart; + KisPoint m_dragEnd; + TQRect m_final_lines; + + bool m_dragging; + KisImageSP m_currentImage; +}; + +class KisToolRectangleFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolRectangleFactory() : super() {}; + virtual ~KisToolRectangleFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolRectangle(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("rectangle", i18n("Rectangle Tool")); } +}; + + +#endif // __KIS_TOOL_RECTANGLE_H__ + diff --git a/chalk/plugins/tools/defaulttools/kis_tool_text.cc b/chalk/plugins/tools/defaulttools/kis_tool_text.cc new file mode 100644 index 00000000..df247917 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_text.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "kis_point.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_cursor.h" +#include "kis_tool_text.h" +#include "kis_paint_device.h" +#include "kis_canvas_subject.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_color.h" +#include "kis_undo_adapter.h" + +KisToolText::KisToolText() + : super(i18n("Text")) + , m_wasPressed( false ) + , m_windowIsBeingShown( false ) +{ + setName("tool_text"); + m_subject = 0; + setCursor(KisCursor::load("tool_text_cursor.png", 6, 6)); +} + +KisToolText::~KisToolText() +{ +} + +void KisToolText::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(subject); +} + +void KisToolText::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton) { + m_wasPressed = true; + } +} + +void KisToolText::buttonRelease(KisButtonReleaseEvent *e) +{ + if ( m_windowIsBeingShown ) return; + + if (m_subject && e->button() == Qt::LeftButton) { + if(!m_wasPressed) return; + m_wasPressed = false; + KisImageSP img = m_subject->currentImg(); + + m_windowIsBeingShown = true; + bool ok; + TQString text = KInputDialog::getText(i18n("Font Tool"), i18n("Enter text:"), + TQString(), &ok); + if (!ok) { + m_windowIsBeingShown = false; + return; + } + + KisUndoAdapter *undoAdapter = img->undoAdapter(); + if (undoAdapter) { + undoAdapter->beginMacro(i18n("Text")); + } + + TQFontMetrics metrics(m_font); + TQRect boundingRect = TQT_TQRECT_OBJECT(metrics.boundingRect(text)).normalize(); + int xB = - boundingRect.x(); + int yB = - boundingRect.y(); + + if (boundingRect.x() < 0 || boundingRect.y() < 0) + boundingRect.moveBy(- boundingRect.x(), - boundingRect.y()); + + TQPixmap pixels(boundingRect.width(), boundingRect.height()); + { + TQPainter paint(&pixels); + paint.fillRect(boundingRect, TQt::white); + paint.setFont(m_font); + paint.setBrush(TQBrush(TQt::black)); + paint.drawText(xB, yB, text); + } + TQImage image = pixels.convertToImage(); + + TQ_INT32 height = boundingRect.height(); + TQ_INT32 width = boundingRect.width(); + KisPaintLayer *layer = new KisPaintLayer(img, '"' + text + '"', OPACITY_OPAQUE); + KisGroupLayerSP tqparent = img->rootLayer(); + if (img->activeLayer()) + tqparent = img->activeLayer()->tqparent(); + img->addLayer(layer, tqparent, img->activeLayer()); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + TQRgb pixel = image.pixel(x, y); + // use the 'blackness' as alpha :) + TQ_UINT8 alpha = 255 - tqRed(pixel) * OPACITY_OPAQUE / 255; + TQColor c = m_subject->fgColor().toTQColor(); + layer->paintDevice()->setPixel(x, y, c, alpha); + } + } + + layer->setOpacity(m_opacity); + layer->setCompositeOp(m_compositeOp); + + layer->setVisible(false); + TQ_INT32 x = TQMAX(0, static_cast(e->x() - width/2)); + TQ_INT32 y = TQMAX(0, static_cast(e->y() - height/2)); + layer->setX(x); + layer->setY(y); + layer->setVisible(true); + layer->setDirty(); + + if (undoAdapter) { + undoAdapter->endMacro(); + } + + m_windowIsBeingShown = false; + } +} + +void KisToolText::setFont() { + KFontDialog::getFont( m_font, false/*, TQWidget* tqparent! */ ); + m_lbFontName->setText(TQString(m_font.family() + ", %1").tqarg(m_font.pointSize())); +} + +TQWidget* KisToolText::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + + m_lbFont = new TQLabel(i18n("Font: "), widget); + + TQHBox *fontBox = new TQHBox(widget); + m_lbFontName = new KSqueezedTextLabel(TQString(m_font.family() + ", %1") + .tqarg(m_font.pointSize()), fontBox); + m_btnMoreFonts = new TQPushButton("...", fontBox); + + connect(m_btnMoreFonts, TQT_SIGNAL(released()), this, TQT_SLOT(setFont())); + + addOptionWidgetOption(fontBox, m_lbFont); + + return widget; +} + +void KisToolText::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("T&ext"), + "tool_text", + TQt::SHIFT+TQt::Key_T, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Text")); + m_ownAction = true; + } +} + +#include "kis_tool_text.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_text.h b/chalk/plugins/tools/defaulttools/kis_tool_text.h new file mode 100644 index 00000000..b2aa7e18 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_text.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_TEXT_H_ +#define KIS_TOOL_TEXT_H_ + +#include "kis_tool_paint.h" + +#include "kis_tool_factory.h" + +class TQFont; +class TQLabel; +class TQWidget; +class TQPushButton; +class KSqueezedTextLabel; + + + +class KisToolText : public KisToolPaint { + typedef KisToolPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolText(); + virtual ~KisToolText(); + + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FILL; } + virtual TQ_UINT32 priority() { return 2; } + virtual void buttonPress(KisButtonPressEvent*); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); +public slots: + virtual void setFont(); + +private: + KisCanvasSubject *m_subject; + TQFont m_font; + TQLabel *m_lbFont; + KSqueezedTextLabel *m_lbFontName; + TQPushButton *m_btnMoreFonts; + bool m_wasPressed; // use for preventing bug:136151 + bool m_windowIsBeingShown; +}; + + +class KisToolTextFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolTextFactory() : super() {}; + virtual ~KisToolTextFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolText(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("text", i18n("Text Tool")); } +}; + + +#endif // KIS_TOOL_TEXT_H_ diff --git a/chalk/plugins/tools/defaulttools/kis_tool_zoom.cc b/chalk/plugins/tools/defaulttools/kis_tool_zoom.cc new file mode 100644 index 00000000..f866e5e2 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_zoom.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "kis_image.h" +#include "kis_paint_device.h" +#include "kis_paint_layer.h" +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_tool_zoom.h" + + +KisToolZoom::KisToolZoom() + : super(i18n("Zoom Tool")) +{ + setName("tool_zoom"); + m_subject = 0; + m_dragging = false; + m_startPos = TQPoint(0, 0); + m_endPos = TQPoint(0, 0); + m_plusCursor = KisCursor::load("tool_zoom_plus_cursor.png", 8, 8); + m_minusCursor = KisCursor::load("tool_zoom_minus_cursor.png", 8, 8); + setCursor(m_plusCursor); + connect(&m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimer())); +} + +KisToolZoom::~KisToolZoom() +{ +} + +void KisToolZoom::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolZoom::paint(KisCanvasPainter& gc) +{ + if (m_dragging) + paintOutline(gc, TQRect()); +} + +void KisToolZoom::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + if (m_dragging) + paintOutline(gc, rc); +} + +void KisToolZoom::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && m_subject->currentImg() && !m_dragging) { + if (e->button() == Qt::LeftButton) { + m_startPos = e->pos().floorTQPoint(); + m_endPos = e->pos().floorTQPoint(); + m_dragging = true; + } + } +} + +void KisToolZoom::move(KisMoveEvent *e) +{ + if (m_subject && m_dragging) { + if (m_startPos != m_endPos) + paintOutline(); + + m_endPos = e->pos().floorTQPoint(); + paintOutline(); + } +} + +void KisToolZoom::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_dragging && e->button() == Qt::LeftButton) { + + KisCanvasController *controller = m_subject->canvasController(); + m_endPos = e->pos().floorTQPoint(); + m_dragging = false; + + TQPoint delta = m_endPos - m_startPos; + + if (sqrt(delta.x() * delta.x() + delta.y() * delta.y()) < 10) { + if (e->state() & TQt::ControlButton) { + controller->zoomOut(m_endPos.x(), m_endPos.y()); + } else { + controller->zoomIn(m_endPos.x(), m_endPos.y()); + } + } else { + controller->zoomTo(TQRect(m_startPos, m_endPos)); + } + } +} + +void KisToolZoom::activate() +{ + super::activate(); + m_timer.start(50); +} + +void KisToolZoom::deactivate() +{ + m_timer.stop(); +} + +void KisToolZoom::slotTimer() +{ +#if KDE_IS_VERSION(3,4,0) + int state = kapp->keyboardMouseState() & (TQt::ShiftButton|TQt::ControlButton|TQt::AltButton); +#else + int state = kapp->keyboardModifiers() & (KApplication::ShiftModifier + |KApplication::ControlModifier|KApplication::Modifier1); +#endif + + if (state & TQt::ControlButton) { + m_subject->canvasController()->setCanvasCursor(m_minusCursor); + } else { + m_subject->canvasController()->setCanvasCursor(m_plusCursor); + } +} + +void KisToolZoom::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolZoom::paintOutline(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::DotLine); + TQPoint start; + TQPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos); + end = controller->windowToView(m_endPos); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawRect(TQRect(start, end)); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolZoom::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Zoom"), "tool_zoom", TQt::Key_Z, this, TQT_SLOT(activate()), collection, name()); + m_action->setToolTip(i18n("Zoom")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_zoom.moc" diff --git a/chalk/plugins/tools/defaulttools/kis_tool_zoom.h b/chalk/plugins/tools/defaulttools/kis_tool_zoom.h new file mode 100644 index 00000000..3faa5bf1 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/kis_tool_zoom.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_ZOOM_TOOL_H_ +#define KIS_ZOOM_TOOL_H_ + +#include + +#include "kis_tool_non_paint.h" + +#include "kis_tool_factory.h" + +class KisCanvasSubject; + +class KisToolZoom : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolZoom(); + virtual ~KisToolZoom(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_VIEW; } + virtual TQ_UINT32 priority() { return 2; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + +private: + void paintOutline(); + void paintOutline(KisCanvasPainter& gc, const TQRect& rc); + + +public slots: + + void activate(); + void deactivate(); + + +private slots: + void slotTimer(); + +private: + KisCanvasSubject *m_subject; + TQPoint m_startPos; + TQPoint m_endPos; + bool m_dragging; + TQCursor m_plusCursor; + TQCursor m_minusCursor; + TQTimer m_timer; +}; + + +class KisToolZoomFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolZoomFactory() : super() {}; + virtual ~KisToolZoomFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolZoom(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("zoom", i18n("Zoom Tool")); } +}; + + +#endif // KIS_ZOOM_TOOL_H_ diff --git a/chalk/plugins/tools/defaulttools/openhand_cursor.xpm b/chalk/plugins/tools/defaulttools/openhand_cursor.xpm new file mode 100644 index 00000000..607879d5 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/openhand_cursor.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char *openhand_cursor[]={ +"22 22 3 1", +". c None", +"# c #000000", +"a c #ffffff", +"......................", +"..........##..........", +".........#aa###.......", +".......###aa#aa#......", +"......#aa#aa#aa##.....", +"......#aa#aa#aa#a#....", +"......#aa#aa#aa#aa#...", +"..###.#aa#aa#aa#aa#...", +"..#aa##aaaaaaaa#aa#...", +"..#aaa#aaaaaaaaaaa#...", +"...#aa#aaaaaaaaaaa#...", +"....#a#aaaaaaaaaaa#...", +"....#aaaaaaaaaaaaa#...", +".....#aaaaaaaaaaaa#...", +".....#aaaaaaaaaaa#....", +"......#aaaaaaaaaa#....", +"......#aaaaaaaaaa#....", +".......#aaaaaaaa#.....", +".......#aaaaaaaa#.....", +".......##########.....", +"......................", +"......................"}; diff --git a/chalk/plugins/tools/defaulttools/tool_color_fill.png b/chalk/plugins/tools/defaulttools/tool_color_fill.png new file mode 100644 index 00000000..fdbe9ae5 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_color_fill.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_colorpicker.png b/chalk/plugins/tools/defaulttools/tool_colorpicker.png new file mode 100644 index 00000000..06164f7e Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_colorpicker.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_duplicate.png b/chalk/plugins/tools/defaulttools/tool_duplicate.png new file mode 100644 index 00000000..1710cf5d Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_duplicate.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_duplicate_cursor.png b/chalk/plugins/tools/defaulttools/tool_duplicate_cursor.png new file mode 100644 index 00000000..31418815 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_duplicate_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_ellipse.png b/chalk/plugins/tools/defaulttools/tool_ellipse.png new file mode 100644 index 00000000..a8ac0bd1 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_ellipse.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_ellipse_cursor.png b/chalk/plugins/tools/defaulttools/tool_ellipse_cursor.png new file mode 100644 index 00000000..b97f215b Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_ellipse_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_fill_cursor.png b/chalk/plugins/tools/defaulttools/tool_fill_cursor.png new file mode 100644 index 00000000..66691cb1 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_fill_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_freehand.png b/chalk/plugins/tools/defaulttools/tool_freehand.png new file mode 100644 index 00000000..c313410d Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_freehand.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_freehand_cursor.png b/chalk/plugins/tools/defaulttools/tool_freehand_cursor.png new file mode 100644 index 00000000..194bb200 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_freehand_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_gradient.png b/chalk/plugins/tools/defaulttools/tool_gradient.png new file mode 100644 index 00000000..a45075a8 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_gradient.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_gradient_cursor.png b/chalk/plugins/tools/defaulttools/tool_gradient_cursor.png new file mode 100644 index 00000000..fd20079a Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_gradient_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_line.png b/chalk/plugins/tools/defaulttools/tool_line.png new file mode 100644 index 00000000..49f6fe2b Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_line.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_line_cursor.png b/chalk/plugins/tools/defaulttools/tool_line_cursor.png new file mode 100644 index 00000000..66ec6b05 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_line_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_move.png b/chalk/plugins/tools/defaulttools/tool_move.png new file mode 100644 index 00000000..386224ed Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_move.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_pan.png b/chalk/plugins/tools/defaulttools/tool_pan.png new file mode 100644 index 00000000..c45a9c69 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_pan.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_rectangle.png b/chalk/plugins/tools/defaulttools/tool_rectangle.png new file mode 100644 index 00000000..4da56ecd Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_rectangle.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_rectangle_cursor.png b/chalk/plugins/tools/defaulttools/tool_rectangle_cursor.png new file mode 100644 index 00000000..0dba614b Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_rectangle_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_text.png b/chalk/plugins/tools/defaulttools/tool_text.png new file mode 100644 index 00000000..c1683fc0 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_text.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_text_cursor.png b/chalk/plugins/tools/defaulttools/tool_text_cursor.png new file mode 100644 index 00000000..e241beaf Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_text_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_zoom.png b/chalk/plugins/tools/defaulttools/tool_zoom.png new file mode 100644 index 00000000..10689553 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_zoom.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_zoom_minus_cursor.png b/chalk/plugins/tools/defaulttools/tool_zoom_minus_cursor.png new file mode 100644 index 00000000..7089eaf3 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_zoom_minus_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/tool_zoom_plus_cursor.png b/chalk/plugins/tools/defaulttools/tool_zoom_plus_cursor.png new file mode 100644 index 00000000..52c59b45 Binary files /dev/null and b/chalk/plugins/tools/defaulttools/tool_zoom_plus_cursor.png differ diff --git a/chalk/plugins/tools/defaulttools/wdgcolorpicker.ui b/chalk/plugins/tools/defaulttools/wdgcolorpicker.ui new file mode 100644 index 00000000..a2b9d7d3 --- /dev/null +++ b/chalk/plugins/tools/defaulttools/wdgcolorpicker.ui @@ -0,0 +1,167 @@ + +ColorPickerOptionsWidget + + + ColorPickerOptionsWidget + + + + 0 + 0 + 263 + 307 + + + + Color Picker + + + + unnamed + + + 0 + + + 0 + + + + + Sample All Visible Layers + + + + + Current Layer + + + + cmbSources + + + + 0 + 0 + 0 + 0 + + + + + 200 + 0 + + + + + 200 + 32767 + + + + + + cbUpdateCurrentColour + + + Update current color + + + + + tqlayout2 + + + + unnamed + + + + cbPalette + + + Add to palette: + + + + + cmbPalette + + + + + + + cbNormaliseValues + + + Show colors as percentages + + + + + tqlayout1 + + + + unnamed + + + + textLabel1 + + + Sample radius: + + + + + radius + + + 9 + + + 1 + + + + + + + + Channel + + + false + + + true + + + + + Value + + + false + + + true + + + + listViewChannels + + + true + + + NoSelection + + + + + + diff --git a/chalk/plugins/tools/selectiontools/Makefile.am b/chalk/plugins/tools/selectiontools/Makefile.am new file mode 100644 index 00000000..dc0ad90e --- /dev/null +++ b/chalk/plugins/tools/selectiontools/Makefile.am @@ -0,0 +1,56 @@ +kde_services_DATA = chalkselectiontools.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkselectiontools_la_SOURCES = kis_tool_move_selection.cc \ + kis_tool_select_brush.cc kis_tool_select_contiguous.cc kis_tool_select_elliptical.cc \ + kis_tool_select_eraser.cc kis_tool_select_outline.cc kis_tool_select_polygonal.cc \ + kis_tool_select_rectangular.cc selection_tools.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalkselectiontools.la + +noinst_HEADERS = \ + selection_tools.h \ + kis_tool_select_outline.h \ + kis_tool_select_polygonal.h \ + kis_tool_select_rectangular.h \ + kis_tool_select_brush.h \ + kis_tool_select_eraser.h \ + kis_tool_select_contiguous.h \ + kis_tool_select_elliptical.h + + +chalkselectiontools_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalkselectiontools_la_LIBADD = ../../../libchalkcommon.la + +chalkselectiontools_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_rect_selection.png \ + tool_eraser_selection.png \ + tool_brush_selection.png \ + tool_contiguous_selection.png \ + tool_elliptical_selection.png \ + tool_outline_selection.png \ + tool_polygonal_selection.png \ + tool_rectangular_selection_cursor.png \ + tool_eraser_selection_cursor.png \ + tool_brush_selection_cursor.png \ + tool_contiguous_selection_cursor.png \ + tool_elliptical_selection_cursor.png \ + tool_outline_selection_cursor.png \ + tool_polygonal_selection_cursor.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/selectiontools/chalkselectiontools.desktop b/chalk/plugins/tools/selectiontools/chalkselectiontools.desktop new file mode 100644 index 00000000..72a7f217 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/chalkselectiontools.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Selection Tools +Name[bg]=Инструмент за маркиране +Name[br]=Ostilhoù choazh +Name[ca]=Eines de selecció +Name[cy]=Offer Detholi +Name[da]=Markeringsværktøj +Name[de]=Auswahlwerkzeuge +Name[el]=Εργαλεία επιλογής +Name[eo]=Elektado-iloj +Name[es]=Herramientas de selección +Name[et]=Valikutööriistad +Name[eu]=Hautapen-tresnak +Name[fa]=ابزارهای گزینش +Name[fi]=Valintatyökalut +Name[fr]=Outils de sélection +Name[fy]=Seleksje-ark +Name[ga]=Uirlisí Roghnúcháin +Name[gl]=Ferramentas de Selección +Name[he]=כלי בחירה +Name[hu]=Kiválasztó eszközök +Name[is]=Valtól +Name[it]=Strumenti di selezione +Name[ja]=選択ツール +Name[km]=ឧបករណ៍​ជ្រើស​ +Name[lt]=Pažymėjimo įrankiai +Name[lv]=Izvēles rīki +Name[ms]=Alat Pemilihan +Name[nb]=Velgeverktøy +Name[nds]=Utwahlwarktüüch +Name[ne]=चयन उपकरण +Name[nl]=Selectiegereedschappen +Name[nn]=Veljeverktøy +Name[pl]=Narzędzia wyboru +Name[pt]=Ferramentas de Selecção +Name[pt_BR]=Ferramentas de Seleção +Name[ru]=Инструменты выделения +Name[se]=Válljenreaiddut +Name[sk]=Štetec výberu +Name[sl]=Orodja za izbiro +Name[sr]=Алати за избор +Name[sr@Latn]=Alati za izbor +Name[sv]=Markeringsverktyg +Name[uk]=Засоби виділення +Name[uz]=Tanlash vositalari +Name[uz@cyrillic]=Танлаш воситалари +Name[zh_CN]=选择工具 +Name[zh_TW]=選取區工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalkselectiontools +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/selectiontools/kis_tool_move_selection.cc b/chalk/plugins/tools/selectiontools/kis_tool_move_selection.cc new file mode 100644 index 00000000..b7b123d7 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_move_selection.cc @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_tool_move_selection.h" + +#include +#include +#include +#include +#include +#include +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_paint_device.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_selection.h" +#include "kis_selection_manager.h" +#include "kis_undo_adapter.h" + +class KisSelectionOffsetCommand : public KNamedCommand { + typedef KNamedCommand super; + +public: + KisSelectionOffsetCommand(KisSelectionSP layer, const TQPoint& oldpos, const TQPoint& newpos); + virtual ~KisSelectionOffsetCommand(); + + virtual void execute(); + virtual void unexecute(); + +private: + void moveTo(const TQPoint& pos); + +private: + KisSelectionSP m_layer; + TQPoint m_oldPos; + TQPoint m_newPos; +}; + + KisSelectionOffsetCommand::KisSelectionOffsetCommand(KisSelectionSP layer, const TQPoint& oldpos, const TQPoint& newpos) : + super(i18n("Move Layer")) + { + m_layer = layer; + m_oldPos = oldpos; + m_newPos = newpos; + + } + + KisSelectionOffsetCommand::~KisSelectionOffsetCommand() + { + } + + void KisSelectionOffsetCommand::execute() + { + moveTo(m_newPos); + } + + void KisSelectionOffsetCommand::unexecute() + { + moveTo(m_oldPos); + } + + void KisSelectionOffsetCommand::moveTo(const TQPoint& pos) + { + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(false); + } + + m_layer->setX(pos.x()); + m_layer->setY(pos.y()); + + m_layer->tqparentPaintDevice()->setDirty(); + + if (m_layer->undoAdapter()) { + m_layer->undoAdapter()->setUndo(true); + } + } + + +KisToolMoveSelection::KisToolMoveSelection() + : super(i18n("Move Selection Tool")) +{ + setName("tool_move_selection"); + m_subject = 0; + setCursor(KisCursor::moveCursor()); +} + +KisToolMoveSelection::~KisToolMoveSelection() +{ +} + +void KisToolMoveSelection::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(subject); + m_dragging = false; +} + +void KisToolMoveSelection::buttonPress(KisButtonPressEvent *e) +{ + m_dragging = false; + if (m_subject && e->button() == Qt::LeftButton) { + TQPoint pos = e->pos().floorTQPoint(); + KisImageSP img = m_subject->currentImg(); + KisPaintLayerSP lay; + + if (!img || !(lay = dynamic_cast( img->activeLayer().data() ))) + return; + + m_dragStart = pos; + + if ( !lay->visible() || !lay->paintDevice()->hasSelection()) + return; + KisSelectionSP sel = lay->paintDevice()->selection(); + + m_dragging = true; + m_dragStart.setX(pos.x()); + m_dragStart.setY(pos.y()); + m_layerStart.setX(sel->getX()); + m_layerStart.setY(sel->getY()); + m_layerPosition = m_layerStart; + + } +} + +void KisToolMoveSelection::move(KisMoveEvent *e) +{ + if (m_subject && m_dragging) { + TQPoint pos = e->pos().floorTQPoint(); + if((e->state() & TQt::AltButton) || (e->state() & TQt::ControlButton)) { + if(fabs(pos.x() - m_dragStart.x()) > fabs(pos.y() - m_dragStart.y())) + pos.setY(m_dragStart.y()); + else + pos.setX(m_dragStart.x()); + } + + KisImageSP img = m_subject->currentImg(); + KisPaintLayerSP lay = dynamic_cast(m_subject->currentImg()->activeLayer().data()); + if(!lay) return; + KisSelectionSP sel = lay->paintDevice()->selection(); + + TQRect rc; + + pos -= m_dragStart; // convert to delta + rc = sel->selectedRect(); + sel->setX(sel->getX() + pos.x()); + sel->setY(sel->getY() + pos.y()); + rc = rc.unite(sel->selectedRect()); + + m_layerPosition = TQPoint(sel->getX(), sel->getY()); + m_dragStart = e->pos().floorTQPoint(); + + lay->paintDevice()->setDirty(rc); + } + +} + +void KisToolMoveSelection::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton && m_dragging) { + m_dragging = false; + KisImageSP img = m_subject->currentImg(); + if(!img) return; + KisPaintLayerSP lay = dynamic_cast(img->activeLayer().data()); + + if (lay->paintDevice()->hasSelection()) { + KisSelectionSP dev = lay->paintDevice()->selection(); + m_dragging = false; + + if (img->undo()) { + KCommand *cmd = new KisSelectionOffsetCommand( dev, m_layerStart, m_layerPosition); + Q_CHECK_PTR(cmd); + KisUndoAdapter *adapter = img->undoAdapter(); + if (adapter) { + adapter->addCommand(cmd); + } else { + delete cmd; + } + } + img->setModified(); + lay->setDirty(); + } + } +} + +void KisToolMoveSelection::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Move selection"), + "tool_move", + TQt::SHIFT+TQt::Key_V, + this, + TQT_SLOT(activate()), + collection, + name()); + m_action->setToolTip(i18n("Move the selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_move_selection.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_move_selection.h b/chalk/plugins/tools/selectiontools/kis_tool_move_selection.h new file mode 100644 index 00000000..60d73a9b --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_move_selection.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_MOVE_H_ +#define KIS_TOOL_MOVE_H_ + +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" + +// XXX: Moving is not nearly smooth enough! +class KisToolMoveSelection : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolMoveSelection(); + virtual ~KisToolMoveSelection(); + +public: + virtual void update(KisCanvasSubject *subject); + +public: + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQ_UINT32 priority() { return 10; } + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + +private: + KisCanvasSubject *m_subject; + TQPoint m_dragStart; + TQPoint m_layerStart; + TQPoint m_layerPosition; + bool m_dragging; +}; + + +class KisToolMoveSelectionFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolMoveSelectionFactory() : super() {}; + virtual ~KisToolMoveSelectionFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolMoveSelection(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("moveselection", i18n("Move Selection Tool")); } +}; + + + +#endif // KIS_TOOL_MOVE_H_ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_brush.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_brush.cc new file mode 100644 index 00000000..ff5242d6 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_brush.cc @@ -0,0 +1,168 @@ +/* + * kis_tool_select_brush.cc - part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_brush.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_cmb_composite.h" +#include "kis_cursor.h" +#include "kis_doc.h" +#include "kis_paintop.h" +#include "kis_paintop_registry.h" +#include "kis_move_event.h" +#include "kis_painter.h" +#include "kis_selection.h" +#include "kis_tool_select_brush.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_view.h" +#include "kis_selection_options.h" +#include "kis_selected_transaction.h" + +KisToolSelectBrush::KisToolSelectBrush() + : super(i18n("SelectBrush")) +{ + setName("tool_select_brush"); + m_optWidget = 0; + setCursor(KisCursor::load("tool_brush_selection_cursor.png", 5, 5)); + m_paintOnSelection = true; +} + +KisToolSelectBrush::~KisToolSelectBrush() +{ +} + +void KisToolSelectBrush::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectBrush::initPaint(KisEvent* /*e*/) +{ + if (!m_currentImage || !m_currentImage->activeDevice()) return; + + m_mode = PAINT; + m_dragDist = 0; + + // Create painter + KisPaintDeviceSP dev = m_currentImage->activeDevice(); + if (m_painter) + delete m_painter; + bool hasSelection = dev->hasSelection(); + if (m_currentImage->undo()) m_transaction = new KisSelectedTransaction(i18n("Selection Brush"), dev); + if(! hasSelection) + { + dev->selection()->clear(); + dev->emitSelectionChanged(); + } + KisSelectionSP selection = dev->selection(); + + m_target = selection; + m_painter = new KisPainter(selection.data()); + Q_CHECK_PTR(m_painter); + m_painter->setPaintColor(KisColor(TQt::black, selection->colorSpace())); + m_painter->setBrush(m_subject->currentBrush()); + m_painter->setOpacity(OPACITY_OPAQUE);//m_subject->fgColor().colorSpace()->intensity8(m_subject->fgColor().data())); + m_painter->setCompositeOp(COMPOSITE_OVER); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("paintbrush", 0, painter()); + painter()->setPaintOp(op); // And now the painter owns the op and will destroy it. + + // Set the cursor -- ideally. this should be a tqmask created from the brush, + // now that X11 can handle colored cursors. +#if 0 + // Setting cursors has no effect until the tool is selected again; this + // should be fixed. + setCursor(KisCursor::brushCursor()); +#endif +} + +void KisToolSelectBrush::endPaint() +{ + m_mode = HOVER; + if (m_currentImage && m_currentImage->activeLayer()) { + if (m_currentImage->undo() && m_painter) { + // If painting in mouse release, make sure painter + // is destructed or end()ed + m_currentImage->undoAdapter()->addCommand(m_transaction); + } + delete m_painter; + m_painter = 0; + if (m_currentImage->activeDevice()) + m_currentImage->activeDevice()->emitSelectionChanged(); + notifyModified(); + } +} + + +void KisToolSelectBrush::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Selection Brush"), + "tool_brush_selection", "Ctrl+Shift+B", this, + TQT_SLOT(activate()), collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Paint a selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQWidget* KisToolSelectBrush::createOptionWidget(TQWidget* tqparent) +{ + Q_UNUSED(tqparent); + // Commented out due to the fact that this doesn't actually work if you change the action +#if 0 + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Selection Brush")); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +#endif + return 0; +} + +TQWidget* KisToolSelectBrush::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_select_brush.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_brush.h b/chalk/plugins/tools/selectiontools/kis_tool_select_brush.h new file mode 100644 index 00000000..374050f6 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_brush.h @@ -0,0 +1,83 @@ +/* + * kis_tool_select_brush.h - part of Chalk + * + * Copyright (c) 2003-2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_SELECT_BRUSH_H_ +#define KIS_TOOL_SELECT_BRUSH_H_ + +#include +#include +#include + +class TQWidget; +class KisPoint; +class KisSelectedTransaction; +class KisSelectionOptions; + +/** + * The selection brush creates a selection by painting with the current + * brush tqshape. Not sure what kind of an icon could represent this... + * Depends a bit on how we're going to visualize selections. + */ +class KisToolSelectBrush : public KisToolFreehand { + Q_OBJECT + TQ_OBJECT + typedef KisToolFreehand super; + +public: + KisToolSelectBrush(); + virtual ~KisToolSelectBrush(); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 1; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + +public slots: + virtual void activate(); + +protected: + + virtual void initPaint(KisEvent *e); + virtual void endPaint(); + +private: + KisSelectionOptions * m_optWidget; + KisSelectedTransaction *m_transaction; +}; + +class KisToolSelectBrushFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectBrushFactory() : super() {}; + virtual ~KisToolSelectBrushFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectBrush(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("brushselect", i18n("Brush Select Tool")); } +}; + + +#endif // KIS_TOOL_SELECT_BRUSH_H_ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.cc new file mode 100644 index 00000000..c4c908fc --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.cc @@ -0,0 +1,234 @@ +/* + * kis_tool_select_contiguous - part of Krayon^WChalk + * + * Copyright (c) 1999 Michael Koch + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_tool_select_contiguous.h" + +KisToolSelectContiguous::KisToolSelectContiguous() : super(i18n("Contiguous Select")) +{ + setName("tool_select_contiguous"); + m_subject = 0; + m_optWidget = 0; + m_fuzziness = 20; + m_sampleMerged = false; + m_selectAction = SELECTION_ADD; + + setCursor(KisCursor::load("tool_contiguous_selection_cursor.png", 6, 6)); +} + +KisToolSelectContiguous::~KisToolSelectContiguous() +{ +} + +void KisToolSelectContiguous::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectContiguous::buttonPress(KisButtonPressEvent * e) +{ + if (m_subject) { + + KisImageSP img; + KisPaintDeviceSP dev; + TQPoint pos; + + if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) + return; + + if (!(img = m_subject->currentImg())) + return; + + dev = img->activeDevice(); + + if (!dev || !img->activeLayer()->visible()) + return; + + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + + pos = TQPoint(e->pos().floorX(), e->pos().floorY()); + + KisFillPainter fillpainter(dev); + fillpainter.setFillThreshold(m_fuzziness); + fillpainter.setSampleMerged(m_sampleMerged); + KisSelectionSP selection = fillpainter.createFloodSelection(pos.x(), pos.y()); + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Contiguous Area Selection"), dev); + + if (!dev->hasSelection()) { + dev->selection()->clear(); + if(m_selectAction==SELECTION_SUBTRACT) + selection->invert(); + } + + switch (m_selectAction) { + case SELECTION_SUBTRACT: + dev->subtractSelection(selection); + break; + case SELECTION_ADD: + default: + dev->addSelection(selection); + break; + + } + + dev->setDirty(selection->selectedRect()); // A bit too wide, but that's not that bad + dev->emitSelectionChanged(); + + + if (img->undo()) + img->undoAdapter()->addCommand(t); + + TQApplication::restoreOverrideCursor(); + } + +} + +void KisToolSelectContiguous::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Contiguous Area Selection"), + "tool_contiguous_selection" , + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Select a contiguous area")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolSelectContiguous::update(KisCanvasSubject *subject) +{ + super::update(subject); + m_subject = subject; +} + +void KisToolSelectContiguous::slotSetFuzziness(int fuzziness) +{ + m_fuzziness = fuzziness; +} + + +void KisToolSelectContiguous::slotSetAction(int action) +{ + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +// XXX: Fix cursors when then are done. +// switch(m_selectAction) { +// case SELECTION_ADD: +// m_subject->setCanvasCursor(KisCursor::pickerPlusCursor()); +// break; +// case SELECTION_SUBTRACT: +// m_subject->setCanvasCursor(KisCursor::pickerMinusCursor()); +// }; +} + + +TQWidget* KisToolSelectContiguous::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Contiguous Area Selection")); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->setSpacing( 6 ); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQHBoxLayout * hbox = new TQHBoxLayout(l); + Q_CHECK_PTR(hbox); + + TQLabel * lbl = new TQLabel(i18n("Fuzziness: "), m_optWidget); + hbox->addWidget(lbl); + + KIntNumInput * input = new KIntNumInput(m_optWidget, "fuzziness"); + Q_CHECK_PTR(input); + + input->setRange(0, 200, 10, true); + input->setValue(20); + hbox->addWidget(input); + connect(input, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetFuzziness(int))); + + TQCheckBox* samplemerged = new TQCheckBox(i18n("Sample merged"), m_optWidget); + l->addWidget( samplemerged ); + samplemerged->setChecked(m_sampleMerged); + connect(samplemerged, TQT_SIGNAL(stateChanged(int)), + this, TQT_SLOT(slotSetSampleMerged(int))); + + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectContiguous::optionWidget() +{ + return m_optWidget; +} + +void KisToolSelectContiguous::slotSetSampleMerged(int state) +{ + if (state == TQButton::NoChange) + return; + m_sampleMerged = (state == TQButton::On); +} + +#include "kis_tool_select_contiguous.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.h b/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.h new file mode 100644 index 00000000..e4beb6b7 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_contiguous.h @@ -0,0 +1,95 @@ +/* + * kis_tool_select_contiguous.h - part of KImageShop^WKrayon^Chalk + * + * Copyright (c) 1999 Michael Koch + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_SELECT_CONTIGUOUS_H__ +#define __KIS_TOOL_SELECT_CONTIGUOUS_H__ + +#include +#include +#include +#include + +class KisCanvasSubject; +class TQWidget; +class TQVBoxLayout; +class TQCheckBox; +class KisSelectionOptions; + +/** + * The 'magic wand' selection tool -- in fact just + * a floodfill that only creates a selection. + */ +class KisToolSelectContiguous : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolSelectContiguous(); + virtual ~KisToolSelectContiguous(); + +public: + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 7; } + virtual enumToolType toolType() { return TOOL_SELECT; }; + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void buttonPress(KisButtonPressEvent *event); + +public slots: + virtual void slotSetFuzziness(int); + virtual void slotSetAction(int); + virtual void slotSetSampleMerged(int); + virtual void activate(); + + +private: + KisCanvasSubject *m_subject; + KisSelectionOptions * m_optWidget; + + int m_fuzziness; + enumSelectionMode m_selectAction; + bool m_sampleMerged; +}; + +class KisToolSelectContiguousFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectContiguousFactory() : super() {}; + virtual ~KisToolSelectContiguousFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectContiguous(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("contiguousselect", i18n("Contiguous Select Tool")); } +}; + + +#endif //__KIS_TOOL_SELECT_CONTIGUOUS_H__ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.cc new file mode 100644 index 00000000..efdae2f3 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.cc @@ -0,0 +1,321 @@ +/* + * kis_tool_select_elliptical.cc -- part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_autobrush_resource.h" +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_painter.h" +#include "kis_tool_select_elliptical.h" +#include "kis_layer.h" +#include "kis_undo_adapter.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_selection.h" +#include "kis_selection_options.h" +#include "kis_selected_transaction.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +KisToolSelectElliptical::KisToolSelectElliptical() + : super(i18n("Elliptical Select")) +{ + setName("tool_select_elliptical"); + setCursor(KisCursor::load("tool_elliptical_selection_cursor.png", 6, 6)); + + m_subject = 0; + m_selecting = false; + m_centerPos = KisPoint(0, 0); + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); + m_optWidget = 0; + m_selectAction = SELECTION_ADD; +} + +KisToolSelectElliptical::~KisToolSelectElliptical() +{ +} + +void KisToolSelectElliptical::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectElliptical::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolSelectElliptical::paint(KisCanvasPainter& gc) +{ + if (m_selecting) + paintOutline(gc, TQRect()); +} + +void KisToolSelectElliptical::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + if (m_selecting) + paintOutline(gc, rc); +} + +void KisToolSelectElliptical::clearSelection() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisImageSP img = m_subject->currentImg(); + + Q_ASSERT(controller); + +// if (img && img->floatingSelection().data() != 0) { +// img->unsetFloatingSelection(); +// controller->canvas()->update(); +// } + + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); + m_selecting = false; + } +} + +void KisToolSelectElliptical::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && e->button() == Qt::LeftButton) { + clearSelection(); + m_startPos = m_endPos = m_centerPos = e->pos(); + m_selecting = true; + paintOutline(); + } + } +} + +void KisToolSelectElliptical::move(KisMoveEvent *e) +{ + if (m_subject && m_selecting) { + paintOutline(); + // move (alt) or resize ellipse + if (e->state() & TQt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else { + KisPoint diag = e->pos() - (e->state() & TQt::ControlButton + ? m_centerPos : m_startPos); + // circle? + if (e->state() & TQt::ShiftButton) { + double size = TQMAX(fabs(diag.x()), fabs(diag.y())); + double w = diag.x() < 0 ? -size : size; + double h = diag.y() < 0 ? -size : size; + diag = KisPoint(w, h); + } + + // resize around center point? + if (e->state() & TQt::ControlButton) { + m_startPos = m_centerPos - diag; + m_endPos = m_centerPos + diag; + } else { + m_endPos = m_startPos + diag; + } + } + paintOutline(); + m_centerPos = KisPoint((m_startPos.x() + m_endPos.x()) / 2, + (m_startPos.y() + m_endPos.y()) / 2); + } +} + +void KisToolSelectElliptical::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_selecting && e->button() == Qt::LeftButton) { + + paintOutline(); + + if (m_startPos == m_endPos) { + clearSelection(); + } else { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + + if (m_endPos.y() < 0) + m_endPos.setY(0); + + if (m_endPos.y() > img->height()) + m_endPos.setY(img->height()); + + if (m_endPos.x() < 0) + m_endPos.setX(0); + + if (m_endPos.x() > img->width()) + m_endPos.setX(img->width()); + + if (img && img->activeDevice()) { + KisPaintDeviceSP dev = img->activeDevice(); + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Elliptical Selection"), dev); + + bool hasSelection = dev->hasSelection(); + if(! hasSelection) + { + dev->selection()->clear(); + if(m_selectAction==SELECTION_SUBTRACT) + dev->selection()->invert(); + } + TQRect rc( m_startPos.floorTQPoint(), m_endPos.floorTQPoint()); + rc = rc.normalize(); + + KisSelectionSP tmpSel = new KisSelection(dev); + KisAutobrushCircleShape tqshape(rc.width(),rc.height(), 1, 1); + TQ_UINT8 value; + for (int y = 0; y <= rc.height(); y++) + for (int x = 0; x <= rc.width(); x++) + { + value = MAX_SELECTED - tqshape.valueAt(x,y); + tmpSel->setSelected( x+rc.x(), y+rc.y(), value); + } + switch(m_selectAction) + { + case SELECTION_ADD: + dev->addSelection(tmpSel); + break; + case SELECTION_SUBTRACT: + dev->subtractSelection(tmpSel); + break; + } + + if(hasSelection) { + dev->setDirty(rc); + dev->emitSelectionChanged(rc); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) + img->undoAdapter()->addCommand(t); + + TQApplication::restoreOverrideCursor(); + } + } + m_selecting = false; + } +} + +void KisToolSelectElliptical::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolSelectElliptical::paintOutline(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::DotLine); + TQPoint start; + TQPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos).floorTQPoint(); + end = controller->windowToView(m_endPos).floorTQPoint(); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawEllipse(TQRect(start, end)); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolSelectElliptical::slotSetAction(int action) { + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +} + +void KisToolSelectElliptical::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Elliptical Selection"), + "tool_elliptical_selection" , + TQt::Key_J, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Select an elliptical area")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQWidget* KisToolSelectElliptical::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Elliptical Selection")); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectElliptical::optionWidget() +{ + return m_optWidget; +} + + + +#include "kis_tool_select_elliptical.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.h b/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.h new file mode 100644 index 00000000..f0d1a039 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_elliptical.h @@ -0,0 +1,99 @@ +/* + * kis_tool_select_elliptical.h - part of Krayon^WChalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_SELECT_ELLIPTICAL_H__ +#define __KIS_TOOL_SELECT_ELLIPTICAL_H__ + +#include + +#include "kis_point.h" +#include "kis_selection.h" +#include "kis_tool_factory.h" +#include "kis_tool_non_paint.h" + +class KisSelectionOptions; + +class KisToolSelectElliptical : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolSelectElliptical(); + virtual ~KisToolSelectElliptical(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 4; } + virtual TQWidget * createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + virtual enumToolType toolType() { return TOOL_SELECT; } + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + + +private: + void clearSelection(); + void paintOutline(); + void paintOutline(KisCanvasPainter& gc, const TQRect& rc); + +private: + KisCanvasSubject *m_subject; + KisPoint m_centerPos; + KisPoint m_startPos; + KisPoint m_endPos; + bool m_selecting; + KisSelectionOptions * m_optWidget; + enumSelectionMode m_selectAction; +}; + +class KisToolSelectEllipticalFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectEllipticalFactory() : super() {}; + virtual ~KisToolSelectEllipticalFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectElliptical(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("ellipticalselect", i18n("Elliptical Select Tool")); } +}; + + + + + +#endif //__KIS_TOOL_SELECT_ELLIPTICAL_H__ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.cc new file mode 100644 index 00000000..58a7778c --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.cc @@ -0,0 +1,156 @@ +/* + * kis_tool_select_brush.cc - part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_brush.h" +#include "kis_layer.h" +#include "kis_paintop.h" +#include "kis_paintop_registry.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_cmb_composite.h" +#include "kis_cursor.h" +#include "kis_doc.h" +#include "kis_move_event.h" +#include "kis_painter.h" +#include "kis_selection.h" +#include "kis_tool_select_eraser.h" +#include "kis_types.h" +#include "kis_view.h" +#include "kis_selection_options.h" + +KisToolSelectEraser::KisToolSelectEraser() + : super(i18n("SelectEraser")) +{ + setName("tool_select_eraser"); + setCursor(KisCursor::load("tool_eraser_selection_cursor.png", 5, 5)); + m_optWidget = 0; + m_paintOnSelection = true; +} + +KisToolSelectEraser::~KisToolSelectEraser() +{ +} + +void KisToolSelectEraser::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectEraser::initPaint(KisEvent */*e*/) +{ + if (!m_currentImage || !m_currentImage->activeDevice()) return; + + m_mode = PAINT; + m_dragDist = 0; + + // Create painter + KisPaintDeviceSP dev = m_currentImage->activeDevice(); + + if (dev == 0) return; + + if (m_painter) + delete m_painter; + if(! dev->hasSelection()) + { + dev->selection()->clear(); + dev->emitSelectionChanged(); + } + KisSelectionSP selection = dev->selection(); + + m_target = selection; + m_painter = new KisPainter(selection.data()); + Q_CHECK_PTR(m_painter); + m_painter->beginTransaction(i18n("Selection Eraser")); + m_painter->setPaintColor(KisColor(TQt::white, selection->colorSpace())); + m_painter->setBrush(m_subject->currentBrush()); + m_painter->setOpacity(OPACITY_OPAQUE); + m_painter->setCompositeOp(COMPOSITE_ERASE); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("eraser", 0, painter()); + painter()->setPaintOp(op); // And now the painter owns the op and will destroy it. + + // Set the cursor -- ideally. this should be a tqmask created from the brush, + // now that X11 can handle colored cursors. +#if 0 + // Setting cursors has no effect until the tool is selected again; this + // should be fixed. + setCursor(KisCursor::eraserCursor()); +#endif +} + +void KisToolSelectEraser::endPaint() { + super::endPaint(); + if (m_currentImage && m_currentImage->activeDevice()) + m_currentImage->activeDevice()->emitSelectionChanged(); +} +void KisToolSelectEraser::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("Selection &Eraser"), + "tool_eraser_selection", "Ctrl+Shift+E", this, + TQT_SLOT(activate()), collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Erase parts of a selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQWidget* KisToolSelectEraser::createOptionWidget(TQWidget* tqparent) +{ + Q_UNUSED(tqparent); + // Commented out due to the fact that this doesn't actually work if you change the action +#if 0 + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Selection Eraser")); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +#endif + return 0; +} + +TQWidget* KisToolSelectEraser::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_select_eraser.moc" + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.h b/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.h new file mode 100644 index 00000000..85bd5509 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_eraser.h @@ -0,0 +1,82 @@ +/* + * kis_tool_select_eraser.h - part of Chalk + * + * Copyright (c) 2003-2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_SELECT_ERASER_H_ +#define KIS_TOOL_SELECT_ERASER_H_ + +#include +#include + +class KisPoint; +class KisSelectionOptions; + + +/** + * The selection eraser makes a selection smaller by painting with the + * current eraser tqshape. Not sure what kind of an icon could represent + * this... Depends a bit on how we're going to visualize selections. + */ +class KisToolSelectEraser : public KisToolFreehand { + Q_OBJECT + TQ_OBJECT + typedef KisToolFreehand super; + +public: + KisToolSelectEraser(); + virtual ~KisToolSelectEraser(); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 2; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + +public slots: + virtual void activate(); + +protected: + + virtual void initPaint(KisEvent *e); + virtual void endPaint(); +private: + KisSelectionOptions * m_optWidget; + +}; + + +class KisToolSelectEraserFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectEraserFactory() : super() {}; + virtual ~KisToolSelectEraserFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectEraser(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("eraserselect", i18n("Eraser Select Tool")); } +}; + + + +#endif // KIS_TOOL_SELECT_ERASER_H_ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_outline.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_outline.cc new file mode 100644 index 00000000..b81762fb --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_outline.cc @@ -0,0 +1,295 @@ +/* + * kis_tool_select_freehand.h - part of Krayon^WChalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_selected_transaction.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +KisToolSelectOutline::KisToolSelectOutline() + : super(i18n("Select Outline")) +{ + setName("tool_select_outline"); + setCursor(KisCursor::load("tool_outline_selection_cursor.png", 5, 5)); + + m_subject = 0; + m_dragging = false; + m_optWidget = 0; + m_selectAction = SELECTION_ADD; +} + +KisToolSelectOutline::~KisToolSelectOutline() +{ +} + +void KisToolSelectOutline::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectOutline::update (KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolSelectOutline::buttonPress(KisButtonPressEvent *event) +{ + if (event->button() == Qt::LeftButton) { + m_dragging = true; + + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.clear(); + m_points.append(m_dragStart); + } +} + +void KisToolSelectOutline::move(KisMoveEvent *event) +{ + if (m_dragging) { + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + m_points.append (m_dragEnd); + // draw new lines on canvas + draw(); + } +} + +void KisToolSelectOutline::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + m_dragging = false; + deactivate(); + + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice()) { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintDeviceSP dev = img->activeDevice(); + bool hasSelection = dev->hasSelection(); + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Outline Selection"), dev); + KisSelectionSP selection = dev->selection(); + + if (!hasSelection) { + selection->clear(); + } + + KisPainter painter(selection.data()); + + painter.setPaintColor(KisColor(TQt::black, selection->colorSpace())); + painter.setFillStyle(KisPainter::FillStyleForegroundColor); + painter.setStrokeStyle(KisPainter::StrokeStyleNone); + painter.setBrush(m_subject->currentBrush()); + painter.setOpacity(OPACITY_OPAQUE); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("paintbrush", 0, &painter); + painter.setPaintOp(op); // And now the painter owns the op and will destroy it. + + switch (m_selectAction) { + case SELECTION_ADD: + painter.setCompositeOp(COMPOSITE_OVER); + break; + case SELECTION_SUBTRACT: + painter.setCompositeOp(COMPOSITE_SUBTRACT); + break; + default: + break; + } + + painter.paintPolygon(m_points); + + + if(hasSelection) { + TQRect dirty(painter.dirtyRect()); + dev->setDirty(dirty); + dev->emitSelectionChanged(dirty); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) + img->undoAdapter()->addCommand(t); + + TQApplication::restoreOverrideCursor(); + } + + m_points.clear(); + } +} + +void KisToolSelectOutline::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolSelectOutline::paint(KisCanvasPainter& gc, const TQRect&) +{ + draw(gc); +} + +void KisToolSelectOutline::draw() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + draw(gc); + } +} + +void KisToolSelectOutline::draw(KisCanvasPainter& gc) +{ + if (!m_subject) + return; + + if (m_dragging && !m_points.empty()) { + TQPen pen(TQt::white, 0, TQt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + startPos = controller->windowToView(m_dragStart.floorTQPoint()); + endPos = controller->windowToView(m_dragEnd.floorTQPoint()); + gc.drawLine(startPos, endPos); + } +} + +void KisToolSelectOutline::deactivate() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + TQPen pen(TQt::white, 0, TQt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + +void KisToolSelectOutline::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Outline Selection"), + "tool_outline_selection", + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select an outline")); + m_ownAction = true; + } +} + + +TQWidget* KisToolSelectOutline::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Outline Selection")); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectOutline::optionWidget() +{ + return m_optWidget; +} + +void KisToolSelectOutline::slotSetAction(int action) { + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +} + +#include "kis_tool_select_outline.moc" + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_outline.h b/chalk/plugins/tools/selectiontools/kis_tool_select_outline.h new file mode 100644 index 00000000..74ecab78 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_outline.h @@ -0,0 +1,101 @@ +/* + * kis_tool_select_freehand.h - part of Krayon^WChalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __selecttoolfreehand_h__ +#define __selecttoolfreehand_h__ + +#include +#include + +#include "kis_point.h" +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" +#include "kis_selection.h" + +class KisSelectionOptions; + +class KisToolSelectOutline : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT +public: + KisToolSelectOutline(); + virtual ~KisToolSelectOutline(); + + virtual void update (KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 6; } + virtual enumToolType toolType() { return TOOL_SELECT; } + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + + TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef TQValueVector KisPointVector; + KisCanvasSubject *m_subject; + KisPointVector m_points; + KisSelectionOptions * m_optWidget; + enumSelectionMode m_selectAction; +}; + + +class KisToolSelectOutlineFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectOutlineFactory() : super() {}; + virtual ~KisToolSelectOutlineFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectOutline(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("selectoutline", i18n("Select Outline tool")); } +}; + + +#endif //__selecttoolfreehand_h__ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.cc new file mode 100644 index 00000000..7bac7cc3 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.cc @@ -0,0 +1,315 @@ +/* + * kis_tool_select_polygonal.h - part of Krayon^WChalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_selected_transaction.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +KisToolSelectPolygonal::KisToolSelectPolygonal() + : super(i18n("Select Polygonal")) +{ + setName("tool_select_polygonal"); + setCursor(KisCursor::load("tool_polygonal_selection_cursor.png", 6, 6)); + + m_subject = 0; + m_dragging = false; + m_optWidget = 0; + m_selectAction = SELECTION_ADD; +} + +KisToolSelectPolygonal::~KisToolSelectPolygonal() +{ +} + +void KisToolSelectPolygonal::activate() +{ + m_points.clear(); + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectPolygonal::deactivate() +{ + draw(); + m_points.clear(); + m_dragging = false; +} + + +void KisToolSelectPolygonal::update (KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolSelectPolygonal::buttonPress(KisButtonPressEvent *event) +{ + if (event->button() == Qt::LeftButton) { + m_dragging = true; + + if (m_points.isEmpty()) + { + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.append(m_dragStart); + } else { + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + draw(); + } + } else if (event->button() == Qt::LeftButton && event->state() == ShiftButton) { + finish(); + } +} + + +void KisToolSelectPolygonal::doubleClick( KisDoubleClickEvent * ) +{ + finish(); +} + +void KisToolSelectPolygonal::finish() +{ + // erase old lines on canvas + draw(); + m_dragging = false; + + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice()) { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintDeviceSP dev = img->activeDevice(); + + bool hasSelection = dev->hasSelection(); + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Polygonal Selection"), dev); + KisSelectionSP selection = dev->selection(); + + if (!hasSelection) + { + selection->clear(); + } + + KisPainter painter(selection.data()); + painter.setPaintColor(KisColor(TQt::black, selection->colorSpace())); + painter.setFillStyle(KisPainter::FillStyleForegroundColor); + painter.setStrokeStyle(KisPainter::StrokeStyleNone); + painter.setBrush(m_subject->currentBrush()); + painter.setOpacity(OPACITY_OPAQUE); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("paintbrush", 0, &painter); + painter.setPaintOp(op); // And now the painter owns the op and will destroy it. + + switch(m_selectAction) + { + case SELECTION_ADD: + painter.setCompositeOp(COMPOSITE_OVER); + break; + case SELECTION_SUBTRACT: + painter.setCompositeOp(COMPOSITE_SUBTRACT); + break; + default: + break; + } + + painter.paintPolygon(m_points); + + if(hasSelection) { + TQRect rect(painter.dirtyRect()); + dev->setDirty(rect); + dev->emitSelectionChanged(rect); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) img->undoAdapter()->addCommand(t); + + TQApplication::restoreOverrideCursor(); + } + + m_points.clear(); + +} + +void KisToolSelectPolygonal::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(); + // get current mouse position + m_dragEnd = event->pos(); + // draw new lines on canvas + draw(); + } +} + +void KisToolSelectPolygonal::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == Qt::RightButton) { + + } +} + +void KisToolSelectPolygonal::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolSelectPolygonal::paint(KisCanvasPainter& gc, const TQRect&) +{ + draw(gc); +} + +void KisToolSelectPolygonal::draw() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + draw(gc); + } +} + +void KisToolSelectPolygonal::draw(KisCanvasPainter& gc) +{ + if (!m_subject) + return; + + TQPen pen(TQt::white, 0, TQt::DotLine); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorTQPoint()); + endPos = controller->windowToView(m_dragEnd.floorTQPoint()); + gc.drawLine(startPos, endPos); + } else { + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + + +void KisToolSelectPolygonal::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Polygonal Selection"), + "tool_polygonal_selection" , + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select a polygonal area")); + m_ownAction = true; + } +} + + +TQWidget* KisToolSelectPolygonal::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Polygonal Selection")); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectPolygonal::optionWidget() +{ + return m_optWidget; +} + +void KisToolSelectPolygonal::slotSetAction(int action) { + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +} + + + +#include "kis_tool_select_polygonal.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.h b/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.h new file mode 100644 index 00000000..65a32ee6 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_polygonal.h @@ -0,0 +1,106 @@ +/* + * kis_tool_select_polygonal.h - part of Krayon^WChalk + * + * Copyright (c) 2000 John Califf + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __selecttoolpolygonal_h__ +#define __selecttoolpolygonal_h__ + +#include "kis_point.h" +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" +#include "kis_selection.h" + +class KisSelectionOptions; + +class KisToolSelectPolygonal : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT +public: + KisToolSelectPolygonal(); + virtual ~KisToolSelectPolygonal(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 5; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual void doubleClick(KisDoubleClickEvent * event); + + void finish(); + TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef TQValueVector KisPointVector; + KisCanvasSubject *m_subject; + KisPointVector m_points; + KisSelectionOptions * m_optWidget; + enumSelectionMode m_selectAction; +}; + + +class KisToolSelectPolygonalFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectPolygonalFactory() : super() {}; + virtual ~KisToolSelectPolygonalFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectPolygonal(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("polygonalselect", i18n("Polygonal Select Tool")); } +}; + + +#endif //__selecttoolpolygonal_h__ + diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.cc b/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.cc new file mode 100644 index 00000000..aa7052af --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.cc @@ -0,0 +1,323 @@ + +/* + * kis_tool_select_rectangular.cc -- part of Chalk + * + * Copyright (c) 1999 Michael Koch + * 2001 John Califf + * 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_painter.h" +#include "kis_layer.h" +#include "kis_tool_select_rectangular.h" +#include "kis_undo_adapter.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_selection.h" +#include "kis_selection_options.h" +#include +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +KisToolSelectRectangular::KisToolSelectRectangular() + : super(i18n("Rectangular Select Tool")) +{ + setName("tool_select_rectangular"); + setCursor(KisCursor::load("tool_rectangular_selection_cursor.png", 6, 6)); + m_subject = 0; + m_selecting = false; + m_centerPos = KisPoint(0, 0); + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); + m_optWidget = 0; + m_selectAction = SELECTION_ADD; +} + +KisToolSelectRectangular::~KisToolSelectRectangular() +{ +} + +void KisToolSelectRectangular::activate() +{ + super::activate(); + + if (!m_optWidget) + return; + + m_optWidget->slotActivated(); +} + +void KisToolSelectRectangular::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolSelectRectangular::paint(KisCanvasPainter& gc) +{ + if (m_selecting) + paintOutline(gc, TQRect()); +} + +void KisToolSelectRectangular::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + if (m_selecting) + paintOutline(gc, rc); +} + +void KisToolSelectRectangular::clearSelection() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisImageSP img = m_subject->currentImg(); + + Q_ASSERT(controller); + + m_centerPos = KisPoint(0, 0); + m_startPos = KisPoint(0, 0); + m_endPos = KisPoint(0, 0); + m_selecting = false; + } +} + +void KisToolSelectRectangular::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && e->button() == Qt::LeftButton) { + clearSelection(); + m_startPos = m_endPos = m_centerPos = e->pos(); + m_selecting = true; + } + } +} + +void KisToolSelectRectangular::move(KisMoveEvent *e) +{ + if (m_subject && m_selecting) { + paintOutline(); + // move (alt) or resize rectangle + if (e->state() & TQt::AltButton) { + KisPoint trans = e->pos() - m_endPos; + m_startPos += trans; + m_endPos += trans; + } else { + KisPoint diag = e->pos() - (e->state() & TQt::ControlButton + ? m_centerPos : m_startPos); + // square? + if (e->state() & TQt::ShiftButton) { + double size = TQMAX(fabs(diag.x()), fabs(diag.y())); + double w = diag.x() < 0 ? -size : size; + double h = diag.y() < 0 ? -size : size; + diag = KisPoint(w, h); + } + + // resize around center point? + if (e->state() & TQt::ControlButton) { + m_startPos = m_centerPos - diag; + m_endPos = m_centerPos + diag; + } else { + m_endPos = m_startPos + diag; + } + } + paintOutline(); + m_centerPos = KisPoint((m_startPos.x() + m_endPos.x()) / 2, + (m_startPos.y() + m_endPos.y()) / 2); + } +} + +void KisToolSelectRectangular::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_selecting && e->button() == Qt::LeftButton) { + + paintOutline(); + + if (m_startPos == m_endPos) { + clearSelection(); + } else { + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + + if (m_endPos.y() < 0) + m_endPos.setY(0); + + if (m_endPos.y() > img->height()) + m_endPos.setY(img->height()); + + if (m_endPos.x() < 0) + m_endPos.setX(0); + + if (m_endPos.x() > img->width()) + m_endPos.setX(img->width()); + if (img && img->activeDevice()) { + + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintDeviceSP dev = img->activeDevice(); + bool hasSelection = dev->hasSelection(); + + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Rectangular Selection"), dev); + KisSelectionSP selection = dev->selection(); + TQRect rc(m_startPos.floorTQPoint(), m_endPos.floorTQPoint()); + rc = rc.normalize(); + + // We don't want the border of the 'rectangle' to be included in our selection + rc.setSize(rc.size() - TQSize(1,1)); + + if(! hasSelection) + { + selection->clear(); + if(m_selectAction==SELECTION_SUBTRACT) + selection->invert(); + } + + KisSelectionSP tmpSel = new KisSelection(dev); + tmpSel->select(rc); + switch(m_selectAction) + { + case SELECTION_ADD: + dev->addSelection(tmpSel); + break; + case SELECTION_SUBTRACT: + dev->subtractSelection(tmpSel); + break; + default: + break; + } + + + if(hasSelection) { + dev->setDirty(rc); + dev->emitSelectionChanged(rc); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (img->undo()) + img->undoAdapter()->addCommand(t); + + KisCanvasController *controller = m_subject -> canvasController(); + controller -> kiscanvas() -> update(); + + TQApplication::restoreOverrideCursor(); + } + } + + m_selecting = false; + } +} + +void KisToolSelectRectangular::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolSelectRectangular::paintOutline(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::DotLine); + TQPoint start; + TQPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_startPos.floorTQPoint()); + end = controller->windowToView(m_endPos.floorTQPoint()); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawRect(TQRect(start, end)); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolSelectRectangular::slotSetAction(int action) { + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +} + +void KisToolSelectRectangular::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Rectangular Selection"), + "tool_rect_selection", + TQt::Key_R, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Select a rectangular area")); + m_ownAction = true; + } +} + +TQWidget* KisToolSelectRectangular::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(i18n("Rectangular Selection")); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectRectangular::optionWidget() +{ + return m_optWidget; +} + + + + +#include "kis_tool_select_rectangular.moc" diff --git a/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.h b/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.h new file mode 100644 index 00000000..eb286cca --- /dev/null +++ b/chalk/plugins/tools/selectiontools/kis_tool_select_rectangular.h @@ -0,0 +1,95 @@ +/* + * kis_tool_select_rectangular.h - part of Chalk + * + * Copyright (c) 1999 Michael Koch + * 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_SELECT_RECTANGULAR_H_ +#define KIS_TOOL_SELECT_RECTANGULAR_H_ + +#include "kis_point.h" +#include "kis_tool_non_paint.h" +#include "kis_selection.h" +#include "kis_tool_factory.h" + +class KisSelectionOptions; + +class KisToolSelectRectangular : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolSelectRectangular(); + virtual ~KisToolSelectRectangular(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 3; } + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQWidget * createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + +public slots: + virtual void slotSetAction(int); + virtual void activate(); + + +private: + void clearSelection(); + void paintOutline(); + void paintOutline(KisCanvasPainter& gc, const TQRect& rc); + +private: + KisCanvasSubject *m_subject; + KisPoint m_centerPos; + KisPoint m_startPos; + KisPoint m_endPos; + bool m_selecting; + KisSelectionOptions * m_optWidget; + enumSelectionMode m_selectAction; + +}; + +class KisToolSelectRectangularFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectRectangularFactory() : super() {}; + virtual ~KisToolSelectRectangularFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectRectangular(); + t->setup(ac); + Q_CHECK_PTR(t); + return t; + } + virtual KisID id() { return KisID("rectangularselect", i18n("Rectangular Select Tool")); } +}; + + + +#endif // KIS_TOOL_SELECT_RECTANGULAR_H_ + diff --git a/chalk/plugins/tools/selectiontools/selection_tools.cc b/chalk/plugins/tools/selectiontools/selection_tools.cc new file mode 100644 index 00000000..db4df1ab --- /dev/null +++ b/chalk/plugins/tools/selectiontools/selection_tools.cc @@ -0,0 +1,77 @@ +/* + * selection_tools.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "selection_tools.h" + +#include "kis_tool_select_outline.h" +#include "kis_tool_select_polygonal.h" +#include "kis_tool_select_rectangular.h" +#include "kis_tool_select_contiguous.h" +#include "kis_tool_select_elliptical.h" +#include "kis_tool_select_eraser.h" +#include "kis_tool_select_brush.h" +#include "kis_tool_move_selection.h" + +typedef KGenericFactory SelectionToolsFactory; +K_EXPORT_COMPONENT_FACTORY( chalkselectiontools, SelectionToolsFactory( "chalk" ) ) + + +SelectionTools::SelectionTools(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(SelectionToolsFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + r->add(new KisToolSelectOutlineFactory()); + r->add(new KisToolSelectPolygonalFactory()); + r->add(new KisToolSelectRectangularFactory()); + r->add(new KisToolSelectBrushFactory()); + r->add(new KisToolSelectContiguousFactory()); + r->add(new KisToolSelectEllipticalFactory()); + r->add(new KisToolSelectEraserFactory()); + r->add(new KisToolMoveSelectionFactory()); + } +} + +SelectionTools::~SelectionTools() +{ +} + +#include "selection_tools.moc" diff --git a/chalk/plugins/tools/selectiontools/selection_tools.h b/chalk/plugins/tools/selectiontools/selection_tools.h new file mode 100644 index 00000000..2e448e3e --- /dev/null +++ b/chalk/plugins/tools/selectiontools/selection_tools.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SELECTION_TOOLS_H_ +#define SELECTION_TOOLS_H_ + +#include + +/** + * A module wrapper around Chalk's selection tools. + * Despite the fact that new tools are created for every new view, + * it is not possible to make tools standard parts of the type of the + * imagesize plugin, because we need to create a new set of tools for every + * pointer device (mouse, stylus, eraser, puck, etc.). So this plugin is + * a module which is loaded once into Chalk. For every tool there is a factory + * class that is registered with the tool registry, and that is used to create + * new instances of the tools. + */ +class SelectionTools : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + SelectionTools(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~SelectionTools(); + +}; + +#endif // SELECTION_TOOLS_H_ diff --git a/chalk/plugins/tools/selectiontools/tool_brush_selection.png b/chalk/plugins/tools/selectiontools/tool_brush_selection.png new file mode 100644 index 00000000..3d1bba3f Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_brush_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_brush_selection.svg b/chalk/plugins/tools/selectiontools/tool_brush_selection.svg new file mode 100644 index 00000000..228a411f --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_brush_selection.svg @@ -0,0 +1,827 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_brush_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_brush_selection_cursor.png new file mode 100644 index 00000000..96929d8f Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_brush_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_contiguous_selection.png b/chalk/plugins/tools/selectiontools/tool_contiguous_selection.png new file mode 100644 index 00000000..fcc8f36d Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_contiguous_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png new file mode 100644 index 00000000..0e3572cd Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_contiguous_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_elliptical_selection.png b/chalk/plugins/tools/selectiontools/tool_elliptical_selection.png new file mode 100644 index 00000000..ad585848 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_elliptical_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_elliptical_selection.svg b/chalk/plugins/tools/selectiontools/tool_elliptical_selection.svg new file mode 100644 index 00000000..31ff66f4 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_elliptical_selection.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png new file mode 100644 index 00000000..5e02f87b Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_elliptical_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_eraser_selection.png b/chalk/plugins/tools/selectiontools/tool_eraser_selection.png new file mode 100644 index 00000000..ffe2e440 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_eraser_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_eraser_selection.svg b/chalk/plugins/tools/selectiontools/tool_eraser_selection.svg new file mode 100644 index 00000000..9c147c1b --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_eraser_selection.svg @@ -0,0 +1,1993 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_eraser_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_eraser_selection_cursor.png new file mode 100644 index 00000000..e6b01060 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_eraser_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_outline_selection.png b/chalk/plugins/tools/selectiontools/tool_outline_selection.png new file mode 100644 index 00000000..ca1cb1d1 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_outline_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_outline_selection.svg b/chalk/plugins/tools/selectiontools/tool_outline_selection.svg new file mode 100644 index 00000000..2795dc86 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_outline_selection.svg @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_outline_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_outline_selection_cursor.png new file mode 100644 index 00000000..10ef65fe Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_outline_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_polygonal_selection.png b/chalk/plugins/tools/selectiontools/tool_polygonal_selection.png new file mode 100644 index 00000000..eda50984 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_polygonal_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_polygonal_selection.svg b/chalk/plugins/tools/selectiontools/tool_polygonal_selection.svg new file mode 100644 index 00000000..441dc125 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_polygonal_selection.svg @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png new file mode 100644 index 00000000..6bf000a7 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_polygonal_selection_cursor.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_rect_selection.png b/chalk/plugins/tools/selectiontools/tool_rect_selection.png new file mode 100644 index 00000000..7cb658c8 Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_rect_selection.png differ diff --git a/chalk/plugins/tools/selectiontools/tool_rect_selection.svg b/chalk/plugins/tools/selectiontools/tool_rect_selection.svg new file mode 100644 index 00000000..824bcc78 --- /dev/null +++ b/chalk/plugins/tools/selectiontools/tool_rect_selection.svg @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png b/chalk/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png new file mode 100644 index 00000000..548d8ace Binary files /dev/null and b/chalk/plugins/tools/selectiontools/tool_rectangular_selection_cursor.png differ diff --git a/chalk/plugins/tools/tool_crop/Makefile.am b/chalk/plugins/tools/tool_crop/Makefile.am new file mode 100644 index 00000000..66157332 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/Makefile.am @@ -0,0 +1,37 @@ +kde_services_DATA = chalktoolcrop.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolcrop_la_SOURCES = \ + wdg_tool_crop.ui \ + tool_crop.cc \ + kis_tool_crop.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolcrop.la + +noinst_HEADERS = \ + tool_crop.h \ + kis_tool_crop.h + +chalktoolcrop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolcrop_la_LIBADD = ../../../libchalkcommon.la + +chalktoolcrop_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_crop_cursor.png \ + tool_crop.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_crop/chalktoolcrop.desktop b/chalk/plugins/tools/tool_crop/chalktoolcrop.desktop new file mode 100644 index 00000000..ef80a5e6 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/chalktoolcrop.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Name=Crop Tool +Name[bg]=Инструмент за изрязване +Name[br]=Ostilh krennañ +Name[ca]=Eina de tall +Name[cy]=Hidlen Docio +Name[da]=Beskæringsværktøj +Name[de]=Zuschneidewerkzeug +Name[el]=Εργαλείο αποκοπής +Name[eo]=Tondado-ilo +Name[es]=Herramienta para recortar +Name[et]=Kärpimistööriist +Name[eu]=Ebaki tresna +Name[fa]=ابزار خط برش +Name[fr]=Outil découpage +Name[fy]=Bysnei-ark +Name[ga]=Uirlis Bhearrtha +Name[gl]=Ferramenta de Recorte +Name[he]=כלי חיתוך +Name[hu]=Levágó eszköz +Name[is]=Sniðtól +Name[it]=Strumento di taglio +Name[ja]=切り取りツール +Name[km]=ឧបករណ៍​ច្រឹប +Name[ms]=Alat Pangkas +Name[nb]=Beskjæringsverktøy +Name[nds]=Tosniedwarktüüch +Name[ne]=उपकरण काटछाँट गर्नुहोस् +Name[nl]=Snijgereedschap +Name[nn]=Beskjæringsverktøy +Name[pl]=Narzędzie przycinania +Name[pt]=Ferramenta de Recorte +Name[pt_BR]=Ferramenta de Recorte +Name[ru]=Обрезка +Name[se]=Čuohpanreaiddut +Name[sk]=Orezávač +Name[sl]=Orodje za obrezavo +Name[sr]=Алат за сасецање +Name[sr@Latn]=Alat za sasecanje +Name[sv]=Beskärningsverktyg +Name[uk]=Засіб обрізування +Name[zh_CN]=裁剪工具 +Name[zh_TW]=剪裁工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolcrop +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_crop/kis_tool_crop.cc b/chalk/plugins/tools/tool_crop/kis_tool_crop.cc new file mode 100644 index 00000000..30709fd7 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/kis_tool_crop.cc @@ -0,0 +1,925 @@ +/* + * kis_tool_crop.cc -- part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Michael Thaler + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_tool_crop.h" +#include "wdg_tool_crop.h" + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + + + +KisToolCrop::KisToolCrop() + : super(i18n("Crop")) +{ + setName("tool_crop"); + m_cropCursor = KisCursor::load("tool_crop_cursor.png", 6, 6); + setCursor(m_cropCursor); + m_subject = 0; + m_selecting = false; + m_rectCrop = TQRect(0, 0, 0, 0); + m_handleSize = 13; + m_haveCropSelection = false; + m_optWidget = 0; +} + +KisToolCrop::~KisToolCrop() +{ +} + +void KisToolCrop::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolCrop::activate() +{ + super::activate(); + + // No current crop rectangle, try to use the selection of the device to make a rectangle + if (m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice()) { + KisPaintDeviceSP device = m_subject->currentImg()->activeDevice(); + if (!device->hasSelection()) { + //m_rectCrop = m_subject->currentImg()->bounds(); + //validateSelection(); + m_haveCropSelection = false; + m_selecting = false; + } + else { + + m_rectCrop = device->selection()->selectedRect(); + validateSelection(); + crop(); + } + } +} + +void KisToolCrop::deactivate() +{ + clearRect(); +} + + +void KisToolCrop::paint(KisCanvasPainter& gc) +{ + paintOutlineWithHandles(gc, TQRect()); +} + +void KisToolCrop::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + paintOutlineWithHandles(gc, rc); +} + +void KisToolCrop::clearRect() +{ + kdDebug() << "Clearing\n"; + if (m_subject) { + + KisCanvasController *controller = m_subject->canvasController(); + KisImageSP img = m_subject->currentImg(); + + Q_ASSERT(controller); + + controller->kiscanvas()->update(); + + m_rectCrop = TQRect(0,0,0,0); + + updateWidgetValues(); + m_selecting = false; + } +} + +void KisToolCrop::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && e->button() == Qt::LeftButton) { + + TQPoint pos = e->pos().floorTQPoint(); + TQRect b = img->bounds(); + + if (pos.x() < b.x()) + pos.setX(b.x()); + else if (pos.x() > b.x() + b.width()) + pos.setX(b.x() + b.width()); + + if (pos.y() < b.y()) + pos.setY(b.y()); + else if (pos.y() > b.y() + b.height()) + pos.setY(b.y() + b.height()); + + m_selecting = true; + + if( !m_haveCropSelection ) //if the selection is not set + { + m_rectCrop = TQRect( pos.x(), pos.y(), 0, 0); + paintOutlineWithHandles(); + } + else + { + KisCanvasController *controller = m_subject->canvasController(); + m_mouseOnHandleType = mouseOnHandle(controller ->windowToView(pos)); + m_dragStart = pos; + } + + updateWidgetValues(); + } + } +} + +void KisToolCrop::move(KisMoveEvent *e) +{ + if ( m_subject && m_subject->currentImg()) + { + if( m_selecting ) //if the user selects + { + if( !m_haveCropSelection ) //if the cropSelection is not yet set + { + paintOutlineWithHandles(); + + m_rectCrop.setBottomRight( e->pos().floorTQPoint()); + + KisImageSP image = m_subject->currentImg(); + + m_rectCrop.setRight( TQMIN(m_rectCrop.right(), image->width())); + m_rectCrop.setBottom( TQMIN(m_rectCrop.bottom(), image->width())); + m_rectCrop = m_rectCrop.normalize(); + + paintOutlineWithHandles(); + } + else //if the crop selection is set + { + m_dragStop = e->pos().floorTQPoint(); + if (m_mouseOnHandleType != None && m_dragStart != m_dragStop ) { + + + TQ_INT32 imageWidth = m_subject->currentImg()->width(); + TQ_INT32 imageHeight = m_subject->currentImg()->height(); + + paintOutlineWithHandles(); + + TQPoint pos = e->pos().floorTQPoint(); + if( m_mouseOnHandleType == Inside ) + { + m_rectCrop.moveBy( ( m_dragStop.x() - m_dragStart.x() ), ( m_dragStop.y() - m_dragStart.y() ) ); + if( m_rectCrop.left() < 0 ) + { + m_rectCrop.moveLeft( 0 ); + } + if( m_rectCrop.right() > imageWidth ) + { + m_rectCrop.moveRight( imageWidth ); + } + if( m_rectCrop.top() < 0 ) + { + m_rectCrop.moveTop( 0 ); + } + if( m_rectCrop.bottom() > imageHeight ) + { + m_rectCrop.moveBottom( imageHeight ); + } + } else if(m_optWidget->boolRatio->isChecked()) + { + TQPoint drag = m_dragStop - m_dragStart; + if( ! m_optWidget->boolWidth->isChecked() && !m_optWidget->boolHeight->isChecked() ) + { + switch (m_mouseOnHandleType) + { + case (UpperLeft): + { + TQ_INT32 dep = (drag.x() + drag.y()) / 2; + m_rectCrop.setTop( m_rectCrop.top() + dep ); + m_rectCrop.setLeft( (int) ( m_rectCrop.right() - m_optWidget->doubleRatio->value() * m_rectCrop.height() ) ); + } + break; + case (LowerRight): + { + TQ_INT32 dep = (drag.x() + drag.y()) / 2; + m_rectCrop.setBottom( m_rectCrop.bottom() + dep ); + m_rectCrop.setWidth( (int) ( m_optWidget->doubleRatio->value() * m_rectCrop.height() ) ); + break; + } + case (UpperRight): + { + TQ_INT32 dep = (drag.x() - drag.y()) / 2; + m_rectCrop.setTop( m_rectCrop.top() - dep ); + m_rectCrop.setWidth( (int) ( m_optWidget->doubleRatio->value() * m_rectCrop.height() ) ); + break; + } + case (LowerLeft): + { + TQ_INT32 dep = (drag.x() - drag.y()) / 2; + m_rectCrop.setBottom( m_rectCrop.bottom() - dep ); + m_rectCrop.setLeft( (int) ( m_rectCrop.right() - m_optWidget->doubleRatio->value() * m_rectCrop.height() ) ); + break; + } + case (Upper): + m_rectCrop.setTop( pos.y() + m_dy ); + m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) ); + break; + case (Lower): + m_rectCrop.setBottom( pos.y() + m_dy ); + m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) ); + break; + case (Left): + m_rectCrop.setLeft( pos.x() + m_dx ); + m_rectCrop.setHeight( (int) (m_rectCrop.width() / m_optWidget->doubleRatio->value()) ); + break; + case (Right): + m_rectCrop.setRight( pos.x() + m_dx ); + m_rectCrop.setHeight( (int) (m_rectCrop.width() / m_optWidget->doubleRatio->value()) ); + break; + case (Inside): // never happen + break; + } + } + } else { + if( m_optWidget->boolWidth->isChecked() ) + { + m_rectCrop.setWidth( m_optWidget->intWidth->value() + 1 ); + } else { + switch (m_mouseOnHandleType) + { + case (LowerLeft): + case (Left): + case (UpperLeft): + m_rectCrop.setLeft( pos.x() + m_dx ); + break; + case (Right): + case (UpperRight): + case (LowerRight): + m_rectCrop.setRight( pos.x() + m_dx ); + break; + default: + break; + } + } + if( m_optWidget->boolHeight->isChecked() ) + { + m_rectCrop.setHeight( m_optWidget->intHeight->value() + 1 ); + } else { + switch (m_mouseOnHandleType) + { + case (UpperLeft): + case (Upper): + case (UpperRight): + m_rectCrop.setTop( pos.y() + m_dy ); + break; + case (LowerRight): + case (LowerLeft): + case (Lower): + m_rectCrop.setBottom( pos.y() + m_dy ); + break; + default: + break; + } + } + } + if( m_rectCrop.height() < 0) + { + if( m_mouseOnHandleType == Lower) + m_mouseOnHandleType = Upper; + else if( m_mouseOnHandleType == LowerLeft) + m_mouseOnHandleType = UpperLeft; + else if( m_mouseOnHandleType == LowerRight) + m_mouseOnHandleType = UpperRight; + else if( m_mouseOnHandleType == Upper) + m_mouseOnHandleType = Lower; + else if( m_mouseOnHandleType == UpperLeft) + m_mouseOnHandleType = LowerLeft; + else if( m_mouseOnHandleType == UpperRight) + m_mouseOnHandleType = LowerRight; + } + if( m_rectCrop.width() < 0) + { + if( m_mouseOnHandleType == Right) + m_mouseOnHandleType = Left; + else if( m_mouseOnHandleType == UpperRight) + m_mouseOnHandleType = UpperLeft; + else if( m_mouseOnHandleType == LowerRight) + m_mouseOnHandleType = LowerLeft; + else if( m_mouseOnHandleType == Left) + m_mouseOnHandleType = Right; + else if( m_mouseOnHandleType == UpperLeft) + m_mouseOnHandleType = UpperRight; + else if( m_mouseOnHandleType == LowerLeft) + m_mouseOnHandleType = LowerRight; + } + + m_rectCrop = m_rectCrop.normalize(); + m_rectCrop = m_rectCrop.intersect( TQRect(0,0, imageWidth + 1, imageHeight + 1 ) ); + m_dragStart = e->pos().floorTQPoint(); + paintOutlineWithHandles(); + } + } + updateWidgetValues(); + } + else //if we are not selecting + { + if ( m_haveCropSelection ) //if the crop selection is set + { + KisCanvasController *controller = m_subject->canvasController(); + TQ_INT32 type = mouseOnHandle(controller->windowToView(e->pos().floorTQPoint())); + //set resize cursor if we are on one of the handles + setMoveResizeCursor(type); + } + } + } +} + +void KisToolCrop::updateWidgetValues(bool updateratio) +{ + TQRect r = realRectCrop(); + setOptionWidgetX(r.x()); + setOptionWidgetY(r.y()); + setOptionWidgetWidth(r.width() ); + setOptionWidgetHeight(r.height() ); + if(updateratio && !m_optWidget->boolRatio->isChecked() ) + setOptionWidgetRatio((double)r.width() / (double)r.height() ); +} + +void KisToolCrop::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_subject->currentImg() && m_selecting && e->button() == Qt::LeftButton) { + + m_selecting = false; + m_haveCropSelection = true; + + paintOutlineWithHandles(); + validateSelection(); + paintOutlineWithHandles(); + } +} + +void KisToolCrop::doubleClick(KisDoubleClickEvent *) +{ + if (m_haveCropSelection) crop(); +} + +void KisToolCrop::validateSelection(bool updateratio) +{ + if (m_subject) { + KisImageSP image = m_subject->currentImg(); + + if (image) { + TQ_INT32 imageWidth = image->width(); + TQ_INT32 imageHeight = image->height(); + m_rectCrop.setLeft(TQMAX(0, m_rectCrop.left())); + m_rectCrop.setTop(TQMAX(0, m_rectCrop.top())); + m_rectCrop.setRight(TQMIN(imageWidth, m_rectCrop.right())); + m_rectCrop.setBottom(TQMIN(imageHeight, m_rectCrop.bottom())); + + updateWidgetValues(updateratio); + } + } +} + +void KisToolCrop::paintOutlineWithHandles() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutlineWithHandles(gc, rc); + } +} + +void KisToolCrop::paintOutlineWithHandles(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject && (m_selecting || m_haveCropSelection)) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::SolidLine); + pen.setWidth(1); + TQPoint start; + TQPoint end; + + Q_ASSERT(controller); + start = controller->windowToView(m_rectCrop.topLeft()); + end = controller->windowToView(m_rectCrop.bottomRight()); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + //draw handles + m_handlesRegion = handles(TQRect(start, end)); + + TQ_INT32 startx; + TQ_INT32 starty; + TQ_INT32 endx; + TQ_INT32 endy; + if(start.x()<=end.x()) + { + startx=start.x(); + endx=end.x(); + } + else + { + startx=end.x(); + endx=start.x(); + } + if(start.y()<=end.y()) + { + starty=start.y(); + endy=end.y(); + } + else + { + starty=end.y(); + endy=start.y(); + } + //draw upper line of selection + gc.drawLine(startx + m_handleSize / 2 + 1, starty, startx + (endx - startx - m_handleSize) / 2 + 1, starty); + gc.drawLine(startx + (endx - startx + m_handleSize) / 2 + 1, starty, endx - m_handleSize / 2, starty); + //draw lower line of selection + gc.drawLine(startx + m_handleSize / 2 + 1, endy, startx + (endx - startx - m_handleSize) / 2 + 1, endy); + gc.drawLine(startx + (endx - startx + m_handleSize) / 2 + 1, endy, endx - m_handleSize / 2 , endy); + //draw right line of selection + gc.drawLine(startx, starty + m_handleSize / 2 + 1, startx, starty + (endy - starty - m_handleSize) / 2 + 1); + gc.drawLine(startx, starty + (endy - starty + m_handleSize) / 2 + 1, startx, endy - m_handleSize / 2); + //draw left line of selection + gc.drawLine(endx, starty + m_handleSize / 2 + 1, endx, starty + (endy - starty - m_handleSize) / 2 + 1); + gc.drawLine(endx, starty + (endy - starty + m_handleSize) / 2 + 1, endx, endy - m_handleSize / 2); + + //draw guides + gc.drawLine(0,endy,startx - m_handleSize / 2,endy); + gc.drawLine(startx,endy + m_handleSize / 2 + 1, startx, controller->kiscanvas()->height()); + gc.drawLine(endx,0,endx,starty - m_handleSize / 2); + gc.drawLine(endx + m_handleSize / 2 + 1,starty, controller->kiscanvas()->width(), starty); + TQMemArray rects = m_handlesRegion.tqrects (); + for (TQMemArray ::ConstIterator it = rects.begin (); it != rects.end (); ++it) + { + gc.fillRect (*it, TQt::black); + } + + + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolCrop::crop() { + // XXX: Should cropping be part of KisImage/KisPaintDevice's API? + + m_haveCropSelection = false; + setCursor(m_cropCursor); + + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + + TQRect rc = realRectCrop().normalize(); + + // The visitor adds the undo steps to the macro + if (m_optWidget->cmbType->currentItem() == 0) { + + TQRect dirty = img->bounds(); + + // The layer(s) under the current layer will take care of adding + // undo information to the Crop macro. + if (img->undo()) + img->undoAdapter()->beginMacro(i18n("Crop")); + + KisCropVisitor v(rc, false); + KisLayerSP layer = img->activeLayer(); + layer->accept(v); + layer->setDirty( dirty ); + if (img->undo()) + img->undoAdapter()->endMacro(); + + } + else { + // Resize creates the undo macro itself + img->resize(rc, true); + } + + m_rectCrop = TQRect(0,0,0,0); + + updateWidgetValues(); +} + +void KisToolCrop::setCropX(int x) +{ + if (!m_haveCropSelection) { + m_haveCropSelection = true; + } + else { + paintOutlineWithHandles(); // remove outlines + } + + m_rectCrop.setX(x); + + validateSelection(); + paintOutlineWithHandles(); +} + +void KisToolCrop::setCropY(int y) +{ + if (!m_haveCropSelection) { + m_haveCropSelection = true; + } + else { + paintOutlineWithHandles(); // remove outlines + } + + m_rectCrop.setY(y); + + validateSelection(); + paintOutlineWithHandles(); + +} + +void KisToolCrop::setCropWidth(int w) +{ + if (!m_haveCropSelection) { + m_haveCropSelection = true; + } + else { + paintOutlineWithHandles(); // remove outlines + } + + m_rectCrop.setWidth(w + 1); + + if( m_optWidget->boolRatio->isChecked() ) + { + m_rectCrop.setHeight( (int) ( w / m_optWidget->doubleRatio->value() ) ); + } else { + setOptionWidgetRatio((double)m_rectCrop.width() / (double)m_rectCrop.height() ); + } + + validateSelection(); + paintOutlineWithHandles(); + +} + +void KisToolCrop::setCropHeight(int h) +{ + if (!m_haveCropSelection) { + m_haveCropSelection = true; + } + else { + paintOutlineWithHandles(); // remove outlines + } + + m_rectCrop.setHeight(h + 1); + + if( m_optWidget->boolRatio->isChecked() ) + { + m_rectCrop.setWidth( (int) ( h * m_optWidget->doubleRatio->value() ) ); + } else { + setOptionWidgetRatio((double)m_rectCrop.width() / (double)m_rectCrop.height() ); + } + + validateSelection(); + paintOutlineWithHandles(); + +} + +void KisToolCrop::setRatio(double ) +{ + if( ! (m_optWidget->boolWidth->isChecked() && m_optWidget->boolHeight->isChecked() )) + { + if (!m_haveCropSelection) { + m_haveCropSelection = true; + } + else { + paintOutlineWithHandles(); // remove outlines + } + if( m_optWidget->boolWidth->isChecked() ) + { + m_rectCrop.setHeight( (int) ( m_rectCrop.width() / m_optWidget->doubleRatio->value()) ); + setOptionWidgetHeight( m_rectCrop.height() ); + } else if(m_optWidget->boolHeight->isChecked()) { + m_rectCrop.setWidth( (int) (m_rectCrop.height() * m_optWidget->doubleRatio->value()) ); + setOptionWidgetWidth( m_rectCrop.width() ); + } else { + int newwidth = (int) (m_optWidget->doubleRatio->value() * m_rectCrop.height()); + newwidth = (newwidth + m_rectCrop.width()) / 2; + m_rectCrop.setWidth( newwidth + 1); + setOptionWidgetWidth( newwidth ); + m_rectCrop.setHeight( (int) (newwidth / m_optWidget->doubleRatio->value()) + 1 ); + setOptionWidgetHeight( m_rectCrop.height() - 1 ); + } + validateSelection(false); + paintOutlineWithHandles(); + } +} + +void KisToolCrop::setOptionWidgetX(TQ_INT32 x) +{ + // Disable signals otherwise we get the valueChanged signal, which we don't want + // to go through the logic for setting values that way. + m_optWidget->intX->blockSignals(true); + m_optWidget->intX->setValue(x); + m_optWidget->intX->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetY(TQ_INT32 y) +{ + m_optWidget->intY->blockSignals(true); + m_optWidget->intY->setValue(y); + m_optWidget->intY->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetWidth(TQ_INT32 x) +{ + m_optWidget->intWidth->blockSignals(true); + m_optWidget->intWidth->setValue(x); + m_optWidget->intWidth->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetHeight(TQ_INT32 y) +{ + m_optWidget->intHeight->blockSignals(true); + m_optWidget->intHeight->setValue(y); + m_optWidget->intHeight->blockSignals(false); +} + +void KisToolCrop::setOptionWidgetRatio(double ratio) +{ + m_optWidget->doubleRatio->blockSignals(true); + m_optWidget->doubleRatio->setValue(ratio); + m_optWidget->doubleRatio->blockSignals(false); +} + + +TQWidget* KisToolCrop::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new WdgToolCrop(tqparent); + Q_CHECK_PTR(m_optWidget); + + connect(m_optWidget->bnCrop, TQT_SIGNAL(clicked()), this, TQT_SLOT(crop())); + + connect(m_optWidget->intX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropX(int))); + connect(m_optWidget->intY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropY(int))); + connect(m_optWidget->intWidth, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropWidth(int))); + connect(m_optWidget->intHeight, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setCropHeight(int))); + connect(m_optWidget->doubleRatio, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(setRatio( double ))); + + return m_optWidget; +} + +TQWidget* KisToolCrop::optionWidget() +{ + return m_optWidget; +} + +void KisToolCrop::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Crop"), + "tool_crop", + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Crop an area")); + m_action->setExclusiveGroup("tools"); + + m_ownAction = true; + } +} + +TQRect toTQRect(double x, double y, int w, int h) +{ + return TQRect(int(x), int(y), w, h); +} + +TQRegion KisToolCrop::handles(TQRect rect) +{ + TQRegion handlesRegion; + + //add handle at the lower right corner + handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0, TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the upper right corner + handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0 , 0 - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add rectangle at the lower left corner + handlesRegion += toTQRect( 0 - m_handleSize / 2.0 , TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add rectangle at the upper left corner + handlesRegion += toTQRect( 0 - m_handleSize / 2.0, 0 - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the lower edge of the rectangle + handlesRegion += toTQRect( ( TQABS( rect.width() ) - m_handleSize ) / 2.0 , TQABS( rect.height() ) - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the right edge of the rectangle + handlesRegion += toTQRect( TQABS( rect.width() ) - m_handleSize / 2.0 , ( TQABS( rect.height() ) - m_handleSize ) / 2.0, m_handleSize, m_handleSize ); + //add handle at the upper edge of the rectangle + handlesRegion += toTQRect( ( TQABS( rect.width() ) - m_handleSize ) / 2.0 , 0 - m_handleSize / 2.0, m_handleSize, m_handleSize ); + //add handle at the left edge of the rectangle + handlesRegion += toTQRect( 0 - m_handleSize / 2.0, ( TQABS( rect.height() ) - m_handleSize ) / 2.0, m_handleSize, m_handleSize ); + + //move the handles to the correct position + if( rect.width() >= 0 && rect.height() >= 0) + { + handlesRegion.translate ( rect.x(), rect.y() ); + } + else if( rect.width() < 0 && rect.height() >= 0) + { + handlesRegion.translate ( rect.x() - TQABS( rect.width() ), rect.y() ); + } + else if( rect.width() >= 0 && rect.height() < 0) + { + handlesRegion.translate ( rect.x(), rect.y() - TQABS( rect.height() ) ); + } + else if( rect.width() < 0 && rect.height() < 0) + { + handlesRegion.translate ( rect.x() - TQABS( rect.width() ), rect.y() - TQABS( rect.height() ) ); + } + return handlesRegion; +} + +TQ_INT32 KisToolCrop::mouseOnHandle(TQPoint currentViewPoint) +{ + KisCanvasController *controller = m_subject->canvasController(); + Q_ASSERT(controller); + TQPoint start = controller->windowToView(m_rectCrop.topLeft()); + TQPoint end = controller->windowToView(m_rectCrop.bottomRight()); + + TQ_INT32 startx; + TQ_INT32 starty; + TQ_INT32 endx; + TQ_INT32 endy; + if(start.x()<=end.x()) + { + startx=start.x(); + endx=end.x(); + } + else + { + startx=end.x(); + endx=start.x(); + } + if(start.y()<=end.y()) + { + starty=start.y(); + endy=end.y(); + } + else + { + starty=end.y(); + endy=start.y(); + } + + if ( toTQRect ( startx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx= startx-currentViewPoint.x(); + m_dy = starty - currentViewPoint.y(); + } + return UpperLeft; + } + else if ( toTQRect ( startx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = startx-currentViewPoint.x(); + m_dy = endy-currentViewPoint.y(); + } + return LowerLeft; + } + else if ( toTQRect ( endx - m_handleSize / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx - currentViewPoint.x(); + m_dy = starty - currentViewPoint.y() ; + } + return UpperRight; + } + else if ( toTQRect ( endx - m_handleSize / 2.0, endy - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx - currentViewPoint.x(); + m_dy= endy - currentViewPoint.y(); + } + return LowerRight; + } + else if ( toTQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, starty - m_handleSize / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dy = starty - currentViewPoint.y() ; + } + return Upper; + } + else if ( toTQRect ( startx + ( endx - startx - m_handleSize ) / 2.0, endy - m_handleSize / 2, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dy = endy - currentViewPoint.y(); + } + return Lower; + } + else if ( toTQRect ( startx - m_handleSize / 2.0, starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = startx - currentViewPoint.x() ; + } + return Left; + } + else if ( toTQRect ( endx - m_handleSize / 2.0 , starty + ( endy - starty - m_handleSize ) / 2.0, m_handleSize, m_handleSize ).tqcontains( currentViewPoint ) ) + { + if( !m_selecting ) + { + m_dx = endx-currentViewPoint.x(); + } + return Right; + } + else if ( toTQRect ( startx , starty, endx - startx , endy - starty ).tqcontains( currentViewPoint ) ) + { + return Inside; + } + else return None; +} + +void KisToolCrop::setMoveResizeCursor (TQ_INT32 handle) +{ + switch (handle) + { + case (UpperLeft): + case (LowerRight): + m_subject->canvasController()->setCanvasCursor(KisCursor::sizeFDiagCursor()); + return; + case (LowerLeft): + case (UpperRight): + m_subject->canvasController()->setCanvasCursor(KisCursor::sizeBDiagCursor()); + return; + case (Upper): + case (Lower): + m_subject->canvasController()->setCanvasCursor(KisCursor::sizeVerCursor()); + return; + case (Left): + case (Right): + m_subject->canvasController()->setCanvasCursor(KisCursor::sizeHorCursor()); + return; + case (Inside): + m_subject->canvasController()->setCanvasCursor(KisCursor::sizeAllCursor()); + return; + } + m_subject->canvasController()->setCanvasCursor(KisCursor::arrowCursor()); + return; +} + + +#include "kis_tool_crop.moc" diff --git a/chalk/plugins/tools/tool_crop/kis_tool_crop.h b/chalk/plugins/tools/tool_crop/kis_tool_crop.h new file mode 100644 index 00000000..7ad7c9fd --- /dev/null +++ b/chalk/plugins/tools/tool_crop/kis_tool_crop.h @@ -0,0 +1,149 @@ +/* + * kis_tool_crop.h - part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_CROP_H_ +#define KIS_TOOL_CROP_H_ + +#include +#include +#include +#include + +class TQRect; +class TQCursor; +class WdgToolCrop; + +/** + * Crop tool + * + * TODO: - crop from selection -- i.e, set crop outline to the exact bounds of the selection. + * - (when moving to TQt 4: replace rectangle with darker, dimmer overlay layer + * like we have for selections right now) + */ +class KisToolCrop : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + + KisToolCrop(); + virtual ~KisToolCrop(); + + virtual void update(KisCanvasSubject *subject); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual TQ_UINT32 priority() { return 1; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void doubleClick(KisDoubleClickEvent *); + +public slots: + + virtual void activate(); + virtual void deactivate(); + +private: + + void clearRect(); + TQRegion handles(TQRect rect); + void paintOutlineWithHandles(); + void paintOutlineWithHandles(KisCanvasPainter& gc, const TQRect& rc); + TQ_INT32 mouseOnHandle (const TQPoint currentViewPoint); + void setMoveResizeCursor (TQ_INT32 handle); + void validateSelection(bool updateratio = true); + void setOptionWidgetX(TQ_INT32 x); + void setOptionWidgetY(TQ_INT32 y); + void setOptionWidgetWidth(TQ_INT32 x); + void setOptionWidgetHeight(TQ_INT32 y); + void setOptionWidgetRatio(double ratio); + +private slots: + + void crop(); + void setCropX(int x); + void setCropY(int y); + void setCropWidth(int x); + void setCropHeight(int y); + void setRatio(double ratio); + + inline TQRect realRectCrop() { TQRect r = m_rectCrop; r.setSize(r.size() - TQSize(1,1)); return r; } + +private: + void updateWidgetValues(bool updateratio = true); + KisCanvasSubject *m_subject; + TQRect m_rectCrop; // Is the coordinate of the outline rect and not of the region to crop (to get the region to crop you need to remove 1 to width and height +// TQPoint m_startPos; +// TQPoint m_endPos; + bool m_selecting; + TQPoint m_dragStart; + TQPoint m_dragStop; + + WdgToolCrop* m_optWidget; + + TQ_INT32 m_handleSize; + TQRegion m_handlesRegion; + bool m_haveCropSelection; + TQ_INT32 m_dx, m_dy; + TQ_INT32 m_mouseOnHandleType; + TQCursor m_cropCursor; + + enum handleType + { + None = 0, + UpperLeft = 1, + UpperRight = 2, + LowerLeft = 3, + LowerRight = 4, + Upper = 5, + Lower = 6, + Left = 7, + Right = 8, + Inside = 9 + }; +}; + +class KisToolCropFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolCropFactory() : super() {}; + virtual ~KisToolCropFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolCrop(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("crop", i18n("Crop Tool")); } +}; + + + +#endif // KIS_TOOL_CROP_H_ + diff --git a/chalk/plugins/tools/tool_crop/tool_crop.cc b/chalk/plugins/tools/tool_crop/tool_crop.cc new file mode 100644 index 00000000..599c7562 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/tool_crop.cc @@ -0,0 +1,62 @@ +/* + * tool_crop.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_crop.h" +#include "kis_tool_crop.h" + + +typedef KGenericFactory ToolCropFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolcrop, ToolCropFactory( "chalk" ) ) + + +ToolCrop::ToolCrop(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolCropFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + r->add(new KisToolCropFactory()); + } + +} + +ToolCrop::~ToolCrop() +{ +} + +#include "tool_crop.moc" diff --git a/chalk/plugins/tools/tool_crop/tool_crop.h b/chalk/plugins/tools/tool_crop/tool_crop.h new file mode 100644 index 00000000..df5d7c28 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/tool_crop.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_CROP_H_ +#define TOOL_CROP_H_ + +#include + +class KisView; + +/** + * A module that provides a crop tool. + */ +class ToolCrop : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolCrop(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolCrop(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_CROP_H_ diff --git a/chalk/plugins/tools/tool_crop/tool_crop.png b/chalk/plugins/tools/tool_crop/tool_crop.png new file mode 100644 index 00000000..ce53d708 Binary files /dev/null and b/chalk/plugins/tools/tool_crop/tool_crop.png differ diff --git a/chalk/plugins/tools/tool_crop/tool_crop_cursor.png b/chalk/plugins/tools/tool_crop/tool_crop_cursor.png new file mode 100644 index 00000000..325461bb Binary files /dev/null and b/chalk/plugins/tools/tool_crop/tool_crop_cursor.png differ diff --git a/chalk/plugins/tools/tool_crop/wdg_tool_crop.ui b/chalk/plugins/tools/tool_crop/wdg_tool_crop.ui new file mode 100644 index 00000000..4f857cf9 --- /dev/null +++ b/chalk/plugins/tools/tool_crop/wdg_tool_crop.ui @@ -0,0 +1,216 @@ + +WdgToolCrop + + + WdgToolCrop + + + + 0 + 0 + 346 + 123 + + + + Crop + + + + unnamed + + + 0 + + + 0 + + + + tqlayout3 + + + + unnamed + + + 0 + + + 3 + + + + textLabel1 + + + X: + + + isbX + + + + + intX + + + 1000000000 + + + + + intHeight + + + 1000000000 + + + + + boolWidth + + + W&idth: + + + Will keep the width of the crop constant + + + + + intWidth + + + 1000000000 + + + + + intY + + + 1000000000 + + + + + boolHeight + + + &Height: + + + Will keep the height of the crop constant + + + + + textLabel3 + + + Y: + + + isbY + + + + + doubleRatio + + + 2 + + + + + boolRatio + + + R&atio: + + + Will keep the ratio constant + + + + + + + tqlayout9 + + + + unnamed + + + 0 + + + + + Layer + + + + + Image + + + + cmbType + + + 1 + + + + + bnCrop + + + &Crop + + + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + + + intX + intY + intWidth + intHeight + cmbType + bnCrop + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/tools/tool_curves/Makefile.am b/chalk/plugins/tools/tool_curves/Makefile.am new file mode 100644 index 00000000..5233106a --- /dev/null +++ b/chalk/plugins/tools/tool_curves/Makefile.am @@ -0,0 +1,56 @@ +kde_services_DATA = chalktoolcurves.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolcurves_la_SOURCES = \ + kis_curve_framework.cc \ + kis_tool_curve.cc \ + tool_curves.cc \ + wdg_tool_example.ui \ + kis_tool_example.cc \ + kis_tool_bezier.cc \ + kis_tool_bezier_paint.cc \ + kis_tool_bezier_select.cc \ + kis_tool_moutline.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolcurves.la + +noinst_HEADERS = \ + kis_curve_framework.h \ + kis_tool_curve.h \ + tool_curves.h \ + kis_tool_example.h \ + kis_tool_bezier.h \ + kis_tool_bezier_paint.h \ + kis_tool_bezier_select.h \ + kis_tool_moutline.h + +chalktoolcurves_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolcurves_la_LIBADD = ../../../libchalkcommon.la + +chalktoolcurves_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_example.png \ + tool_example_cursor.png \ + tool_bezier_paint.png \ + tool_bezier_select.png \ + tool_bezier_cursor.png \ + tool_moutline.png \ + tool_moutline_cursor.png \ + tool_curve_dragging.png \ + tool_moutline_editing.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_curves/chalktoolcurves.desktop b/chalk/plugins/tools/tool_curves/chalktoolcurves.desktop new file mode 100644 index 00000000..1ab54038 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/chalktoolcurves.desktop @@ -0,0 +1,36 @@ +[Desktop Entry] +Name=Curves Tool +Name[bg]=Инструмент криви +Name[ca]=Eina de corbes +Name[da]=Kurveværktøj +Name[de]=Kurvenwerkzeug +Name[el]=Εργαλείο καμπύλων +Name[eo]=Kurvado-ilo +Name[es]=Herramienta Curvas +Name[et]=Kõverate tööriist +Name[fa]=ابزار منحنیها +Name[fy]=Krommings-ark +Name[gl]=Ferramenta de Curvas +Name[hu]=Görberajzoló +Name[it]=Strumento curve +Name[ja]=曲線ツール +Name[km]=ឧបករណ៍​ខ្សែ​កោង +Name[nb]=Kurveverktøy +Name[nds]=Bagenwarktüüch +Name[ne]=वक्र उपकरण +Name[nl]=Krommen-gereedschap +Name[pl]=Narzędzie krzywych +Name[pt]=Ferramenta de Curvas +Name[pt_BR]=Ferramenta de Curvas +Name[ru]=Кривые +Name[sk]=Krivky +Name[sl]=Orodje za krivulje +Name[sr]=Алат за криве +Name[sr@Latn]=Alat za krive +Name[sv]=Kurvverktyg +Name[uk]=Криві +Name[zh_TW]=曲線工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolcurves +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_curves/kis_curve_framework.cc b/chalk/plugins/tools/tool_curves/kis_curve_framework.cc new file mode 100644 index 00000000..416d3bfd --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_curve_framework.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "kis_point.h" + +#include "kis_curve_framework.h" + +/* **************************** * + * KisCurve methods definitions * + * **************************** */ + +KisCurve::iterator KisCurve::addPivot (KisCurve::iterator it, const KisPoint& point) +{ + return iterator(*this,m_curve.insert(it.position(), CurvePoint(point,true,false,NOHINTS))); +} + +KisCurve::iterator KisCurve::pushPivot (const KisPoint& point) +{ + return selectPivot(iterator(*this,m_curve.append(CurvePoint(point,true,false,NOHINTS))), true); +} + +KisCurve::iterator KisCurve::addPoint (KisCurve::iterator it, const KisPoint& point, bool pivot, bool selected, int hint) +{ + return iterator(*this,m_curve.insert(it.position(), CurvePoint(point,pivot,selected, hint))); +} + +KisCurve::iterator KisCurve::addPoint (KisCurve::iterator it, const CurvePoint& point) +{ + return iterator(*this,m_curve.insert(it.position(), point)); +} + +KisCurve::iterator KisCurve::pushPoint (const KisPoint& point, bool pivot, bool selected,int hint) +{ + return iterator(*this,m_curve.append(CurvePoint(point,pivot,selected,hint))); +} + +KisCurve::iterator KisCurve::pushPoint (const CurvePoint& point) +{ + return iterator(*this,m_curve.append(point)); +} + +KisCurve KisCurve::pivots() +{ + KisCurve temp; + + for (iterator it = begin(); it != end(); it = it.nextPivot()) + temp.pushPoint((*it)); + + return temp; +} + +KisCurve KisCurve::selectedPivots(bool selected) +{ + KisCurve temp; + + for (iterator it = begin(); it != end(); it = it.nextPivot()) + if ((*it).isSelected() == selected) + temp.pushPoint((*it)); + + return temp; +} + +KisCurve KisCurve::subCurve(const KisPoint& tend) +{ + return subCurve(tqfind(tend).previousPivot(),tqfind(tend)); +} + +KisCurve KisCurve::subCurve(const CurvePoint& tend) +{ + return subCurve(tqfind(tend).previousPivot(),tqfind(tend)); +} + +KisCurve KisCurve::subCurve(iterator tend) +{ + return subCurve(tend.previousPivot(),tend); +} + +KisCurve KisCurve::subCurve(const KisPoint& tstart, const KisPoint& tend) +{ + return subCurve(tqfind(tstart),tqfind(tend)); +} + +KisCurve KisCurve::subCurve(const CurvePoint& tstart, const CurvePoint& tend) +{ + return subCurve(tqfind(tstart),tqfind(tend)); +} + +KisCurve KisCurve::subCurve(iterator tstart, iterator tend) +{ + KisCurve temp; + + while (tstart != tend && tstart != m_curve.end()) + temp.pushPoint((*++tstart)); + + return temp; +} + +void KisCurve::deleteFirstPivot () +{ + if (!m_curve.isEmpty()) { + m_curve.pop_front(); + while (m_curve.count() > 1 && !first().isPivot()) + m_curve.pop_front(); + } +} + +void KisCurve::deleteLastPivot () +{ + if (!m_curve.isEmpty()) { + m_curve.pop_back(); + while (m_curve.count() > 1 && !last().isPivot()) + m_curve.pop_back(); + } +} + +KisCurve::iterator KisCurve::deleteCurve (const KisPoint& pos1, const KisPoint& pos2) +{ + return deleteCurve (CurvePoint(pos1),CurvePoint(pos2)); +} + +KisCurve::iterator KisCurve::deleteCurve (const CurvePoint& pos1, const CurvePoint& pos2) +{ + return deleteCurve (tqfind(pos1),tqfind(pos2)); +} + +KisCurve::iterator KisCurve::deleteCurve (KisCurve::iterator pos1, KisCurve::iterator pos2) +{ + if (pos1 == pos2) + return end(); + iterator pos = pos1; + pos++; + while (pos != pos2 && pos != end()) { + pos = m_curve.erase(pos.position()); + } + return pos; +} + +KisCurve::iterator KisCurve::selectPivot(const KisPoint& pt, bool isSelected) +{ + return selectPivot(tqfind(CurvePoint(pt,true)),isSelected); +} + +KisCurve::iterator KisCurve::selectPivot(const CurvePoint& pt, bool isSelected) +{ + return selectPivot(tqfind(pt),isSelected); +} + +KisCurve::iterator KisCurve::selectPivot(KisCurve::iterator it, bool isSelected) +{ + bool sel = false; + if (m_standardkeepselected) { + if (m_actionOptions & KEEPSELECTEDOPTION) + sel = true; + } + KisCurve selected = pivots(); + for (iterator i = selected.begin(); i != selected.end(); i++) + (*tqfind((*i))).setSelected(sel); + (*it).setSelected(isSelected); + + return it; +} + +KisCurve::iterator KisCurve::movePivot(const KisPoint& oldPt, const KisPoint& newPt) +{ + return movePivot(CurvePoint(oldPt,true), newPt); +} + +KisCurve::iterator KisCurve::movePivot(const CurvePoint& oldPt, const KisPoint& newPt) +{ + return movePivot(tqfind(oldPt), newPt); +} + +KisCurve::iterator KisCurve::movePivot(KisCurve::iterator it, const KisPoint& newPt) +{ + if (!(*it).isPivot()) + return end(); + + (*it).setPoint(newPt); + + if ((*it) != first()) { + deleteCurve (it.previousPivot(), it); + calculateCurve (it.previousPivot(), it, it); + } + if ((*it) != last()) { + deleteCurve (it, it.nextPivot()); + calculateCurve (it, it.nextPivot(), it.nextPivot()); + } + + return it; +} + +void KisCurve::deletePivot (const KisPoint& pt) +{ + deletePivot(CurvePoint(pt)); +} + +void KisCurve::deletePivot (const CurvePoint& pt) +{ + deletePivot(tqfind(pt)); +} + +void KisCurve::deletePivot (KisCurve::iterator it) +{ + if (!(*it).isPivot()) + return; + + iterator start = it.previousPivot(); + iterator end = it.nextPivot(); + + if (end == m_curve.end()) + deleteLastPivot(); + else if (start == it) + deleteFirstPivot(); + else { + deleteCurve(start,end); + calculateCurve(start,end,end); + } +} + +// Probably it can be optimized - it is smooth though. +void KisCurve::moveSelected (const KisPoint& trans) +{ + KisPoint p; + KisCurve sel = selectedPivots(); + + for (iterator it = sel.begin(); it != sel.end(); it++) { + p = (*it).point() + trans; + movePivot((*it),p); + } +} + +void KisCurve::deleteSelected () +{ + KisCurve sel = selectedPivots(); + for (iterator it = sel.begin(); it != sel.end(); it++) + deletePivot((*it)); +} + +void KisCurve::selectAll(bool sel) +{ + for (iterator i = begin(); i != end(); i = i.nextPivot()) + (*i).setSelected(sel); +} diff --git a/chalk/plugins/tools/tool_curves/kis_curve_framework.h b/chalk/plugins/tools/tool_curves/kis_curve_framework.h new file mode 100644 index 00000000..c27369aa --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_curve_framework.h @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CURVE_FRAMEWORK_H_ +#define KIS_CURVE_FRAMEWORK_H_ + +#include "kis_point.h" + +const int NOHINTS = 0x0000; +const int POINTHINT = 0x0001; +const int LINEHINT = 0x0002; + +const int NOOPTIONS = 0x0000; +const int SHIFTOPTION = 0x0001; +const int CONTROLOPTION = 0x0002; +const int ALTOPTION = 0x0004; + +const int KEEPSELECTEDOPTION = CONTROLOPTION; + +class CurvePoint { + + KisPoint m_point; + bool m_pivot; + bool m_selected; // Only pivots can be selected + + int m_hint; + +public: + + /* Constructors and Destructor */ + + CurvePoint (); + CurvePoint (const KisPoint&, bool = false, bool = false, int = POINTHINT); + CurvePoint (double, double, bool = false, bool = false, int = POINTHINT); + + ~CurvePoint () {} + +public: + + /* Generic Functions */ + + bool operator!= (KisPoint p2) const { if (p2 != m_point) return true; else return false; } + bool operator!= (CurvePoint p2) const { if (p2.point() != m_point || + p2.isPivot() != m_pivot || + p2.hint() != m_hint) return true; else return false; } + + bool operator== (KisPoint p2) const { if (p2 == m_point) return true; else return false; } + bool operator== (CurvePoint p2) const { if (p2.point() == m_point && + p2.isPivot() == m_pivot && + p2.hint() == m_hint) return true; else return false; } + + KisPoint point() const {return m_point;} + + void setPoint(const KisPoint&); + void setPoint(double, double); + + bool isPivot() const {return m_pivot;} + bool isSelected() const {return m_selected;} + int hint() const {return m_hint;} + + void setPivot(bool p) {m_pivot = p;} + void setSelected(bool s) {m_selected = ((m_pivot) ? s : false);} /* Only pivots can be selected */ + void setHint(int h) {m_hint = h;} +}; + +typedef TQValueList PointList; +typedef TQValueList::iterator BaseIterator; + +class CurveIterator; + +class KisCurve { + +public: + + KisCurve () {m_actionOptions = NOOPTIONS; m_standardkeepselected = true;} + virtual ~KisCurve () {m_curve.clear();} + + friend class CurveIterator; + typedef CurveIterator iterator; + +protected: + /* I need it to be mutable because my iterator needs to access + m_curve's end() and begin() functions using a const KisCurve + (see below in CurveIterator) */ + mutable PointList m_curve; + int m_actionOptions; + + bool m_standardkeepselected; + + bool checkIterator (iterator checking) const; + +public: + + void setActionOptions (int options) {m_actionOptions = options;} + void endActionOptions () {m_actionOptions = NOOPTIONS;} + + CurvePoint& operator[](int i) {return m_curve[i];} + + iterator addPoint(iterator, const CurvePoint&); + iterator addPoint(iterator, const KisPoint&, bool = false, bool = false, int = POINTHINT); + + iterator pushPoint(const CurvePoint&); + iterator pushPoint(const KisPoint&, bool = false, bool = false, int = POINTHINT); + + virtual iterator addPivot(iterator, const KisPoint&); + virtual iterator pushPivot(const KisPoint&); + + int count() const {return m_curve.count();} + bool isEmpty() const {return m_curve.isEmpty();} + CurvePoint first() {return m_curve.front();} + CurvePoint last() {return m_curve.back();} + void clear() {m_curve.clear();} + + /* These needs iterators so they are implemented inline after the definition of CurveIterator */ + iterator begin() const; + iterator lastIterator() const; + iterator end() const; + iterator tqfind(const CurvePoint& pt); + iterator tqfind(const KisPoint& pt); + iterator tqfind(iterator it, const CurvePoint& pt); + iterator tqfind(iterator it, const KisPoint& pt); + + KisCurve pivots(); + KisCurve selectedPivots(bool = true); + KisCurve subCurve(const KisPoint&); + KisCurve subCurve(const CurvePoint&); + KisCurve subCurve(iterator); + KisCurve subCurve(const KisPoint&, const KisPoint&); + KisCurve subCurve(const CurvePoint&, const CurvePoint&); + KisCurve subCurve(iterator,iterator); + + /* Core virtual functions */ + virtual void deleteFirstPivot(); + virtual void deleteLastPivot(); + + virtual iterator deleteCurve(const KisPoint&, const KisPoint&); + virtual iterator deleteCurve(const CurvePoint&, const CurvePoint&); + virtual iterator deleteCurve(iterator, iterator); + + /* Core of the Core, calculateCurve is the only function that *needs* an implementation in the derived curves */ + virtual void calculateCurve(const KisPoint&, const KisPoint&, iterator); + virtual void calculateCurve(const CurvePoint&, const CurvePoint&, iterator); + virtual void calculateCurve(iterator, iterator, iterator); + virtual void calculateCurve(iterator*); + virtual void calculateCurve(); + + virtual iterator selectPivot(const CurvePoint&, bool = true); + virtual iterator selectPivot(const KisPoint&, bool = true); + virtual iterator selectPivot(iterator, bool = true); + + virtual iterator movePivot(const CurvePoint&, const KisPoint&); + virtual iterator movePivot(const KisPoint&, const KisPoint&); + virtual iterator movePivot(iterator, const KisPoint&); + + virtual void deletePivot(const CurvePoint&); + virtual void deletePivot(const KisPoint&); + virtual void deletePivot(iterator); + + virtual void moveSelected(const KisPoint&); + virtual void deleteSelected(); + virtual void selectAll(bool = true); +}; + +class CurveIterator { + + const KisCurve *m_target; + + BaseIterator m_position; + +public: + + CurveIterator () { m_target = 0; m_position = 0;} + + CurveIterator (const KisCurve &target) + {m_target = ⌖} + + CurveIterator (const CurveIterator &it) + {m_position = it.position(); m_target = it.target();} + + CurveIterator (const KisCurve &target, BaseIterator it) + {m_position = it; m_target = ⌖} + + ~CurveIterator () {} + + bool operator==(BaseIterator it) {return m_position == it;} + bool operator==(CurveIterator it) {return m_position == it.position();} + bool operator!=(BaseIterator it) {return m_position != it;} + bool operator!=(CurveIterator it) {return m_position != it.position();} + + CurveIterator operator++() {++m_position;return *this;} + CurveIterator operator++(int) {CurveIterator temp = *this; m_position++; return temp;} + CurveIterator operator--() {--m_position;return *this;} + CurveIterator operator--(int) {CurveIterator temp = *this; m_position--; return temp;} + CurveIterator operator+=(int i) {m_position+=i;return *this;} + CurveIterator operator-=(int i) {m_position-=i;return *this;} + CurveIterator operator=(const BaseIterator &it) {m_position=it; return *this;} + CurvePoint& operator*() {return (*m_position);} + + const KisCurve* target() const {return m_target;} + BaseIterator position() const {return m_position;} + + CurveIterator next() + { + CurveIterator it = *this; + return ++it; + } + + CurveIterator previous() + { + CurveIterator it = *this; + return --it; + } + + CurveIterator previousPivot() + { + CurveIterator it = *this; + while (it != m_target->m_curve.begin()) { + it-=1; + if ((*it).isPivot()) + return it; + } + + return it; + } + + CurveIterator nextPivot() + { + CurveIterator it = *this; + while (it != m_target->m_curve.end()) { + it+=1; + if ((*it).isPivot()) + return it; + } + return it; + } +}; + +/* ************************************* * + * CurvePoint inline methods definitions * + * ************************************* */ + +inline CurvePoint::CurvePoint () + : m_pivot(0), m_selected(0), m_hint(POINTHINT) +{ + +} + +inline CurvePoint::CurvePoint (const KisPoint& pt, bool p, bool s, int h) + : m_pivot(p), m_selected((p) ? s : false), m_hint(h) +{ + m_point = pt; +} + +inline CurvePoint::CurvePoint (double x, double y, bool p, bool s, int h) + : m_pivot(p), m_selected((p) ? s : false), m_hint(h) +{ + KisPoint tmp(x,y); + m_point = tmp; +} + +inline void CurvePoint::setPoint(const KisPoint& p) +{ + m_point = p; +} + +inline void CurvePoint::setPoint(double x, double y) +{ + KisPoint tmp(x,y); + m_point = tmp; +} + + +/* *********************************** * + * KisCurve inline methods definitions * + * *********************************** */ + +inline bool KisCurve::checkIterator (KisCurve::iterator checking) const +{ + if (checking.target() != this) + return false; + else + return true; +} + +inline KisCurve::iterator KisCurve::begin() const +{ + return iterator(*this,m_curve.begin()); +} + +inline KisCurve::iterator KisCurve::lastIterator() const +{ + return (iterator(*this,--m_curve.end())); +} + +inline KisCurve::iterator KisCurve::end() const +{ + return iterator(*this,m_curve.end()); +} + +inline KisCurve::iterator KisCurve::tqfind (const CurvePoint& pt) +{ + return iterator(*this,m_curve.tqfind(pt)); +} + +inline KisCurve::iterator KisCurve::tqfind (const KisPoint& pt) +{ + return iterator(*this,m_curve.tqfind(CurvePoint(pt))); +} + +inline KisCurve::iterator KisCurve::tqfind (KisCurve::iterator it, const CurvePoint& pt) +{ + return iterator(*this,m_curve.tqfind(it.position(),pt)); +} + +inline KisCurve::iterator KisCurve::tqfind (iterator it, const KisPoint& pt) +{ + return iterator(*this,m_curve.tqfind(it.position(),CurvePoint(pt))); +} + +inline void KisCurve::calculateCurve(const KisPoint& start, const KisPoint& end, KisCurve::iterator it) +{ + calculateCurve(tqfind(CurvePoint(start)),tqfind(CurvePoint(end)),it); +} + +inline void KisCurve::calculateCurve(const CurvePoint& start, const CurvePoint& end, KisCurve::iterator it) +{ + calculateCurve(tqfind(start),tqfind(end),it); +} + +inline void KisCurve::calculateCurve(KisCurve::iterator, KisCurve::iterator, KisCurve::iterator) +{ + return; +} + +/* Really generic functions, provided if someone _really_ needs them: array of iterators and no iterators. */ +inline void KisCurve::calculateCurve(KisCurve::iterator*) {return;} +inline void KisCurve::calculateCurve() {return;} + +#endif // KIS_CURVE_FRAMEWORK_H_ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier.cc b/chalk/plugins/tools/tool_curves/kis_tool_bezier.cc new file mode 100644 index 00000000..e3baf49c --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier.cc @@ -0,0 +1,366 @@ +/* + * kis_tool_bezier.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_doc.h" +#include "kis_painter.h" +#include "kis_point.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_vec.h" + +#include "kis_curve_framework.h" +#include "kis_tool_bezier.h" + +KisCurve::iterator KisCurveBezier::groupEndpoint (KisCurve::iterator it) const +{ + iterator temp = it; + if ((*it).hint() == BEZIERNEXTCONTROLHINT) + temp -= 1; + if ((*it).hint() == BEZIERPREVCONTROLHINT) + temp += 1; + return temp; +} + +KisCurve::iterator KisCurveBezier::groupPrevControl (KisCurve::iterator it) const +{ + iterator temp = it; + if ((*it).hint() == BEZIERENDHINT) + temp -= 1; + if ((*it).hint() == BEZIERNEXTCONTROLHINT) + temp -= 2; + return temp; +} + +KisCurve::iterator KisCurveBezier::groupNextControl (KisCurve::iterator it) const +{ + iterator temp = it; + if ((*it).hint() == BEZIERENDHINT) + temp += 1; + if ((*it).hint() == BEZIERPREVCONTROLHINT) + temp += 2; + return temp; +} + +bool KisCurveBezier::groupSelected (KisCurve::iterator it) const +{ + if ((*groupPrevControl(it)).isSelected() || (*groupEndpoint(it)).isSelected() || (*groupNextControl(it)).isSelected()) + return true; + return false; +} + +KisCurve::iterator KisCurveBezier::nextGroupEndpoint (KisCurve::iterator it) const +{ + iterator temp = it; + if ((*it).hint() == BEZIERPREVCONTROLHINT) { + temp += 2; + temp = temp.nextPivot(); + } + if ((*it).hint() == BEZIERENDHINT) { + temp += 1; + temp = temp.nextPivot(); + } + if ((*it).hint() == BEZIERNEXTCONTROLHINT) { + temp = temp.nextPivot(); + } + temp = temp.nextPivot(); + return temp; +} + +KisCurve::iterator KisCurveBezier::prevGroupEndpoint (KisCurve::iterator it) const +{ + iterator temp = it; + if ((*it).hint() == BEZIERNEXTCONTROLHINT) { + temp -= 1; + temp = temp.previousPivot().previousPivot(); + } + if ((*it).hint() == BEZIERENDHINT) { + temp = temp.previousPivot().previousPivot(); + } + if ((*it).hint() == BEZIERPREVCONTROLHINT) { + temp = temp.previousPivot(); + } + temp = temp.previousPivot(); + return temp; +} + +KisPoint KisCurveBezier::midpoint (const KisPoint& P1, const KisPoint& P2) +{ + KisPoint temp; + temp.setX((P1.x()+P2.x())/2); + temp.setY((P1.y()+P2.y())/2); + return temp; +} + +void KisCurveBezier::recursiveCurve (const KisPoint& P1, const KisPoint& P2, const KisPoint& P3, + const KisPoint& P4, int level, KisCurve::iterator it) +{ + if (level > m_maxLevel) { + addPoint(it,midpoint(P1,P4),false,false,LINEHINT); + return; + } + + KisPoint L1, L2, L3, L4; + KisPoint H, R1, R2, R3, R4; + + L1 = P1; + L2 = midpoint(P1, P2); + H = midpoint(P2, P3); + R3 = midpoint(P3, P4); + R4 = P4; + L3 = midpoint(L2, H); + R2 = midpoint(R3, H); + L4 = midpoint(L3, R2); + R1 = L4; + recursiveCurve(L1, L2, L3, L4, level + 1, it); + recursiveCurve(R1, R2, R3, R4, level + 1, it); +} + +void KisCurveBezier::calculateCurve(KisCurve::iterator tstart, KisCurve::iterator tend, KisCurve::iterator) +{ + if (pivots().count() < 4) + return; + + iterator origin, dest, control1, control2; + + if ((*tstart).hint() == BEZIERENDHINT) { + origin = tstart; + control1 = tstart.nextPivot(); + } else if ((*tstart).hint() == BEZIERNEXTCONTROLHINT) { + origin = tstart.previousPivot(); + control1 = tstart; + } else if ((*tstart).hint() == BEZIERPREVCONTROLHINT) { + origin = tstart.nextPivot(); + control1 = origin.nextPivot(); + } else + return; + + if ((*tend).hint() == BEZIERENDHINT) { + dest = tend; + control2 = tend.previousPivot(); + } else if ((*tend).hint() == BEZIERPREVCONTROLHINT) { + dest = tend.nextPivot(); + control2 = tend; + } else if ((*tend).hint() == BEZIERNEXTCONTROLHINT) { + dest = tend.previousPivot(); + control2 = dest.previousPivot(); + } else + return; + + deleteCurve(control1,control2); + recursiveCurve((*origin).point(),(*control1).point(),(*control2).point(),(*dest).point(),1,control2); + +} + +KisCurve::iterator KisCurveBezier::pushPivot (const KisPoint& point) +{ + iterator it; + + it = pushPoint(point,true,false,BEZIERENDHINT); + if (count() > 1) + addPoint(it,point,true,false,BEZIERPREVCONTROLHINT); + + it = pushPoint(point,true,false,BEZIERNEXTCONTROLHINT); + + return selectPivot(it); +} + +KisCurve::iterator KisCurveBezier::movePivot(KisCurve::iterator it, const KisPoint& newPt) +{ + if (!(*it).isPivot()) + return end(); + + int hint = (*it).hint(); + iterator thisEnd, prevEnd, nextEnd; + + thisEnd = groupEndpoint(it); + prevEnd = prevGroupEndpoint(it); + nextEnd = nextGroupEndpoint(it); + + if (hint == BEZIERENDHINT) { + KisPoint trans = newPt - (*it).point(); + (*thisEnd).setPoint((*thisEnd).point()+trans); + (*thisEnd.previous()).setPoint((*thisEnd.previous()).point()+trans); + (*thisEnd.next()).setPoint((*thisEnd.next()).point()+trans); + } else if (!(m_actionOptions & KEEPSELECTEDOPTION)) + (*it).setPoint(newPt); + if (!(m_actionOptions & KEEPSELECTEDOPTION) && hint != BEZIERENDHINT) { + if (nextEnd == end() || (m_actionOptions & SYMMETRICALCONTROLSOPTION)) { + KisPoint trans = (*it).point() - (*thisEnd).point(); + trans = KisPoint(-trans.x()*2,-trans.y()*2); + if (hint == BEZIERNEXTCONTROLHINT) + (*groupPrevControl(it)).setPoint(newPt+trans); + else + (*groupNextControl(it)).setPoint(newPt+trans); + } + } + + if (nextEnd != end() && count() > 4) + calculateCurve (thisEnd,nextEnd,iterator()); + if (prevEnd != thisEnd && count() > 4) + calculateCurve (prevEnd,thisEnd,iterator()); + + return it; +} + +void KisCurveBezier::deletePivot (KisCurve::iterator it) +{ + if (!(*it).isPivot()) + return; + + iterator prevControl,thisEnd,nextControl; + + prevControl = prevGroupEndpoint(it).nextPivot(); + thisEnd = groupEndpoint(it); + nextControl = nextGroupEndpoint(it).previousPivot(); + + if ((*thisEnd) == first()) { + deleteFirstPivot(); + deleteFirstPivot(); + deleteFirstPivot(); + } else if ((*thisEnd.next()) == last()) { + deleteLastPivot(); + deleteLastPivot(); + deleteLastPivot(); + } else { + deleteCurve(prevControl,nextControl); + calculateCurve(prevControl,nextControl,iterator()); + } +} + +KisToolBezier::KisToolBezier(const TQString& UIName) + : super(UIName) +{ + m_derivated = new KisCurveBezier; + m_curve = m_derivated; + + m_supportMinimalDraw = false; + + m_transactionMessage = i18n("Bezier Curve"); +} + +KisToolBezier::~KisToolBezier() +{ + +} + +KisCurve::iterator KisToolBezier::handleUnderMouse(const TQPoint& pos) +{ + TQPoint qpos; + KisCurve pivs = m_curve->pivots(), inHandle; + KisCurve::iterator it; + int hint; + for (it = pivs.begin(); it != pivs.end(); it++) { + qpos = m_subject->canvasController()->windowToView((*it).point().toTQPoint()); + hint = (*it).hint(); + if (hint != BEZIERENDHINT && !m_derivated->groupSelected(it)) + continue; + if (hint == BEZIERENDHINT && (m_actionOptions & SHIFTOPTION)) + continue; + if (pivotRect(qpos).tqcontains(pos)) { + inHandle.pushPoint((*it)); + if (hint == BEZIERENDHINT && !(m_actionOptions & SHIFTOPTION)) + break; + if (hint != BEZIERENDHINT && (m_actionOptions & SHIFTOPTION)) + break; + } + } + if (inHandle.isEmpty()) + return m_curve->end(); + + return m_curve->tqfind(inHandle.last()); +} + +KisCurve::iterator KisToolBezier::drawPoint (KisCanvasPainter& gc, KisCurve::iterator point) +{ + if ((*point).hint() != BEZIERENDHINT) + return ++point; + + KisCanvasController *controller = m_subject->canvasController(); + + // Now draw the bezier + + KisCurve::iterator origin,control1,control2,destination; + + origin = point; + control1 = origin.next(); + control2 = control1.nextPivot(); + destination = control2.next(); + + if (control2 != m_curve->end()) { + point = control2; + TQPointArray vec(4); + vec[0] = controller->windowToView((*origin).point().toTQPoint()); + vec[1] = controller->windowToView((*control1).point().toTQPoint()); + vec[2] = controller->windowToView((*control2).point().toTQPoint()); + vec[3] = controller->windowToView((*destination).point().toTQPoint()); + gc.drawCubicBezier(vec); + } + + point += 1; + + return point; +} + +void KisToolBezier::drawPivotHandle (KisCanvasPainter& gc, KisCurve::iterator point) +{ + if ((*point).hint() != BEZIERENDHINT) + return; + + KisCanvasController *controller = m_subject->canvasController(); + + TQPoint endpPos = controller->windowToView((*point).point().toTQPoint()); + + if (!m_derivated->groupSelected(point)) { + gc.setPen(m_pivotPen); + gc.drawRoundRect(pivotRect(endpPos),m_pivotRounding,m_pivotRounding); + } else { + TQPoint nextControlPos = controller->windowToView((*point.next()).point().toTQPoint()); + TQPoint prevControlPos = controller->windowToView((*point.previousPivot()).point().toTQPoint()); + + gc.setPen(m_selectedPivotPen); + gc.drawRoundRect(selectedPivotRect(endpPos),m_selectedPivotRounding,m_selectedPivotRounding); + if ((prevControlPos != endpPos || nextControlPos != endpPos) && !(m_actionOptions & CONTROLOPTION)) { + gc.drawRoundRect(pivotRect(nextControlPos),m_pivotRounding,m_pivotRounding); + gc.drawLine(endpPos,nextControlPos); + gc.drawRoundRect(pivotRect(prevControlPos),m_pivotRounding,m_pivotRounding); + gc.drawLine(prevControlPos,endpPos); + } + } + + gc.setPen(m_drawingPen); +} + +#include "kis_tool_bezier.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier.h b/chalk/plugins/tools/tool_curves/kis_tool_bezier.h new file mode 100644 index 00000000..e1e0521a --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier.h @@ -0,0 +1,98 @@ +/* + * kis_tool_bezier.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_BEZIER_H_ +#define KIS_TOOL_BEZIER_H_ + +#include "kis_tool_factory.h" +#include "kis_tool_curve.h" +#include "kis_point.h" + +class CurvePoint; +class KisPoint; +class KisCanvas; +class KisCurve; +class KisPainter; +class KisPoint; + +const int BEZIERENDHINT = 0x0010; +const int BEZIERPREVCONTROLHINT = 0x0020; +const int BEZIERNEXTCONTROLHINT = 0x0040; + +const int SYMMETRICALCONTROLSOPTION = ALTOPTION; +const int PREFERCONTROLSOPTION = SHIFTOPTION; + +class KisCurveBezier : public KisCurve { + + typedef KisCurve super; + + void recursiveCurve (const KisPoint& P1, const KisPoint& P2, const KisPoint& P3, + const KisPoint& P4, int level, iterator it); + KisPoint midpoint (const KisPoint&, const KisPoint&); + + int m_maxLevel; + +public: + + KisCurveBezier() : super() {m_maxLevel = 5;} + + ~KisCurveBezier() {} + + virtual void calculateCurve(iterator, iterator, iterator); + virtual iterator pushPivot(const KisPoint&); + virtual iterator movePivot(iterator, const KisPoint&); + virtual void deletePivot(iterator); + +public: + + iterator groupEndpoint (iterator) const; + iterator groupPrevControl (iterator) const; + iterator groupNextControl (iterator) const; + + bool groupSelected (iterator) const; + + iterator nextGroupEndpoint (iterator) const; + iterator prevGroupEndpoint (iterator) const; + +}; + +class KisToolBezier : public KisToolCurve { + + typedef KisToolCurve super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolBezier(const TQString&); + virtual ~KisToolBezier(); + +protected: + + virtual KisCurve::iterator handleUnderMouse(const TQPoint& pos); + virtual void drawPivotHandle(KisCanvasPainter& gc, KisCurve::iterator point); + virtual KisCurve::iterator drawPoint(KisCanvasPainter& gc, KisCurve::iterator point); + +protected: + + KisCurveBezier *m_derivated; + +}; + +#endif //__KIS_TOOL_BEZIER_H__ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.cc b/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.cc new file mode 100644 index 00000000..663e1324 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.cc @@ -0,0 +1,115 @@ +/* + * kis_tool_curve.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_cmb_composite.h" +#include "kis_colorspace.h" +#include "kis_config.h" +#include "kis_cursor.h" +#include "kis_doc.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_int_spinbox.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_point.h" +#include "kis_tool_controller.h" +#include "kis_tool_paint.h" + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_canvas_subject.h" + +#include "kis_curve_framework.h" +#include "kis_tool_bezier_paint.h" + +KisToolBezierPaint::KisToolBezierPaint() + : super(i18n("Bezier Painting Tool")) +{ + setName("tool_bezier_paint"); + m_cursor = "tool_bezier_cursor.png"; + setCursor(KisCursor::load(m_cursor, 6, 6)); +} + +KisToolBezierPaint::~KisToolBezierPaint() +{ + +} + +KisCurve::iterator KisToolBezierPaint::paintPoint (KisPainter& painter, KisCurve::iterator point) +{ + KisCurve::iterator origin,destination,control1,control2; + switch ((*point).hint()) { + case BEZIERENDHINT: + origin = point++; + control1 = point; + control2 = control1.nextPivot(); + destination = control2.next(); + if (m_curve->count() > 4 && (*point) != m_curve->last()) { + point = point.nextPivot().next(); + painter.paintAt((*origin).point(),PRESSURE_DEFAULT,0,0); + painter.paintBezierCurve((*origin).point(),PRESSURE_DEFAULT,0,0,(*control1).point(), + (*control2).point(),(*destination).point(),PRESSURE_DEFAULT,0,0,0); + } + break; + default: + point = super::paintPoint(painter,point); + } + + return point; +} + +void KisToolBezierPaint::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Bezier"), + "tool_bezier_paint", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Draw cubic beziers. Keep Alt, Control or Shift pressed for options. Return or double-click to finish.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_bezier_paint.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.h b/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.h new file mode 100644 index 00000000..c2a3715b --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier_paint.h @@ -0,0 +1,63 @@ +/* + * kis_tool_curve_paint.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_BEZIER_PAINT_H_ +#define KIS_TOOL_BEZIER_PAINT_H_ + +#include "kis_tool_factory.h" +#include "kis_tool_bezier.h" +#include "kis_point.h" + +class KisToolBezierPaint : public KisToolBezier { + + typedef KisToolBezier super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolBezierPaint(); + virtual ~KisToolBezierPaint(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 7; } + +protected: + + virtual KisCurve::iterator paintPoint(KisPainter& painter, KisCurve::iterator point); + +}; + +class KisToolBezierPaintFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolBezierPaintFactory() : super() {}; + virtual ~KisToolBezierPaintFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolBezierPaint(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("beziertqshape", i18n("Bezier Painting Tool")); } +}; + +#endif //__KIS_TOOL_CURVE_PAINT_H_ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.cc b/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.cc new file mode 100644 index 00000000..ed1200d4 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.cc @@ -0,0 +1,104 @@ +/* + * kis_tool_curve.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_cmb_composite.h" +#include "kis_colorspace.h" +#include "kis_config.h" +#include "kis_cursor.h" +#include "kis_doc.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_int_spinbox.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_point.h" +#include "kis_tool_controller.h" +#include "kis_tool_paint.h" + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_canvas_subject.h" + +#include "kis_curve_framework.h" +#include "kis_tool_bezier_select.h" + +KisToolBezierSelect::KisToolBezierSelect() + : super(i18n("Bezier Selection Tool")) +{ + setName("tool_bezier_select"); + m_cursor = "tool_bezier_cursor.png"; + setCursor(KisCursor::load(m_cursor, 6, 6)); +} + +KisToolBezierSelect::~KisToolBezierSelect() +{ + +} + +TQValueVector KisToolBezierSelect::convertCurve() +{ + TQValueVector points; + + for (KisCurve::iterator i = m_curve->begin(); i != m_curve->end(); i++) { + if (((*i).hint() != BEZIERPREVCONTROLHINT) && ((*i).hint() != BEZIERNEXTCONTROLHINT)) + points.append((*i).point()); + } + + return points; +} + +void KisToolBezierSelect::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Bezier"), + "tool_bezier_select", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Select areas of the image with bezier paths.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_bezier_select.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.h b/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.h new file mode 100644 index 00000000..07aecc3a --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_bezier_select.h @@ -0,0 +1,63 @@ +/* + * kis_tool_curve_paint.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_BEZIER_SELECT_H_ +#define KIS_TOOL_BEZIER_SELECT_H_ + +#include "kis_tool_factory.h" +#include "kis_tool_bezier.h" +#include "kis_point.h" + +class KisToolBezierSelect : public KisToolBezier { + + typedef KisToolBezier super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolBezierSelect(); + virtual ~KisToolBezierSelect(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQ_UINT32 priority() { return 10; } + +protected: + + virtual TQValueVector convertCurve(); + +}; + +class KisToolBezierSelectFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolBezierSelectFactory() : super() {}; + virtual ~KisToolBezierSelectFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolBezierSelect(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("bezierselection", i18n("Bezier Selection Tool")); } +}; + +#endif //__KIS_TOOL_CURVE_PAINT_H_ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_curve.cc b/chalk/plugins/tools/tool_curves/kis_tool_curve.cc new file mode 100644 index 00000000..f98d2c72 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_curve.cc @@ -0,0 +1,593 @@ +/* + * kis_tool_curve.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_doc.h" +#include "kis_painter.h" +#include "kis_point.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_tool_controller.h" +#include "kis_vec.h" +#include "kis_selection.h" +#include "kis_selection_options.h" +#include "kis_selected_transaction.h" +#include "kis_paintop_registry.h" + +#include "kis_curve_framework.h" +#include "kis_tool_curve.h" + +TQRect KisToolCurve::pivotRect (const TQPoint& pos) +{ + return TQRect (pos-TQPoint(4,4),pos+TQPoint(4,4)); +} + +TQRect KisToolCurve::selectedPivotRect (const TQPoint& pos) +{ + return TQRect (pos-TQPoint(5,5),pos+TQPoint(5,5)); +} + +KisToolCurve::KisToolCurve(const TQString& UIName) + : super(UIName) +{ + m_UIName = UIName; + m_currentImage = 0; + m_optWidget = 0; + + m_curve = 0; + + m_dragging = false; + m_draggingCursor = false; + m_drawPivots = true; + m_drawingPen = TQPen(TQt::white, 0, TQt::SolidLine); + m_pivotPen = TQPen(TQt::gray, 0, TQt::SolidLine); + m_selectedPivotPen = TQPen(TQt::yellow, 0, TQt::SolidLine); + m_pivotRounding = m_selectedPivotRounding = 55; + + m_actionOptions = NOOPTIONS; + m_supportMinimalDraw = true; + m_selectAction = SELECTION_ADD; +} + +KisToolCurve::~KisToolCurve() +{ + +} + +void KisToolCurve::update (KisCanvasSubject *subject) +{ + super::update(subject); + if (m_subject) + m_currentImage = m_subject->currentImg(); +} + +void KisToolCurve::deactivate() +{ + draw(false); + if (m_curve) { + m_curve->clear(); + m_curve->endActionOptions(); + } + + m_actionOptions = NOOPTIONS; + m_dragging = false; + m_drawPivots = true; +} + +void KisToolCurve::buttonPress(KisButtonPressEvent *event) +{ + updateOptions(event->state()); + if (!m_currentImage) + return; + if (event->button() == Qt::LeftButton) { + m_dragging = true; + m_currentPoint = event->pos(); + PointPair temp = pointUnderMouse (m_subject->canvasController()->windowToView(event->pos().toTQPoint())); + if (temp.first == m_curve->end() && !(m_actionOptions)) { + draw(true, true); + m_curve->selectAll(false); + draw(true, true); + draw(m_curve->end()); + m_previous = m_curve->tqfind(m_curve->last()); + m_current = m_curve->pushPivot(event->pos()); + if (m_curve->pivots().count() > 1) + m_curve->calculateCurve(m_previous,m_current,m_current); + draw(m_current); + } else { + draw(true, true); + if (temp.second) + m_current = m_curve->selectPivot(temp.first); + else + m_current = selectByMouse(temp.first); + + if (!(*m_current).isSelected()) + m_dragging = false; + draw(true, true); + } + } +} + +void KisToolCurve::keyPress(TQKeyEvent *event) +{ + if (event->key() == TQt::Key_Return) { + m_dragging = false; + commitCurve(); + } else + if (event->key() == TQt::Key_Escape) { + m_dragging = false; + draw(false); + m_curve->clear(); + } else + if (event->key() == TQt::Key_Delete) { + draw(false); + m_dragging = false; + m_curve->deleteSelected(); + m_current = m_curve->tqfind(m_curve->last()); + m_previous = m_curve->selectPivot(m_current); + draw(false); + } +} + +void KisToolCurve::keyRelease(TQKeyEvent *) +{ + +} + +void KisToolCurve::buttonRelease(KisButtonReleaseEvent *event) +{ + updateOptions(event->state()); + m_dragging = false; +} + +void KisToolCurve::doubleClick(KisDoubleClickEvent *) +{ + commitCurve(); +} + +void KisToolCurve::move(KisMoveEvent *event) +{ + updateOptions(event->state()); + PointPair temp = pointUnderMouse(m_subject->canvasController()->windowToView(event->pos().toTQPoint())); + if (temp.first == m_curve->end() && !m_dragging) { + if (m_draggingCursor) { + setCursor(KisCursor::load(m_cursor, 6, 6)); + m_draggingCursor = false; + } + } else { + setCursor(KisCursor::load("tool_curve_dragging.png", 6, 6)); + m_draggingCursor = true; + } + if (m_dragging) { + draw(); + KisPoint trans = event->pos() - m_currentPoint; + m_curve->moveSelected(trans); + m_currentPoint = event->pos(); + draw(); + } +} + +double pointToSegmentDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1) +{ + double lineLength = sqrt((l1.x() - l0.x()) * (l1.x() - l0.x()) + (l1.y() - l0.y()) * (l1.y() - l0.y())); + double distance = 0; + KisVector2D v0(l0), v1(l1), v(p), seg(v0-v1), dist0(v0-p), dist1(v1-p); + + if (seg.length() < dist0.length() || + seg.length() < dist1.length()) // the point doesn't perpendicolarly intersecate the segment (or it's too far from the segment) + return (double)INT_MAX; + + if (lineLength > DBL_EPSILON) { + distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / lineLength; + distance = fabs(distance); + } + + return distance; +} + +PointPair KisToolCurve::pointUnderMouse(const TQPoint& pos) +{ + KisCurve::iterator it, next; + TQPoint pos1, pos2; + it = handleUnderMouse(pos); + if (it != m_curve->end()) + return PointPair(it,true); + + for (it = m_curve->begin(); it != m_curve->end(); it++) { + next = it.next(); + if (next == m_curve->end() || it == m_curve->end()) + return PointPair(m_curve->end(),false); + if ((*it).hint() > LINEHINT || (*next).hint() > LINEHINT) + continue; + pos1 = m_subject->canvasController()->windowToView((*it).point().toTQPoint()); + pos2 = m_subject->canvasController()->windowToView((*next).point().toTQPoint()); + if (pos1 == pos2) + continue; + if (pointToSegmentDistance(pos,pos1,pos2) <= MAXDISTANCE) + break; + } + + return PointPair(it,false); +} + +KisCurve::iterator KisToolCurve::handleUnderMouse(const TQPoint& pos) +{ + KisCurve pivs = m_curve->pivots(), inHandle; + KisCurve::iterator it; + for (it = pivs.begin(); it != pivs.end(); it++) { + if (pivotRect(m_subject->canvasController()->windowToView((*it).point().toTQPoint())).tqcontains(pos)) + inHandle.pushPoint((*it)); + } + if (inHandle.isEmpty()) + return m_curve->end(); + return m_curve->tqfind(inHandle.last()); +} + +KisCurve::iterator KisToolCurve::selectByMouse(KisCurve::iterator it) +{ + KisCurve::iterator prevPivot, nextPivot; + + if ((*it).isPivot()) + prevPivot = it; + else + prevPivot = it.previousPivot(); + nextPivot = it.nextPivot(); + + m_curve->selectPivot(prevPivot); + (*nextPivot).setSelected(true); + + return prevPivot; +} + +int KisToolCurve::updateOptions(int key) +{ + int options = 0x0000; + + if (key & TQt::ControlButton) + options |= CONTROLOPTION; + + if (key & TQt::ShiftButton) + options |= SHIFTOPTION; + + if (key & TQt::AltButton) + options |= ALTOPTION; + + if (options != m_actionOptions) { + draw(false); + m_actionOptions = options; + m_curve->setActionOptions(m_actionOptions); + draw(false); + } + + return m_actionOptions; +} + +void KisToolCurve::draw(bool m, bool o) +{ + draw(KisCurve::iterator(), o, m); +} + +void KisToolCurve::draw(KisCurve::iterator inf, bool pivotonly, bool minimal) +{ + if (m_curve->isEmpty()) + return; + KisCanvasPainter *gc; + KisCanvasController *controller; + KisCanvas *canvas; + if (m_subject && m_currentImage) { + controller = m_subject->canvasController(); + canvas = controller->kiscanvas(); + gc = new KisCanvasPainter(canvas); + } else + return; + + gc->setPen(m_drawingPen); + gc->setRasterOp(TQt::XorROP); + + KisCurve::iterator it, finish; + + if (minimal && m_supportMinimalDraw) { + if (pivotonly) { + KisCurve p = m_curve->pivots(); + for (KisCurve::iterator i = p.begin(); i != p.end(); i++) + drawPivotHandle (*gc, i); + delete gc; + return; + } + if (inf.target() != 0) { + if (inf != m_curve->end()) { + it = inf.previousPivot(); + finish = inf.nextPivot(); + } else { + it = --m_curve->end(); + finish = m_curve->end(); + } + } else { + KisCurve sel = m_curve->selectedPivots(); + if (sel.isEmpty()) { + delete gc; + return; + } + for (KisCurve::iterator i = sel.begin(); i != sel.end(); i++) { + it = m_curve->tqfind(*i).previousPivot(); + finish = m_curve->tqfind(*i).nextPivot(); + if ((*finish).isSelected()) + finish = finish.previousPivot(); + while (it != finish) { + if ((*it).isPivot()) + drawPivotHandle (*gc, it); + it = drawPoint (*gc, it); + } + } + delete gc; + return; + } + } else { + it = m_curve->begin(); + finish = m_curve->end(); + } + while (it != finish) { + if ((*it).isPivot()) + drawPivotHandle (*gc, it); + it = drawPoint (*gc, it); + } + + delete gc; +} + +KisCurve::iterator KisToolCurve::drawPoint(KisCanvasPainter& gc, KisCurve::iterator point) +{ + KisCanvasController *controller = m_subject->canvasController(); + + TQPoint pos1, pos2; + pos1 = controller->windowToView((*point).point().toTQPoint()); + + switch ((*point).hint()) { + case POINTHINT: + gc.drawPoint(pos1); + point += 1; + break; + case LINEHINT: + gc.drawPoint(pos1); + if (++point != m_curve->end() && (*point).hint() <= LINEHINT) { + pos2 = controller->windowToView((*point).point().toTQPoint()); + gc.drawLine(pos1,pos2); + } + break; + default: + point += 1; + } + + return point; +} + +void KisToolCurve::drawPivotHandle(KisCanvasPainter& gc, KisCurve::iterator point) +{ + KisCanvasController *controller = m_subject->canvasController(); + + if (m_drawPivots) { + TQPoint pos = controller->windowToView((*point).point().toTQPoint()); + if ((*point).isSelected()) { + gc.setPen(m_selectedPivotPen); + gc.drawRoundRect(selectedPivotRect(pos),m_selectedPivotRounding,m_selectedPivotRounding); + } else { + gc.setPen(m_pivotPen); + gc.drawRoundRect(pivotRect(pos),m_pivotRounding,m_pivotRounding); + } + gc.setPen(m_drawingPen); + } +} + +void KisToolCurve::paint(KisCanvasPainter&) +{ + draw(false); +} + +void KisToolCurve::paint(KisCanvasPainter&, const TQRect&) +{ + draw(false); +} + +void KisToolCurve::commitCurve() +{ + if (toolType() == TOOL_SHAPE || toolType() == TOOL_FREEHAND) + paintCurve(); + else if (toolType() == TOOL_SELECT) + selectCurve(); + else + kdDebug(0) << "NO SUPPORT FOR THIS TYPE OF TOOL" << endl; + + m_curve->clear(); + m_curve->endActionOptions(); +} + +void KisToolCurve::paintCurve() +{ + KisPaintDeviceSP device = m_currentImage->activeDevice (); + if (!device) return; + + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (m_transactionMessage); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBrush(m_subject->currentBrush()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + +// Call paintPoint + KisCurve::iterator it = m_curve->begin(); + while (it != m_curve->end()) + it = paintPoint(painter,it); +// Finish + + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + + draw(false); +} + +KisCurve::iterator KisToolCurve::paintPoint (KisPainter& painter, KisCurve::iterator point) +{ + KisCurve::iterator next = point; next+=1; + switch ((*point).hint()) { + case POINTHINT: + painter.paintAt((*point++).point(), PRESSURE_DEFAULT, 0, 0); + break; + case LINEHINT: + if (next != m_curve->end() && (*next).hint() <= LINEHINT) + painter.paintLine((*point++).point(), PRESSURE_DEFAULT, 0, 0, (*next).point(), PRESSURE_DEFAULT, 0, 0); + else + painter.paintAt((*point++).point(), PRESSURE_DEFAULT, 0, 0); + break; + default: + point += 1; + } + + return point; +} + +TQValueVector KisToolCurve::convertCurve() +{ + TQValueVector points; + + for (KisCurve::iterator i = m_curve->begin(); i != m_curve->end(); i++) + if ((*i).hint() != NOHINTS) + points.append((*i).point()); + + return points; +} + +void KisToolCurve::selectCurve() +{ + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintDeviceSP dev = m_currentImage->activeDevice(); + bool hasSelection = dev->hasSelection(); + KisSelectedTransaction *t = 0; + if (m_currentImage->undo()) t = new KisSelectedTransaction(m_transactionMessage, dev); + KisSelectionSP selection = dev->selection(); + + if (!hasSelection) { + selection->clear(); + } + + KisPainter painter(selection.data()); + + painter.setPaintColor(KisColor(TQt::black, selection->colorSpace())); + painter.setFillStyle(KisPainter::FillStyleForegroundColor); + painter.setStrokeStyle(KisPainter::StrokeStyleNone); + painter.setBrush(m_subject->currentBrush()); + painter.setOpacity(OPACITY_OPAQUE); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("paintbrush", 0, &painter); + painter.setPaintOp(op); // And now the painter owns the op and will destroy it. + + switch (m_selectAction) { + case SELECTION_ADD: + painter.setCompositeOp(COMPOSITE_OVER); + break; + case SELECTION_SUBTRACT: + painter.setCompositeOp(COMPOSITE_SUBTRACT); + break; + default: + break; + } + + painter.paintPolygon(convertCurve()); + + + if(hasSelection) { + TQRect dirty(painter.dirtyRect()); + dev->setDirty(dirty); + dev->emitSelectionChanged(dirty); + } else { + dev->setDirty(); + dev->emitSelectionChanged(); + } + + if (m_currentImage->undo()) + m_currentImage->undoAdapter()->addCommand(t); + + TQApplication::restoreOverrideCursor(); + + draw(false); +} + +TQWidget* KisToolCurve::createOptionWidget(TQWidget* tqparent) +{ + if (toolType() == TOOL_SHAPE || toolType() == TOOL_FREEHAND) + return super::createOptionWidget(tqparent); + else if (toolType() == TOOL_SELECT) + return createSelectionOptionWidget(tqparent); + else + kdDebug(0) << "NO SUPPORT FOR THIS TOOL TYPE" << endl; + return 0; +} + +void KisToolCurve::slotSetAction(int action) { + if (action >= SELECTION_ADD && action <= SELECTION_SUBTRACT) + m_selectAction =(enumSelectionMode)action; +} + +TQWidget* KisToolCurve::createSelectionOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new KisSelectionOptions(tqparent, m_subject); + Q_CHECK_PTR(m_optWidget); + m_optWidget->setCaption(m_UIName); + + connect (m_optWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolCurve::optionWidget() +{ + if (toolType() == TOOL_SELECT) + return m_optWidget; + else + return super::optionWidget(); +} + +#include "kis_tool_curve.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_curve.h b/chalk/plugins/tools/tool_curves/kis_tool_curve.h new file mode 100644 index 00000000..74d1ccda --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_curve.h @@ -0,0 +1,205 @@ +/* + * kis_tool_curve.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_CURVE_H_ +#define KIS_TOOL_CURVE_H_ + +#include +#include + +#include "kis_selection.h" +#include "kis_tool_paint.h" +#include "kis_canvas_subject.h" +#include "kis_point.h" + +#include "kis_curve_framework.h" + +class TQRect; +class KisPainter; +class KisSelectionOptions; + +typedef TQPair PointPair; + +const double MAXDISTANCE = 2.5; +double pointToSegmentDistance(const KisPoint& p, const KisPoint& l0, const KisPoint& l1); + +class KisToolCurve : public KisToolPaint { + + typedef KisToolPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolCurve(const TQString& UIName); + virtual ~KisToolCurve(); + + virtual void update (KisCanvasSubject *subject); + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual void doubleClick(KisDoubleClickEvent *event); + virtual void keyPress(TQKeyEvent *event); + virtual void keyRelease(TQKeyEvent *event); + +public slots: + + virtual void deactivate(); + +protected: + + virtual void paint(KisCanvasPainter&); + virtual void paint(KisCanvasPainter&, const TQRect&); + + /* ********************** * + * KisToolCurve interface * + * ********************** */ + + /* + * This keep in sync the options of the tool with the options of the curve + */ + virtual int updateOptions(int); + + virtual PointPair pointUnderMouse(const TQPoint& pos); + virtual KisCurve::iterator handleUnderMouse(const TQPoint& pos); + + /* + * Select the needed points; called after pointUnderMouse + */ + virtual KisCurve::iterator selectByMouse(KisCurve::iterator it); + + /* + * draw() initializes the KisCanvasPainter and then loop on the points of the curve for drawing them. + */ + virtual void draw(bool = true, bool = false); + virtual void draw(KisCurve::iterator inf, bool = false, bool = true); + + /* + * Used by draw() to draw the current point of the curve. Can draw more than one point and then returns the last one + */ + virtual KisCurve::iterator drawPoint(KisCanvasPainter& gc, KisCurve::iterator point); + + /* + * Used by draw(), if a point is a pivot, this draw the handle around it (if m_drawPivots is set to true) + */ + virtual void drawPivotHandle(KisCanvasPainter& gc, KisCurve::iterator point); + + /* + * Methods for commiting the curve + */ + + /* + * Called by selectCurve(), this convert m_curve to a vector of KisPoint in order to be used by paintPolygon() + */ + virtual TQValueVector convertCurve(); + + /* + * Called by paintCurve(), it behaves essentially like drawPoint(), but this uses a KisPainter + */ + virtual KisCurve::iterator paintPoint(KisPainter&, KisCurve::iterator); + + /* + * Finish the curve: if the tool is a TOOL_SHAPE or TOOL_FREEHAND, calls paintCurve(), if it's a TOOL_SELECT, then selectCurve() + */ + virtual void commitCurve(); + + /* + * Used by commitCurve() if the tool is a painting tool + */ + virtual void paintCurve(); + + /* + * Used by commitCurve() if the tool is a selection tool + */ + virtual void selectCurve(); + + /* + * Return the rect around a given point, assuming that that point is an unselected pivot + */ + TQRect pivotRect (const TQPoint&); + + /* + * Same as above for selected pivots + */ + TQRect selectedPivotRect (const TQPoint&); + +protected: + + KisImageSP m_currentImage; + + KisCurve *m_curve; + KisCurve::iterator m_current; + KisCurve::iterator m_previous; + KisPoint m_currentPoint; + + bool m_dragging; + bool m_drawPivots; + TQPen m_drawingPen; + TQPen m_pivotPen; + TQPen m_selectedPivotPen; + int m_pivotRounding; + int m_selectedPivotRounding; + + int m_actionOptions; + bool m_supportMinimalDraw; + bool m_draggingCursor; + + TQString m_transactionMessage; + TQString m_cursor; + +private: + + TQString m_UIName; + + +/* ********************************** * + * Selection Tools specific functions * + * ********************************** */ + +public: + + /* + * This initializes our Option Widget (called by createOptionWidget()) + */ + virtual TQWidget* createSelectionOptionWidget(TQWidget* tqparent); + + /* + * This return our internal KisSelectionOptions if toolType() returns TOOL_SELECT + */ + virtual TQWidget* optionWidget(); + +public slots: + + /* + * Slot for createSelectionOptionWidget() + */ + virtual void slotSetAction(int); + +private: + + /* + * Members used by slotSetAction() and selectCurve() + */ + KisSelectionOptions* m_optWidget; + enumSelectionMode m_selectAction; +}; + +#endif //__KIS_TOOL_CURVE_H_ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_example.cc b/chalk/plugins/tools/tool_curves/kis_tool_example.cc new file mode 100644 index 00000000..e14abcb5 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_example.cc @@ -0,0 +1,108 @@ +/* + * kis_tool_example.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_doc.h" +#include "kis_painter.h" +#include "kis_point.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_vec.h" + +#include "kis_curve_framework.h" + +#include "kis_tool_example.h" + + +class KisCurveExample : public KisCurve { + + typedef KisCurve super; + +public: + + KisCurveExample() : super() {} + + ~KisCurveExample() {} + + virtual iterator pushPivot (const KisPoint&); + +}; + +KisCurve::iterator KisCurveExample::pushPivot (const KisPoint& point) +{ + return selectPivot(iterator(*this,m_curve.append(CurvePoint(point,true,false,LINEHINT))), true); +} + +KisToolExample::KisToolExample() + : super(i18n("Tool for Curves - Example")) +{ + setName("tool_example"); + m_cursor = "tool_example_cursor.png"; + setCursor(KisCursor::load(m_cursor, 6, 6)); + + m_curve = new KisCurveExample; +} + +KisToolExample::~KisToolExample() +{ + +} + +void KisToolExample::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Example"), + "tool_example", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("This is a test tool for the Curve Framework.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_example.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_example.h b/chalk/plugins/tools/tool_curves/kis_tool_example.h new file mode 100644 index 00000000..e7bfd89e --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_example.h @@ -0,0 +1,67 @@ +/* + * kis_tool_example.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_EXAMPLE_H_ +#define KIS_TOOL_EXAMPLE_H_ + +#include "kis_tool_factory.h" +#include "kis_tool_curve.h" +#include "kis_point.h" + +class CurvePoint; +class KisPoint; +class KisCanvas; +class KisCurve; +class KisPainter; +class KisPoint; +class WdgToolExample; + +class KisToolExample : public KisToolCurve { + + typedef KisToolCurve super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolExample(); + virtual ~KisToolExample(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + +}; + +class KisToolExampleFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolExampleFactory() : super() {}; + virtual ~KisToolExampleFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolExample(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("exampletqshape", i18n("Example Tool")); } +}; + + +#endif //__KIS_TOOL_EXAMPLE_H__ diff --git a/chalk/plugins/tools/tool_curves/kis_tool_moutline.cc b/chalk/plugins/tools/tool_curves/kis_tool_moutline.cc new file mode 100644 index 00000000..4b7e51d4 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_moutline.cc @@ -0,0 +1,809 @@ +/* + * kis_tool_moutline.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_global.h" +#include "kis_iterators_pixel.h" +#include "kis_colorspace.h" +#include "kis_channelinfo.h" +#include "kis_doc.h" +#include "kis_painter.h" +#include "kis_point.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_tool_controller.h" +#include "kis_vec.h" +#include "kis_selection.h" +#include "kis_selection_options.h" +#include "kis_selected_transaction.h" +#include "kis_paintop_registry.h" +#include "kis_convolution_painter.h" + +#include "kis_tool_moutline.h" + +using namespace std; + +#define RMS(a, b) (sqrt ((a) * (a) + (b) * (b))) +#define ROUND(x) ((int) ((x) + 0.5)) + +const int NOEDGE = 0x0000; + +const int ORTHOGONAL_COST = 10; // 1*10 +const int DIAGONAL_COST = 14; // sqrt(2)*10 +const int MALUS = 20; // This applies to NOEDGE nodes + +const int DEFAULTDIST = 40; // Default distance between two automatic pivots +const int MAXDIST = 55; // Max distance +const int MINDIST = 15; +const int PAGESTEP = 5; + +class Node { + + TQPoint m_pos; + int m_gCost; + int m_hCost; + int m_tCost; + bool m_malus; + TQPoint m_parent; + +public: + + Node() + { + m_pos = m_parent = TQPoint(-1,-1); + m_gCost = m_hCost = m_tCost = 0; + m_malus = false; + } + + Node(const Node& node) + { + m_pos = node.pos(); + m_gCost = node.gCost(); + m_hCost = node.hCost(); + m_tCost = node.tCost(); + m_malus = node.malus(); + m_parent = node.tqparent(); + } + + Node(const TQPoint& tqparent, const TQPoint& pos, int g, int h, bool malus) + : m_pos(pos), m_hCost(h), m_malus(malus) + { + setGCost(g); + m_parent = tqparent; + } + ~Node () + { + } + + int gCost () const {return m_gCost;} + int hCost () const {return m_hCost;} + int tCost () const {return m_tCost;} + bool malus () const {return m_malus;} + TQPoint pos () const {return m_pos;} + int col () const {return m_pos.x();} + int row () const {return m_pos.y();} + TQPoint tqparent () const {return m_parent;} + + void setGCost (int g) + { + m_gCost = g+(m_malus?MALUS:0); + m_tCost = m_gCost+m_hCost; + } + void setHCost (int h) + { + m_hCost = h; + m_tCost = m_gCost+m_hCost; + } + void setPos (const TQPoint& pos) + { + m_pos = pos; + } + void setMalus (bool malus) + { + m_malus = malus; + } + void clear () + { + m_pos = TQPoint(-1,-1); + } + + bool operator== (const Node& n2) const + { + return m_pos == n2.pos(); + } + bool operator!= (const Node& n2) const + { + return m_pos != n2.pos(); + } + bool operator== (const TQPoint& n2) const + { + return m_pos == n2; + } + bool operator!= (const TQPoint& n2) const + { + return m_pos != n2; + } + bool operator< (const Node& n2) const + { + return m_tCost < n2.tCost(); + } + bool operator> (const Node& n2) const + { + return m_tCost > n2.tCost(); + } + + TQValueList getNeighbor(const GrayMatrix& src, const Node& end) + { + TQPoint tmpdist; + TQValueList temp; + int dcol, drow; + int g, h; + bool malus; + int x[8] = { 1, 1, 0,-1,-1,-1, 0, 1}, + y[8] = { 0,-1,-1,-1, 0, 1, 1, 1}; + + for (int i = 0; i < 8; i++) { + dcol = m_pos.x() + x[i]; + drow = m_pos.y() + y[i]; + tmpdist = TQPoint(dcol,drow) - end.pos(); + // I use src[0] here because all cols have same number of rows + if (dcol == (int)src.count() || dcol < 0 || + drow == (int)src[0].count() || drow < 0) + continue; + if (src[dcol][drow]) + malus = false; + else + malus = true; + if (i%2) + g = m_gCost + DIAGONAL_COST; + else + g = m_gCost + ORTHOGONAL_COST; + h = ORTHOGONAL_COST * (abs(tmpdist.x()) + abs(tmpdist.y())); + temp.append(Node(m_pos,TQPoint(dcol,drow),g,h,malus)); + } + return temp; + } + +}; + +KisKernelSP createKernel( TQ_INT32 i0, TQ_INT32 i1, TQ_INT32 i2, + TQ_INT32 i3, TQ_INT32 i4, TQ_INT32 i5, + TQ_INT32 i6, TQ_INT32 i7, TQ_INT32 i8, + TQ_INT32 factor, TQ_INT32 offset ) +{ + KisKernelSP kernel = new KisKernel(); + kernel->width = 3; + kernel->height = 3; + + kernel->factor = factor; + kernel->offset = offset; + + kernel->data = new TQ_INT32[9]; + kernel->data[0] = i0; + kernel->data[1] = i1; + kernel->data[2] = i2; + kernel->data[3] = i3; + kernel->data[4] = i4; + kernel->data[5] = i5; + kernel->data[6] = i6; + kernel->data[7] = i7; + kernel->data[8] = i8; + + return kernel; +} + +KisCurveMagnetic::KisCurveMagnetic (KisToolMagnetic *tqparent) + : m_parent(tqparent) +{ + m_standardkeepselected = false; +} + +KisCurveMagnetic::~KisCurveMagnetic () +{ + +} + +KisCurve::iterator KisCurveMagnetic::addPivot (KisCurve::iterator it, const KisPoint& point) +{ + return iterator(*this,m_curve.insert(it.position(), CurvePoint(point,true,false,LINEHINT))); +} + +KisCurve::iterator KisCurveMagnetic::pushPivot (const KisPoint& point) +{ + iterator it; + + it = pushPoint(point,true,false,LINEHINT); +// if (count() == 1 && !m_parent->editingMode()) +// addPoint(it,point,true,false,LINEHINT); + + return selectPivot(it); +} + +void KisCurveMagnetic::calculateCurve (KisCurve::iterator p1, KisCurve::iterator p2, KisCurve::iterator it) +{ + if (p1 == m_curve.end() || p2 == m_curve.end()) // It happens sometimes, for example on the first click + return; + if (m_parent->editingMode()) + return; + TQPoint start = (*p1).point().roundTQPoint(); + TQPoint end = (*p2).point().roundTQPoint(); + TQRect rc = TQRect(start,end).normalize(); + rc.setTopLeft(rc.topLeft()+TQPoint(-8,-8)); // Enlarge the view, so problems with gaussian blur can be removed + rc.setBottomRight(rc.bottomRight()+TQPoint(8,8)); // and we are able to find paths that go beyond the rect. + + KisPaintDeviceSP src = m_parent->m_currentImage->activeDevice(); + GrayMatrix dst = GrayMatrix(rc.width(),GrayCol(rc.height())); + + detectEdges (rc, src, dst); + reduceMatrix (rc, dst, 3, 3, 3, 3); + + Node startNode, endNode; + multiset openSet; + NodeMatrix openMatrix = NodeMatrix(rc.width(),NodeCol(rc.height())); + NodeMatrix closedMatrix = NodeMatrix(rc.width(),NodeCol(rc.height())); + + TQPoint tl(rc.topLeft().x(),rc.topLeft().y()); + start -= tl; // Relative to the matrix + end -= tl; // Relative to the matrix + + findEdge (start.x(), start.y(), dst, startNode); + openMatrix[startNode.col()][startNode.row()] = *openSet.insert(startNode); + endNode.setPos(end); + + while (!openSet.empty()) { + Node current = *openSet.begin(); + + openSet.erase(openSet.begin()); + openMatrix[current.col()][current.row()].clear(); + + TQValueList successors = current.getNeighbor(dst,endNode); + for (TQValueList::iterator i = successors.begin(); i != successors.end(); i++) { + int col = (*i).col(); + int row = (*i).row(); + if ((*i) == endNode) { + while (current.tqparent() != TQPoint(-1,-1)) { + it = addPoint(it,KisPoint(tl+current.pos()),false,false,LINEHINT); + current = closedMatrix[current.tqparent().x()][current.tqparent().y()]; + } + return; + } + Node *openNode = &openMatrix[col][row]; + if (*openNode != TQPoint(-1,-1)) { + if (*i > *openNode) + continue; + else { + openSet.erase(tqFind(openSet.begin(),openSet.end(),*openNode)); + openNode->clear(); // Clear the Node + } + } + Node *closedNode = &closedMatrix[col][row]; + if (*closedNode != TQPoint(-1,-1)) { + if ((*i) > (*closedNode)) + continue; + else { + openMatrix[col][row] = *openSet.insert(*closedNode); + closedNode->clear(); // Clear the Node + continue; + } + } + openMatrix[col][row] = *openSet.insert(*i); + } + closedMatrix[current.col()][current.row()] = current; + } +} + +void KisCurveMagnetic::findEdge (int col, int row, const GrayMatrix& src, Node& node) +{ + int x = -1; + int y = -1; + + // tmpdist out of range + KisVector2D mindist(5.0,5.0), tmpdist(1000.0,1000.0); + for (int i = -5; i < 6; i++) { + for (int j = -5; j < 6; j++) { + if (src[col+i][row+j] != NOEDGE) { + tmpdist = KisVector2D(i,j); + if (tmpdist.length() < mindist.length()) + mindist = tmpdist; + } + } + } + if (tmpdist.x() == 1000.0) + mindist = KisVector2D(0.0,0.0); + + x = (int)(col + mindist.x()); + y = (int)(row + mindist.y()); + + node.setPos(TQPoint(x,y)); +} + +void KisCurveMagnetic::reduceMatrix (TQRect& rc, GrayMatrix& m, int top, int right, int bottom, int left) +{ + TQPoint topleft(top, left); + TQPoint bottomright(bottom, right); + + rc.setTopLeft(rc.topLeft()+topleft); + rc.setBottomRight(rc.bottomRight()-bottomright); + + if (left) + m.erase(m.begin(),m.begin()+left); + if (right) + m.erase(m.end()-right,m.end()); + if (top) { + for (uint i = 0; i < m.count(); i++) + m[i].erase(m[i].begin(),m[i].begin()+top); + } + if (bottom) { + for (uint i = 0; i < m.count(); i++) + m[i].erase(m[i].end()-bottom,m[i].end()); + } +} + +void KisCurveMagnetic::detectEdges (const TQRect & rect, KisPaintDeviceSP src, GrayMatrix& dst) +{ + GrayMatrix graysrc(rect.width(),GrayCol(rect.height())); + GrayMatrix xdeltas(rect.width(),GrayCol(rect.height())); + GrayMatrix ydeltas(rect.width(),GrayCol(rect.height())); + GrayMatrix magnitude(rect.width(),GrayCol(rect.height())); + KisPaintDeviceSP smooth = new KisPaintDevice(src->colorSpace()); + + gaussianBlur(rect, src, smooth); + toGrayScale(rect, smooth, graysrc); + getDeltas(graysrc, xdeltas, ydeltas); + getMagnitude(xdeltas, ydeltas, magnitude); + nonMaxSupp(magnitude, xdeltas, ydeltas, dst); +} + +void KisCurveMagnetic::gaussianBlur (const TQRect& rect, KisPaintDeviceSP src, KisPaintDeviceSP dst) +{ + int grectx = rect.x(); + int grecty = rect.y(); + int grectw = rect.width(); + int grecth = rect.height(); + if (dst != src) { + KisPainter gc(dst); + gc.bitBlt(grectx, grecty, COMPOSITE_COPY, src, grectx, grecty, grectw, grecth); + gc.end(); + } + + KisConvolutionPainter painter( dst ); + // FIXME createKernel could create dynamic gaussian kernels having sigma as argument + KisKernelSP kernel = createKernel( 1, 1, 1, 1, 24, 1, 1, 1, 1, 32, 0); + painter.applyMatrix(kernel, grectx, grecty, grectw, grecth, BORDER_AVOID); +} + +void KisCurveMagnetic::toGrayScale (const TQRect& rect, KisPaintDeviceSP src, GrayMatrix& dst) +{ + int grectx = rect.x(); + int grecty = rect.y(); + int grectw = rect.width(); + int grecth = rect.height(); + TQColor c; + KisColorSpace *cs = src->colorSpace(); + + for (int row = 0; row < grecth; row++) { + KisHLineIteratorPixel srcIt = src->createHLineIterator(grectx, grecty+row, grectw, false); + for (int col = 0; col < grectw; col++) { + cs->toTQColor(srcIt.rawData(),&c); + dst[col][row] = tqGray(c.rgb()); + ++srcIt; + } + } +} + +void KisCurveMagnetic::getDeltas (const GrayMatrix& src, GrayMatrix& xdelta, GrayMatrix& ydelta) +{ + uint start = 1, xend = src[0].count()-1, yend = src.count()-1; + TQ_INT16 deri; + for (uint col = 0; col < src.count(); col++) { + for (uint row = 0; row < src[col].count(); row++) { + if (row >= start && row < xend) { + deri = src[col][row+1] - src[col][row-1]; + xdelta[col][row] = deri; + } else + xdelta[col][row] = 0; + if (col >= start && col < yend) { + deri = src[col+1][row] - src[col-1][row]; + ydelta[col][row] = deri; + } else + ydelta[col][row] = 0; + } + } +} + +void KisCurveMagnetic::getMagnitude (const GrayMatrix& xdelta, const GrayMatrix& ydelta, GrayMatrix& gradient) +{ + for (uint col = 0; col < xdelta.count(); col++) { + for (uint row = 0; row < xdelta[col].count(); row++) + gradient[col][row] = (TQ_INT16)(ROUND(RMS(xdelta[col][row],ydelta[col][row]))); + } +} + +void KisCurveMagnetic::nonMaxSupp (const GrayMatrix& magnitude, const GrayMatrix& xdelta, const GrayMatrix& ydelta, GrayMatrix& nms) +{ + // Directions: + // 1: 0 - 22.5 degrees + // 2: 22.5 - 67.5 degrees + // 3: 67.5 - 90 degrees + // Second direction is relative to a quadrant. The quadrant is known by looking at x and y derivatives + // First quadrant: Gx < 0 & Gy >= 0 + // Second quadrant: Gx < 0 & Gy < 0 + // Third quadrant: Gx >= 0 & Gy < 0 + // Fourth quadrant: Gx >= 0 & Gy >= 0 + // For this reason: first direction is relative to Gy only and third direction to Gx only + + double theta; // theta = invtan (|Gy| / |Gx|) This give the direction relative to a quadrant + TQ_INT16 mag; // Current magnitude + TQ_INT16 lmag; // Magnitude at the left (So this pixel is "more internal" than the current + TQ_INT16 rmag; // Magnitude at the right (So this pixel is "more external") + double xdel; // Current xdelta + double ydel; // Current ydelta + TQ_INT16 result; + + for (uint col = 0; col < magnitude.count(); col++) { + for (uint row = 0; row < magnitude[col].count(); row++) { + mag = magnitude[col][row]; + if (!mag || row == 0 || row == (magnitude[col].count()-1) || + col == 0 || col == (magnitude.count()-1)) + { + result = NOEDGE; + } else { + xdel = (double)xdelta[col][row]; + ydel = (double)ydelta[col][row]; + theta = atan(fabs(ydel)/fabs(xdel)); + if (theta < 0) + theta = fabs(theta)+M_PI_2; + theta = (theta * 360.0) / (2.0*M_PI); // Radians -> degrees + if (theta >= 0 && theta < 22.5) { // .0 - .3926990816 + if (ydel >= 0) { + lmag = magnitude[col][row-1]; + rmag = magnitude[col][row+1]; + } else { + lmag = magnitude[col][row+1]; + rmag = magnitude[col][row-1]; + } + } + if (theta >= 22.5 && theta < 67.5) { // .3926990816 - 1.1780972449 + if (xdel >= 0) { + if (ydel >= 0) { + lmag = magnitude[col-1][row-1]; + rmag = magnitude[col+1][row+1]; + } else { + lmag = magnitude[col+1][row-1]; + rmag = magnitude[col-1][row+1]; + } + } else { + if (ydel >= 0) { + lmag = magnitude[col-1][row+1]; + rmag = magnitude[col+1][row-1]; + } else { + lmag = magnitude[col+1][row+1]; + rmag = magnitude[col-1][row-1]; + } + } + } + if (theta >= 67.5 && theta <= 90.0) { // 1.1780972449 - 1.5707963266 + if (xdel >= 0) { + lmag = magnitude[col+1][row]; + rmag = magnitude[col-1][row]; + } else { + lmag = magnitude[col-1][row]; + rmag = magnitude[col+1][row]; + } + } + + if ((mag < lmag) || (mag < rmag)) { + result = NOEDGE; + } else { + if (rmag == mag) // If the external magnitude is equal to the current, suppress current. + result = NOEDGE; + else + result = (mag > 255) ? 255 : mag; + } + } + nms[col][row] = result; + } + } +} + +KisToolMagnetic::KisToolMagnetic () + : super("Magnetic Outline Tool") +{ + setName("tool_moutline"); + setCursor(KisCursor::load("tool_moutline_cursor.png", 6, 6)); + + m_editingMode = false; + m_editingCursor = m_draggingCursor = false; + + m_mode = 0; + m_curve = m_derived = 0; + m_current = m_previous = 0; + + m_distance = DEFAULTDIST; + + m_transactionMessage = i18n("Magnetic Outline Selection"); +} + +KisToolMagnetic::~KisToolMagnetic () +{ + m_curve = 0; + delete m_derived; +} + +void KisToolMagnetic::update (KisCanvasSubject *subject) +{ + super::update(subject); +} + +void KisToolMagnetic::activate () +{ + super::activate(); + if (!m_derived) { + m_derived = new KisCurveMagnetic(this); + m_curve = m_derived; + } +} + +void KisToolMagnetic::deactivate () +{ + m_curve->endActionOptions(); + m_actionOptions = NOOPTIONS; + m_dragging = false; + m_drawPivots = true; +} + +void KisToolMagnetic::keyPress(TQKeyEvent *event) +{ + if (event->key() == TQt::Key_Control) { + draw(false); + if (m_editingMode) { + m_editingMode = false; + if (m_current != 0) + m_curve->selectPivot(m_current,false); + m_mode->setText(i18n("Automatic Mode")); + } else { + m_editingMode = true; + m_mode->setText(i18n("Manual Mode")); + } + draw(false); + } else if (event->key() == TQt::Key_Delete && m_curve->count()) { + draw(false); + m_dragging = false; + if (m_curve->pivots().count() == 2) + m_curve->clear(); + else { + if ((*m_current) == m_curve->last() && !(m_editingMode)) { + m_curve->deletePivot(m_current.previousPivot()); + m_previous = m_current.previousPivot(); + } else { + m_editingMode = false; + m_curve->deletePivot(m_current); + m_previous = m_current = m_curve->selectPivot(m_curve->lastIterator()); + m_editingMode = true; + } + } + draw(false); + } else + super::keyPress(event); +} + +void KisToolMagnetic::buttonRelease(KisButtonReleaseEvent *event) +{ + if (m_editingMode) { + draw(m_current); + m_editingMode = false; + if (!m_curve->isEmpty()) + m_curve->movePivot(m_current, m_currentPoint); + m_editingMode = true; + draw(m_current); + } + super::buttonRelease(event); +} + +void KisToolMagnetic::buttonPress(KisButtonPressEvent *event) +{ + updateOptions(event->state()); + if (!m_currentImage) + return; + if (event->button() == Qt::LeftButton) { + m_dragging = true; + m_currentPoint = event->pos(); + PointPair temp(m_curve->end(),false); + if (m_editingMode) + temp = pointUnderMouse (m_subject->canvasController()->windowToView(event->pos().toTQPoint())); + if (temp.first == m_curve->end() && !(m_actionOptions)) { + if (m_editingMode) { + draw(true, true); + m_curve->selectAll(false); + draw(true, true); + } + draw(m_curve->end()); + if (!m_curve->isEmpty()) { + m_previous = m_current; + m_current = m_curve->pushPivot(event->pos()); + } else { + m_previous = m_current = m_curve->pushPivot(event->pos()); + } + if (m_curve->pivots().count() > 1) + m_curve->calculateCurve(m_previous,m_current,m_current); + if (m_editingMode) + draw(); + else { + if ((*m_previous).point() == (*m_current).point()) + draw(m_curve->end()); + else + draw(); + } + } else if (temp.first != m_curve->end() && m_editingMode) { + if (temp.second) { + draw(true, true); + m_current = m_curve->selectPivot(temp.first); + draw(true, true); + } else { + draw(false); + m_current = selectByMouse(temp.first); + draw(false); + } + if (!(*m_current).isSelected()) + m_dragging = false; + } + } +} + +void KisToolMagnetic::move(KisMoveEvent *event) +{ + updateOptions(event->state()); + if (m_currentPoint == event->pos().floorTQPoint()) + return; + if (m_editingMode) { + PointPair temp = pointUnderMouse(m_subject->canvasController()->windowToView(event->pos().toTQPoint())); + if (temp.first == m_curve->end() && !m_dragging) { + if (m_editingCursor || m_draggingCursor) { + setCursor(KisCursor::load("tool_moutline_cursor.png", 6, 6)); + m_editingCursor = m_draggingCursor = false; + } + } else { + if (!m_draggingCursor && temp.second) { + setCursor(KisCursor::load("tool_moutline_dragging.png", 6, 6)); + m_editingCursor = false; + m_draggingCursor = true; + } + if (!m_editingCursor && !temp.second) { + setCursor(KisCursor::load("tool_moutline_editing.png", 6, 6)); + m_editingCursor = true; + m_draggingCursor = false; + } + } + if (!m_dragging) + return; + } else { + if (m_editingCursor || m_draggingCursor) { + setCursor(KisCursor::load("tool_moutline_cursor.png", 6, 6)); + m_editingCursor = m_draggingCursor = false; + } + } + if (m_curve->selectedPivots().isEmpty()) + return; + + KisPoint trans = event->pos() - m_currentPoint; + KisPoint dist; + dist = (*m_current).point() - (*m_current.previousPivot()).point(); + if ((m_distance >= MINDIST && (fabs(dist.x()) + fabs(dist.y())) > m_distance && !(m_editingMode)) + || m_curve->pivots().count() == 1) { + draw(m_curve->end()); + m_previous = m_current; + m_current = m_curve->pushPivot(event->pos()); + } else if ((*m_previous).point() == (*m_current).point() && (*m_previous).point() == m_curve->last().point()) + draw(m_curve->end()); + else + draw(m_current); + m_curve->movePivot(m_current,event->pos()); + m_currentPoint = event->pos().floorTQPoint(); + draw(m_current); +} + +KisCurve::iterator KisToolMagnetic::selectByMouse(KisCurve::iterator it) +{ + KisCurve::iterator currPivot = m_curve->selectPivot(m_curve->addPivot(it, KisPoint(0,0))); + m_curve->movePivot(currPivot,(*it).point()); + + return currPivot; +} + +void KisToolMagnetic::slotCommitCurve () +{ + if (!m_curve->isEmpty()) + commitCurve(); +} + +void KisToolMagnetic::slotSetDistance (int dist) +{ + m_distance = dist; +} + +TQWidget* KisToolMagnetic::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = super::createOptionWidget(tqparent); + TQVBoxLayout * l = dynamic_cast(m_optWidget->tqlayout()); + TQGridLayout *box = new TQGridLayout(l, 2, 2, 3); + box->setColStretch(0, 1); + box->setColStretch(1, 1); + Q_CHECK_PTR(box); + + m_mode = new TQLabel(i18n("Automatic mode"), m_optWidget); + m_lbDistance = new TQLabel(i18n("Distance: "), m_optWidget); + TQPushButton *finish = new TQPushButton(i18n("To Selection"), m_optWidget); + m_slDistance = new TQSlider(MINDIST, MAXDIST, PAGESTEP, m_distance, Qt::Horizontal, m_optWidget); + + connect(m_slDistance, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetDistance(int))); + connect(finish, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotCommitCurve())); + + box->addWidget(m_lbDistance, 0, 0); + box->addWidget(m_slDistance, 0, 1); + box->addWidget(m_mode, 1, 0); + box->addWidget(finish, 1, 1); + + return m_optWidget; +} + +void KisToolMagnetic::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("Magnetic Outline"), + "tool_moutline", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Magnetic Selection: move around an edge to select it. Hit Ctrl to enter/quit manual mode, and double click to finish.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_moutline.moc" diff --git a/chalk/plugins/tools/tool_curves/kis_tool_moutline.h b/chalk/plugins/tools/tool_curves/kis_tool_moutline.h new file mode 100644 index 00000000..ac7327fe --- /dev/null +++ b/chalk/plugins/tools/tool_curves/kis_tool_moutline.h @@ -0,0 +1,132 @@ +/* + * kis_tool_moutline.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_MOUTLINE_H_ +#define KIS_TOOL_MOUTLINE_H_ + +#include "kis_tool_factory.h" +#include "kis_curve_framework.h" +#include "kis_tool_curve.h" + +class TQSlider; +class KisToolMagnetic; +class KisVector2D; +class Node; + +typedef TQValueVector NodeCol; +typedef TQValueVector NodeMatrix; +typedef TQValueVector GrayCol; +typedef TQValueVector GrayMatrix; + +class KisCurveMagnetic : public KisCurve { + + typedef KisCurve super; + + KisToolMagnetic *m_parent; + + void reduceMatrix (TQRect&, GrayMatrix&, int, int, int, int); + void findEdge (int, int, const GrayMatrix&, Node&); + void detectEdges (const TQRect&, KisPaintDeviceSP, GrayMatrix&); + + void gaussianBlur (const TQRect&, KisPaintDeviceSP, KisPaintDeviceSP); + void toGrayScale (const TQRect&, KisPaintDeviceSP, GrayMatrix&); + void getDeltas (const GrayMatrix&, GrayMatrix&, GrayMatrix&); + void getMagnitude (const GrayMatrix&, const GrayMatrix&, GrayMatrix&); + void nonMaxSupp (const GrayMatrix&, const GrayMatrix&, const GrayMatrix&, GrayMatrix&); + +public: + + KisCurveMagnetic (KisToolMagnetic *tqparent); + ~KisCurveMagnetic (); + + virtual KisCurve::iterator addPivot (iterator, const KisPoint&); + virtual KisCurve::iterator pushPivot (const KisPoint&); + virtual void calculateCurve (iterator, iterator, iterator); + +}; + +class KisToolMagnetic : public KisToolCurve { + + typedef KisToolCurve super; + Q_OBJECT + TQ_OBJECT + + friend class KisCurveMagnetic; + +public: + + KisToolMagnetic(); + ~KisToolMagnetic(); + + virtual void update (KisCanvasSubject*); + virtual void setup (KActionCollection*); + virtual enumToolType toolType() { return TOOL_SELECT; } + virtual TQ_UINT32 priority() { return 9; } + + virtual void keyPress(TQKeyEvent*); + virtual void buttonPress(KisButtonPressEvent*); + virtual void buttonRelease(KisButtonReleaseEvent*); + virtual void move(KisMoveEvent*); + + virtual KisCurve::iterator selectByMouse(KisCurve::iterator it); + + bool editingMode() {return m_editingMode;} + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + +public slots: + + virtual void activate (); + virtual void deactivate (); + + void slotCommitCurve (); + void slotSetDistance (int); + +private: + + KisCurveMagnetic *m_derived; + TQWidget* m_optWidget; + TQLabel* m_mode; + TQLabel* m_lbDistance; + TQSlider* m_slDistance; + bool m_editingMode; + bool m_editingCursor; + bool m_draggingCursor; + bool m_needNewPivot; + + int m_distance; + +}; + +class KisToolMagneticFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolMagneticFactory() : super() {}; + virtual ~KisToolMagneticFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolMagnetic(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("magneticoutline", i18n("Magnetic Outline Selection Tool")); } +}; + +#endif // KIS_TOOL_MOUTLINE_H_ diff --git a/chalk/plugins/tools/tool_curves/tool_bezier_cursor.png b/chalk/plugins/tools/tool_curves/tool_bezier_cursor.png new file mode 100644 index 00000000..d25a4ab1 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_bezier_cursor.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_bezier_paint.png b/chalk/plugins/tools/tool_curves/tool_bezier_paint.png new file mode 100644 index 00000000..290a1f02 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_bezier_paint.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_bezier_select.png b/chalk/plugins/tools/tool_curves/tool_bezier_select.png new file mode 100644 index 00000000..106c47ff Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_bezier_select.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_curve_dragging.png b/chalk/plugins/tools/tool_curves/tool_curve_dragging.png new file mode 100644 index 00000000..a7669ef1 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_curve_dragging.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_curves.cc b/chalk/plugins/tools/tool_curves/tool_curves.cc new file mode 100644 index 00000000..f9f5be33 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/tool_curves.cc @@ -0,0 +1,67 @@ +/* + * tool_bezier.cc -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_curves.h" +#include "kis_tool_bezier_paint.h" +#include "kis_tool_bezier_select.h" +#include "kis_tool_moutline.h" + + +typedef KGenericFactory ToolCurvesFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolcurves, ToolCurvesFactory( "chalk" ) ) + + +ToolCurves::ToolCurves(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolCurvesFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( tqparent ); + r->add(new KisToolBezierPaintFactory()); + r->add(new KisToolBezierSelectFactory()); + r->add(new KisToolMagneticFactory()); + } + +} + +ToolCurves::~ToolCurves() +{ +} + +#include "tool_curves.moc" diff --git a/chalk/plugins/tools/tool_curves/tool_curves.h b/chalk/plugins/tools/tool_curves/tool_curves.h new file mode 100644 index 00000000..82199e48 --- /dev/null +++ b/chalk/plugins/tools/tool_curves/tool_curves.h @@ -0,0 +1,36 @@ +/* + * tool_bezier.h -- part of Chalk + * + * Copyright (c) 2006 Emanuele Tamponi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_BEZIER_H_ +#define TOOL_BEZIER_H_ + +#include + +class ToolCurves : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolCurves(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolCurves(); + +}; + +#endif // TOOL_BEZIER_H__ diff --git a/chalk/plugins/tools/tool_curves/tool_example.png b/chalk/plugins/tools/tool_curves/tool_example.png new file mode 100644 index 00000000..893d2514 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_example.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_example_cursor.png b/chalk/plugins/tools/tool_curves/tool_example_cursor.png new file mode 100644 index 00000000..d25a4ab1 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_example_cursor.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_moutline.png b/chalk/plugins/tools/tool_curves/tool_moutline.png new file mode 100644 index 00000000..e2670292 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_moutline.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_moutline_cursor.png b/chalk/plugins/tools/tool_curves/tool_moutline_cursor.png new file mode 100644 index 00000000..283a86d1 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_moutline_cursor.png differ diff --git a/chalk/plugins/tools/tool_curves/tool_moutline_editing.png b/chalk/plugins/tools/tool_curves/tool_moutline_editing.png new file mode 100644 index 00000000..3a308901 Binary files /dev/null and b/chalk/plugins/tools/tool_curves/tool_moutline_editing.png differ diff --git a/chalk/plugins/tools/tool_curves/wdg_tool_example.ui b/chalk/plugins/tools/tool_curves/wdg_tool_example.ui new file mode 100644 index 00000000..eac06e2b --- /dev/null +++ b/chalk/plugins/tools/tool_curves/wdg_tool_example.ui @@ -0,0 +1,128 @@ + +WdgToolExample + + + WdgToolExample + + + + 0 + 0 + 280 + 50 + + + + Example + + + + unnamed + + + 0 + + + + tqlayout8 + + + + unnamed + + + + textLabel1 + + + Vertices: + + + isbX + + + + + verticesSpinBox + + + 100 + + + 2 + + + 5 + + + + + + + tqlayout7 + + + + unnamed + + + + textLabel2 + + + Ratio: + + + isbWidth + + + + + ratioSpinBox + + + + 0 + 5 + 0 + 0 + + + + + + + + + verticesSpinBox + ratioSpinBox + + + + KisIntSpinbox +
kis_int_spinbox.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image4 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + knuminput.h + knuminput.h + +
diff --git a/chalk/plugins/tools/tool_filter/Makefile.am b/chalk/plugins/tools/tool_filter/Makefile.am new file mode 100644 index 00000000..e1f6d5b4 --- /dev/null +++ b/chalk/plugins/tools/tool_filter/Makefile.am @@ -0,0 +1,38 @@ +kde_services_DATA = chalktoolfilter.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolfilter_la_SOURCES = \ + kis_filterop.cc \ + kis_tool_filter.cc \ + tool_filter.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolfilter.la + +noinst_HEADERS = \ + kis_filterop.h \ + kis_tool_filter.h \ + tool_filter.h + +chalktoolfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolfilter_la_LIBADD = ../../../libchalkcommon.la + +chalktoolfilter_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_filter.png \ + tool_filter_cursor.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_filter/chalktoolfilter.desktop b/chalk/plugins/tools/tool_filter/chalktoolfilter.desktop new file mode 100644 index 00000000..d22b19df --- /dev/null +++ b/chalk/plugins/tools/tool_filter/chalktoolfilter.desktop @@ -0,0 +1,92 @@ +[Desktop Entry] +Name=Filter Tool +Name[bg]=Инструмент за филтриране +Name[br]=Ostil ar sil +Name[ca]=Eina de filtre +Name[cy]=Erfyn Hidlen +Name[da]=Filterværktøj +Name[de]=Filterwerkzeug +Name[el]=Εργαλείο φίλτρου +Name[eo]=Filtrado-ilo +Name[es]=Herramienta para filtrar +Name[et]=Filtritööriist +Name[eu]=Iragazkia tresna +Name[fa]=ابزار پالایه +Name[fi]=Suodintyökalu +Name[fr]=Outil filtre +Name[fy]=Filter-ark +Name[ga]=Uirlis Scagaire +Name[gl]=Ferramenta de Filtraxe +Name[he]=כלי סינון +Name[hu]=Szűrő eszköz +Name[is]=Síutól +Name[it]=Strumento di filtro +Name[ja]=フィルタツール +Name[km]=ឧបករណ៍​ត្រង +Name[lv]=Filtru rīki +Name[ms]=Alat Penapis +Name[nb]=Filterverktøy +Name[nds]=Filterwarktüüch +Name[ne]=फिल्टर उपकरण +Name[nl]=Filtergereedschap +Name[nn]=Filterverktøy +Name[pl]=Narzędzie filtru +Name[pt]=Ferramenta de Filtragem +Name[pt_BR]=Ferramenta de Filtragem +Name[ru]=Фильтр +Name[se]=Sillenreaidu +Name[sk]=Filter +Name[sl]=Orodje za filtriranje +Name[sr]=Филтерски алат +Name[sr@Latn]=Filterski alat +Name[sv]=Filtreringsverktyg +Name[uk]=Засіб фільтрування +Name[uz]=Filter vositasi +Name[uz@cyrillic]=Филтер воситаси +Name[zh_CN]=过滤工具 +Name[zh_TW]=濾鏡工具 +Comment=Filter tool and paint operation +Comment[bg]=Инструмент за филтриране и рисуване +Comment[ca]=Operació d'eina de filtre i pintura +Comment[cy]=Erfyn hidlen a gweithrediadau paent +Comment[da]=Filterværktøj og maleoperation +Comment[de]=Filterwerkzeug und Maloperation +Comment[el]=Εργαλείο φίλτρου και λειτουργία ζωγραφικής +Comment[eo]=Escepto ĉe kalkulado kun realaj nombroj. +Comment[es]=Herramienta de filtrado y operaciones de pintado +Comment[et]=Filtritööriist ja joonistamistoiming +Comment[eu]=Iragazkia tresna eta margotze-eragiketa +Comment[fa]=ابزار پالایه و عمل رنگ‌آمیزی +Comment[fi]=Suodintyökalu ja väritystoimepinde +Comment[fr]=Outil de filtrage et opération de dessin +Comment[fy]=Filter-ark en skildersaksje +Comment[gl]=Ferramenta de filtraxe e operación de pintura +Comment[he]=כלי סינון ופעולת ציור +Comment[hu]=Szűrő eszköz és festési művelet +Comment[is]=Síutól og málunaraðgerðir +Comment[it]=Strumento di filtro e operazione di disegno +Comment[ja]=フィルタツールと画像操作 +Comment[km]=ដំណើរ​ការ​គូរ និង​ឧបករណ៍​តម្រង +Comment[ms]=Alat penapis dan operasi warna +Comment[nb]=Filterverktøy og maleteknikker +Comment[nds]=Filterwarktüüch un Malen +Comment[ne]=फिल्टर उपकरण र पेन्ट अपरेसन +Comment[nl]=Filtergereedschap en schilderoperatie +Comment[nn]=Filterverktøy og måleoperasjon +Comment[pl]=Narzędzie filtrat oraz operacje malowania +Comment[pt]=Ferramenta de filtragem e operação de pintura +Comment[pt_BR]=Ferramenta de filtragem e operação de pintura +Comment[ru]=Фильтр обработки изображения +Comment[se]=Sillenreaidu ja málendoaibma +Comment[sk]=Nástroj filter a operácie kreslenia +Comment[sl]=Orodje za filtriranje in operacije za slikanje +Comment[sr]=Филтерски алат и операција цртања +Comment[sr@Latn]=Filterski alat i operacija crtanja +Comment[sv]=Filtreringsverktyg och målningsåtgärd +Comment[uk]=Засіб фільтрування та дій малювання +Comment[zh_CN]=过滤器工具和绘图集成 +Comment[zh_TW]=濾鏡工具與繪圖操作 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolfilter +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_filter/kis_filterop.cc b/chalk/plugins/tools/tool_filter/kis_filterop.cc new file mode 100644 index 00000000..1f2200b3 --- /dev/null +++ b/chalk/plugins/tools/tool_filter/kis_filterop.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_iterators_pixel.h" +#include "kis_paintop.h" +#include "kis_colorspace.h" +#include "kis_selection.h" +#include "kis_filterop.h" + + +KisPaintOp * KisFilterOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisFilterOp(painter); + return op; +} + + +KisFilterOp::KisFilterOp(KisPainter * painter) + : super(painter) +{ + m_filterConfiguration = 0; +} + +KisFilterOp::~KisFilterOp() +{ + delete m_filterConfiguration; +} + +void KisFilterOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + if (!m_painter) return; + + KisFilterSP filter = m_painter->filter(); + if (!filter) return; + + if ( ! m_source ) return; + + KisBrush * brush = m_painter->brush(); + if (!brush) return; + + KisColorSpace * colorSpace = m_source->colorSpace(); + + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + // Filters always work with a tqmask, never with an image; that + // wouldn't be useful at all. + KisAlphaMaskSP tqmask = brush->tqmask(info, xFraction, yFraction); + + m_painter->setPressure(info.pressure); + + TQ_INT32 tqmaskWidth = tqmask->width(); + TQ_INT32 tqmaskHeight = tqmask->height(); + + // Create a temporary paint device + KisPaintDeviceSP tmpDev = new KisPaintDevice(colorSpace, "filterop tmpdev"); + Q_CHECK_PTR(tmpDev); + + // Copy the layer data onto the new paint device + + KisPainter p( tmpDev ); + p.bitBlt( 0, 0, COMPOSITE_COPY, m_source, OPACITY_OPAQUE, x, y, tqmaskWidth, tqmaskHeight ); + + // Filter the paint device + filter->disableProgress(); + filter->process( tmpDev, tmpDev, m_filterConfiguration, TQRect( 0, 0, tqmaskWidth, tqmaskHeight )); + filter->enableProgress(); + + // Apply the tqmask on the paint device (filter before tqmask because edge pixels may be important) + for (int y = 0; y < tqmaskHeight; y++) + { + KisHLineIterator hiter = tmpDev->createHLineIterator(0, y, tqmaskWidth, false); + int x=0; + while(! hiter.isDone()) + { + TQ_UINT8 alpha = tqmask->alphaAt( x++, y ); + colorSpace->setAlpha(hiter.rawData(), alpha, 1); + + ++hiter; + } + } + + // Blit the paint device onto the layer + TQRect dabRect = TQRect(0, 0, tqmaskWidth, tqmaskHeight); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = m_painter->device()->image(); + + if (image != 0) { + dstRect &= image->bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + if (m_source->hasSelection()) { + m_painter->bltSelection(dstRect.x(), dstRect.y(), m_painter->compositeOp(), tmpDev.data(), + m_source->selection(), m_painter->opacity(), sx, sy, sw, sh); + } + else { + m_painter->bitBlt(dstRect.x(), dstRect.y(), m_painter->compositeOp(), tmpDev.data(), m_painter->opacity(), sx, sy, sw, sh); + } + + m_painter->addDirtyRect(dstRect); +} + +void KisFilterOp::setFilterConfiguration(KisFilterConfiguration* filterConfiguration) +{ + delete m_filterConfiguration; + m_filterConfiguration = filterConfiguration; +} diff --git a/chalk/plugins/tools/tool_filter/kis_filterop.h b/chalk/plugins/tools/tool_filter/kis_filterop.h new file mode 100644 index 00000000..06703b34 --- /dev/null +++ b/chalk/plugins/tools/tool_filter/kis_filterop.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2004 Clarence Dang + * Copyright (c) 2004 Adrian Page + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_FILTEROP_H_ +#define KIS_FILTEROP_H_ + +#include "kis_paintop.h" +#include + +class KisPoint; +class KisPainter; +class KisFilterConfiguration; + +class KisFilterOpFactory : public KisPaintOpFactory { + +public: + KisFilterOpFactory() {} + virtual ~KisFilterOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID(("filter"), i18n("Filter")); } + virtual bool userVisible(KisColorSpace * = 0) { return false; } +}; + + + +class KRITAPAINT_EXPORT KisFilterOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisFilterOp(KisPainter * painter); + virtual ~KisFilterOp(); + + void paintAt(const KisPoint &pos, const KisPaintInformation& info); +public: + void setFilterConfiguration(KisFilterConfiguration*); +private: + KisFilterConfiguration* m_filterConfiguration; +}; + + +#endif // KIS_FILTEROP_H_ diff --git a/chalk/plugins/tools/tool_filter/kis_tool_filter.cc b/chalk/plugins/tools/tool_filter/kis_tool_filter.cc new file mode 100644 index 00000000..e9fdad9e --- /dev/null +++ b/chalk/plugins/tools/tool_filter/kis_tool_filter.cc @@ -0,0 +1,154 @@ +/* + * kis_tool_filter.cc - part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_filter_config_widget.h" +#include "kis_tool_filter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +KisToolFilter::KisToolFilter() + : super(i18n("Filter Brush")), m_filterConfigurationWidget(0) +{ + setName("tool_filter"); + m_subject = 0; + setCursor(KisCursor::load("tool_filter_cursor.png", 5, 5)); +} + +KisToolFilter::~KisToolFilter() +{ +} + +void KisToolFilter::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Filter Brush"), + "tool_filter", 0, this, + TQT_SLOT(activate()), collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Paint with filters")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolFilter::initPaint(KisEvent *e) +{ + // Some filters want to paint directly on the current state of + // the canvas, others cannot handle that and need a temporary layer + // so they can work on the old data before painting started. + m_paintIncremental = m_filter->supportsIncrementalPainting(); + + super::initPaint(e); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp("filter", 0, painter()); + op->setSource ( m_source ); + painter()->setPaintOp(op); // And now the painter owns the op and will destroy it. + painter()->setFilter( m_filter ); + + // XXX: Isn't there a better way to set the config? The filter config widget needs to + // to go into the tool options widget, and just the data carried over to the filter. + // I've got a bit of a problem with core classes having too much GUI about them. + // BSAR. + dynamic_cast(op)->setFilterConfiguration( m_filter->configuration( m_filterConfigurationWidget) ); +} + +TQWidget* KisToolFilter::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + + m_cbFilter = new KisCmbIDList(widget); + Q_CHECK_PTR(m_cbFilter); + + TQLabel* lbFilter = new TQLabel(i18n("Filter:"), widget); + Q_CHECK_PTR(lbFilter); + + // Check which filters support painting + KisIDList l = KisFilterRegistry::instance()->listKeys(); + KisIDList l2; + KisIDList::iterator it; + for (it = l.begin(); it != l.end(); ++it) { + KisFilterSP f = KisFilterRegistry::instance()->get(*it); + if (f->supportsPainting()) { + l2.push_back(*it); + } + } + m_cbFilter ->setIDList( l2 ); + + addOptionWidgetOption(m_cbFilter, lbFilter); + + m_optionLayout = new TQGridLayout(widget, 1, 1, 0, 6); + Q_CHECK_PTR(m_optionLayout); + super::addOptionWidgetLayout(m_optionLayout); + + connect(m_cbFilter, TQT_SIGNAL(activated ( const KisID& )), this, TQT_SLOT( changeFilter( const KisID& ) ) ); + changeFilter( m_cbFilter->currentItem () ); + + return widget; +} + +void KisToolFilter::changeFilter( const KisID & id) +{ + m_filter = KisFilterRegistry::instance()->get( id ); + Q_ASSERT(m_filter != 0); + if( m_filterConfigurationWidget != 0 ) + { + m_optionLayout->remove ( m_filterConfigurationWidget ); + delete m_filterConfigurationWidget; + } + + m_source = m_currentImage->activeDevice(); + if (!m_source) return; + + m_filterConfigurationWidget = m_filter->createConfigurationWidget( optionWidget(), m_source ); + if( m_filterConfigurationWidget != 0 ) + { + m_optionLayout->addMultiCellWidget ( m_filterConfigurationWidget, 2, 2, 0, 1 ); + m_filterConfigurationWidget->show(); + } +} + +#include "kis_tool_filter.moc" diff --git a/chalk/plugins/tools/tool_filter/kis_tool_filter.h b/chalk/plugins/tools/tool_filter/kis_tool_filter.h new file mode 100644 index 00000000..e8b5e86b --- /dev/null +++ b/chalk/plugins/tools/tool_filter/kis_tool_filter.h @@ -0,0 +1,81 @@ +/* + * kis_tool_filter.h - part of Chalk + * + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_TOOL_FILTER_H__ +#define __KIS_TOOL_FILTER_H__ + +#include "kis_tool_freehand.h" +#include "kis_tool_factory.h" + +class TQComboBox; +class TQGridLayout; +class KisEvent; +class KisFilterConfigurationWidget; +class KisButtonPressEvent; +class KisView; +class KisID; +class KisCmbIDList; + + +class KisToolFilter : public KisToolFreehand { + Q_OBJECT + TQ_OBJECT + typedef KisToolFreehand super; + +public: + KisToolFilter(); + virtual ~KisToolFilter(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual TQ_UINT32 priority() { return 1; } + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + +public slots: + void changeFilter( const KisID & filter); + +protected: + virtual void initPaint(KisEvent *e); + +private: + KisFilterSP m_filter; + TQWidget* m_filterConfigurationWidget; + TQGridLayout* m_optionLayout; + KisCmbIDList * m_cbFilter; +}; + + +class KisToolFilterFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolFilterFactory() : super() {}; + virtual ~KisToolFilterFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolFilter(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("filter", i18n("Filter Tool")); } +}; + +#endif //__KIS_TOOL_FILTER_H__ + diff --git a/chalk/plugins/tools/tool_filter/tool_filter.cc b/chalk/plugins/tools/tool_filter/tool_filter.cc new file mode 100644 index 00000000..484ed39a --- /dev/null +++ b/chalk/plugins/tools/tool_filter/tool_filter.cc @@ -0,0 +1,68 @@ +/* + * tool_filter.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tool_filter.h" +#include "kis_filterop.h" +#include "kis_tool_filter.h" + + +typedef KGenericFactory ToolFilterFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolfilter, ToolFilterFactory( "chalk" ) ) + + +ToolFilter::ToolFilter(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolFilterFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + r->add( new KisToolFilterFactory()); + + // XXX: Put this in a separate plugin? + KisPaintOpRegistry * pr = KisPaintOpRegistry::instance(); + pr->add( new KisFilterOpFactory ); + + } +} + +ToolFilter::~ToolFilter() +{ +} + +#include "tool_filter.moc" diff --git a/chalk/plugins/tools/tool_filter/tool_filter.h b/chalk/plugins/tools/tool_filter/tool_filter.h new file mode 100644 index 00000000..7bf33dca --- /dev/null +++ b/chalk/plugins/tools/tool_filter/tool_filter.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_FILTER_H_ +#define TOOL_FILTER_H_ + +#include + +class KisView; + +/** + * A module that provides a filter tool. + */ +class ToolFilter : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolFilter(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolFilter(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_FILTER_H_ diff --git a/chalk/plugins/tools/tool_filter/tool_filter.png b/chalk/plugins/tools/tool_filter/tool_filter.png new file mode 100644 index 00000000..6598d9fc Binary files /dev/null and b/chalk/plugins/tools/tool_filter/tool_filter.png differ diff --git a/chalk/plugins/tools/tool_filter/tool_filter.svg b/chalk/plugins/tools/tool_filter/tool_filter.svg new file mode 100644 index 00000000..eb808919 --- /dev/null +++ b/chalk/plugins/tools/tool_filter/tool_filter.svg @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/tool_filter/tool_filter_cursor.png b/chalk/plugins/tools/tool_filter/tool_filter_cursor.png new file mode 100644 index 00000000..d1e7f3d5 Binary files /dev/null and b/chalk/plugins/tools/tool_filter/tool_filter_cursor.png differ diff --git a/chalk/plugins/tools/tool_perspectivegrid/Makefile.am b/chalk/plugins/tools/tool_perspectivegrid/Makefile.am new file mode 100644 index 00000000..b3b0f74f --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/Makefile.am @@ -0,0 +1,35 @@ +kde_services_DATA = chalktoolperspectivegrid.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolperspectivegrid_la_SOURCES = \ + tool_perspectivegrid.cc \ + kis_tool_perspectivegrid.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolperspectivegrid.la + +noinst_HEADERS = \ + tool_perspectivegrid.h \ + kis_tool_perspectivegrid.h + +chalktoolperspectivegrid_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolperspectivegrid_la_LIBADD = ../../../libchalkcommon.la + +METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_perspectivegrid.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_perspectivegrid/chalktoolperspectivegrid.desktop b/chalk/plugins/tools/tool_perspectivegrid/chalktoolperspectivegrid.desktop new file mode 100644 index 00000000..70001614 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/chalktoolperspectivegrid.desktop @@ -0,0 +1,35 @@ +[Desktop Entry] +Name=Perspective Grid Tool +Name[bg]=Инструмент мрежа +Name[ca]=Eina de graella de perspectiva +Name[da]=Perspektivgitterværktøj +Name[de]=Perspektive-Raster-Werkzeug +Name[el]=Εργαλείο προοπτικού πλέγματος +Name[eo]=Perspektivkrado-ilo +Name[es]=Herramienta Cuadrícula de perspectiva +Name[et]=Perspektiivvõrgu tööriist +Name[fa]=ابزار توری بُعدنما +Name[fy]=Perspeksjeraster-ark +Name[hu]=Perspektívarács +Name[it]=Strumento di reticolo prospettico +Name[ja]=遠近法グリッドツール +Name[km]=ឧបករណ៍​ក្រឡា​ចត្រង្គ​យថាទស្សន៍ +Name[nb]=Perspektivnett-verktøy +Name[nds]=Kiekwinkelgadder-Warktüüch +Name[ne]=दृश्यात्मक ग्रीड उपकरण +Name[nl]=Perspectiefraster-gereedschap +Name[pl]=Narzędzie siatki perspektywy +Name[pt]=Ferramenta de Grelha em Perspectiva +Name[pt_BR]=Ferramenta de Grade em Perspectiva +Name[ru]=Перспектива +Name[sk]=Perspektívna mriežka +Name[sl]=Orodja Mreža za perspektivo +Name[sr]=Алат за мрежу у перспективи +Name[sr@Latn]=Alat za mrežu u perspektivi +Name[sv]=Perspektivrutnätsverktyg +Name[uk]=Засіб ґратки перспективи +Name[zh_TW]=透視格工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolperspectivegrid +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc b/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc new file mode 100644 index 00000000..3a21e72e --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.cc @@ -0,0 +1,499 @@ +/* + * kis_tool_perspectivegrid.cc - part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +KisToolPerspectiveGrid::KisToolPerspectiveGrid() + : super(i18n("Perspective Grid")), m_handleSize(13), m_handleHalfSize(6) + +{ + setName("tool_perspectivegrid"); + + m_subject = 0; + m_dragging = false; +} + +KisToolPerspectiveGrid::~KisToolPerspectiveGrid() +{ +} + +void KisToolPerspectiveGrid::activate() +{ + m_subject->perspectiveGridManager()->startEdition(); + if( ! m_subject->currentImg()->perspectiveGrid()->hasSubGrids() ) + { + m_mode = MODE_CREATION; + m_points.clear(); + } else { + m_mode = MODE_EDITING; + drawGrid(); + } + super::activate(); +} + +void KisToolPerspectiveGrid::deactivate() +{ + m_subject->perspectiveGridManager()->stopEdition(); + m_subject->perspectiveGridManager()->setGridVisible( true); + if( m_mode == MODE_CREATION ) + { + drawGridCreation(); + m_points.clear(); + m_dragging = false; + } else { + drawGrid(); + } +} + + +void KisToolPerspectiveGrid::update (KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +bool KisToolPerspectiveGrid::mouseNear(const TQPoint& mousep, const TQPoint point) +{ + return (TQRect( (point.x() - m_handleHalfSize), (point.y() - m_handleHalfSize), m_handleSize, m_handleSize).tqcontains(mousep) ); +} + +void KisToolPerspectiveGrid::buttonPress(KisButtonPressEvent *event) +{ + KisPerspectiveGrid* pGrid = m_subject->currentImg()->perspectiveGrid(); + if(!pGrid->hasSubGrids() && m_mode != MODE_CREATION) + { // it's possible that the perspectiv grid was cleared + m_mode = MODE_CREATION; + m_points.clear(); + } + if( m_mode == MODE_CREATION && event->button() == Qt::LeftButton) + { + m_dragging = true; + + if (m_points.isEmpty()) + { + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.append(m_dragStart); + } else { + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + drawGridCreation(); + } + } else if(m_mode == MODE_EDITING && event->button() == Qt::LeftButton){ + // Look for the handle which was pressed + if (!m_subject) + return; + KisCanvasController *controller = m_subject->canvasController(); + Q_ASSERT(controller); + TQPoint mousep = controller->windowToView( event->pos().roundTQPoint() ); + + for( TQValueList::const_iterator it = pGrid->begin(); it != pGrid->end(); ++it) + { + KisSubPerspectiveGrid* grid = *it; + if( mouseNear( mousep, controller->windowToView(grid->topLeft()->roundTQPoint() ) ) ) + { + kdDebug() << " PRESS TOPLEFT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->topLeft(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->topRight()->roundTQPoint() ) ) ) + { + kdDebug() << " PRESS TOPRIGHT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->topRight(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->bottomLeft()->roundTQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMLEFT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->bottomLeft(); + break; + } + else if( mouseNear( mousep, controller->windowToView(grid->bottomRight()->roundTQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMRIGHT HANDLE " << endl; + m_mode = MODE_DRAGING_NODE; + m_selectedNode1 = grid->bottomRight(); + break; + } + else if( !grid->leftGrid() && mouseNear( mousep, controller->windowToView( ((*grid->topLeft() + *grid->bottomLeft() )*0.5) ).roundTQPoint() ) ) + { + kdDebug() << " PRESS LEFT HANDLE " << endl; + m_mode = MODE_DRAGING_TRANSLATING_TWONODES; + drawGrid(); + m_selectedNode1 = new KisPerspectiveGridNode( *grid->topLeft() ); + m_selectedNode2 = new KisPerspectiveGridNode( *grid->bottomLeft() ); + KisSubPerspectiveGrid* newsubgrid = new KisSubPerspectiveGrid( m_selectedNode1, grid->topLeft() , grid->bottomLeft(), m_selectedNode2); + m_dragEnd = event->pos(); + newsubgrid->setRightGrid( grid); + grid->setLeftGrid( newsubgrid); + pGrid->addNewSubGrid( newsubgrid); + drawGrid(); + break; + } + else if( !grid->rightGrid() && mouseNear( mousep, controller->windowToView( ((*grid->topRight() + *grid->bottomRight() )*0.5) ).roundTQPoint() ) ) + { + kdDebug() << " PRESS RIGHT HANDLE " << endl; + m_mode = MODE_DRAGING_TRANSLATING_TWONODES; + drawGrid(); + m_selectedNode1 = new KisPerspectiveGridNode( *grid->topRight() ); + m_selectedNode2 = new KisPerspectiveGridNode( *grid->bottomRight() ); + KisSubPerspectiveGrid* newsubgrid = new KisSubPerspectiveGrid( grid->topRight(), m_selectedNode1, m_selectedNode2, grid->bottomRight()); + m_dragEnd = event->pos(); + newsubgrid->setLeftGrid( grid); + grid->setRightGrid( newsubgrid); + pGrid->addNewSubGrid( newsubgrid); + drawGrid(); + break; + } + else if( !grid->topGrid() && mouseNear( mousep, controller->windowToView( ((*grid->topLeft() + *grid->topRight() )*0.5) ).roundTQPoint() ) ) + { + kdDebug() << " PRESS TOP HANDLE " << endl; + m_mode = MODE_DRAGING_TRANSLATING_TWONODES; + drawGrid(); + m_selectedNode1 = new KisPerspectiveGridNode( *grid->topLeft() ); + m_selectedNode2 = new KisPerspectiveGridNode( *grid->topRight() ); + KisSubPerspectiveGrid* newsubgrid = new KisSubPerspectiveGrid( m_selectedNode1, m_selectedNode2, grid->topRight(), grid->topLeft() ); + m_dragEnd = event->pos(); + newsubgrid->setBottomGrid( grid); + grid->setTopGrid( newsubgrid); + pGrid->addNewSubGrid( newsubgrid); + drawGrid(); + break; + } + else if( !grid->bottomGrid() && mouseNear( mousep, controller->windowToView( ((*grid->bottomLeft() + *grid->bottomRight() )*0.5) ).roundTQPoint() ) ) + { + kdDebug() << " PRESS BOTTOM HANDLE " << endl; + m_mode = MODE_DRAGING_TRANSLATING_TWONODES; + drawGrid(); + m_selectedNode1 = new KisPerspectiveGridNode( *grid->bottomLeft() ); + m_selectedNode2 = new KisPerspectiveGridNode( *grid->bottomRight() ); + KisSubPerspectiveGrid* newsubgrid = new KisSubPerspectiveGrid( grid->bottomLeft(), grid->bottomRight(), m_selectedNode2, m_selectedNode1); + m_dragEnd = event->pos(); + newsubgrid->setTopGrid( grid); + grid->setBottomGrid( newsubgrid); + pGrid->addNewSubGrid( newsubgrid); + drawGrid(); + break; + } + } + } +} + + +void KisToolPerspectiveGrid::move(KisMoveEvent *event) +{ + if( m_mode == MODE_CREATION ) + { + if (m_dragging) { + // erase old lines on canvas + drawGridCreation(); + // get current mouse position + m_dragEnd = event->pos(); + // draw new lines on canvas + drawGridCreation(); + } + } else { + if( m_mode == MODE_DRAGING_NODE) + { + drawGrid(); + m_selectedNode1->setX( event->pos().x() ); + m_selectedNode1->setY( event->pos().y() ); + drawGrid(); + } + if( m_mode == MODE_DRAGING_TRANSLATING_TWONODES) + { + drawGrid(); + KisPoint translate = event->pos() - m_dragEnd; + m_dragEnd = event->pos(); + *m_selectedNode1 += translate;; + *m_selectedNode2 += translate;; + drawGrid(); + } + } +} + +void KisToolPerspectiveGrid::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject) + return; + + if( m_mode == MODE_CREATION ) + { + if (m_dragging && event->button() == Qt::LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + if( m_points.size() == 4) + { // wow we have a grid, isn't that cool ? + drawGridCreation(); // Clean + m_subject->currentImg()->perspectiveGrid()->addNewSubGrid( new KisSubPerspectiveGrid( new KisPerspectiveGridNode(m_points[0]), new KisPerspectiveGridNode(m_points[1]), new KisPerspectiveGridNode(m_points[2]), new KisPerspectiveGridNode(m_points[3]) ) ); + drawGrid(); + m_mode = MODE_EDITING; + } + } + } else { + m_mode = MODE_EDITING; + m_selectedNode1 = 0; + m_selectedNode2 = 0; + } + +/* if (m_dragging && event->button() == RightButton) { + + }*/ +} + +void KisToolPerspectiveGrid::paint(KisCanvasPainter& gc) +{ + if( m_mode == MODE_CREATION ) + { + drawGridCreation(gc); + } else { + drawGrid(gc); + } +} + +void KisToolPerspectiveGrid::paint(KisCanvasPainter& gc, const TQRect&) +{ + if( m_mode == MODE_CREATION ) + { + drawGridCreation(gc); + } else { + drawGrid(gc); + } +} + +void KisToolPerspectiveGrid::drawGridCreation() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + drawGridCreation(gc); + } +} + + +void KisToolPerspectiveGrid::drawGridCreation(KisCanvasPainter& gc) +{ + if (!m_subject) + return; + + TQPen pen(TQt::white); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorTQPoint()); + endPos = controller->windowToView(m_dragEnd.floorTQPoint()); + gc.drawLine(startPos, endPos); + } else { + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + +void KisToolPerspectiveGrid::drawSmallRectangle(KisCanvasPainter& gc, TQPoint p) +{ + gc.drawRect( p.x() - m_handleHalfSize - 1, p.y() - m_handleHalfSize - 1, m_handleSize, m_handleSize); +} + +void KisToolPerspectiveGrid::drawGrid(KisCanvasPainter& gc) +{ + + if (!m_subject) + return; + + KisCanvasController *controller = m_subject->canvasController(); + + TQPen pen(TQt::white); + TQPoint startPos; + TQPoint endPos; + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + KisPerspectiveGrid* pGrid = m_subject->currentImg()->perspectiveGrid(); + + for( TQValueList::const_iterator it = pGrid->begin(); it != pGrid->end(); ++it) + { + KisSubPerspectiveGrid* grid = *it; + int index = grid->index(); + bool drawLeft = !(grid->leftGrid() && (index > grid->leftGrid()->index() ) ); + bool drawRight = !(grid->rightGrid() && (index > grid->rightGrid()->index() ) ); + bool drawTop = !(grid->topGrid() && (index > grid->topGrid()->index() ) ); + bool drawBottom = !(grid->bottomGrid() && (index > grid->bottomGrid()->index() ) ); + if(drawTop) { + startPos = controller->windowToView(grid->topLeft()->roundTQPoint()); + endPos = controller->windowToView(grid->topRight()->roundTQPoint()); + gc.drawLine( startPos, endPos ); + if( !grid->topGrid() ) + { + drawSmallRectangle(gc, (endPos + startPos) / 2); + } + if(drawLeft) { + drawSmallRectangle(gc, startPos); + } + if(drawRight) { + drawSmallRectangle(gc, endPos); + } + } + if(drawRight) { + startPos = controller->windowToView(grid->topRight()->roundTQPoint()); + endPos = controller->windowToView(grid->bottomRight()->roundTQPoint()); + gc.drawLine( startPos, endPos ); + if( !grid->rightGrid() ) + { + drawSmallRectangle(gc, (endPos + startPos) / 2); + } + } + if(drawBottom) { + startPos = controller->windowToView(grid->bottomRight()->roundTQPoint()); + endPos = controller->windowToView(grid->bottomLeft()->roundTQPoint()); + gc.drawLine( startPos, endPos ); + if( !grid->bottomGrid() ) + { + drawSmallRectangle(gc, (endPos + startPos) / 2); + } + if(drawLeft) { + drawSmallRectangle(gc, endPos); + } + if(drawRight) { + drawSmallRectangle(gc, startPos); + } + } + if(drawLeft) { + startPos = controller->windowToView(grid->bottomLeft()->roundTQPoint()); + endPos = controller->windowToView(grid->topLeft()->roundTQPoint()); + gc.drawLine( startPos, endPos ); + if( !grid->leftGrid() ) + { + drawSmallRectangle(gc, (endPos + startPos) / 2); + } + } + KisPoint tbVpf = grid->topBottomVanishingPoint(); + if( fabs(tbVpf.x()) < 30000000. && fabs(tbVpf.y()) < 30000000.) + { + TQPoint tbVp = controller->windowToView(tbVpf.roundTQPoint()); + gc.drawLine( tbVp.x() - m_handleHalfSize, tbVp.y() - m_handleHalfSize, tbVp.x() + m_handleHalfSize, tbVp.y() + m_handleHalfSize); + gc.drawLine( tbVp.x() - m_handleHalfSize, tbVp.y() + m_handleHalfSize, tbVp.x() + m_handleHalfSize, tbVp.y() - m_handleHalfSize); + } + KisPoint lrVpf = grid->leftRightVanishingPoint(); + if( fabs(lrVpf.x()) < 30000000. && fabs(lrVpf.y()) < 30000000.) + { // Don't display it, if it is too far, or you get funny results + TQPoint lrVp = controller->windowToView(lrVpf.roundTQPoint()); + gc.drawLine( lrVp.x() - m_handleHalfSize, lrVp.y() - m_handleHalfSize, lrVp.x() + m_handleHalfSize, lrVp.y() + m_handleHalfSize); + gc.drawLine( lrVp.x() - m_handleHalfSize, lrVp.y() + m_handleHalfSize, lrVp.x() + m_handleHalfSize, lrVp.y() - m_handleHalfSize); + } + } +} + +void KisToolPerspectiveGrid::drawGrid() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + drawGrid(gc); + } + +} + + +void KisToolPerspectiveGrid::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Perspective Grid"), + "tool_perspectivegrid" , + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setExclusiveGroup("tools"); + m_action->setToolTip(i18n("Edit the perspective grid")); + m_ownAction = true; + } +} + + +// TQWidget* KisToolPerspectiveGrid::createOptionWidget(TQWidget* tqparent) +// { +// return 0; +// } +// +// TQWidget* KisToolPerspectiveGrid::optionWidget() +// { +// return 0; +// } + + +#include "kis_tool_perspectivegrid.moc" diff --git a/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h b/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h new file mode 100644 index 00000000..69f6407a --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/kis_tool_perspectivegrid.h @@ -0,0 +1,111 @@ +/* + * kis_tool_perspectivegrid.h - part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TOOL_PERSPECTIVE_GRID_H_ +#define _KIS_TOOL_PERSPECTIVE_GRID_H_ + +#include +#include +#include +#include + +class KisToolPerspectiveGrid : public KisToolNonPaint { + Q_OBJECT + TQ_OBJECT + enum PerspectiveGridEditionMode { + MODE_CREATION, // This is the mode when there is not yet a perspective grid + MODE_EDITING, // This is the mode when the grid has been created, and we are waiting for the user to click on a control box + MODE_DRAGING_NODE, // In this mode one node is translated + MODE_DRAGING_TRANSLATING_TWONODES // This mode is used when creating a new sub perspective grid + }; + typedef KisToolNonPaint super; +public: + KisToolPerspectiveGrid(); + virtual ~KisToolPerspectiveGrid(); + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 3; } + virtual enumToolType toolType() { return TOOL_VIEW; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + +// TQWidget* createOptionWidget(TQWidget* tqparent); +// virtual TQWidget* optionWidget(); + +public slots: + virtual void activate(); + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + void drawGridCreation(KisCanvasPainter& gc); + void drawGridCreation(); + void drawGrid(KisCanvasPainter& gc); + void drawGrid(); + +private: + void drawSmallRectangle(KisCanvasPainter& gc, TQPoint p); + bool mouseNear(const TQPoint& mousep, const TQPoint point); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; +private: + typedef TQValueVector KisPointVector; + KisCanvasSubject *m_subject; + KisPointVector m_points; + PerspectiveGridEditionMode m_mode; + TQ_INT32 m_handleSize, m_handleHalfSize; + KisPerspectiveGridNodeSP m_selectedNode1, m_selectedNode2; + +}; + + +class KisToolPerspectiveGridFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolPerspectiveGridFactory() : super() {}; + virtual ~KisToolPerspectiveGridFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolPerspectiveGrid(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("perspectivegridtool", i18n("Perspective Grid Tool")); } +}; + + +#endif + diff --git a/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc new file mode 100644 index 00000000..69158e21 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.cc @@ -0,0 +1,62 @@ +/* + * tool_perspectivegrid.cc -- Part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_perspectivegrid.h" +#include "kis_tool_perspectivegrid.h" + + +typedef KGenericFactory ToolPerspectiveGridFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolperspectivegrid, ToolPerspectiveGridFactory( "chalk" ) ) + + +ToolPerspectiveGrid::ToolPerspectiveGrid(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolPerspectiveGridFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + r->add(new KisToolPerspectiveGridFactory()); + } + +} + +ToolPerspectiveGrid::~ToolPerspectiveGrid() +{ +} + +#include "tool_perspectivegrid.moc" diff --git a/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h new file mode 100644 index 00000000..aed4a60c --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_PERSPECTIVE_GRID_H_ +#define TOOL_PERSPECTIVE_GRID_H_ + +#include + +class KisView; + +/** + * A module that provides a tool for editing the perspective grid. + */ +class ToolPerspectiveGrid : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolPerspectiveGrid(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolPerspectiveGrid(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_PERSPECTIVE_GRID_H_ diff --git a/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png new file mode 100644 index 00000000..ac4efbfa Binary files /dev/null and b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.png differ diff --git a/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg new file mode 100644 index 00000000..3dd79413 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivegrid/tool_perspectivegrid.svg @@ -0,0 +1,87 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/tool_perspectivetransform/Makefile.am b/chalk/plugins/tools/tool_perspectivetransform/Makefile.am new file mode 100644 index 00000000..416bdcc3 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/Makefile.am @@ -0,0 +1,35 @@ +kde_services_DATA = chalktoolperspectivetransform.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolperspectivetransform_la_SOURCES = \ + tool_perspectivetransform.cc \ + kis_tool_perspectivetransform.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolperspectivetransform.la + +noinst_HEADERS = \ + tool_perspectivetransform.h \ + kis_tool_perspectivetransform.h + +chalktoolperspectivetransform_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolperspectivetransform_la_LIBADD = ../../../libchalkcommon.la + +chalktoolperspectivetransform_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_perspectivetransform.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_perspectivetransform/chalktoolperspectivetransform.desktop b/chalk/plugins/tools/tool_perspectivetransform/chalktoolperspectivetransform.desktop new file mode 100644 index 00000000..860efc69 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/chalktoolperspectivetransform.desktop @@ -0,0 +1,37 @@ +[Desktop Entry] +Icon= +Name=Perspective transform Tool +Name[bg]=Инструмент трансформиране +Name[ca]=Eina de transformació de perspectiva +Name[da]=Perspectivetransformeringsværktøj +Name[de]=Perspektive-Transformationswerkzeug +Name[el]=Εργαλείο προοπτικού μετασχηματισμού +Name[eo]=Perspektivŝanĝo-ilo +Name[es]=Herramienta Transformar perspectiva +Name[et]=Perspektiivteisenduse tööriist +Name[fa]=ابزار تبدیل بُعدنما +Name[fr]=Outils de transformation de perspective +Name[fy]=Perspeksje oerset ark +Name[hu]=Perspektívaátalakító eszköz +Name[it]=Strumento di trasformazione della prospettiva +Name[ja]=視点変更ツール +Name[km]=ឧបករណ៍​ប្លែង​យថាទស្សន៍ +Name[nb]=Verktøy for perspektivtransformasjon +Name[nds]=Warktüüch för't Kiekwinkeltopassen +Name[ne]=दृश्यात्मक रूपान्तरण उपकरण +Name[nl]=Perspectiefrooster-gereedschap +Name[pl]=Narzędzie zmiany perspektywy +Name[pt]=Ferramenta de Transformação em Perspectiva +Name[pt_BR]=Ferramentas de Transformação em Perspectiva +Name[ru]=Перспектива +Name[sk]=Perspektívna transformácia +Name[sl]=Orodje za transformacijo perspektive +Name[sr]=Алати за трансформацију перспективе +Name[sr@Latn]=Alati za transformaciju perspektive +Name[sv]=Perspektivtransformverktyg +Name[uk]=Засіб перспективи +Name[zh_TW]=透視轉換工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolperspectivetransform +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc b/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc new file mode 100644 index 00000000..809d1a7d --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.cc @@ -0,0 +1,742 @@ +/* + * kis_tool_transform.cc -- part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * Based on the transform tool from : + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_tool_perspectivetransform.h" + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "wdg_tool_transform.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +namespace { + class PerspectiveTransformCmd : public KisSelectedTransaction { + typedef KisSelectedTransaction super; + + public: + PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, KisPoint topleft, KisPoint topright, KisPoint bottomleft, KisPoint bottomright, KisSelectionSP origSel, TQRect initialRect); + virtual ~PerspectiveTransformCmd(); + + public: + virtual void execute(); + virtual void unexecute(); + void transformArgs(KisPoint &topleft, KisPoint &topright, KisPoint &bottomleft, KisPoint& bottomright) const; + KisSelectionSP origSelection(TQRect& initialRect) const; + KisPaintDeviceSP theDevice(); + KisPaintDeviceSP origDevice(); + + private: + TQRect m_initialRect; + KisPoint m_topleft, m_topright, m_bottomleft, m_bottomright; + KisToolPerspectiveTransform *m_tool; + KisSelectionSP m_origSelection; + KisPaintDeviceSP m_device; + KisPaintDeviceSP m_origDevice; + }; + + PerspectiveTransformCmd::PerspectiveTransformCmd(KisToolPerspectiveTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, KisPoint topleft, KisPoint topright, KisPoint bottomleft, KisPoint bottomright, KisSelectionSP origSel, TQRect initialRect) : + super(i18n("Perspective Transform"), device), m_initialRect(initialRect) + , m_topleft(topleft), m_topright(topright), m_bottomleft(bottomleft), m_bottomright(bottomright) + , m_tool(tool), m_origSelection(origSel), m_device(device), m_origDevice(origDevice) + { + } + + PerspectiveTransformCmd::~PerspectiveTransformCmd() + { + } + + void PerspectiveTransformCmd::transformArgs(KisPoint &topleft, KisPoint &topright, KisPoint &bottomleft, KisPoint& bottomright) const + { + topleft = m_topleft; + topright = m_topright; + bottomleft = m_bottomleft; + bottomright = m_bottomright; + } + + KisSelectionSP PerspectiveTransformCmd::origSelection(TQRect& initialRect) const + { + initialRect = m_initialRect; + return m_origSelection; + } + + void PerspectiveTransformCmd::execute() + { + super::execute(); + } + + void PerspectiveTransformCmd::unexecute() + { + super::unexecute(); + } + + KisPaintDeviceSP PerspectiveTransformCmd::theDevice() + { + return m_device; + } + + KisPaintDeviceSP PerspectiveTransformCmd::origDevice() + { + return m_origDevice; + } +} + +KisToolPerspectiveTransform::KisToolPerspectiveTransform() + : super(i18n("Perspective Transform")) +{ + setName("tool_perspectivetransform"); + setCursor(KisCursor::selectCursor()); + m_subject = 0; + m_origDevice = 0; + m_origSelection = 0; + m_handleHalfSize = 8; + m_handleSize = 2 * m_handleHalfSize; + m_handleSelected = NOHANDLE; +} + +KisToolPerspectiveTransform::~KisToolPerspectiveTransform() +{ +} + +void KisToolPerspectiveTransform::deactivate() +{ + if (m_subject && m_subject->undoAdapter()) m_subject->undoAdapter()->removeCommandHistoryListener( this ); + + KisImageSP img = m_subject->currentImg(); + if (!img) return; + + paintOutline(); + + disconnect(m_subject->currentImg().data(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolPerspectiveTransform::activate() +{ + super::activate(); + m_currentSelectedPoint = 0; + if(m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice()) + { + //connect(m_subject, commandExecuted(KCommand *c), this, notifyCommandAdded( KCommand * c)); + m_subject->undoAdapter()->setCommandHistoryListener( this ); + +// KisToolControllerInterface *controller = m_subject->toolController(); +// if (controller) +// controller->setCurrentTool(this); + + PerspectiveTransformCmd * cmd=0; + + if(m_subject->currentImg()->undoAdapter()->presentCommand()) + cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); + + // One of our commands is on top + if(cmd &&cmd->theDevice() == m_subject->currentImg()->activeDevice()) + { + m_interractionMode = EDITRECTINTERRACTION; + // and it even has the same device + // We should ask for tool args and orig selection + m_origDevice = cmd->origDevice(); + cmd->transformArgs(m_topleft, m_topright, m_bottomleft, m_bottomright); + m_origSelection = cmd->origSelection(m_initialRect); + paintOutline(); + } + else + { + m_interractionMode = DRAWRECTINTERRACTION; + m_points.clear(); + initHandles(); + } + } + connect(m_subject->currentImg(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolPerspectiveTransform::initHandles() +{ +// TQ_INT32 x,y,w,h; + KisImageSP img = m_subject->currentImg(); + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev ) return; + + // Create a lazy copy of the current state + m_origDevice = new KisPaintDevice(*dev.data()); + Q_ASSERT(m_origDevice); + + if(dev->hasSelection()) + { + KisSelectionSP sel = dev->selection(); + m_origSelection = new KisSelection(*sel.data()); + m_initialRect = sel->selectedExactRect(); + } + else { + m_initialRect = dev->exactBounds(); + } + m_topleft = KisPoint(m_initialRect.topLeft()); + m_topright = KisPoint(m_initialRect.topRight()); + m_bottomleft = KisPoint(m_initialRect.bottomLeft()); + m_bottomright = KisPoint(m_initialRect.bottomRight()); + + m_subject->canvasController() ->updateCanvas(); +} + +void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc) +{ + paintOutline(gc, TQRect()); +} + +void KisToolPerspectiveTransform::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + paintOutline(gc, rc); +} + +bool KisToolPerspectiveTransform::mouseNear(const TQPoint& mousep, const TQPoint point) +{ + return (TQRect( (point.x() - m_handleHalfSize), (point.y() - m_handleHalfSize), m_handleSize, m_handleSize).tqcontains(mousep) ); +} + +void KisToolPerspectiveTransform::buttonPress(KisButtonPressEvent *event) +{ + if (m_subject) { + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + if (m_points.isEmpty()) + { + m_dragging = false; + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.append(m_dragStart); + paintOutline(); + } else { + m_dragging = true; + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + paintOutline(); + } + } + case EDITRECTINTERRACTION: + { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && event->button() == Qt::LeftButton) { + m_actualyMoveWhileSelected = false; + m_dragEnd = event->pos(); + KisCanvasController *controller = m_subject->canvasController(); + TQPoint mousep = controller->windowToView( event->pos().roundTQPoint() ); + if( mouseNear( mousep, controller->windowToView(m_topleft.roundTQPoint() ) ) ) + { + kdDebug() << " PRESS TOPLEFT HANDLE " << endl; + m_currentSelectedPoint = &m_topleft; + } + else if( mouseNear( mousep, controller->windowToView(m_topright.roundTQPoint() ) ) ) + { + kdDebug() << " PRESS TOPRIGHT HANDLE " << endl; + m_currentSelectedPoint = &m_topright; + } + else if( mouseNear( mousep, controller->windowToView(m_bottomleft.roundTQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMLEFT HANDLE " << endl; + m_currentSelectedPoint = &m_bottomleft; + } + else if( mouseNear( mousep, controller->windowToView(m_bottomright.roundTQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOMRIGHT HANDLE " << endl; + m_currentSelectedPoint = &m_bottomright; + } else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_topright)*0.5).roundTQPoint() ) ) ) + { + kdDebug() << " PRESS TOP HANDLE " << endl; + m_handleSelected = TOPHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_bottomleft)*0.5).roundTQPoint() ) ) ) + { + kdDebug() << " PRESS LEFT HANDLE " << endl; + m_handleSelected = LEFTHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomleft+m_bottomright)*0.5).roundTQPoint() ) ) ) + { + kdDebug() << " PRESS BOTTOM HANDLE " << endl; + m_handleSelected = BOTTOMHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_bottomright+m_topright)*0.5).roundTQPoint() ) ) ) + { + kdDebug() << " PRESS RIGHT HANDLE " << endl; + m_handleSelected = RIGHTHANDLE; + }else if( mouseNear( mousep, controller->windowToView(KisPoint((m_topleft+m_bottomleft + m_bottomright+m_topright)*0.25).roundTQPoint() ) ) ) + { + kdDebug() << " PRESS MIDDLE HANDLE " << endl; + m_handleSelected = MIDDLEHANDLE; + } + } + } + } + } +} + +void KisToolPerspectiveTransform::move(KisMoveEvent *event) +{ + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + if (m_dragging) { + // erase old lines on canvas + paintOutline(); + // get current mouse position + m_dragEnd = event->pos(); + // draw new lines on canvas + paintOutline(); + } + } + + case EDITRECTINTERRACTION: + { + if(m_currentSelectedPoint) + { + paintOutline(); + KisPoint translate = event->pos() - m_dragEnd; + m_dragEnd = event->pos(); + *m_currentSelectedPoint += translate;; + paintOutline(); + m_actualyMoveWhileSelected = true; + } + else if(m_handleSelected == TOPHANDLE || m_handleSelected == LEFTHANDLE || m_handleSelected == BOTTOMHANDLE || m_handleSelected == RIGHTHANDLE) + { + paintOutline(); + + KisPoint translate = event->pos() - m_dragEnd; + m_dragEnd = event->pos(); + + double matrixFrom[3][3]; + double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(m_topleft, m_topright, m_bottomleft, m_bottomright, m_initialRect); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + matrixFrom[i][j] = b[3*i+j]; + } + } + delete b; + + KisPoint topLeft = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.topLeft()) ); + KisPoint topRight = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.topRight()) ); + KisPoint bottomLeft = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.bottomLeft()) ); + KisPoint bottomRight = KisPerspectiveMath::matProd(matrixFrom, KisPoint(m_initialRect.bottomRight()) ); + TQRect dstRect = m_initialRect; + switch(m_handleSelected) + { + case TOPHANDLE: + dstRect.setTop( static_cast( dstRect.top() + translate.y() ) ) ; + break; + case LEFTHANDLE: + dstRect.setLeft( static_cast( dstRect.left() + translate.x() ) ); + break; + case BOTTOMHANDLE: + dstRect.setBottom( static_cast( dstRect.bottom() + translate.y() ) ); + break; + case RIGHTHANDLE: + dstRect.setRight( static_cast( dstRect.right() + translate.x() ) ); + break; + case MIDDLEHANDLE: + case NOHANDLE: + kdDebug() << "Should NOT happen" << endl; + } + double matrixTo[3][3]; + b = KisPerspectiveMath::computeMatrixTransfoToPerspective(topLeft, topRight, bottomLeft, bottomRight, dstRect ); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + matrixTo[i][j] = b[3*i+j]; + } + } + delete b; + m_topleft = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.topLeft())); + m_topright = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.topRight())); + m_bottomleft = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.bottomLeft())); + m_bottomright = KisPerspectiveMath::matProd(matrixTo, KisPoint(m_initialRect.bottomRight())); + + paintOutline(); + m_actualyMoveWhileSelected = true; + } else if (m_handleSelected == MIDDLEHANDLE) { + paintOutline(); + KisPoint translate = event->pos() - m_dragEnd; + m_dragEnd = event->pos(); + m_topleft += translate; + m_topright += translate; + m_bottomleft += translate; + m_bottomright += translate; + paintOutline(); + m_actualyMoveWhileSelected = true; + } + } + }; +} + +void KisToolPerspectiveTransform::buttonRelease(KisButtonReleaseEvent * event) +{ + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + if( event->button() == Qt::LeftButton) + { + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + if (m_dragging && event->button() == Qt::LeftButton) { + paintOutline(); + m_dragging = false; + m_points.append (m_dragEnd); + if( m_points.size() == 4) + { + // from the points, select which is topleft ? topright ? bottomright ? and bottomleft ? + m_topleft = m_points[0]; + m_topright = m_points[1]; + m_bottomleft = m_points[3]; + m_bottomright = m_points[2]; + double matrix[3][3]; + double* b = KisPerspectiveMath::computeMatrixTransfoToPerspective(m_topleft, m_topright, m_bottomleft, m_bottomright, m_initialRect ); + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + kdDebug() << "sol[" << 3*i+j << "]=" << b[3*i+j] << endl; + matrix[i][j] = b[3*i+j]; + } + } + m_topleft = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.topLeft())); + m_topright = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.topRight())); + m_bottomleft = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.bottomLeft())); + m_bottomright = KisPerspectiveMath::matProd(matrix, KisPoint(m_initialRect.bottomRight())); + m_interractionMode = EDITRECTINTERRACTION; + paintOutline(); + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + TQApplication::restoreOverrideCursor(); + } else { + paintOutline(); + } + } + } + break; + case EDITRECTINTERRACTION: + { + if(m_currentSelectedPoint ) + { + m_currentSelectedPoint = 0; + if(m_actualyMoveWhileSelected) + { + paintOutline(); + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + TQApplication::restoreOverrideCursor(); + } + } + if(m_handleSelected != NOHANDLE) + { + m_handleSelected = NOHANDLE; + if(m_actualyMoveWhileSelected) + { +// paintOutline(); + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + TQApplication::restoreOverrideCursor(); + } + } + } + break; + } + } +} + +void KisToolPerspectiveTransform::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolPerspectiveTransform::paintOutline(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::SolidLine); + pen.setWidth(1); + Q_ASSERT(controller); + + switch(m_interractionMode) + { + case DRAWRECTINTERRACTION: + { + kdDebug() << "DRAWRECTINTERRACTION paintOutline " << m_points.size() << endl; + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } + break; + case EDITRECTINTERRACTION: + { + TQPoint topleft = controller->windowToView(m_topleft ).roundTQPoint(); + TQPoint topright = controller->windowToView(m_topright).roundTQPoint(); + TQPoint bottomleft = controller->windowToView(m_bottomleft).roundTQPoint(); + TQPoint bottomright = controller->windowToView(m_bottomright).roundTQPoint(); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawRect(topleft.x()-4, topleft.y()-4, 8, 8); + gc.drawLine(topleft.x(), topleft.y(), (topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2); + gc.drawRect((topleft.x()+topright.x())/2-4, (topleft.y()+topright.y())/2-4, 8, 8); + gc.drawLine((topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2, topright.x(), topright.y()); + gc.drawRect(topright.x()-4, topright.y()-4, 8, 8); + gc.drawLine(topright.x(), topright.y(), (topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2); + gc.drawRect((topright.x()+bottomright.x())/2-4, (topright.y()+bottomright.y())/2-4, 8, 8); + gc.drawLine((topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2,bottomright.x(), bottomright.y()); + gc.drawRect(bottomright.x()-4, bottomright.y()-4, 8, 8); + gc.drawLine(bottomright.x(), bottomright.y(), (bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2); + gc.drawRect((bottomleft.x()+bottomright.x())/2-4, (bottomleft.y()+bottomright.y())/2-4, 8, 8); + gc.drawLine((bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2, bottomleft.x(), bottomleft.y()); + gc.drawRect(bottomleft.x()-4, bottomleft.y()-4, 8, 8); + gc.drawLine(bottomleft.x(), bottomleft.y(), (topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2); + gc.drawRect((topleft.x()+bottomleft.x())/2-4, (topleft.y()+bottomleft.y())/2-4, 8, 8); + gc.drawLine((topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2, topleft.x(), topleft.y()); + gc.drawRect((bottomleft.x()+bottomright.x()+topleft.x()+topright.x())/4-4, (bottomleft.y()+bottomright.y()+topleft.y()+topright.y())/4-4, 8, 8); + } + break; + } + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolPerspectiveTransform::transform() +{ + KisImageSP img = m_subject->currentImg(); + + if (!img || !img->activeDevice()) + return; + + KisProgressDisplayInterface *progress = m_subject->progressDisplay(); + + // This mementoes the current state of the active device. + PerspectiveTransformCmd * transaction = new PerspectiveTransformCmd(this, img->activeDevice(), m_origDevice, + m_topleft, m_topright, m_bottomleft, m_bottomright, m_origSelection, m_initialRect); + + // Copy the original state back. + TQRect rc = m_origDevice->extent(); + rc = rc.normalize(); + img->activeDevice()->clear(); + KisPainter gc(img->activeDevice()); + gc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origDevice, rc.x(), rc.y(), rc.width(), rc.height()); + gc.end(); + + // Also restore the original selection. + if(m_origSelection) + { + TQRect rc = m_origSelection->selectedRect(); + rc = rc.normalize(); + img->activeDevice()->selection()->clear(); + KisPainter sgc(img->activeDevice()->selection().data()); + sgc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origSelection.data(), rc.x(), rc.y(), rc.width(), rc.height()); + sgc.end(); + } + else + if(img->activeDevice()->hasSelection()) + img->activeDevice()->selection()->clear(); + + // Perform the transform. Since we copied the original state back, this doesn't degrade + // after many tweaks. Since we started the transaction before the copy back, the memento + // has the previous state. + KisPerspectiveTransformWorker t(img->activeDevice(),m_topleft, m_topright, m_bottomleft, m_bottomright, progress); + t.run(); + + // If canceled, go back to the memento + if(t.isCanceled()) + { + transaction->unexecute(); + delete transaction; + return; + } + + img->activeDevice()->setDirty(rc); // XXX: This is not enough - should union with new extent + + // Else add the command -- this will have the memento from the previous state, + // and the transformed state from the original device we cached in our activated() + // method. + if (transaction) { + if (img->undo()) + img->undoAdapter()->addCommand(transaction); + else + delete transaction; + } +} + +void KisToolPerspectiveTransform::notifyCommandAdded( KCommand * command) +{ + PerspectiveTransformCmd * cmd = dynamic_cast(command); + if (cmd == 0) { + // The last added command wasn't one of ours; + // we should reset to the new state of the canvas. + // In effect we should treat this as if the tool has been just activated + initHandles(); + } +} + +void KisToolPerspectiveTransform::notifyCommandExecuted( KCommand * command) +{ + Q_UNUSED(command); + PerspectiveTransformCmd * cmd=0; + if(m_subject->currentImg()->undoAdapter()->presentCommand()) + cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); + + if (cmd == 0) { + // The command now on the top of the stack isn't one of ours + // We should treat this as if the tool has been just activated + initHandles(); + } + else + { + // One of our commands is now on top + // We should ask for tool args and orig selection + m_origDevice = cmd->origDevice(); + cmd->transformArgs(m_topleft, m_topright, m_bottomleft, m_bottomright); + m_origSelection = cmd->origSelection(m_initialRect); + m_subject->canvasController() ->updateCanvas(); + } +} + +void KisToolPerspectiveTransform::slotLayerActivated(KisLayerSP) +{ + activate(); +} + + +TQWidget* KisToolPerspectiveTransform::createOptionWidget(TQWidget* /*tqparent*/) +{ +#if 0 + m_optWidget = new WdgToolPerspectiveTransform(tqparent); + Q_CHECK_PTR(m_optWidget); + + m_optWidget->cmbFilter->clear(); + m_optWidget->cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); + + m_optWidget->cmbFilter->setCurrentText("Mitchell"); + connect(m_optWidget->cmbFilter, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(slotSetFilter(const KisID &))); + + KisID filterID = m_optWidget->cmbFilter->currentItem(); + m_filter = KisFilterStrategyRegistry::instance()->get(filterID); + +/* + connect(m_optWidget->intStartX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartX(int))); + connect(m_optWidget->intStartY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartY(int))); + connect(m_optWidget->intEndX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndX(int))); + connect(m_optWidget->intEndY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndY(int))); +*/ + m_optWidget->intStartX->hide(); + m_optWidget->intStartY->hide(); + m_optWidget->intEndX->hide(); + m_optWidget->intEndY->hide(); + m_optWidget->textLabel1->hide(); + m_optWidget->textLabel2->hide(); + m_optWidget->textLabel3->hide(); + m_optWidget->textLabel4->hide(); +#endif + return 0; +} + +TQWidget* KisToolPerspectiveTransform::optionWidget() +{ + return 0; +} + +void KisToolPerspectiveTransform::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Perspective Transform"), + "tool_perspectivetransform", + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Perspective transform a layer or a selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_perspectivetransform.moc" diff --git a/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h b/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h new file mode 100644 index 00000000..5d637ae5 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/kis_tool_perspectivetransform.h @@ -0,0 +1,131 @@ +/* + * kis_tool_transform.h - part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * Based on the transform tool from : + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_PERSPECTIVETRANSFORM_H_ +#define KIS_TOOL_PERSPECTIVETRANSFORM_H_ + +#include + +#include +#include +#include +#include +#include +#include + +class KisTransaction; +class WdgToolPerspectiveTransform; +class KisID; +class KisFilterStrategy; + +/** + * PerspectiveTransform tool + * + */ +class KisToolPerspectiveTransform : public KisToolNonPaint, KisCommandHistoryListener { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + enum InterractionMode { DRAWRECTINTERRACTION, EDITRECTINTERRACTION }; + enum HandleSelected { NOHANDLE, TOPHANDLE, BOTTOMHANDLE, RIGHTHANDLE, LEFTHANDLE, MIDDLEHANDLE }; +public: + KisToolPerspectiveTransform(); + virtual ~KisToolPerspectiveTransform(); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual TQ_UINT32 priority() { return 4; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + void paintOutline(); + +public: + + void notifyCommandAdded(KCommand *); + void notifyCommandExecuted(KCommand *); + +public: + virtual void deactivate(); + +private: + + bool mouseNear(const TQPoint& mousep, const TQPoint point); + void paintOutline(KisCanvasPainter& gc, const TQRect& rc); + void transform(); + void initHandles(); + +private slots: + void slotLayerActivated(KisLayerSP); + +protected slots: + virtual void activate(); + +private: + bool m_dragging; + InterractionMode m_interractionMode; + TQRect m_initialRect; + KisPoint m_dragStart, m_dragEnd; + KisPoint m_topleft, m_topright, m_bottomleft, m_bottomright; + KisPoint* m_currentSelectedPoint; + bool m_actualyMoveWhileSelected; + + WdgToolPerspectiveTransform *m_optWidget; + + KisPaintDeviceSP m_origDevice; + KisSelectionSP m_origSelection; + int m_handleHalfSize, m_handleSize; + + // The following variables are used in during the draw rect interraction mode + typedef TQValueVector KisPointVector; + KisPointVector m_points; + // The following variables are used when moving a middle handle + HandleSelected m_handleSelected; + +}; + +class KisToolPerspectiveTransformFactory : public KisToolFactory { + typedef KisToolFactory super; + +public: + KisToolPerspectiveTransformFactory() : super() {}; + virtual ~KisToolPerspectiveTransformFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolPerspectiveTransform(); + Q_CHECK_PTR(t); + t->setup(ac); return t; + } + virtual KisID id() { return KisID("perspective transform", i18n("Perspective transform Tool")); } +}; + + + +#endif // KIS_TOOL_TRANSFORM_H_ + diff --git a/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc new file mode 100644 index 00000000..2c3c85d4 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.cc @@ -0,0 +1,63 @@ +/* + * tool_perspectivetransform.cc -- Part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_perspectivetransform.h" +#include "kis_tool_perspectivetransform.h" + + +typedef KGenericFactory ToolPerspectiveTransformFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolperspectivetransform, ToolPerspectiveTransformFactory( "chalk" ) ) + + +ToolPerspectiveTransform::ToolPerspectiveTransform(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolPerspectiveTransformFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + kdDebug() << " add perspective transform tool to the registry" << endl; + KisToolRegistry * r = dynamic_cast(tqparent); + r->add(new KisToolPerspectiveTransformFactory()); + } + +} + +ToolPerspectiveTransform::~ToolPerspectiveTransform() +{ +} + +#include "tool_perspectivetransform.moc" diff --git a/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h new file mode 100644 index 00000000..1cbeadee --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_PERSPECTIVE_TRANSFORM_H_ +#define TOOL_PERSPECTIVE_TRANSFORM_H_ + +#include + +class KisView; + +/** + * A module that provides a tool for doinge perspective transformation. + */ +class ToolPerspectiveTransform : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolPerspectiveTransform(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolPerspectiveTransform(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_PERSPECTIVE_TRANSFORM_H_ diff --git a/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png new file mode 100644 index 00000000..c64d09eb Binary files /dev/null and b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.png differ diff --git a/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg new file mode 100644 index 00000000..3dd79413 --- /dev/null +++ b/chalk/plugins/tools/tool_perspectivetransform/tool_perspectivetransform.svg @@ -0,0 +1,87 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/tool_polygon/Makefile.am b/chalk/plugins/tools/tool_polygon/Makefile.am new file mode 100644 index 00000000..66f4d403 --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/Makefile.am @@ -0,0 +1,36 @@ +kde_services_DATA = chalktoolpolygon.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolpolygon_la_SOURCES = \ + tool_polygon.cc \ + kis_tool_polygon.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolpolygon.la + +noinst_HEADERS = \ + tool_polygon.h \ + kis_tool_polygon.h + +chalktoolpolygon_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolpolygon_la_LIBADD = ../../../libchalkcommon.la + +chalktoolpolygon_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_polygon_cursor.png \ + tool_polygon.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_polygon/chalktoolpolygon.desktop b/chalk/plugins/tools/tool_polygon/chalktoolpolygon.desktop new file mode 100644 index 00000000..2b981e8f --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/chalktoolpolygon.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Polygon Tool +Name[bg]=Инструмент многоъгълник +Name[br]=Ostilh liestueg +Name[ca]=Eina de polígon +Name[cy]=Erfyn Polygon +Name[da]=Polygonværktøj +Name[de]=Vieleck-Werkzeug +Name[el]=Εργαλείο πολυγώνου +Name[eo]=Poligon-ilo +Name[es]=Herramienta Polígono +Name[et]=Hulknurga tööriist +Name[eu]=Poligonoa tresna +Name[fa]=ابزار چندضلعی +Name[fi]=Monikulmiotyökalu +Name[fr]=Outil polygone +Name[fy]=Meardere-hoek-ark +Name[ga]=Uirlis Pholagáin +Name[gl]=Ferramenta de Polígonos +Name[he]=כלי מצולע +Name[hu]=Sokszög eszköz +Name[is]=Marghyrnitól +Name[it]=Strumento poligono +Name[ja]=多角形ツール +Name[km]=ឧបករណ៍​រាង​ពហុកោណ +Name[lt]=Daugiakampio įrankis +Name[lv]=Poligonu rīks +Name[ms]=Alat Poligon +Name[nb]=Verktøy for mangekanter +Name[nds]=Veeleck-Warktüüch +Name[ne]=बहुभुज उपकरण +Name[nl]=Veelhoeksgereedschap +Name[nn]=Verktøy for mangekant +Name[pl]=Narzędzie do rysowania wielokątów +Name[pt]=Ferramenta de Polígonos +Name[pt_BR]=Ferramenta Polígono +Name[ru]=Многоугольник +Name[se]=Moanáčiegareaidu +Name[sk]=Mnohouholník +Name[sl]=Orodje za poligon +Name[sr]=Алат за полигоне +Name[sr@Latn]=Alat za poligone +Name[sv]=Polygonverktyg +Name[uk]=Засіб багатокутника +Name[uz]=Pligon vositasi +Name[uz@cyrillic]=Плигон воситаси +Name[zh_CN]=多边形工具 +Name[zh_TW]=多邊形工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolpolygon +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_polygon/kis_tool_polygon.cc b/chalk/plugins/tools/tool_polygon/kis_tool_polygon.cc new file mode 100644 index 00000000..dba84042 --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/kis_tool_polygon.cc @@ -0,0 +1,252 @@ +/* + * kis_tool_polygon.cc -- part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_doc.h" +#include "kis_view.h" +#include "kis_painter.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" + +#include "kis_tool_polygon.h" + +KisToolPolygon::KisToolPolygon() + : super(i18n ("Polygon")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_polygon"); + setCursor(KisCursor::load("tool_polygon_cursor.png", 6, 6)); +} + +KisToolPolygon::~KisToolPolygon() +{ +} + +void KisToolPolygon::update (KisCanvasSubject *subject) +{ + super::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg (); +} + +void KisToolPolygon::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage) { + if (event->button() == Qt::LeftButton && event->state() != ShiftButton) { + + m_dragging = true; + + if (m_points.isEmpty()) + { + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.append(m_dragStart); + } else { + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + draw(); + } + } else if (event->button() == Qt::LeftButton && event->state() == ShiftButton) { + finish(); + } + } +} + +void KisToolPolygon::finish() +{ + // erase old lines on canvas + draw(); + m_dragging = false; + + KisPaintDeviceSP device = m_currentImage->activeDevice (); + if (!device) return; + + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n ("Polygon")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBackgroundColor(m_subject->bgColor()); + painter.setFillStyle(fillStyle()); + painter.setBrush(m_subject->currentBrush()); + painter.setPattern(m_subject->currentPattern()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + + painter.paintPolygon(m_points); + + m_points.clear(); + + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } +} + +void KisToolPolygon::doubleClick( KisDoubleClickEvent * ) +{ + finish(); +} + +void KisToolPolygon::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(); + // get current mouse position + m_dragEnd = event->pos(); + // draw new lines on canvas + draw(); + } +} + +void KisToolPolygon::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject || !m_currentImage) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == Qt::RightButton) { + + } +} + +void KisToolPolygon::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolPolygon::paint(KisCanvasPainter& gc, const TQRect&) +{ + draw(gc); +} + +void KisToolPolygon::draw() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + draw(gc); + } +} + +void KisToolPolygon::draw(KisCanvasPainter& gc) +{ + if (!m_subject || !m_currentImage) + return; + + TQPen pen(TQt::white, 0, TQt::SolidLine); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorTQPoint()); + endPos = controller->windowToView(m_dragEnd.floorTQPoint()); + gc.drawLine(startPos, endPos); + } else { + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + + + +void KisToolPolygon::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Polygon"), + "tool_polygon", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Draw a polygon. Shift-mouseclick ends the polygon.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolPolygon::keyPress(TQKeyEvent *e) +{ + if (e->key()==TQt::Key_Escape) { + // erase old lines on canvas + draw(); + m_dragging = false; + m_points.clear(); + } +} + + +#include "kis_tool_polygon.moc" diff --git a/chalk/plugins/tools/tool_polygon/kis_tool_polygon.h b/chalk/plugins/tools/tool_polygon/kis_tool_polygon.h new file mode 100644 index 00000000..9be3f324 --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/kis_tool_polygon.h @@ -0,0 +1,102 @@ +/* + * kis_tool_polygon.h - part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_POLYGON_H_ +#define KIS_TOOL_POLYGON_H_ + +#include + +#include "kis_tool_shape.h" + +class KisCanvas; +class KisDoc; +class KisPainter; +class KisView; +class KisRect; + +class KisToolPolygon : public KisToolShape { + + typedef KisToolShape super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolPolygon(); + virtual ~KisToolPolygon(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 4; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual TQString quickHelp() const { + return i18n("Shift-click will end the polygon."); + } + virtual void doubleClick(KisDoubleClickEvent * event); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + void finish(); + virtual void keyPress(TQKeyEvent *e); +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; + KisImageSP m_currentImage; +private: + typedef TQValueVector KisPointVector; + KisPointVector m_points; +}; + + +#include "kis_tool_factory.h" + +class KisToolPolygonFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolPolygonFactory() : super() {}; + virtual ~KisToolPolygonFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolPolygon(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("polygon", i18n("Polygon Tool")); } +}; + + +#endif //__KIS_TOOL_POLYGON_H__ diff --git a/chalk/plugins/tools/tool_polygon/tool_polygon.cc b/chalk/plugins/tools/tool_polygon/tool_polygon.cc new file mode 100644 index 00000000..3dbd15d6 --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/tool_polygon.cc @@ -0,0 +1,62 @@ +/* + * tool_polygon.cc -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "tool_polygon.h" +#include "tool_polygon.moc" +#include "kis_tool_polygon.h" + + +typedef KGenericFactory ToolPolygonFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolpolygon, ToolPolygonFactory( "chalk" ) ) + + +ToolPolygon::ToolPolygon(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolPolygonFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( tqparent ); + r->add(new KisToolPolygonFactory()); + } + +} + +ToolPolygon::~ToolPolygon() +{ +} + +//#include "tool_polygon.moc" diff --git a/chalk/plugins/tools/tool_polygon/tool_polygon.h b/chalk/plugins/tools/tool_polygon/tool_polygon.h new file mode 100644 index 00000000..ec816736 --- /dev/null +++ b/chalk/plugins/tools/tool_polygon/tool_polygon.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_POLYGON_H_ +#define TOOL_POLYGON_H_ + +#include + +/** + * A module that provides a polygon tool. + */ +class ToolPolygon : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + +public: + + ToolPolygon(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolPolygon(); + +}; + +#endif // TOOL_POLYGON_H_ diff --git a/chalk/plugins/tools/tool_polygon/tool_polygon.png b/chalk/plugins/tools/tool_polygon/tool_polygon.png new file mode 100644 index 00000000..654083c6 Binary files /dev/null and b/chalk/plugins/tools/tool_polygon/tool_polygon.png differ diff --git a/chalk/plugins/tools/tool_polygon/tool_polygon_cursor.png b/chalk/plugins/tools/tool_polygon/tool_polygon_cursor.png new file mode 100644 index 00000000..bca4bffd Binary files /dev/null and b/chalk/plugins/tools/tool_polygon/tool_polygon_cursor.png differ diff --git a/chalk/plugins/tools/tool_polyline/Makefile.am b/chalk/plugins/tools/tool_polyline/Makefile.am new file mode 100644 index 00000000..39b9ebf6 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/Makefile.am @@ -0,0 +1,36 @@ +kde_services_DATA = chalktoolpolyline.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolpolyline_la_SOURCES = \ + tool_polyline.cc \ + kis_tool_polyline.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolpolyline.la + +noinst_HEADERS = \ + tool_polyline.h \ + kis_tool_polyline.h + +chalktoolpolyline_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolpolyline_la_LIBADD = ../../../libchalkcommon.la + +chalktoolpolyline_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_polyline_cursor.png \ + polyline.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_polyline/chalktoolpolyline.desktop b/chalk/plugins/tools/tool_polyline/chalktoolpolyline.desktop new file mode 100644 index 00000000..0c9c2be1 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/chalktoolpolyline.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +Name=Polyline Tool +Name[bg]=Инструмент съставна линия +Name[br]=Ostilh lieslinenn +Name[ca]=Eina de polilínia +Name[cy]=Erfyn Polylinell +Name[da]=Flerlinjeværktøj +Name[de]=Linienketten-Werkzeug +Name[el]=Εργαλείο συνεχούς γραμμής +Name[eo]=Plurlinio-ilo +Name[es]=Herramienta Polilínea +Name[et]=Kompleksjoone tööriist +Name[eu]=Polilerroa tresna +Name[fa]=ابزار چندخطی +Name[fr]=Outil lignes multiples +Name[fy]=Brútsen-streek-ark +Name[ga]=Uirlis Il-líne +Name[gl]=Ferramenta de Liñas Poligonais +Name[he]=כלי קו שבור +Name[hu]=Sokszögvonal eszköz +Name[is]=Fjöllínutól +Name[it]=Strumento polilinea +Name[ja]=ポリラインツール +Name[km]=ឧបករណ៍​ពហុបន្ទាត់ +Name[ms]=Alat Poligaris +Name[nb]=Verktøy for flerstrekslinje +Name[nds]=Lienenkeden-Warktüüch (Polygon-Tog) +Name[ne]=बहुरेखा उपकरण +Name[nl]=Gebroken-lijngereedschap +Name[nn]=Verktøy for fleirstrekslinje +Name[pl]=Narzędzie do rysowania łamanej +Name[pt]=Ferramenta de Linhas Poligonais +Name[pt_BR]=Ferramenta Poli-linha +Name[ru]=Ломаная +Name[se]=Moanálinnjáreaidu +Name[sk]=Lomená čiara +Name[sl]=Orodje za lomljeno črto +Name[sr]=Алат за полилиније +Name[sr@Latn]=Alat za polilinije +Name[sv]=Flerlinjesverktyg +Name[uk]=Засіб ламаної лінії +Name[uz]=Koʻpburchak asbobi +Name[uz@cyrillic]=Кўпбурчак асбоби +Name[zh_CN]=折线工具 +Name[zh_TW]=任意線工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolpolyline +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_polyline/kis_tool_polyline.cc b/chalk/plugins/tools/tool_polyline/kis_tool_polyline.cc new file mode 100644 index 00000000..4fab06e7 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/kis_tool_polyline.cc @@ -0,0 +1,271 @@ +/* + * kis_tool_polyline.cc -- part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_doc.h" +#include "kis_view.h" +#include "kis_painter.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" + +#include "kis_tool_polyline.h" + +KisToolPolyline::KisToolPolyline() + : super(i18n ("Polyline")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_polyline"); + setCursor(KisCursor::load("tool_polyline_cursor.png", 6, 6)); +} + +KisToolPolyline::~KisToolPolyline() +{ +} + +void KisToolPolyline::update (KisCanvasSubject *subject) +{ + super::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg (); +} + +void KisToolPolyline::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage) { + if (event->button() == Qt::LeftButton && event->state() != TQt::ShiftButton ) { + + m_dragging = true; + + if (m_points.isEmpty()) + { + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_points.append(m_dragStart); + } else { + m_dragStart = m_dragEnd; + m_dragEnd = event->pos(); + draw(); + } + } else if (event->button() == Qt::LeftButton && event->state() == TQt::ShiftButton ) { + finish(); + } + } +} + +void KisToolPolyline::deactivate() +{ + draw(); + m_points.clear(); + m_dragging = false; +} + +void KisToolPolyline::finish() +{ + // erase old lines on canvas + draw(); + m_dragging = false; + + KisPaintDeviceSP device = m_currentImage->activeDevice (); + if (!device) return; + + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n ("Polyline")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBrush(m_subject->currentBrush()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + + KisPoint start,end; + KisPointVector::iterator it; + for( it = m_points.begin(); it != m_points.end(); ++it ) + { + if( it == m_points.begin() ) + { + start = (*it); + } else { + end = (*it); + painter.paintLine(start, PRESSURE_DEFAULT, 0, 0, end, PRESSURE_DEFAULT, 0, 0); + start = end; + } + } + m_points.clear(); + + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + +} +void KisToolPolyline::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(); + // get current mouse position + m_dragEnd = event->pos(); + // draw new lines on canvas + draw(); + } +} + +void KisToolPolyline::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject || !m_currentImage) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + m_dragging = false; + m_points.append (m_dragEnd); + } + + if (m_dragging && event->button() == Qt::RightButton) { + + } +} + + +void KisToolPolyline::doubleClick(KisDoubleClickEvent *) +{ + finish(); +} + + +void KisToolPolyline::paint(KisCanvasPainter& gc) +{ + draw(gc); +} + +void KisToolPolyline::paint(KisCanvasPainter& gc, const TQRect&) +{ + draw(gc); +} + +void KisToolPolyline::draw() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + + draw(gc); + } +} + +void KisToolPolyline::draw(KisCanvasPainter& gc) +{ + if (!m_subject || !m_currentImage) + return; + + TQPen pen(TQt::white, 0, TQt::SolidLine); + + gc.setPen(pen); + gc.setRasterOp(TQt::XorROP); + + KisCanvasController *controller = m_subject->canvasController(); + KisPoint start, end; + TQPoint startPos; + TQPoint endPos; + + if (m_dragging) { + startPos = controller->windowToView(m_dragStart.floorTQPoint()); + endPos = controller->windowToView(m_dragEnd.floorTQPoint()); + gc.drawLine(startPos, endPos); + } else { + for (KisPointVector::iterator it = m_points.begin(); it != m_points.end(); ++it) { + + if (it == m_points.begin()) + { + start = (*it); + } else { + end = (*it); + + startPos = controller->windowToView(start.floorTQPoint()); + endPos = controller->windowToView(end.floorTQPoint()); + + gc.drawLine(startPos, endPos); + + start = end; + } + } + } +} + +void KisToolPolyline::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Polyline"), + "polyline", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Draw a polyline. Shift-mouseclick ends the polyline.")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +TQString KisToolPolyline::quickHelp() const +{ + return i18n("Press shift-mouseclick to end the polyline."); +} + +void KisToolPolyline::keyPress(TQKeyEvent *e) +{ + if (e->key()==TQt::Key_Escape) { + // erase old lines on canvas + draw(); + m_dragging = false; + m_points.clear(); + } +} + +#include "kis_tool_polyline.moc" diff --git a/chalk/plugins/tools/tool_polyline/kis_tool_polyline.h b/chalk/plugins/tools/tool_polyline/kis_tool_polyline.h new file mode 100644 index 00000000..a7cee195 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/kis_tool_polyline.h @@ -0,0 +1,109 @@ +/* + * kis_tool_polyline.h - part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_POLYLINE_H_ +#define KIS_TOOL_POLYLINE_H_ + +#include +#include + +#include "kis_tool_paint.h" +#include "kis_point.h" + +class KisCanvas; +class KisDoc; +class KisPainter; +class KisView; +class KisRect; + + +class KisToolPolyline : public KisToolPaint { + + typedef KisToolPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolPolyline(); + virtual ~KisToolPolyline(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 5; } + + virtual void buttonPress(KisButtonPressEvent *event); + virtual void doubleClick(KisDoubleClickEvent *e); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + virtual TQString quickHelp() const; + void finish(); + virtual void keyPress(TQKeyEvent *e); + +public slots: + + void deactivate(); + +protected: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + void draw(KisCanvasPainter& gc); + void draw(); + +protected: + KisPoint m_dragStart; + KisPoint m_dragEnd; + + bool m_dragging; + KisImageSP m_currentImage; +private: + typedef TQValueVector KisPointVector; + KisPointVector m_points; +}; + + +#include "kis_tool_factory.h" + +class KisToolPolylineFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolPolylineFactory() : super() {}; + virtual ~KisToolPolylineFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolPolyline(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("polyline", i18n("Polyline Tool")); } +}; + + +#endif //__KIS_TOOL_POLYLINE_H__ diff --git a/chalk/plugins/tools/tool_polyline/polyline.png b/chalk/plugins/tools/tool_polyline/polyline.png new file mode 100644 index 00000000..df36313e Binary files /dev/null and b/chalk/plugins/tools/tool_polyline/polyline.png differ diff --git a/chalk/plugins/tools/tool_polyline/tool_polyline.cc b/chalk/plugins/tools/tool_polyline/tool_polyline.cc new file mode 100644 index 00000000..369169c9 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/tool_polyline.cc @@ -0,0 +1,64 @@ +/* + * tool_polyline.cc -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tool_polyline.h" +#include "kis_tool_polyline.h" + + +typedef KGenericFactory ToolPolylineFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolpolyline, ToolPolylineFactory( "chalk" ) ) + + +ToolPolyline::ToolPolyline(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolPolylineFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + + r->add(new KisToolPolylineFactory()); + } + +} + +ToolPolyline::~ToolPolyline() +{ +} + +#include "tool_polyline.moc" diff --git a/chalk/plugins/tools/tool_polyline/tool_polyline.h b/chalk/plugins/tools/tool_polyline/tool_polyline.h new file mode 100644 index 00000000..9f483363 --- /dev/null +++ b/chalk/plugins/tools/tool_polyline/tool_polyline.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_POLYLINE_H_ +#define TOOL_POLYLINE_H_ + +#include + +class KisView; + +/** + * A module that provides a polyline tool. + */ +class ToolPolyline : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolPolyline(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolPolyline(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_POLYLINE_H_ diff --git a/chalk/plugins/tools/tool_polyline/tool_polyline_cursor.png b/chalk/plugins/tools/tool_polyline/tool_polyline_cursor.png new file mode 100644 index 00000000..b60c2db0 Binary files /dev/null and b/chalk/plugins/tools/tool_polyline/tool_polyline_cursor.png differ diff --git a/chalk/plugins/tools/tool_selectsimilar/Makefile.am b/chalk/plugins/tools/tool_selectsimilar/Makefile.am new file mode 100644 index 00000000..f57296ba --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/Makefile.am @@ -0,0 +1,32 @@ +kde_services_DATA = chalktoolselectsimilar.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +chalktoolselectsimilar_la_SOURCES = selectsimilar.cc kis_tool_selectsimilar.cc +noinst_HEADERS = selectsimilar.h kis_tool_selectsimilar.h + +kde_module_LTLIBRARIES = chalktoolselectsimilar.la + +chalktoolselectsimilar_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolselectsimilar_la_LIBADD = ../../../libchalkcommon.la + +chalktoolselectsimilar_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +# directory for pixmaps +chalkpics_DATA = \ + tool_similar_selection.png \ + tool_similar_selection_plus_cursor.png \ + tool_similar_selection_minus_cursor.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_selectsimilar/chalktoolselectsimilar.desktop b/chalk/plugins/tools/tool_selectsimilar/chalktoolselectsimilar.desktop new file mode 100644 index 00000000..408d1c5a --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/chalktoolselectsimilar.desktop @@ -0,0 +1,43 @@ +[Desktop Entry] +Name=Select Similar Colors Tool +Name[bg]=Инструмент за маркиране на подобни цветове +Name[ca]=Selecciona eines de colors similars +Name[cy]=Offer Detholi Lliwiau Tebyg +Name[da]=Vælg lignende farve-værktøjer +Name[de]="Auswahl nach ähnlichen Farben"-Werkzeug +Name[el]=Εργαλείο επιλογής παρόμοιων χρωμάτων +Name[en_GB]=Select Similar Colours Tool +Name[eo]=Similkolorelekto-ilo +Name[es]=Herramienta de selección de colores similares +Name[et]=Sarnase värvi valimise tööriist +Name[fa]=برگزیدن ابزار رنگهای مشابه +Name[fr]=Outils de sélection des couleurs similaires +Name[fy]=Lykense kleur seleksje ark +Name[gl]=Ferramenta de Selección de Cores Semellantes +Name[he]=בחירת כלי צבעים דומים +Name[hu]=Hasonló színeket kiválasztó eszköz +Name[is]=Velja svipaða liti tól +Name[it]=Strumento per la selezione dei colori simili +Name[ja]=類似色選択ツール +Name[km]=ឧបករណ៍​ជ្រើស​ពណ៌​ស្រដៀង​គ្នា +Name[nb]=Verktøy som velger liknende farger +Name[nds]=Warktüüch för de Utwahl vun lieke Klören +Name[ne]=समान रङ उपकरणहरू चयन गर्नुहोस् +Name[nl]=Gereedschap voor soortgelijke kleuren +Name[pl]=Narzędzie wyboru podobnych kolorów +Name[pt]=Ferramenta de Selecção de Cores Semelhantes +Name[pt_BR]=Ferramenta de Seleção de Cores Semelhantes +Name[ru]=Выделение по цвету +Name[se]=Reaidu mii vállje sullosaš ivnniid +Name[sk]=Výber podobných farieb +Name[sl]=Orodje za izbiro podobnih barv +Name[sr]=Алат за избор сличних боја +Name[sr@Latn]=Alat za izbor sličnih boja +Name[sv]=Välj liknande färg-verktyg +Name[uk]=Засіб вибору подібних кольорів +Name[zh_CN]=选择相似颜色工具 +Name[zh_TW]=選取近似色彩工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolselectsimilar +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc b/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc new file mode 100644 index 00000000..2dfe40f1 --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.cc @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_tool_selectsimilar.h" + +void selectByColor(KisPaintDeviceSP dev, KisSelectionSP selection, const TQ_UINT8 * c, int fuzziness, enumSelectionMode mode) +{ + // XXX: Multithread this! + TQ_INT32 x, y, w, h; + + dev->exactBounds(x, y, w, h); + + KisColorSpace * cs = dev->colorSpace(); + + for (int y2 = y; y2 < y + h; ++y2) { + KisHLineIterator hiter = dev->createHLineIterator(x, y2, w, false); + KisHLineIterator selIter = selection->createHLineIterator(x, y2, w, true); + while (!hiter.isDone()) { + //if (dev->colorSpace()->hasAlpha()) + // opacity = dev->colorSpace()->getAlpha(hiter.rawData()); + + TQ_UINT8 match = cs->difference(c, hiter.rawData()); + + if (mode == SELECTION_ADD) { + if (match <= fuzziness) { + *(selIter.rawData()) = MAX_SELECTED; + } + } + else if (mode == SELECTION_SUBTRACT) { + if (match <= fuzziness) { + *(selIter.rawData()) = MIN_SELECTED; + } + } + ++hiter; + ++selIter; + } + } + +} + + + +KisToolSelectSimilar::KisToolSelectSimilar() + : super(i18n("Select Similar Colors")) +{ + setName("tool_select_similar"); + m_addCursor = KisCursor::load("tool_similar_selection_plus_cursor.png", 1, 21); + m_subtractCursor = KisCursor::load("tool_similar_selection_minus_cursor.png", 1, 21); + setCursor(m_addCursor); + m_subject = 0; + m_optWidget = 0; + m_selectionOptionsWidget = 0; + m_fuzziness = 20; + m_currentSelectAction = m_defaultSelectAction = SELECTION_ADD; + m_timer = new TQTimer(this); + connect(m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotTimer()) ); +} + +KisToolSelectSimilar::~KisToolSelectSimilar() +{ +} + +void KisToolSelectSimilar::activate() +{ + KisToolNonPaint::activate(); + m_timer->start(50); + setPickerCursor(m_currentSelectAction); + + if (m_selectionOptionsWidget) { + m_selectionOptionsWidget->slotActivated(); + } +} + +void KisToolSelectSimilar::deactivate() +{ + m_timer->stop(); +} + +void KisToolSelectSimilar::buttonPress(KisButtonPressEvent *e) +{ + + if (m_subject) { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisImageSP img; + KisPaintDeviceSP dev; + TQPoint pos; + TQ_UINT8 opacity = OPACITY_OPAQUE; + + if (e->button() != Qt::LeftButton && e->button() != Qt::RightButton) + return; + + if (!(img = m_subject->currentImg())) + return; + + dev = img->activeDevice(); + + if (!dev || !img->activeLayer()->visible()) + return; + + pos = TQPoint(e->pos().floorX(), e->pos().floorY()); + KisSelectedTransaction *t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Similar Selection"),dev); + + KisColor c = dev->colorAt(pos.x(), pos.y()); + opacity = dev->colorSpace()->getAlpha(c.data()); + + // XXX we should make this configurable: "allow to select transparent" + // if (opacity > OPACITY_TRANSPARENT) + selectByColor(dev, dev->selection(), c.data(), m_fuzziness, m_currentSelectAction); + + dev->setDirty(); + dev->emitSelectionChanged(); + + if(img->undo()) + img->undoAdapter()->addCommand(t); + m_subject->canvasController()->updateCanvas(); + + TQApplication::restoreOverrideCursor(); + } +} + +void KisToolSelectSimilar::slotTimer() +{ +#if KDE_IS_VERSION(3,4,0) + int state = kapp->keyboardMouseState() & (TQt::ShiftButton|TQt::ControlButton|TQt::AltButton); +#else + int state = kapp->keyboardModifiers() & (KApplication::ShiftModifier + |KApplication::ControlModifier|KApplication::Modifier1); +#endif + enumSelectionMode action; + + if (state == TQt::ShiftButton) + action = SELECTION_ADD; + else if (state == TQt::ControlButton) + action = SELECTION_SUBTRACT; + else + action = m_defaultSelectAction; + + if (action != m_currentSelectAction) { + m_currentSelectAction = action; + setPickerCursor(action); + } +} + +void KisToolSelectSimilar::setPickerCursor(enumSelectionMode action) +{ + switch (action) { + case SELECTION_ADD: + m_subject->canvasController()->setCanvasCursor(m_addCursor); + break; + case SELECTION_SUBTRACT: + m_subject->canvasController()->setCanvasCursor(m_subtractCursor); + } +} + +void KisToolSelectSimilar::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Similar Selection"), "tool_similar_selection", "Ctrl+E", this, TQT_SLOT(activate()), collection, name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Select similar colors")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +void KisToolSelectSimilar::update(KisCanvasSubject *subject) +{ + super::update(subject); + m_subject = subject; +} + +void KisToolSelectSimilar::slotSetFuzziness(int fuzziness) +{ + m_fuzziness = fuzziness; +} + +void KisToolSelectSimilar::slotSetAction(int action) +{ + m_defaultSelectAction = (enumSelectionMode)action; +} + +TQWidget* KisToolSelectSimilar::createOptionWidget(TQWidget* tqparent) +{ + m_optWidget = new TQWidget(tqparent); + Q_CHECK_PTR(m_optWidget); + + m_optWidget->setCaption(i18n("Similar Selection")); + + TQVBoxLayout * l = new TQVBoxLayout(m_optWidget, 0, 6); + Q_CHECK_PTR(l); + + m_selectionOptionsWidget = new KisSelectionOptions(m_optWidget, m_subject); + Q_CHECK_PTR(m_selectionOptionsWidget); + + l->addWidget(m_selectionOptionsWidget); + connect (m_selectionOptionsWidget, TQT_SIGNAL(actionChanged(int)), this, TQT_SLOT(slotSetAction(int))); + + TQHBoxLayout * hbox = new TQHBoxLayout(l); + Q_CHECK_PTR(hbox); + + TQLabel * lbl = new TQLabel(i18n("Fuzziness: "), m_optWidget); + Q_CHECK_PTR(lbl); + + hbox->addWidget(lbl); + + KIntNumInput * input = new KIntNumInput(m_optWidget, "fuzziness"); + Q_CHECK_PTR(input); + + input->setRange(0, 200, 10, true); + input->setValue(20); + hbox->addWidget(input); + connect(input, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetFuzziness(int))); + + l->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Fixed, TQSizePolicy::Expanding)); + + return m_optWidget; +} + +TQWidget* KisToolSelectSimilar::optionWidget() +{ + return m_optWidget; +} + +#include "kis_tool_selectsimilar.moc" diff --git a/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h b/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h new file mode 100644 index 00000000..d98659d0 --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/kis_tool_selectsimilar.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TOOL_SELECT_PICKER_H_ +#define KIS_TOOL_SELECT_PICKER_H_ + +#include +#include +#include + +class KisCanvasSubject; +class TQWidget; +class TQVBoxLayout; +class TQCheckBox; +class KisIntSpinbox; + +/** + * Tool to select colours by pointing at a color on the image. + * TODO: + * Implement shift/shift-ctrl keyboard shortcuts for + * temporary add/subtract selection mode. + */ + +class KisSelectionOptions; + +class KisToolSelectSimilar : public KisToolNonPaint { + + Q_OBJECT + TQ_OBJECT + typedef KisToolNonPaint super; + +public: + KisToolSelectSimilar(); + virtual ~KisToolSelectSimilar(); + + virtual void update(KisCanvasSubject *subject); + virtual void setup(KActionCollection *collection); + virtual TQ_UINT32 priority() { return 8; } + virtual enumToolType toolType() { return TOOL_SELECT; } + +public slots: + + void activate(); + void deactivate(); + + virtual void slotSetFuzziness(int); + virtual void slotSetAction(int); + +private: + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void buttonPress(KisButtonPressEvent *e); + void setPickerCursor(enumSelectionMode); + + KisCanvasSubject *m_subject; + TQWidget *m_optWidget; + KisSelectionOptions *m_selectionOptionsWidget; + + int m_fuzziness; + enumSelectionMode m_defaultSelectAction; + enumSelectionMode m_currentSelectAction; + TQTimer *m_timer; + TQCursor m_addCursor; + TQCursor m_subtractCursor; + +private slots: + void slotTimer(); +}; + +class KisToolSelectSimilarFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolSelectSimilarFactory() : super() {}; + virtual ~KisToolSelectSimilarFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolSelectSimilar(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("selectsimilar", i18n("Select Similar")); } +}; + + +#endif // KIS_TOOL_SELECT_PICKER_H_ + diff --git a/chalk/plugins/tools/tool_selectsimilar/selectsimilar.cc b/chalk/plugins/tools/tool_selectsimilar/selectsimilar.cc new file mode 100644 index 00000000..539f534a --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/selectsimilar.cc @@ -0,0 +1,61 @@ +/* + * selectsimilar.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "selectsimilar.h" +#include "kis_tool_selectsimilar.h" + +typedef KGenericFactory SelectSimilarFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolselectsimilar, SelectSimilarFactory( "chalk" ) ) + +SelectSimilar::SelectSimilar(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(SelectSimilarFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + r->add(new KisToolSelectSimilarFactory()); + } +} + +SelectSimilar::~SelectSimilar() +{ +} + +#include "selectsimilar.moc" + diff --git a/chalk/plugins/tools/tool_selectsimilar/selectsimilar.h b/chalk/plugins/tools/tool_selectsimilar/selectsimilar.h new file mode 100644 index 00000000..a0588bfb --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/selectsimilar.h @@ -0,0 +1,35 @@ +/* + * selectsimilar.h -- Part of Chalk + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SELECTSIMILAR_H +#define SELECTSIMILAR_H + +#include + +class SelectSimilar : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + public: + SelectSimilar(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~SelectSimilar(); + + +}; + +#endif // SELECTSIMILAR_H diff --git a/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.png b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.png new file mode 100644 index 00000000..3025b100 Binary files /dev/null and b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.png differ diff --git a/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.svg b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.svg new file mode 100644 index 00000000..f1e881bc --- /dev/null +++ b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection.svg @@ -0,0 +1,2118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png new file mode 100644 index 00000000..e6b2da50 Binary files /dev/null and b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_minus_cursor.png differ diff --git a/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png new file mode 100644 index 00000000..d5a5e726 Binary files /dev/null and b/chalk/plugins/tools/tool_selectsimilar/tool_similar_selection_plus_cursor.png differ diff --git a/chalk/plugins/tools/tool_star/Makefile.am b/chalk/plugins/tools/tool_star/Makefile.am new file mode 100644 index 00000000..11cab8a3 --- /dev/null +++ b/chalk/plugins/tools/tool_star/Makefile.am @@ -0,0 +1,37 @@ +kde_services_DATA = chalktoolstar.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktoolstar_la_SOURCES = \ + wdg_tool_star.ui \ + tool_star.cc \ + kis_tool_star.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktoolstar.la + +noinst_HEADERS = \ + tool_star.h \ + kis_tool_star.h + +chalktoolstar_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktoolstar_la_LIBADD = ../../../libchalkcommon.la + +chalktoolstar_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + tool_star.png \ + tool_star_cursor.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_star/chalktoolstar.desktop b/chalk/plugins/tools/tool_star/chalktoolstar.desktop new file mode 100644 index 00000000..546c0d97 --- /dev/null +++ b/chalk/plugins/tools/tool_star/chalktoolstar.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Star Tool +Name[bg]=Инструмент звезда +Name[br]=Ostilh steredenn +Name[ca]=Eina d'estrella +Name[cy]=Erfyn Seren +Name[da]=Stjerneværktøj +Name[de]=Stern-Werkzeug +Name[el]=Εργαλείο αστεριού +Name[eo]=Stelo-ilo +Name[es]=Herramienta Estrella +Name[et]=Tähe tööriist +Name[eu]=Izarra tresna +Name[fa]=ابزار ستاره +Name[fi]=Tähtityökalu +Name[fr]=Outil étoile +Name[fy]=Sjer-ark +Name[ga]=Uirlis Réiltín +Name[gl]=Ferramenta de Estrelas +Name[he]=כלי כוכב +Name[hu]=Csillag eszköz +Name[is]=Stjörnutól +Name[it]=Strumento stella +Name[ja]=星型ツール +Name[km]=ឧបករណ៍​រាង​ផ្កាយ +Name[lt]=Žvaigždės įrankis +Name[lv]=Zvaigznes rīks +Name[ms]=Alat Bintang +Name[nb]=Stjerneverktøy +Name[nds]=Steern-Warktüüch +Name[ne]=तारा उपकरण +Name[nl]=Stergereedschap +Name[nn]=Stjerneverktøy +Name[pl]=Narzędzie do rysowania gwiazdki +Name[pt]=Ferramenta de Estrelas +Name[pt_BR]=Ferramenta Estrela +Name[ru]=Звезда +Name[se]=Nástereaidu +Name[sk]=Hviezda +Name[sl]=Zvezdno orodje +Name[sr]=Алат за звезде +Name[sr@Latn]=Alat za zvezde +Name[sv]=Stjärnverktyg +Name[uk]=Інструмент зірки +Name[uz]=Yulduz vositasi +Name[uz@cyrillic]=Юлдуз воситаси +Name[zh_CN]=星形工具 +Name[zh_TW]=星形工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktoolstar +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_star/kis_tool_star.cc b/chalk/plugins/tools/tool_star/kis_tool_star.cc new file mode 100644 index 00000000..3a804f89 --- /dev/null +++ b/chalk/plugins/tools/tool_star/kis_tool_star.cc @@ -0,0 +1,245 @@ +/* + * kis_tool_star.cc -- part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_doc.h" +#include "kis_view.h" +#include "kis_painter.h" +#include "kis_int_spinbox.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_paintop_registry.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_cursor.h" +#include "kis_int_spinbox.h" + +#include "kis_tool_star.h" +#include "wdg_tool_star.h" + +KisToolStar::KisToolStar() + : super(i18n("Star")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_star"); + setCursor(KisCursor::load("tool_star_cursor.png", 6, 6)); + m_innerOuterRatio=40; + m_vertices=5; +} + +KisToolStar::~KisToolStar() +{ +} + +void KisToolStar::update (KisCanvasSubject *subject) +{ + super::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg (); +} + +void KisToolStar::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage && event->button() == Qt::LeftButton) { + m_dragging = true; + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_vertices = m_optWidget->verticesSpinBox->value(); + m_innerOuterRatio = m_optWidget->ratioSpinBox->value(); + } +} + +void KisToolStar::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + // move (alt) or resize star + if (event->state() & TQt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + m_dragEnd = event->pos(); + } + // draw new lines on canvas + draw(m_dragStart, m_dragEnd); + } +} + +void KisToolStar::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject || !m_currentImage) + return; + + if (m_dragging && event->button() == Qt::LeftButton) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragging = false; + + if (m_dragStart == m_dragEnd) + return; + + if (!m_currentImage) + return; + + if (!m_currentImage->activeDevice()) + return; + + KisPaintDeviceSP device = m_currentImage->activeDevice ();; + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n("Star")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBackgroundColor(m_subject->bgColor()); + painter.setFillStyle(fillStyle()); + painter.setBrush(m_subject->currentBrush()); + painter.setPattern(m_subject->currentPattern()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + + vKisPoint coord = starCoordinates(m_vertices, m_dragStart.x(), m_dragStart.y(), m_dragEnd.x(), m_dragEnd.y()); + + painter.paintPolygon(coord); + + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + } +} + +void KisToolStar::draw(const KisPoint& start, const KisPoint& end ) +{ + if (!m_subject || !m_currentImage) + return; + + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter p (canvas); + TQPen pen(TQt::SolidLine); + + KisPoint startPos; + KisPoint endPos; + startPos = controller->windowToView(start); + endPos = controller->windowToView(end); + + p.setRasterOp(TQt::NotROP); + + vKisPoint points = starCoordinates(m_vertices, startPos.x(), startPos.y(), endPos.x(), endPos.y()); + + for (uint i = 0; i < points.count() - 1; i++) { + p.drawLine(points[i].floorTQPoint(), points[i + 1].floorTQPoint()); + } + p.drawLine(points[points.count() - 1].floorTQPoint(), points[0].floorTQPoint()); + + p.end (); +} + +void KisToolStar::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(TQt::Key_Plus); + shortcut.append(KShortcut(TQt::Key_F9)); + m_action = new KRadioAction(i18n("&Star"), + "tool_star", + shortcut, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Draw a star")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +vKisPoint KisToolStar::starCoordinates(int N, double mx, double my, double x, double y) +{ + double R=0, r=0; + TQ_INT32 n=0; + double angle; + + vKisPoint starCoordinatesArray(2*N); + + // the radius of the outer edges + R=sqrt((x-mx)*(x-mx)+(y-my)*(y-my)); + + // the radius of the inner edges + r=R*m_innerOuterRatio/100.0; + + // the angle + angle=-atan2((x-mx),(y-my)); + + //set outer edges + for(n=0;nratioSpinBox->setValue(m_innerOuterRatio); + + TQGridLayout *optionLayout = new TQGridLayout(widget, 1, 1); + super::addOptionWidgetLayout(optionLayout); + + optionLayout->addWidget(m_optWidget, 0, 0); + + return widget; +} + +#include "kis_tool_star.moc" diff --git a/chalk/plugins/tools/tool_star/kis_tool_star.h b/chalk/plugins/tools/tool_star/kis_tool_star.h new file mode 100644 index 00000000..3bd8df2b --- /dev/null +++ b/chalk/plugins/tools/tool_star/kis_tool_star.h @@ -0,0 +1,101 @@ +/* + * kis_tool_star.h - part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_STAR_H_ +#define KIS_TOOL_STAR_H_ + +#include "kis_tool_shape.h" + +class KisCanvas; +class KisDoc; +class KisPainter; +class KisView; +class KisRect; +class WdgToolStar; + +class KisToolStar : public KisToolShape { + + typedef KisToolShape super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolStar(); + virtual ~KisToolStar(); + + // + // KisCanvasObserver interface + // + + virtual void update (KisCanvasSubject *subject); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + + // + // KisToolPaint interface + // + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_SHAPE; } + virtual TQ_UINT32 priority() { return 6; } + virtual void buttonPress(KisButtonPressEvent *event); + virtual void move(KisMoveEvent *event); + virtual void buttonRelease(KisButtonReleaseEvent *event); + +protected: + virtual void draw(const KisPoint& start, const KisPoint& stop); + //virtual void draw(KisPainter *gc, const TQRect& rc); + +protected: + int m_lineThickness; + + KisPoint m_dragStart; + KisPoint m_dragEnd; + TQRect m_final_lines; + + bool m_dragging; + KisImageSP m_currentImage; +private: + vKisPoint starCoordinates(int N, double mx, double my, double x, double y); + TQ_INT32 m_innerOuterRatio; + TQ_INT32 m_vertices; + WdgToolStar* m_optWidget; +}; + + +#include "kis_tool_factory.h" + +class KisToolStarFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolStarFactory() : super() {}; + virtual ~KisToolStarFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolStar(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("startqshape", i18n("Star Tool")); } +}; + + +#endif //__KIS_TOOL_STAR_H__ diff --git a/chalk/plugins/tools/tool_star/tool_star.cc b/chalk/plugins/tools/tool_star/tool_star.cc new file mode 100644 index 00000000..e399fafa --- /dev/null +++ b/chalk/plugins/tools/tool_star/tool_star.cc @@ -0,0 +1,62 @@ +/* + * tool_star.cc -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_star.h" +#include "kis_tool_star.h" + + +typedef KGenericFactory ToolStarFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolstar, ToolStarFactory( "chalk" ) ) + + +ToolStar::ToolStar(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolStarFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast( tqparent ); + r->add(new KisToolStarFactory()); + } + +} + +ToolStar::~ToolStar() +{ +} + +#include "tool_star.moc" diff --git a/chalk/plugins/tools/tool_star/tool_star.h b/chalk/plugins/tools/tool_star/tool_star.h new file mode 100644 index 00000000..36172dd6 --- /dev/null +++ b/chalk/plugins/tools/tool_star/tool_star.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_STAR_H_ +#define TOOL_STAR_H_ + +#include + +class KisView; + +/** + * A module that provides a star tool. + */ +class ToolStar : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolStar(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolStar(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_STAR_H_ diff --git a/chalk/plugins/tools/tool_star/tool_star.png b/chalk/plugins/tools/tool_star/tool_star.png new file mode 100644 index 00000000..c7627866 Binary files /dev/null and b/chalk/plugins/tools/tool_star/tool_star.png differ diff --git a/chalk/plugins/tools/tool_star/tool_star_cursor.png b/chalk/plugins/tools/tool_star/tool_star_cursor.png new file mode 100644 index 00000000..d3cef598 Binary files /dev/null and b/chalk/plugins/tools/tool_star/tool_star_cursor.png differ diff --git a/chalk/plugins/tools/tool_star/wdg_tool_star.ui b/chalk/plugins/tools/tool_star/wdg_tool_star.ui new file mode 100644 index 00000000..b342a927 --- /dev/null +++ b/chalk/plugins/tools/tool_star/wdg_tool_star.ui @@ -0,0 +1,128 @@ + +WdgToolStar + + + WdgToolStar + + + + 0 + 0 + 280 + 50 + + + + Star + + + + unnamed + + + 0 + + + + tqlayout8 + + + + unnamed + + + + textLabel1 + + + Vertices: + + + isbX + + + + + verticesSpinBox + + + 100 + + + 2 + + + 5 + + + + + + + tqlayout7 + + + + unnamed + + + + textLabel2 + + + Ratio: + + + isbWidth + + + + + ratioSpinBox + + + + 0 + 5 + 0 + 0 + + + + + + + + + verticesSpinBox + ratioSpinBox + + + + KisIntSpinbox +
kis_int_spinbox.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image4 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + knuminput.h + knuminput.h + +
diff --git a/chalk/plugins/tools/tool_transform/Makefile.am b/chalk/plugins/tools/tool_transform/Makefile.am new file mode 100644 index 00000000..7b088383 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/Makefile.am @@ -0,0 +1,37 @@ +kde_services_DATA = chalktooltransform.desktop + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalktooltransform_la_SOURCES = \ + wdg_tool_transform.ui \ + tool_transform.cc \ + kis_tool_transform.cc + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = chalktooltransform.la + +noinst_HEADERS = \ + tool_transform.h \ + kis_tool_transform.h + +chalktooltransform_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui +chalktooltransform_la_LIBADD = ../../../libchalkcommon.la + +chalktooltransform_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal + +chalkpics_DATA = \ + rotate_cursor.xpm \ + tool_transform.png + +chalkpicsdir = $(kde_datadir)/chalk/pics + diff --git a/chalk/plugins/tools/tool_transform/chalktooltransform.desktop b/chalk/plugins/tools/tool_transform/chalktooltransform.desktop new file mode 100644 index 00000000..4ea3db98 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/chalktooltransform.desktop @@ -0,0 +1,46 @@ +[Desktop Entry] +Name=Transform Tool +Name[bg]=Инструмент за трансформиране +Name[br]=Ostilh treuzfurmiñ +Name[ca]=Eina de transformació +Name[cy]=Erfyn Trawsffurfio +Name[da]=Transformeringsværktøj +Name[de]=Transformation-Werkzeug +Name[el]=Εργαλείο μετασχηματισμού +Name[eo]=Transform-ilo +Name[es]=Herramienta para transformar +Name[et]=Transformeermistööriist +Name[fa]=ابزار تبدیل +Name[fr]=Outil transformation +Name[fy]=ferfoarmingsark +Name[ga]=Uirlis Trasfhoirmithe +Name[gl]=Ferramenta de Transformación +Name[hu]=Átalakító eszköz +Name[is]=Ummyndunartól +Name[it]=Strumento di trasformazione +Name[ja]=変換ツール +Name[km]=ឧបករណ៍​ប្លែង +Name[lt]=Transformavimo įrankis +Name[lv]=Transformāciju rīks +Name[nb]=Transformeringsverktøy +Name[nds]=Ümwanneln-Warktüüch +Name[ne]=रूपान्तरण उपकरण +Name[nl]=Vervormgereedschap +Name[pl]=Narzędzie przekształcania +Name[pt]=Ferramenta de Transformação +Name[pt_BR]=Ferramenta de Transformação +Name[ru]=Преобразование +Name[sk]=Transformácia +Name[sl]=Orodje za pretvorbo +Name[sr]=Алат за трансформацију +Name[sr@Latn]=Alat za transformaciju +Name[sv]=Transformeringsverktyg +Name[uk]=Засіб перетворення +Name[uz]=Aylantirish asbobi +Name[uz@cyrillic]=Айлантириш асбоби +Name[zh_CN]=变形工具 +Name[zh_TW]=變形工具 +ServiceTypes=Chalk/Tool +Type=Service +X-KDE-Library=chalktooltransform +X-Chalk-Version=2 diff --git a/chalk/plugins/tools/tool_transform/kis_tool_transform.cc b/chalk/plugins/tools/tool_transform/kis_tool_transform.cc new file mode 100644 index 00000000..5b828122 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/kis_tool_transform.cc @@ -0,0 +1,916 @@ +/* + * kis_tool_transform.cc -- part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_tool_transform.h" +#include "wdg_tool_transform.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +namespace { + class TransformCmd : public KisSelectedTransaction { + typedef KisSelectedTransaction super; + + public: + TransformCmd(KisToolTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, double scaleX, double scaleY, double tX, double tY, double a, KisSelectionSP origSel, TQPoint startPos, TQPoint endPos); + virtual ~TransformCmd(); + + public: + virtual void execute(); + virtual void unexecute(); + void transformArgs(double &sx, double &sy, double &tx, double &ty, double &a); + KisSelectionSP origSelection(TQPoint &startPos, TQPoint &endPos); + KisPaintDeviceSP theDevice(); + KisPaintDeviceSP origDevice(); + + private: + double m_scaleX; + double m_scaleY; + double m_translateX; + double m_translateY; + double m_a; + KisToolTransform *m_tool; + KisSelectionSP m_origSelection; + TQPoint m_startPos; + TQPoint m_endPos; + KisPaintDeviceSP m_device; + KisPaintDeviceSP m_origDevice; + }; + + TransformCmd::TransformCmd(KisToolTransform *tool, KisPaintDeviceSP device, KisPaintDeviceSP origDevice, double scaleX, double scaleY, double tX, double tY, double a, KisSelectionSP origSel, TQPoint startPos, TQPoint endPos) : + super(i18n("Transform"), device) + , m_scaleX(scaleX) + , m_scaleY(scaleY) + , m_translateX(tX) + , m_translateY(tY) + , m_a(a) + , m_tool(tool) + , m_origSelection(origSel) + , m_startPos(startPos) + , m_endPos(endPos) + , m_device(device) + , m_origDevice(origDevice) + { + } + + TransformCmd::~TransformCmd() + { + } + + void TransformCmd::transformArgs(double &sx, double &sy, double &tx, double &ty, double &a) + { + sx = m_scaleX; + sy = m_scaleY; + tx= m_translateX; + ty = m_translateY; + a = m_a; + } + + KisSelectionSP TransformCmd::origSelection(TQPoint &startPos, TQPoint &endPos) + { + startPos = m_startPos; + endPos = m_endPos; + return m_origSelection; + } + + void TransformCmd::execute() + { + super::execute(); + } + + void TransformCmd::unexecute() + { + super::unexecute(); + } + + KisPaintDeviceSP TransformCmd::theDevice() + { + return m_device; + } + + KisPaintDeviceSP TransformCmd::origDevice() + { + return m_origDevice; + } +} + +KisToolTransform::KisToolTransform() + : super(i18n("Transform")) + , m_wasPressed( false ) +{ + setName("tool_transform"); + setCursor(KisCursor::selectCursor()); + m_subject = 0; + m_selecting = false; + m_startPos = TQPoint(0, 0); + m_endPos = TQPoint(0, 0); + m_optWidget = 0; + m_sizeCursors[0] = KisCursor::sizeVerCursor(); + m_sizeCursors[1] = KisCursor::sizeBDiagCursor(); + m_sizeCursors[2] = KisCursor::sizeHorCursor(); + m_sizeCursors[3] = KisCursor::sizeFDiagCursor(); + m_sizeCursors[4] = KisCursor::sizeVerCursor(); + m_sizeCursors[5] = KisCursor::sizeBDiagCursor(); + m_sizeCursors[6] = KisCursor::sizeHorCursor(); + m_sizeCursors[7] = KisCursor::sizeFDiagCursor(); + m_origDevice = 0; + m_origSelection = 0; + +} + +KisToolTransform::~KisToolTransform() +{ +} + +void KisToolTransform::deactivate() +{ + if (m_subject && m_subject->undoAdapter()) m_subject->undoAdapter()->removeCommandHistoryListener( this ); + + KisImageSP img = m_subject->currentImg(); + if (!img) return; + + paintOutline(); + + disconnect(m_subject->currentImg().data(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolTransform::activate() +{ + if(m_subject && m_subject->currentImg() && m_subject->currentImg()->activeDevice()) + { + //connect(m_subject, commandExecuted(KCommand *c), this, notifyCommandAdded( KCommand * c)); + m_subject->undoAdapter()->setCommandHistoryListener( this ); + + KisToolControllerInterface *controller = m_subject->toolController(); + + if (controller) + controller->setCurrentTool(this); + + TransformCmd * cmd=0; + + if(m_subject->currentImg()->undoAdapter()->presentCommand()) + cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); + + if (cmd == 0) { + initHandles(); + } + else + { + // One of our commands is on top + if(cmd->theDevice() == m_subject->currentImg()->activeDevice()) + { + // and it even has the same device + // We should ask for tool args and orig selection + m_origDevice = cmd->origDevice(); + cmd->transformArgs(m_scaleX, m_scaleY, m_translateX, m_translateY, m_a); + m_origSelection = cmd->origSelection(m_startPos, m_endPos); + m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; + m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; + paintOutline(); + } + else + initHandles(); + } + } + connect(m_subject->currentImg(), TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); +} + +void KisToolTransform::initHandles() +{ + TQ_INT32 x,y,w,h; + KisImageSP img = m_subject->currentImg(); + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev ) return; + + // Create a lazy copy of the current state + m_origDevice = new KisPaintDevice(*dev.data()); + Q_ASSERT(m_origDevice); + + if(dev->hasSelection()) + { + KisSelectionSP sel = dev->selection(); + m_origSelection = new KisSelection(*sel.data()); + TQRect r = sel->selectedExactRect(); + r.rect(&x, &y, &w, &h); + } + else { + dev->exactBounds(x,y,w,h); + m_origSelection = 0; + } + m_startPos = TQPoint(x, y); + m_endPos = TQPoint(x+w-1, y+h-1); + m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; + m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; + + m_a = 0.0; + m_scaleX = 1.0; + m_scaleY = 1.0; + m_translateX = m_org_cenX; + m_translateY = m_org_cenY; + + m_subject->canvasController() ->updateCanvas(); +} + +void KisToolTransform::paint(KisCanvasPainter& gc) +{ + paintOutline(gc, TQRect()); +} + +void KisToolTransform::paint(KisCanvasPainter& gc, const TQRect& rc) +{ + paintOutline(gc, rc); +} + + +void KisToolTransform::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton) { + m_wasPressed = true; + } + + if (m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img && img->activeDevice() && e->button() == Qt::LeftButton) { + switch(m_function) + { + case ROTATE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint(static_cast(m_translateX),static_cast(m_translateY)); + m_clickangle = -m_a - atan2(m_clickoffset.x(),m_clickoffset.y()); + m_clickoffset = TQPoint(0, 0); + break; + case MOVE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint(static_cast(m_translateX),static_cast(m_translateY)); + break; + case TOPSCALE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint((m_topleft + m_topright)/2); + break; + case TOPRIGHTSCALE: + m_clickoffset = e->pos().floorTQPoint() - m_topright; + break; + case RIGHTSCALE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint((m_topright + m_bottomright)/2); + break; + case BOTTOMRIGHTSCALE: + m_clickoffset = e->pos().floorTQPoint() - m_bottomright; + break; + case BOTTOMSCALE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint((m_bottomleft + m_bottomright)/2); + break; + case BOTTOMLEFTSCALE: + m_clickoffset = e->pos().floorTQPoint() - m_bottomleft; + break; + case LEFTSCALE: + m_clickoffset = e->pos().floorTQPoint() + - TQPoint((m_topleft + m_bottomleft)/2); + break; + case TOPLEFTSCALE: + m_clickoffset = e->pos().floorTQPoint() - m_topleft; + break; + } + m_selecting = true; + m_actualyMoveWhileSelected = false; + } + } +} + +int KisToolTransform::det(TQPoint v,TQPoint w) +{ + return v.x()*w.y()-v.y()*w.x(); +} +int KisToolTransform::distsq(TQPoint v,TQPoint w) +{ + v -= w; + return v.x()*v.x() + v.y()*v.y(); +} + +void KisToolTransform::setFunctionalCursor() +{ + int rotOctant = 8 + int(8.5 + m_a* 4 / M_PI); + + int s; + if(m_scaleX*m_scaleY<0) + s = -1; + else + s=1; + + switch(m_function) + { + case MOVE: + setCursor(KisCursor::moveCursor()); + break; + case ROTATE: + setCursor(KisCursor::rotateCursor()); + break; + case TOPSCALE: + setCursor(m_sizeCursors[(0*s +rotOctant)%8]); + break; + case TOPRIGHTSCALE: + setCursor(m_sizeCursors[(1*s +rotOctant)%8]); + break; + case RIGHTSCALE: + setCursor(m_sizeCursors[(2*s +rotOctant)%8]); + break; + case BOTTOMRIGHTSCALE: + setCursor(m_sizeCursors[(3*s +rotOctant)%8]); + break; + case BOTTOMSCALE: + setCursor(m_sizeCursors[(4*s +rotOctant)%8]); + break; + case BOTTOMLEFTSCALE: + setCursor(m_sizeCursors[(5*s +rotOctant)%8]); + break; + case LEFTSCALE: + setCursor(m_sizeCursors[(6*s +rotOctant)%8]); + break; + case TOPLEFTSCALE: + setCursor(m_sizeCursors[(7*s +rotOctant)%8]); + break; + } +} + +void KisToolTransform::move(KisMoveEvent *e) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + + Q_ASSERT(controller); + TQPoint topleft = m_topleft; + TQPoint topright = m_topright; + TQPoint bottomleft = m_bottomleft; + TQPoint bottomright = m_bottomright; + + TQPoint mousePos = e->pos().floorTQPoint(); + + if (m_subject && m_selecting) { + paintOutline(); + m_actualyMoveWhileSelected = true; + mousePos -= m_clickoffset; + + // transform mousePos coords, so it seems like it isn't rotated and centered at 0,0 + double newX = invrotX(mousePos.x() - m_translateX, mousePos.y() - m_translateY); + double newY = invrotY(mousePos.x() - m_translateX, mousePos.y() - m_translateY); + double dx=0, dy=0; + double oldScaleX = m_scaleX; + double oldScaleY = m_scaleY; + + if(m_function == MOVE) + { + m_translateX += mousePos.x() - m_translateX; + m_translateY += mousePos.y() - m_translateY; + } + + if(m_function == ROTATE) + { + m_a = -atan2(mousePos.x() - m_translateX, mousePos.y() - m_translateY) + - m_clickangle; + } + + if(m_function == TOPSCALE) + { + dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + } + } + + if(m_function == TOPRIGHTSCALE) + { + dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); + + dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); + + // enforce same aspect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX < m_scaleY) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + dx = (m_scaleX - oldScaleX) * (m_endPos.x() - m_org_cenX); + } + else + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + dy = (m_scaleY - oldScaleY) * (m_startPos.y() - m_org_cenY); + } + } + } + + if(m_function == RIGHTSCALE) + { + dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + } + } + + if(m_function == BOTTOMRIGHTSCALE) + { + dx = (newX - m_scaleX * (m_endPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_endPos.x() - m_org_cenX); + + dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX < m_scaleY) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + dx = (m_scaleX - oldScaleX) * (m_endPos.x() - m_org_cenX); + } + else + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + dy = (m_scaleY - oldScaleY) * (m_endPos.y() - m_org_cenY); + } + } + } + + if(m_function == BOTTOMSCALE) + { + dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + } + } + + if(m_function == BOTTOMLEFTSCALE) + { + dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); + + dy = (newY - m_scaleY * (m_endPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_endPos.y() - m_org_cenY); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX < m_scaleY) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + dx = (m_scaleX - oldScaleX) * (m_startPos.x() - m_org_cenX); + } + else + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + dy = (m_scaleY - oldScaleY) * (m_endPos.y() - m_org_cenY); + } + } + } + + if(m_function == LEFTSCALE) + { + dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + } + } + + if(m_function == TOPLEFTSCALE) + { + dx = (newX - m_scaleX * (m_startPos.x() - m_org_cenX)) / 2; + m_scaleX = (newX - dx) / (m_startPos.x() - m_org_cenX); + + dy = (newY - m_scaleY * (m_startPos.y() - m_org_cenY)) / 2; + m_scaleY = (newY - dy) / (m_startPos.y() - m_org_cenY); + + // enforce same acpect if shift button is pressed + if(e->state() & TQt::ShiftButton) + { + if(m_scaleX < m_scaleY) + { + if(m_scaleX>0) // handle the mirrored cases + m_scaleX = fabs(m_scaleY); + else + m_scaleX = -fabs(m_scaleY); + dx = (m_scaleX - oldScaleX) * (m_startPos.x() - m_org_cenX); + } + else + { + if(m_scaleY>0) // handle the mirrored cases + m_scaleY = fabs(m_scaleX); + else + m_scaleY = -fabs(m_scaleX); + dy = (m_scaleY - oldScaleY) * (m_startPos.y() - m_org_cenY); + } + } + } + + m_translateX += rotX(dx, dy); + m_translateY += rotY(dx, dy); + + paintOutline(); + } + else + { + if(det(mousePos - topleft, topright - topleft)>0) + m_function = ROTATE; + else if(det(mousePos - topright, bottomright - topright)>0) + m_function = ROTATE; + else if(det(mousePos - bottomright, bottomleft - bottomright)>0) + m_function = ROTATE; + else if(det(mousePos - bottomleft, topleft - bottomleft)>0) + m_function = ROTATE; + else + m_function = MOVE; + + int handleradius = int( 25 / (m_subject->zoomFactor() * m_subject->zoomFactor()) ); + + if(distsq(mousePos, (m_topleft + m_topright)/2)<=handleradius) + m_function = TOPSCALE; + if(distsq(mousePos, m_topright)<=handleradius) + m_function = TOPRIGHTSCALE; + if(distsq(mousePos, (m_topright + m_bottomright)/2)<=handleradius) + m_function = RIGHTSCALE; + if(distsq(mousePos, m_bottomright)<=handleradius) + m_function = BOTTOMRIGHTSCALE; + if(distsq(mousePos, (m_bottomleft + m_bottomright)/2)<=handleradius) + m_function = BOTTOMSCALE; + if(distsq(mousePos, m_bottomleft)<=handleradius) + m_function = BOTTOMLEFTSCALE; + if(distsq(mousePos, (m_topleft + m_bottomleft)/2)<=handleradius) + m_function = LEFTSCALE; + if(distsq(mousePos, m_topleft)<=handleradius) + m_function = TOPLEFTSCALE; + + setFunctionalCursor(); + } + } +} + +void KisToolTransform::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && e->button() == Qt::LeftButton) { + if(!m_wasPressed) return; + m_wasPressed = false; + + KisImageSP img = m_subject->currentImg(); + + if (!img) + return; + + m_selecting = false; + + if(m_actualyMoveWhileSelected) + { + paintOutline(); + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + transform(); + TQApplication::restoreOverrideCursor(); + } + } +} + +void KisToolTransform::paintOutline() +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter gc(canvas); + TQRect rc; + + paintOutline(gc, rc); + } +} + +void KisToolTransform::recalcOutline() +{ + double x,y; + + m_sina = sin(m_a); + m_cosa = cos(m_a); + + x = (m_startPos.x() - m_org_cenX) * m_scaleX; + y = (m_startPos.y() - m_org_cenY) * m_scaleY; + m_topleft = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); + + x = (m_endPos.x() - m_org_cenX) * m_scaleX; + y = (m_startPos.y() - m_org_cenY) * m_scaleY; + m_topright = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); + + x = (m_startPos.x() - m_org_cenX) * m_scaleX; + y = (m_endPos.y() - m_org_cenY) * m_scaleY; + m_bottomleft = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); + + x = (m_endPos.x() - m_org_cenX) * m_scaleX; + y = (m_endPos.y() - m_org_cenY) * m_scaleY; + m_bottomright = TQPoint(int(rotX(x,y) + m_translateX+0.5), int(rotY(x,y) + m_translateY+0.5)); +} + +void KisToolTransform::paintOutline(KisCanvasPainter& gc, const TQRect&) +{ + if (m_subject) { + KisCanvasController *controller = m_subject->canvasController(); + RasterOp op = gc.rasterOp(); + TQPen old = gc.pen(); + TQPen pen(TQt::SolidLine); + pen.setWidth(1); + Q_ASSERT(controller); + + recalcOutline(); + TQPoint topleft = controller->windowToView(m_topleft); + TQPoint topright = controller->windowToView(m_topright); + TQPoint bottomleft = controller->windowToView(m_bottomleft); + TQPoint bottomright = controller->windowToView(m_bottomright); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.drawRect(topleft.x()-4, topleft.y()-4, 8, 8); + gc.drawLine(topleft.x(), topleft.y(), (topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2); + gc.drawRect((topleft.x()+topright.x())/2-4, (topleft.y()+topright.y())/2-4, 8, 8); + gc.drawLine((topleft.x()+topright.x())/2, (topleft.y()+topright.y())/2, topright.x(), topright.y()); + gc.drawRect(topright.x()-4, topright.y()-4, 8, 8); + gc.drawLine(topright.x(), topright.y(), (topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2); + gc.drawRect((topright.x()+bottomright.x())/2-4, (topright.y()+bottomright.y())/2-4, 8, 8); + gc.drawLine((topright.x()+bottomright.x())/2, (topright.y()+bottomright.y())/2,bottomright.x(), bottomright.y()); + gc.drawRect(bottomright.x()-4, bottomright.y()-4, 8, 8); + gc.drawLine(bottomright.x(), bottomright.y(), (bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2); + gc.drawRect((bottomleft.x()+bottomright.x())/2-4, (bottomleft.y()+bottomright.y())/2-4, 8, 8); + gc.drawLine((bottomleft.x()+bottomright.x())/2, (bottomleft.y()+bottomright.y())/2, bottomleft.x(), bottomleft.y()); + gc.drawRect(bottomleft.x()-4, bottomleft.y()-4, 8, 8); + gc.drawLine(bottomleft.x(), bottomleft.y(), (topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2); + gc.drawRect((topleft.x()+bottomleft.x())/2-4, (topleft.y()+bottomleft.y())/2-4, 8, 8); + gc.drawLine((topleft.x()+bottomleft.x())/2, (topleft.y()+bottomleft.y())/2, topleft.x(), topleft.y()); + gc.setRasterOp(op); + gc.setPen(old); + } +} + +void KisToolTransform::transform() +{ + + KisImageSP img = m_subject->currentImg(); + + if (!img || !img->activeDevice()) + return; + + double tx = m_translateX - rotX(m_org_cenX * m_scaleX, m_org_cenY * m_scaleY); + double ty = m_translateY - rotY(m_org_cenX * m_scaleX, m_org_cenY * m_scaleY); + KisProgressDisplayInterface *progress = m_subject->progressDisplay(); + + // This mementoes the current state of the active device. + TransformCmd * transaction = new TransformCmd(this, img->activeDevice(), m_origDevice, + m_scaleX, m_scaleY, m_translateX, m_translateY, m_a, m_origSelection, m_startPos, m_endPos); + + // Copy the original state back. + TQRect rc = m_origDevice->extent(); + rc = rc.normalize(); + img->activeDevice()->clear(); + KisPainter gc(img->activeDevice()); + gc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origDevice, rc.x(), rc.y(), rc.width(), rc.height()); + gc.end(); + + // Also restore the original selection. + if(m_origSelection) + { + //TQRect rc = m_origSelection->extent(); + TQRect rc = m_origSelection->selectedRect(); + rc = rc.normalize(); + img->activeDevice()->selection()->clear(); + KisPainter sgc(img->activeDevice()->selection().data()); + sgc.bitBlt(rc.x(), rc.y(), COMPOSITE_COPY, m_origSelection.data(), rc.x(), rc.y(), rc.width(), rc.height()); + sgc.end(); + } + else + if(img->activeDevice()->hasSelection()) + img->activeDevice()->selection()->clear(); + + // Perform the transform. Since we copied the original state back, this doesn't degrade + // after many tweaks. Since we started the transaction before the copy back, the memento + // has the previous state. + KisTransformWorker t(img->activeDevice(), m_scaleX, m_scaleY, 0, 0, m_a, int(tx), int(ty), progress, m_filter); + t.run(); + + // If canceled, go back to the memento + if(t.isCanceled()) + { + transaction->unexecute(); + delete transaction; + return; + } + + img->activeDevice()->setDirty(rc); // XXX: This is not enough - should union with new extent + + // Else add the command -- this will have the memento from the previous state, + // and the transformed state from the original device we cached in our activated() + // method. + if (transaction) { + if (img->undo()) + img->undoAdapter()->addCommand(transaction); + else + delete transaction; + } +} + +void KisToolTransform::notifyCommandAdded( KCommand * command) +{ + TransformCmd * cmd = dynamic_cast(command); + if (cmd == 0) { + // The last added command wasn't one of ours; + // we should reset to the new state of the canvas. + // In effect we should treat this as if the tool has been just activated + initHandles(); + } +} + +void KisToolTransform::notifyCommandExecuted( KCommand * command) +{ + Q_UNUSED(command); + TransformCmd * cmd=0; + + if(m_subject->currentImg()->undoAdapter()->presentCommand()) + cmd = dynamic_cast(m_subject->currentImg()->undoAdapter()->presentCommand()); + + if (cmd == 0) { + // The command now on the top of the stack isn't one of ours + // We should treat this as if the tool has been just activated + initHandles(); + } + else + { + // One of our commands is now on top + // We should ask for tool args and orig selection + cmd->transformArgs(m_scaleX, m_scaleY, m_translateX, m_translateY, m_a); + m_origSelection = cmd->origSelection(m_startPos, m_endPos); + m_origDevice = cmd->origDevice(); + m_org_cenX = (m_startPos.x() + m_endPos.x()) / 2.0; + m_org_cenY = (m_startPos.y() + m_endPos.y()) / 2.0; + m_subject->canvasController() ->updateCanvas(); + } +} + +void KisToolTransform::slotSetFilter(const KisID &filterID) +{ + m_filter = KisFilterStrategyRegistry::instance()->get(filterID); +} + +void KisToolTransform::slotLayerActivated(KisLayerSP) +{ + activate(); +} + + +TQWidget* KisToolTransform::createOptionWidget(TQWidget* tqparent) +{ + + m_optWidget = new WdgToolTransform(tqparent); + Q_CHECK_PTR(m_optWidget); + + m_optWidget->cmbFilter->clear(); + m_optWidget->cmbFilter->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); + + m_optWidget->cmbFilter->setCurrentText("Mitchell"); + connect(m_optWidget->cmbFilter, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(slotSetFilter(const KisID &))); + + KisID filterID = m_optWidget->cmbFilter->currentItem(); + m_filter = KisFilterStrategyRegistry::instance()->get(filterID); + +/* + connect(m_optWidget->intStartX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartX(int))); + connect(m_optWidget->intStartY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setStartY(int))); + connect(m_optWidget->intEndX, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndX(int))); + connect(m_optWidget->intEndY, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(setEndY(int))); +*/ + m_optWidget->intStartX->hide(); + m_optWidget->intStartY->hide(); + m_optWidget->intEndX->hide(); + m_optWidget->intEndY->hide(); + m_optWidget->textLabel1->hide(); + m_optWidget->textLabel2->hide(); + m_optWidget->textLabel3->hide(); + m_optWidget->textLabel4->hide(); + return m_optWidget; +} + +TQWidget* KisToolTransform::optionWidget() +{ + return m_optWidget; +} + +void KisToolTransform::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Transform"), + "tool_transform", + 0, + this, + TQT_SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + m_action->setToolTip(i18n("Transform a layer or a selection")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + +#include "kis_tool_transform.moc" diff --git a/chalk/plugins/tools/tool_transform/kis_tool_transform.h b/chalk/plugins/tools/tool_transform/kis_tool_transform.h new file mode 100644 index 00000000..a98cd4f7 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/kis_tool_transform.h @@ -0,0 +1,155 @@ +/* + * kis_tool_transform.h - part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_TRANSFORM_H_ +#define KIS_TOOL_TRANSFORM_H_ + +#include + +#include +#include +#include +#include + +class KisTransaction; +class WdgToolTransform; +class KisID; +class KisFilterStrategy; + +/** + * Transform tool + * + */ +class KisToolTransform : public KisToolNonPaint, KisCommandHistoryListener { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolTransform(); + virtual ~KisToolTransform(); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + + virtual void setup(KActionCollection *collection); + virtual enumToolType toolType() { return TOOL_TRANSFORM; } + virtual TQ_UINT32 priority() { return 3; } + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + void setScaleX(double sx) { m_scaleX = sx; } + void setScaleY(double sy) { m_scaleY = sy; } + void setTranslateX(double tx) { m_translateX = tx; } + void setTranslateY(double ty) { m_translateY = ty; } + void setAngle(double a) { m_a = a; } + void paintOutline(); + +public: + + void notifyCommandAdded(KCommand *); + void notifyCommandExecuted(KCommand *); + +public: + virtual void deactivate(); + +private: + + void paintOutline(KisCanvasPainter& gc, const TQRect& rc); + void transform(); + void recalcOutline(); + double rotX(double x, double y) { return m_cosa*x - m_sina*y;}; + double rotY(double x, double y) { return m_sina*x + m_cosa*y;}; + double invrotX(double x, double y) { return m_cosa*x + m_sina*y;}; + double invrotY(double x, double y) { return -m_sina*x + m_cosa*y;}; + int det(TQPoint v,TQPoint w); + int distsq(TQPoint v,TQPoint w); + void setFunctionalCursor(); + void initHandles(); + +private slots: + + void slotLayerActivated(KisLayerSP); + void slotSetFilter(const KisID &); + void setStartX(int x) { m_startPos.setX(x); } + void setStartY(int y) { m_startPos.setY(y); } + void setEndX(int x) { m_endPos.setX(x); } + void setEndY(int y) { m_endPos.setY(y); } + +protected slots: + virtual void activate(); + +private: + enum function {ROTATE,MOVE,TOPLEFTSCALE,TOPSCALE,TOPRIGHTSCALE,RIGHTSCALE, + BOTTOMRIGHTSCALE, BOTTOMSCALE,BOTTOMLEFTSCALE, LEFTSCALE}; + TQCursor m_sizeCursors[8]; + function m_function; + TQPoint m_startPos; + TQPoint m_endPos; + bool m_selecting; + bool m_actualyMoveWhileSelected; + TQPoint m_topleft; + TQPoint m_topright; + TQPoint m_bottomleft; + TQPoint m_bottomright; + double m_scaleX; + double m_scaleY; + double m_translateX; + double m_translateY; + TQPoint m_clickoffset; + double m_org_cenX; + double m_org_cenY; + double m_cosa; + double m_sina; + double m_a; + double m_clickangle; + KisFilterStrategy *m_filter; + + WdgToolTransform *m_optWidget; + + KisPaintDeviceSP m_origDevice; + KisSelectionSP m_origSelection; + + bool m_wasPressed; +}; + +class KisToolTransformFactory : public KisToolFactory { + typedef KisToolFactory super; + +public: + KisToolTransformFactory() : super() {}; + virtual ~KisToolTransformFactory(){}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolTransform(); + Q_CHECK_PTR(t); + t->setup(ac); return t; + } + virtual KisID id() { return KisID("transform", i18n("Transform Tool")); } +}; + + + +#endif // KIS_TOOL_TRANSFORM_H_ + diff --git a/chalk/plugins/tools/tool_transform/rotate_cursor.xpm b/chalk/plugins/tools/tool_transform/rotate_cursor.xpm new file mode 100644 index 00000000..f3860232 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/rotate_cursor.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static char *rotate_cursor[]={ +"22 22 4 1", +"b c None", +". c None", +"a c #000000", +"# c #ffffff", +"......................", +"......................", +"....##...#####........", +"....#a###aaaaa##......", +"....#aaaabbbbbaa#.....", +"....#aaa#.....bba#....", +"....#aaaa#......ba#...", +"....######......bba#..", +".................ba#..", +"..bbb.............ba#.", +"..#ab.............ba#.", +"..#ab.............ba#.", +"..#ab.............ba#.", +"..#ab.............ba#.", +"...#ab............bbb.", +"...#ab.......######...", +"....#ab......#aaaa#...", +".....#abbb....#aaa#...", +"......#aabbbb#aaaa#...", +".......##aaaaa###a#...", +".........#####...##...", +"......................"}; diff --git a/chalk/plugins/tools/tool_transform/tool_transform.cc b/chalk/plugins/tools/tool_transform/tool_transform.cc new file mode 100644 index 00000000..2ee002de --- /dev/null +++ b/chalk/plugins/tools/tool_transform/tool_transform.cc @@ -0,0 +1,64 @@ +/* + * tool_transform.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tool_transform.h" +#include "kis_tool_transform.h" + + +typedef KGenericFactory ToolTransformFactory; +K_EXPORT_COMPONENT_FACTORY( chalktooltransform, ToolTransformFactory( "chalk" ) ) + + +ToolTransform::ToolTransform(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ToolTransformFactory::instance()); + + if ( tqparent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast(tqparent); + KisToolTransformFactory * f = new KisToolTransformFactory(); + Q_CHECK_PTR(f); + r->add(f); + } + +} + +ToolTransform::~ToolTransform() +{ +} + +#include "tool_transform.moc" diff --git a/chalk/plugins/tools/tool_transform/tool_transform.h b/chalk/plugins/tools/tool_transform/tool_transform.h new file mode 100644 index 00000000..04bfbaa9 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/tool_transform.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef TOOL_TRANSFORM_H_ +#define TOOL_TRANSFORM_H_ + +#include + +class KisView; + +/** + * A module that provides a transform tool. + */ +class ToolTransform : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ToolTransform(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ToolTransform(); + +private: + + KisView * m_view; + +}; + +#endif // TOOL_TRANSFORM_H_ diff --git a/chalk/plugins/tools/tool_transform/tool_transform.png b/chalk/plugins/tools/tool_transform/tool_transform.png new file mode 100644 index 00000000..6c601433 Binary files /dev/null and b/chalk/plugins/tools/tool_transform/tool_transform.png differ diff --git a/chalk/plugins/tools/tool_transform/wdg_tool_transform.ui b/chalk/plugins/tools/tool_transform/wdg_tool_transform.ui new file mode 100644 index 00000000..2f41e1b3 --- /dev/null +++ b/chalk/plugins/tools/tool_transform/wdg_tool_transform.ui @@ -0,0 +1,243 @@ + +WdgToolTransform + + + WdgToolTransform + + + + 0 + 0 + 377 + 91 + + + + Transform + + + + unnamed + + + 0 + + + 3 + + + + tqlayout11 + + + + unnamed + + + + tqlayout7 + + + + unnamed + + + + tqlayout1 + + + + unnamed + + + + textLabel1 + + + Move X: + + + isbX + + + + + intStartX + + + 1000000000 + + + + + + + tqlayout2 + + + + unnamed + + + + textLabel2 + + + Scale X: + + + isbWidth + + + + + intEndX + + + 1000000000 + + + + + + + + + tqlayout8 + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + textLabel3 + + + Move Y: + + + isbY + + + + + intStartY + + + 1000000000 + + + + + + + tqlayout4 + + + + unnamed + + + + textLabel4 + + + Scale Y: + + + isbHeight + + + + + intEndY + + + 1000000000 + + + + + + + + + + + textLabel1_2 + + + Filter: + + + AlignVCenter|AlignRight + + + + + cmbFilter + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 21 + + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + + intStartX + intStartY + intEndX + intEndY + + + + knuminput.h + kis_cmb_idlist.h + +
diff --git a/chalk/plugins/viewplugins/Makefile.am b/chalk/plugins/viewplugins/Makefile.am new file mode 100644 index 00000000..e5739b36 --- /dev/null +++ b/chalk/plugins/viewplugins/Makefile.am @@ -0,0 +1,24 @@ +if compile_kross +SCRIPTINGDIR = scripting +endif + +SUBDIRS = \ + substrate \ + colorrange \ + colorspaceconversion \ + dropshadow \ + filtersgallery \ + histogram \ + histogram_docker \ + imagesize \ + modify_selection \ + rotateimage \ + screenshot \ + separate_channels \ + shearimage \ + selectopaque \ + $(SCRIPTINGDIR) + +# variations +# history_docker +# performancetest diff --git a/chalk/plugins/viewplugins/colorrange/Makefile.am b/chalk/plugins/viewplugins/colorrange/Makefile.am new file mode 100644 index 00000000..fc29a370 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/Makefile.am @@ -0,0 +1,25 @@ +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkcolorrange.la + +chalkcolorrange_la_SOURCES = colorrange.cc dlg_colorrange.cc wdg_colorrange.ui +noinst_HEADERS = wdg_colorrange.h dlg_colorrange.h colorrange.h + +chalkcolorrange_la_LIBADD = ../../../libchalkcommon.la +chalkcolorrange_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui + +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = colorrange.rc +EXTRA_DIST = $(chalkrc_DATA) + +kde_services_DATA = chalkcolorrange.desktop + +chalkcolorrange_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/chalk/plugins/viewplugins/colorrange/chalkcolorrange.desktop b/chalk/plugins/viewplugins/colorrange/chalkcolorrange.desktop new file mode 100644 index 00000000..dde9b936 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/chalkcolorrange.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Colorrange +Name[bg]=Цветови обхват +Name[ca]=Rang de color +Name[da]=Farveområde +Name[de]=Farbbereich +Name[el]=Χρωματικό εύρος +Name[en_GB]=Colourrange +Name[eo]=Kolorgamo +Name[et]=Värvivahemik +Name[fa]=گسترۀ رنگ +Name[fr]=Plage de couleurs +Name[fy]=Kleurberik +Name[gl]=Gamas de Cores +Name[he]=טווח צבעים +Name[hu]=Egyszerű +Name[is]=Litasvið +Name[it]=Intervallo di colori +Name[ja]=色の範囲 +Name[km]=ជួរ​ពណ៌ +Name[nb]=Fargeområde +Name[nds]=Klörenrebeet +Name[ne]=रङदायरा +Name[nl]=Kleurbereik +Name[pl]=Zakres kolorów +Name[pt]=Gamas de Cores +Name[pt_BR]=Intervalos de Cores +Name[ru]=Цвета +Name[se]=Ivdnegaskkadat +Name[sk]=Rozsah farieb +Name[sl]=Barvni razpon +Name[sr]=Опсег боја +Name[sr@Latn]=Opseg boja +Name[sv]=Färgintervall +Name[uk]=Діапазон кольорів +Name[zh_TW]=色彩範圍 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkcolorrange +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/colorrange/colorrange.cc b/chalk/plugins/viewplugins/colorrange/colorrange.cc new file mode 100644 index 00000000..1bf90bbc --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/colorrange.cc @@ -0,0 +1,82 @@ +/* + * colorrange.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "colorrange.h" +#include "dlg_colorrange.h" + +typedef KGenericFactory ColorRangeFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcolorrange, ColorRangeFactory( "chalk" ) ) + +ColorRange::ColorRange(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if (tqparent->inherits("KisView")) { + setInstance(ColorRangeFactory::instance()); + setXMLFile(locate("data","chalkplugins/colorrange.rc"), true); + m_view = dynamic_cast(tqparent); + m_view->canvasSubject()->selectionManager()->addSelectionAction( new KAction(i18n("&Color Range..."), 0, 0, this, TQT_SLOT(slotActivated()), actionCollection(), "colorrange") ); + + } +} + +ColorRange::~ColorRange() +{ +} + +void ColorRange::slotActivated() +{ + KisPaintDeviceSP layer = m_view->canvasSubject()->currentImg()->activeDevice(); + if (!layer) return; + + DlgColorRange * dlgColorRange = new DlgColorRange(m_view, layer, m_view, "ColorRange"); + Q_CHECK_PTR(dlgColorRange); + + dlgColorRange->exec(); +} + +#include "colorrange.moc" + diff --git a/chalk/plugins/viewplugins/colorrange/colorrange.h b/chalk/plugins/viewplugins/colorrange/colorrange.h new file mode 100644 index 00000000..38e008d9 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/colorrange.h @@ -0,0 +1,45 @@ +/* + * colorrange.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLORRANGE_H +#define COLORRANGE_H + +#include + +class KisView; + +class ColorRange : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + public: + ColorRange(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ColorRange(); + + private slots: + void slotActivated(); + + private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // COLORRANGE_H diff --git a/chalk/plugins/viewplugins/colorrange/colorrange.rc b/chalk/plugins/viewplugins/colorrange/colorrange.rc new file mode 100644 index 00000000..39d49cd8 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/colorrange.rc @@ -0,0 +1,10 @@ + + + + Select + + + + + + diff --git a/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cc b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cc new file mode 100644 index 00000000..43f98a53 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.cc @@ -0,0 +1,351 @@ +/* + * dlg_colorrange.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dlg_colorrange.h" +#include "wdg_colorrange.h" + +namespace { + +// XXX: Poynton says: hsv/hls is not what one ought to use for colour calculations. +// Unfortunately, I don't know enough to be able to use anything else. + + bool isReddish(int h) + { + return ((h > 330 && h < 360) || ( h > 0 && h < 40)); + } + + bool isYellowish(int h) + { + return (h> 40 && h < 65); + } + + bool isGreenish(int h) + { + return (h > 70 && h < 155); + } + + bool isCyanish(int h) + { + return (h > 150 && h < 190); + } + + bool isBlueish(int h) + { + return (h > 185 && h < 270); + } + + bool isMagentaish(int h) + { + return (h > 265 && h < 330); + } + + bool isHighlight(int v) + { + return (v > 200); + } + + bool isMidTone(int v) + { + return (v > 100 && v < 200); + } + + bool isShadow(int v) + { + return (v < 100); + } + +} + +TQ_UINT32 matchColors(const TQColor & c, enumAction action) +{ + int r = c.red(); + int g = c.green(); + int b = c.blue(); + + int h, s, v; + rgb_to_hsv(r, g, b, &h, &s, &v); + + + + // XXX: Map the degree in which the colors conform to the requirement + // to a range of selectedness between 0 and 255 + + // XXX: Implement out-of-gamut using lcms + + switch(action) { + + case REDS: + if (isReddish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case YELLOWS: + if (isYellowish(h)) { + return MAX_SELECTED; + } + else + return MIN_SELECTED; + case GREENS: + if (isGreenish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case CYANS: + if (isCyanish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case BLUES: + if (isBlueish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case MAGENTAS: + if (isMagentaish(h)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case HIGHLIGHTS: + if (isHighlight(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case MIDTONES: + if (isMidTone(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + case SHADOWS: + if (isShadow(v)) + return MAX_SELECTED; + else + return MIN_SELECTED; + }; + + return MIN_SELECTED; +} + + + +DlgColorRange::DlgColorRange( KisView * view, KisPaintDeviceSP dev, TQWidget * tqparent, const char * name) + : super (tqparent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_dev = dev; + m_view = view; + + m_subject = view->canvasSubject(); + + m_page = new WdgColorRange(this, "color_range"); + Q_CHECK_PTR(m_page); + + setCaption(i18n("Color Range")); + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + if (m_dev->image()->undo()) m_transaction = new KisSelectedTransaction(i18n("Select by Color Range"), m_dev); + + if(! m_dev->hasSelection()) + m_dev->selection()->clear(); + m_selection = m_dev->selection(); + + updatePreview(); + + m_invert = false; + m_mode = SELECTION_ADD; + m_currentAction = REDS; + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + + connect(this, TQT_SIGNAL(cancelClicked()), + this, TQT_SLOT(cancelClicked())); + + connect(m_page->chkInvert, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotInvertClicked())); + + connect(m_page->cmbSelect, TQT_SIGNAL(activated(int)), + this, TQT_SLOT(slotSelectionTypeChanged(int))); + + connect (m_page->radioAdd, TQT_SIGNAL(toggled(bool)), + this, TQT_SLOT(slotAdd(bool))); + + connect (m_page->radioSubtract, TQT_SIGNAL(toggled(bool)), + this, TQT_SLOT(slotSubtract(bool))); + + connect (m_page->bnSelect, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotSelectClicked())); + + connect (m_page->bnDeselect, TQT_SIGNAL(clicked()), + this, TQT_SLOT(slotDeselectClicked())); + +} + +DlgColorRange::~DlgColorRange() +{ + delete m_page; +} + + +void DlgColorRange::updatePreview() +{ + if (!m_selection) return; + + TQ_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + TQPixmap pix = TQPixmap(m_selection->tqmaskImage().smoothScale(350, 350, TQ_ScaleMin)); + m_subject->canvasController()->updateCanvas(); + m_page->pixSelection->setPixmap(pix); +} + +void DlgColorRange::okClicked() +{ + m_dev->setDirty(); + m_dev->emitSelectionChanged(); + + if (m_dev->image()->undo()) m_subject->undoAdapter()->addCommand(m_transaction); + accept(); +} + +void DlgColorRange::cancelClicked() +{ + if (m_dev->image()->undo()) m_transaction->unexecute(); + + m_subject->canvasController()->updateCanvas(); + reject(); +} + +void DlgColorRange::slotInvertClicked() +{ + m_invert = m_page->chkInvert->isChecked(); +} + +void DlgColorRange::slotSelectionTypeChanged(int index) +{ + m_currentAction = (enumAction)index; +} + +void DlgColorRange::slotSubtract(bool on) +{ + if (on) + m_mode = SELECTION_SUBTRACT; +} +void DlgColorRange::slotAdd(bool on) +{ + if (on) + m_mode = SELECTION_ADD; +} + +void DlgColorRange::slotSelectClicked() +{ + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + // XXX: Multithread this! + TQ_INT32 x, y, w, h; + m_dev->exactBounds(x, y, w, h); + KisColorSpace * cs = m_dev->colorSpace(); + TQ_UINT8 opacity; + for (int y2 = y; y2 < h - y; ++y2) { + KisHLineIterator hiter = m_dev->createHLineIterator(x, y2, w, false); + KisHLineIterator selIter = m_selection ->createHLineIterator(x, y2, w, true); + while (!hiter.isDone()) { + TQColor c; + + cs->toTQColor(hiter.rawData(), &c, &opacity); + // Don't try to select transparent pixels. + if (opacity > OPACITY_TRANSPARENT) { + TQ_UINT8 match = matchColors(c, m_currentAction); + + if (match) { + // Personally, I think the invert option a bit silly. But it's possible I don't quite understand it. BSAR. + if (!m_invert) { + if (m_mode == SELECTION_ADD) { + *(selIter.rawData()) = match; + } + else if (m_mode == SELECTION_SUBTRACT) { + TQ_UINT8 selectedness = *(selIter.rawData()); + if (match < selectedness) { + *(selIter.rawData()) = selectedness - match; + } + else { + *(selIter.rawData()) = 0; + } + } + } + else { + if (m_mode == SELECTION_ADD) { + TQ_UINT8 selectedness = *(selIter.rawData()); + if (match < selectedness) { + *(selIter.rawData()) = selectedness - match; + } + else { + *(selIter.rawData()) = 0; + } + } + else if (m_mode == SELECTION_SUBTRACT) { + *(selIter.rawData()) = match; + } + } + } + } + ++hiter; + ++selIter; + } + } + updatePreview(); + TQApplication::restoreOverrideCursor(); +} + +void DlgColorRange::slotDeselectClicked() +{ + m_dev->selection()->clear(); + updatePreview(); +} + + +#include "dlg_colorrange.moc" diff --git a/chalk/plugins/viewplugins/colorrange/dlg_colorrange.h b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.h new file mode 100644 index 00000000..ce39ebd2 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/dlg_colorrange.h @@ -0,0 +1,100 @@ +/* + * dlg_colorrange.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_COLORRANGE +#define DLG_COLORRANGE + +#include + +#include + +#include + +#include // For enums +#include +#include + + +class KisView; +class KisCanvasSubject; +class DlgColorRange; +class KisSelectedTransaction; +class WdgColorRange; + +enum enumAction { + REDS, + YELLOWS, + GREENS, + CYANS, + BLUES, + MAGENTAS, + HIGHLIGHTS, + MIDTONES, + SHADOWS +}; + + + /** + * This dialog allows the user to create a selection tqmask based + * on a (range of) colors. + */ +class DlgColorRange: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + + + +public: + + DlgColorRange(KisView * view, KisPaintDeviceSP layer, TQWidget * tqparent = 0, const char* name = 0); + ~DlgColorRange(); + +private slots: + + void okClicked(); + void cancelClicked(); + + void slotInvertClicked(); + void slotSelectionTypeChanged(int index); + void updatePreview(); + void slotSubtract(bool on); + void slotAdd(bool on); + void slotSelectClicked(); + void slotDeselectClicked(); + +private: + TQImage createMask(KisSelectionSP selection, KisPaintDeviceSP layer); + +private: + + WdgColorRange * m_page; + KisSelectionSP m_selection; + KisPaintDeviceSP m_dev; + KisView * m_view; + KisCanvasSubject * m_subject; + enumSelectionMode m_mode; + TQCursor m_oldCursor; + KisSelectedTransaction *m_transaction; + enumAction m_currentAction; + bool m_invert; +}; + + +#endif // DLG_COLORRANGE diff --git a/chalk/plugins/viewplugins/colorrange/wdg_colorrange.ui b/chalk/plugins/viewplugins/colorrange/wdg_colorrange.ui new file mode 100644 index 00000000..3eafd180 --- /dev/null +++ b/chalk/plugins/viewplugins/colorrange/wdg_colorrange.ui @@ -0,0 +1,252 @@ + +WdgColorRange + + + WdgColorRange + + + + 0 + 0 + 515 + 528 + + + + Color Range + + + + unnamed + + + + tqlayout10 + + + + unnamed + + + + tqlayout8 + + + + unnamed + + + + tqlayout7 + + + + unnamed + + + + + Reds + + + + + Yellows + + + + + Greens + + + + + Cyans + + + + + Blues + + + + + Magentas + + + + + Highlights + + + + + Midtones + + + + + Shadows + + + + + Out of Gamut + + + + cmbSelect + + + + + chkInvert + + + &Invert + + + + + + + grpSelection + + + + + + + unnamed + + + + radioAdd + + + &Add to current selection + + + true + + + + + radioSubtract + + + &Subtract from current selection + + + + + + + + + tqlayout9 + + + + unnamed + + + + bnSelect + + + &Select + + + + + bnDeselect + + + &Deselect + + + + + spacer9 + + + Vertical + + + Expanding + + + + 20 + 40 + + + + + + + + + + grpPreview + + + + 7 + 7 + 1 + 1 + + + + Preview + + + false + + + + unnamed + + + + pixSelection + + + + 7 + 7 + 1 + 1 + + + + NoFrame + + + Plain + + + image0 + + + false + + + AlignCenter + + + + + + + + + 789cccbd47b7eb38b2ef397f9fa2d6e5ecae5e7cf266d0035266cb6da7ed77af1ed07b2f1aa9bf7c83883f704c56d5cd7c75bb5f95d6c9ca5f8a22114044202200f0fccffffcdbe7d3fddffef37ffe8fea625c02eb6f966f947ffb4fbb4e92ebfff57fff9fffcffff88fe160f0b7fecf68389bfe6df41fffc7fff80febf96fd6df9401ff5fcff64232ffde36244f7a762ac953fefd56f29cf35cf2a267f3072ff9f733c906e7836493f35eb2c59fd74ab6797b1f243bfcfb46b2cb7fef0a1e72799c5af2907f7f94cce5732cc963fefd483297cf3a8387d43f992999ffde0c25f3dfb79a64de5f662099dfcfe924cf386f24f3fe4a44ff0fd17e5b327f9e772799dfcfb8078fa87d662499cbebbb9249de6fc9bcbd9d2f99dab795ccc7b31a48e6e3b71a4ae6e315ed25f3f1b04f82a93f0dc1636a9ff32999daf32599f757a54ae6fde17e48e6fae23892b97e78a2bd63ea1f438cef849e97e892f9f7652b99b76f3d91cce53763f0947e6f08fd9c1137b664de5e43c83fc7f53bf0022cf475499c8be719c4f113d824de5cc01671fd0eb6895dbaff50d8ab174ae6f2ad3ac9a47f63c924df4832d73f732a99f777f324998fb73993ccfb5f7f96ccc7df3a49e6e3514592b9bd3aa664ae1fd6bd646eaf9a2b98f4ddf52573fdb58e60d89f6d49e6df9b13c97c3c1d45326fbf634826ffb2934cfee40086fdf88164de7ff65232d9eb9b646e1fa607867e9bbe641a8f816092cf14f2423f4d070c7d8b9f25f3e7bbaf60e89fb791ccfb3b15df43ffe22f30f42f13f240ffea1b18fab716bf877ee967b043dc92bf1f0ea16fdd9af3a8f740bc3dbe64f2f70bc9bcbfcd2fc9bcbfbd4432f90b4730f5cff55e3297bfc9c0187f732899f4772099c6e35b321f7f6b0fc6f8daa6649aff7692f9f3724d32d7f7cb4932ef6ffb4e32e9b302c6f86723c9dcdefc50326f9ff32e99f7975382a10fd75c32d7e795906742fdd3bd49e6df67a2bdd09ff20886beb89164fefcd54932ef9ffa2c98fca72bda0b7d6a9f25f3feb0c4f842bf9a07b0d02fd13fd0afe2090cffd6c660e85b24ae87be05a40f63e1df8277c9bc7debab643e5e575732efef6e2799cb1bfcf89ecbdbed2573fd5cfd781e1fcf952d98fa3b91cf277f74cd24f3fe0f3ec08807ba8d64ae9fc54232e98f27993faff9f13df787ae680ff4d57995cce57103c95c7fac3bc97c7c7c5f308d67b8028bf9f72299cbd3dc49e6f2981f92797fd69664de5f7e2499dbb33b92ccdb6f2dc1d067772099fca72e99b7ff6a49a6f946f437f4b9bd48267934b0d0ef77c9bc7dad68df9cee9fee25f3fe69447fcc31df88f1843eaf6e92f9f3da89649a0fee25f3f1cb85be41ff0331bed07f5f8ca7f0a7d43f13a1df9d2a99f777f32899dfffea80111faeae92b93cee41f090f7effa0c463ce77f48a6f9ee51321fafeb4930f547bb01433fecb164fe7cff5b321f2f2f92ccfb3f93d793bd745b30f421ae2593bfd94be6fd1b2692b93cde4e32b79fda164ced8ddec1d017e74332f9dbb564de5e772899e299140c7dcaa692b93db8df92797fe61d18fe3117e303fd59b792e979b164de3f8918ff05f5cf46f40ff4c715e301fdb9bd80e13f57f792797fad4a30fce906bf17f3f51ae331c4fc19a13d43f89780e693a9f0a7ed028cebfd4e321fafe6198c7cc00b2473f9bc77c95cdf4a4ff0908fc75a5c8f78bfb52553fcf02999ebbfdf08a6f10e5ec1c2bfdc49a6f97c2b99e6ff27c9642f3fbee7fab416f2407fc299643efe912f99ec692099cbd3b492b9bc9ab8ff94c63711fd0bfdb2a792c93e2ac9140f689229df5125f3feed5660e85ffd2a99fce34432efdfee00867e5e14c9941f8ec0d0bfcc904cf9572a99b7a76e25f3fe73c760a1afaa646ebf99e85fe86f2ec61bfaea0b79e11f0ba12f2eda8bfb4b7d267b98897c64dd81a1cfeb503297afbd934cf1d45e30fc93f81ef363b896ccefbf3a4a26793dc1149fae7d30f247ff2a99ea1d3fbee7fed68b05a31eb1924cf9c2083ca5f6076bc9542fd948e6fa900e2473fdbbbc09463d630246be1a6692f9f84481643edef95532b73f5df01cfd7993ccdb7be92453beb5924cf3c14432efbf5cfc7e01fffa2999e6bfb1646e5f9b022ce2cba364de3e37114cfec132c0d047f74d32f9e37b30f26b2f05431f5763c9bc7f42c1d04797e6cf99d0c71be41fc21fa52a18fe24207d9f0bfd5a1d04d3f8570fe009d573dca3642e7fbb054f697ca237c1246f3a944cf53a5b32c5a72f60f81bd796ccaf4f2bc994af2d2593be6f2453bea682e7345eed4e32d5ff14c9bcbf2f57c95cff7dd15ef8a35097ccdb93cd25537e2bfa6b3124fffd055ec2bfcc24537c548045fe518331decda7647ebd2eda6ba37fc478c01f6d44ffb8d43e1ded17e3af3960cc97f5022cf481e257a6dd149fd96bf08cc6ffe64aa6f92604c35eec4032b7efab2799e2375b30e94b2aae5f50ff58aa642e6fe148a67ce1065e927fb80d2553bd2494cc9fdf3e49a6fc45c863c07e1dc97cfcd3a3606a5f7d05633e887682497faf4bb08df8e2030cfb2bc9de17a2ff4bf49f886762f4cf10f666bd80618f3e8dff92f5177f5e914be6ed2f36e005c91b5f24533cf22598ecafeec04be467ae64f28757b041bfaf5f040f29fe68c0268d9726da63917e14a2bdd0c7f424998f5f44fdb314fd91bf83a18f8105467fdc4660e86783e789fee94a30e215e3118c78a3a0f9dc60fd45fa34072f491fc329d8a0f685a964aae7dfc0265d5f2f05537f568f60d86bb091ccfbe36248e6fad988dfbba85f8e24533e48f66f88fe892b30fa67634ba6f97508467f6d1cb0a827435ed11f35fa6388f9c9a7f8c814f157fd065e92fe5f6e6083e42f5cb0897ac417d8227dca3fc036f55fb305431fba77c1747f3b02bba4df3ad9ab29e42f669229df46fb647fe460d8d3aa0243fecd2758d4bbefc0a21eb403a33f2a8a772c263f6fff35055ba827d1f85aa2bf2f1a58f4f70a8cfb252a18febdf1c0f02701f58f2dda7f5d48a6fe9b8071fff21d2cfc83603caf51c1b87fb106433f4b1a1f87fd17eebf1b17ec903efbd43e46b0f71a0c79cb2d58c4e72d18cf2f1bb078be0dc6f3339abf5cd11f8906c6f5de1a8cf846e3f6c1cbe724df068cf6548964ae3f1b130c7f9096608c7f7603a3bde90e8ce7bb2f60b4d77e00c39f075c9f98f639e47fa34832d7e7f84c2c9eb7ba80216ffb08c6f3cc042cd64f1a30e42f9760d88fe382d19e1ced19c11e42aebf0cf17cd306435ecb04a33d610e16f20b16f1470a16ed3981457cf9443c82bdae2660e19f79bc341c8be7d70e18cfd71ec022df8ac178feaa05e379d72bf108e3df70ff369cc8fe1d8345bc9c81d1fe60452cfaeb7a03c3be74ba7e2adbd382f1fbcb3b18e3910dc1689f4df24e657fd4603cafb2c168bffb0cc6f32b1ebf0c67e2fe01e9d34cdcef1283e12faa6f30ee67f860e1ffe660a1efdc7f0ee7e2fed58c58b6e70cc6ef8d002cd6173db0a83f2dc0d0b78edbf77021e5bd078bf6aec1f87d41fabd14f2155bb0f8fd108cdfeb2330da93de83f1fc8ac6d310f2ac1a309ed772ff3734c5fdb48d64ee0fb72e58d4e75ec0f87d7202a33f0d713df4a5237bb7e4782a60b11ee681d15eed112cee1782a1cf158f4f86b6b8bf6581c5fa2af5a733823f762d30eed7d2efdd11f2efcd1d18d76bdc5e468311f2a3c007e379f5082cea75f760e8fbfa8d782cf49dfba3d150fcbebc030b7bdc83a17f099faf472371ffe64c2ceed73460e883cefb6b3416f7ab4fc463e10f2c30e46b8927e279b94b2cee6f6cc1d087ec092cec4930c6f342f24f85fc46442caef75660e8cf85fb93d18cfd9ec783f1162ceaa37cfe19cdc5fd3ceabfb990d79d80d13eeb152cd64fe9fa85f8de7c05a33df9188cf66cbec0d0c7f50d0c7df3b8ff1f2d85bcce002ce227078ceb1d0f2cfca54e3c41fb6f74bd21ef5780f17c5d058bf53beeaf46e618ebd77a2299c77f5bba9f25c6b7f4c1c2bfbd80d19eeb07f104fda1933cb678de2603e37eba01c6ef6f57b0a8ff71ff3d72c6a8b7e8d47faee88fb507c6effd188cdf3bdc1ec67d38c739e2e3c5a63393e21723269e60fde4f22c99d677b93e307577285eb7b8fd8f27ecfe9cf50e0c7d8a79ff8ca7ec7bfefb6b412cc627db81c57e823730ead9eb1158d43fb8bce399b8fe7a0716eb5d7330c663c3fb733c67eda1fa484d2cc6c39a83a11fed193ca57a651282b13e16f3f96ebc9860bdc8d880c5fe810c2cf21bae8fe3e544d4cb23c93c5ed30a30ea071b170cff92d0f81813d443d71730eaed9a07c6f53eb7b7b1c9bee7fa117c49a6f5024b30c5b3760cb6b19ec9e3adb13331e8face93ccfbaf3883f13c23013ba8a72e05d3fd0d1b8c7c734df23b53d8df86facf9da03e7e1b80f1fc82f7e76430813e6d63e229fa3be5e333194e4cd40b52b04ded31b8fe4e4653110ff2fa0a73a736f28d9a788afd67fa180cfd6a1db0588fe3fe7f32610accfb77c3f59721f2c77c493cc5fe0aaf00e37eb731788afa4e059ed1f8361f60d48f6dde1f93d914ebc7460a46bd2fe4fd37994fc7940f6cbec1e89f98cf5f93a578def5013c433d86da6f4c51bf09b9bd4dcce982f2b39cebcbc49a22fff6b83e4dec29ea15d95932adb704c433acffebf43c776ad1fd039d7886f5d315bf3f5356f09acf77d3d1d4a5fa65734f3cc3fe035d134cf7372c30ec355b824dc413dc3fb0e9906574dcdf79c4e2f74501c6fa5b74104cdfb73c3e9d4ea6d6887f7fdb10b3e791bef1f9940ddf1ceb078fe005f5b7c5e7e3e96c86f58f8d0246fd3a76c1f311f9b377b043e31bf07c693a9fa1de19df816dec07f804bb584fa3fe5accc47a86069e517b82002cd6f775b043f39bc6e3dde9923d8eeb7332035bd47f3705ec60ff824d3cc7fecf84ebefd498c19e2faf609bfa2be6f9f0d49c2d51cff5c016e5fb2b176c8f78fb8b15d8a5fa99c9e7d7a93543fdab1b831dfafde6287844f5d10e8cf1af49bfac39c63bff024f499e98ee6fb3fb937f7d023bd4fed407bb435aafb124d37e2d5d30b53f03cf87d43eeb0d8cf5dd7803c67cb7e1f63d75587f707df1e9fece7c30a2fd5d7b30f6b3469f9269fdc792cce5594dc1587fba52ffb84c1edebecd5e326f7f41faebceb19f2cda8271bfa6133ca2e727e0118d4fb2164cfa9c2892f978af4c30eca1f1c19321d7bf2bff7e3660e34ff5e53bb043cfaf5dc174bf6c0076a97fdb929805acfcfb6d0446bdbee4ed9f0d857eddd660f89b6e2298da5f05c4ac3f687e6bc0c311ad87e07a263f9f0fda77f094da537f8067245fc5f569369a1963d29f2b31eb5fdabfe20ba6e7a777e0d188ff3eb9815906c29fa78227d04f053ca3f6b65c3f6663260fd553a93d2cfca4fec91bc95cfeea041e517f5fb8fece2662fcdd023c86ff33c1d31167cd06cf21cf5c308d679d8017d41f0df72fb3e9cc1ef3ebab14ec8c69bfc05432ed47d38885fe5d4cc9b4fe37028fc8fecb37c9649f25784cf6ebbf82e7f47dbc042fe87e05f5cf4ce8936b82e7f4fb36113ca6f17a002fe8f986b8de80fe8bef4dd28fc292cce52fa68269fc4d1effb0db2f49decd0c0c7fdc92fe2ce6131a3f6d2d98fcb7bf02cf49bf370330d68fea5a30fdde38831dfabea3fe59b2fea178b0009bd41e4f03db23aeff37713decb5f00593fc2df5a7c1ee47eb6f2330eadd17156c8ea87ff7609bfc45590b267f78d5c02e714bfa6ab2f1207ff80136c87ef22918f34dfe06c67cd186c48b018dafcee3cd99c5ee47faa48217647f99609bf4c7a0f1b2160392afa3f6da6cfc68bcd69279ff949f6093daef4ec1f067f5817831a4e76de8f70ebb9ece177c806d6abfb3235ec0dfba2bc9b4df9bc6d7ed1376ae5f5c3fe703263f6f4f520a1e53fc99102f66d4be8cf7cf7cc8e4e3d7673e784c7cdd82a7d4de5a03c3fe751e9f3265c2fca09be009d94fc2e397394b87c99f186bf08cfa4fe3fd3b9fb0e7717dacc792e97c0b8f5f58f8bb20d6793d613e5f2cc7b49fc5005bd49e35b56fb1c4fcecf1fe9e2fd9f7743dfdde582ca83f8267b049ed59f3f9686eb2eb69fd782699d62fa83de67244f67de1fa3eb79643b237ef2698f4ab9e8347d4feb0008fc99e1c6a8fbd70d05f4762261e6f9f46e3e730a6f3160618fdbbe6f9c6dc5d0ea8bd0df5bf6b88f89aebdfa25f00a5f8ff4e32edd749c0636aff66019ee17939780e7de2f92a73f643e8bb031e537b7c133c237bf5dec073ba7f44f71f1a225ea3e78f447f79dfe011ddcfe3f22dc68c29feff06e379ba0e9ed2ef0b1effb1747d44f3b1fd0d5ed2f78d0236c65cdf367c7e5fb0009858bf07cfd15f7bf082f4a3492473f96f19d8257b6df8f82e66cb05f55fbe223630ff6f797cbc98b3f67079527afe82319d17e1f6b7581a03fafdc693ccc7d7a0fb194b97da7bbb111b63f2af1bae9f0bd31810eb7cbd61612d1dd2bf94da671943c8cfe7af856d8c69be6e0563be594f2573fdd7b8bd2c1c763ded0f53c01392c7bb4ae6fdd3717d5db8c684fa4bbb134cdfa767f094e28180fba3e5c080fff15fc0b309f5ef9764d24ff13dfc43cae7a3e5d0807d6cf8782d47acbdfcfeed0b783ea1fad50ebca0ef6f3ed82079a32f30f2c5644f6c627f5acce7df655fd0e1e3930460a662dc3f1cc14beaaf40133ca178a8069bf47cdf90ccc74ff3c10e8de78dfa676c8afd09b564daff5982b1ff36a6f64c58ffd2fed40b7836a1fac504bc9c50fd6101c6fc97abc426e2b3700fc67911f3018cf33ac99d643e1edd198cf3176e07463da4fa0063bf8826be47bd53e7fe773965e345fded806db217eb1d8c78f29612b3f6923ea9603cbffb0663bf4949d7b38083c663b3022f68fceb7bb043f6118682a9ff8c02ec92bfcbe9fe7dba49f5c30d18fb636c9e2f2ce7ecf7144f2a6097e4bbe5c4ecf7140fcdc0b0b734018bfde03a784af3c53504cfb15f47dc0ffb0bbb8160ecbffc002fa95e58edc1d8bf1a4dc1163d2f36c1a8575495609c5f1a4aa6f3a134febd83e2ed2f376093faafa3e72fcc01f1f50b3c217ddd5660ac37ad63f00cfe5407cf69beef5230ea35c6026c60bfe55532e55b39d8a4eb6f73b0d8df20ee6f637fe04a32cdff03b043fd757b904cf9d9168c7ae7ed2299ce7b3692697fc898d8c2f99ddb128cf3b317f49f85fa6348f75f1a06d9afb604c37ff817b04dfa1c0ec10ee9bb4ef22ecd015d7fdd8047345eb5079e907e598e60d2d7b40363ffe3762598e2d5750e16e703d692297ffc128cf35768af897afb36108cfaee5c32d56b0f9269fe2e24f3f61731d880ff5125d37ed80558ac974c25d37ec09d64de7fe64132f73fea27d8a2f15732c9b4bea008a6f655a23fb1dfb28c24d3fe470d8c7ae1ed5132e95b2099cf8fa6e82fd4e3c32fc9b4bee3125b38ef7723ff641816d99b7d03dbe48fc22bd8a1f9f95a825d9adf4af28706eb1ede5eaf060fe97aaf133ca1fc5605237e6d8ee009e5bbd5198cf58b4efc1efb6fb71730f67bae66e025c5df8a09c6fecae020998fafd248a6f3ba909fd93b6f4f71025bb0af52329ddf9849e6cf533fc036e993924ba6f96726993f2fcec00ef57ff12e99e2c34a32ed7f0cc1f017d5bb649aef7cc9bc3f22f13c97fa4fc3f859388f5a6d25f3f69443c1d86f3b06e37c4be54ae6edd354c9bc7dd791643aefdc4aa67acf2b18e7f134f13dced325a4ef26d3379affc95f9826e2cb952a99c6f7153ca57835fd0463ff691108267fb579028b78c2001b34dee14532bf7f62814df88b4832d52f2ab085f59d0118eba3752899ecff2699eae307c9b43fb405431f9454329d2fbb97ccdb938cc02ee95b2adaebd2f8b590dfc279e448974ce3f12998e67b4d30ce074713c934ff403e0be72d2dba9fc5e607defeca014fc85f5413f094e2313b954cfea0114cfe467901233fd41792a99e6a49a6f527c198afd71bc9549fb9822dea8fba944cf9502799dad782b17e6d7592c9be6782495fea42321fdff8c7f77cbcb477b043fa1deb9229ff4904e37cc697641a7f0decd27828aa647abfc45032ade7b982495f13b25fcbc2fb0c944032d9cb93606abf5949a6f314cf60bc4fc00a24f3f6b79960d29f5a914cf11dfa53d87bf82999d6df303e16ceb755a4cf369b3fc8ff7660ec3f57de04933ff0f760ac5f665bc114df2b67c1a44f57156c507f5f1cc9b49ff3198cfdc69bab60aac7ac4f601be7fd22c1781fc95132ddaf95ccdbabd492b93e794f60e883229e87fd9ef959326fbf3a964cf9e00318fe5d9d4be6fda192fed916ce83a92f92a93dbe64ca8fd11f229e4c6f92f9f3938164ca1f4f82b1fe994ae6df871f60acf79a6bc9bc7f62f49785f3b1b75230d95775914cf30bfacfc279b22df90f47c413a621995f9f7be011f99b6d2b98e2136d021e4f683d63059e4cb83e7ae2fa19dd4f3b83e734df943118f581f22099cba33c8397549f592dc026d69b8f9279fb6f9f60e453d6156c537f5a63c9644f8160aa47695330fc8dee0aa6e7c5b964f28791648a6fe692297e580aa6fa6628da8bf8c3bc974cf9642118fa38954cf58f89649acf1692e93c27e9936361ffbdd149e6df2b9e609c1f7d96ccf549ad24d37974e887d0676721998f8fba924cf1fa9364b247713df687754f92e9fc672399ea45a23d581f35af92f9f7b9f81eef13885ac1181f4b32d5dfa10f16f6a3044bc974dee9158cfd3f892399fcbb2d993fff26fa6786fd3ba23f711ef146d7bbcc7e283f7b944ce7995ec0639aafab25784af671db0a9e52feb200cfc9fe320f2cec650f5e52beae7d49a6f319e2fe4bd457766083f453bf80b11fa878154cf6b2adc1585f37c4fde0af235530f251717fc45b9e90d7c17ca848a67add5530ad1f74a160aa8f76e279c8e7c34630f97f3b174cf2379a645abf247fe35a781f90ff2818f3c1443297571d49a67cfd4930cd87da1b58e8ff5630ece74b32cd1fa564aaef7982697dc87900633f73694ae6faa0be4aa6fd789a648aa724637fd25a32ed3f79924ceb3d3330f6f325ad64de1fd98364927f2598facbd42553fd3594ccafcf311e16cecbdf22c95c5e652a99de7f267e8ff3c9e1bb641a6f4732bf3efb008bfd812f92297eb32473794b31bec87fa30a2ccea3ee0493ff30f79269bfe23718f53e6b2099ea0377609c7f34be2453fc7b914cf91c1f2f63c0e6478a0fb6e019d58be207c1538aff8fe039e503712b99e6eb5c3297a750c04b1afff22618fb1922c1347fc73bc9b47f4630f2f9eda360b2efab2e98fcd1ea158cfd83452598f47f6b48e6cf8feec1a8b7a40bc1f05f3bc9bcffb61918f596f85d32d5e3447fbaa48ff94030f6ffdc24737bf267c416f6a7ac3f2453fe580bc67e99122cceeb9c24533d6b2299f4ad108cfce30773fd500cc9341f7792a9fe6b0ba6f5da6b2399ce372ec1d85f1d9d25f3efd59b60f89f3bc9bc3fd4a364f22f6f60ec97543792797fa8a960d8c74d32f9932918f61ed49269ff832d99e44d24f3f61a23c1d43f96fc1ef1fe1c8cf763448e645a3f16cfc3fe3d632899e2955832cdafd01f0be7d5ad4a32ad9f3792b9fcc64030ced3d792b93e9723c9b41feb02c6fe67732b99f68b7c4aa6faa3180f9c17f6499ffa032dc46bf098ec5d8f24d3fe08133ca1f530ed049e527eb7f50593ffb83c48a6fd570a7846f7d36b30e6fff25b32d5ab73c1145f28ef82299ed1e660d473b64f92a9def92698fcdd5a3cdf46fd24914cfbcd74c9b43e21e445fda611f7437cb1fe124cf65edcc02edd3f7225d3fb001e05d3fc5ebd108b7879bb93ccfbc72f05937e66a9605abf538e92493f56e021d99f6249a6fa5b2b98fc9f72914cedc3785a789f52f12698e42943c964ef17c9e40fe792697e1849e6f2648e60ac470660bc9f243b4aa6fd3fa1647ebda20826f9d24c32ef0ff55e32d5d7447f60fe2f9f25933f5a4aa6f8e62c18f9502299f40ffa61e1fd4b4a2899f6279492495ed19e29e297028cf795048d64dedef05530e29137c9e47fe4efb19f740cc6fed152134ced0f55c9fcfb488c17dedf74b9934cf64dfa3c326754ffab0cc1643f510ac67a78ba04633e77466083ecb309c026cdffa921998f476582b19fa7ba0aa6f93e5e0ba6fca6188051bf4b447bb1bf4aff00237ff60f92e9fd41f792e9bc7d2599e6f717c1d8cf247e8f7a5d160ba6fecf23c1b4bf21a0f86264e13c72f82499f2fd57c1f06727c954bfcec098df755b30d9ef7a2e98ecdf78974cf54cb447d47b3d5330e2cb0fc9b4df47dc0ffbd12ea9647a9fec1e2cde07f92e99f60b1c05239e3e4ba6f9df974cf9d74932ed9ffff17b2e5f70014f90ef288261df8664b25f5332bd6f0ae36be1fc4ef92499f22d4b3297ff593c0fefb7525dc9e4df3c30de5fa53a9229feb12553bc2ec66f46f2565f92c97f37609ca7b4df25d37e825a32adff89fba39eaafb92293fea24f3ebb7627cb13ebbfd944cfbadbf2453fe37154cf287a664d257d15e715e80fa6fcce673f2af117846f94076075e503d2188c1d88f9a9b82c91f2457c954cf38832df2279ba9647adfe70a8cfaecf62098e2ef6e2699ce27ed04533cb2d5c0d8efaa3c09a6fa46f12199ec5d3c0feba51dcd9f63517f5dbd0886bd3f4be6d76f7f30d59b62c164afde5432d5271f2453bdf0118c7abd77124ced4f1ac914afae2553bd5edc0ff3b9f32498ec6d1308a6f66c55c9341fdd83313f9ba23da8ef46a564dabf664aa6fd21f27b8a37e291643abfe249a6f9ce174cfb13a2028cf78b25b9647a1fd4a364f20fdf92c97f0c25d37a512599d607a03f22bf375ac994ffa49229ff78944cf94a2618fe48fe1ef59e4632bd3f270163becf2ac994bf8beb71fe4b0d2453bd27964cf552d13fa807da2f9269ff612499e627d13ed40f424330b55f13d763bfc6ed4332c50f37c1f0f78a64daff3d964cfb43c578637daf7a138cfd39429f719e6745fa30314df21f590ec6fedd32134cfbb10c5d30f98bcb8b64da2f3c01dbd87fbc174cf5c92001e37c4d25eee760fff1b7605a0fc8b792e9fc81b8bf43f149740263ff68fe2a989eb722fb9c8878201849a6f75f9e25d3f37cc974fee15532bdaf752898ecdd0904d37a475080512faf7e30e9432e18e7f56e82914f5482c91e0bf13ce4ff7e2698c627fb924cebcfe2f7d8ff1b3e80719eaa934cfaee3992491e717ff80f6f2699f22ff13dcecfa753c9e4bf0e92293f394aa6fd139660b2cfc8904cf9df4230e68b4a32add78bf1c0feda740ec6fbebcab3648a8f2792c95fd492299e1848a67ccd164cf25b2d58f887ab64f2379d64de3fea4132bd6f4efc7e8e7827944cfb7f1e2553bd4f134cfa6c799269ffb6781eea8df14432b57f2718ebe591645a2f8b05231f15bfc77e0f652699e229f13cbc7faa9a4ba6f361427fb03f5013fa8cf5e2c495ccbfd73dc924af180fec0fd33e24737922f17c9c6f6cc91ea626f69b5e13f082fccfe64d32d547bfc0385f565ec0886fba1cecd07a663394ccfb237b05633d627b144cf6779949a6f75fd682c93f06349f4dc5fa433d154cfaace982697d721b4aa6f3c11918f585742299fce5bd64aa67958229be5ac560ac27ac12c178bfd79b64da0ff1e37b7adf95fc3dcef70592a95ebb174cfe3a10cf47fda01c08c67e1b5f32bdcfb0134cfde12a92493ed17f585fc81f25d378dc49a6f8e253308d57249e3f417c7a904cfbcd7e30c5d382b11e982592797f24df82b1de954ba67aa6907f4af69baec138af6c8d24533d692f99ea733bc1e4ff3c0b2cde37be944cfe712499f2b1b964b2675732c52bd0670bfb45d54832e58fba64da0fb301e3fd8d4a2499d67f857ee0fc72f82d99be5f81713e3e194aa6fd49e27e588fb89ec1884fae13c9d4ffa27fb0bff0229e67537fae481f66e612fb2d776083ec3debc026eaa53618f18a3b0323fe580f04d3f5c98b64da7f63825df217852e99ce77907c33113f6c4dc134df6f1f24d37c9982b17ee04f05537b9a77c9148f88dfa3deb07a92ccfb7f73168cf365778229be48bf25537d19f28bf501e55e309d4fc94f92c97fcec158cf2b12c1e41fbb4fc9b43e3d104cf3f7f6158cf87ebb170cffe448267942c1e47fba05187f1f455049a6f5614330f4ff0d8cf3b88ab83fde3770d94ba6fafc12bca0f6a557c1c80f6dc9644fb964aa7f1492a99eb1934cf3f718bc44fd632199f2ab67c914bfd782518f16e389f78346a23dd8bfa58c25d379ba4030c95b5f2453fc5c824deacfec2299f6eb6c25d37ae74630e2b94632ad170bf9b13fb87b964cf514713df61bd4aa643a9f0f7bb31cecbf10fa28f6e3f89269bd83e2adb9399f52bd33032fa6fcfef9086cd07e8d95f81eeb1b97a964b2bf0dd8a2f958ff02dbb41fbbbb825d9a3f2eb5608a3fe28560caafb6141fcd45fdb11a83b11e180f05d37e5c5f114cfe669d8051ef6f3dc1a40fab108cf3d9e55a30ce3b1a60d4d78bab649a5fe5f7645f978364dededbb360f247452899ea616730d6e7d6779269fdfb4330f9bbd4148cf8e7058cf5b8e44932bdffe25e30f6835c24d3f9d1b964b27f713decdd16ed9b937fd2f792a99ed2082679a247b0380f33964cf3ab18af05c52f57d1df381f5baf2453bcff0046fcacfe60daaf6a4aa6f9ed4b30ce7fce25d3fedd1918f65f8af1c37e6d4f954cf9cf5a32c927fa17fbede254326faf22aec77c1bd582a9fd971d58ecef3524d3fe5ea1bfd84f97d1f82ec47a83be124cf5c8ca07dba4efbab8de9df2dffba44f0b51afeb5cc1747d32154cf61eecc043ccf74f9269ffd3098cf7495c1e25d3f9c14a30ad9f281f92693de2001ee3bcf34430e94f71114cfe259883f17ef6b52599de2f36144cfaa23c4aa6fafd188cfa79d60a267de832c1345f1786649a3f7e30cd97a2bdc86ff55232c54fb9648a6fc4f367e44fbaa1649a5f669269ffb7f87e4ef6915f2453beaf4ba6f9443c1feb655a2c99e47b944cfb532493ff6bef25d3f86ec1e2bc532318ef1712fa82f3cdc55e32b5ff1b0c7b5acd25d3df9fa04ba67ac25e32bd0f44b4cfc0f95ad13f787f759c08c6fb8f34c9141f6e2453fee80b46fe22fac7c2fbafef24933f17fa8efdf9590dc6fb8d4a8a079626ceb3d513b04bfa5a527cb664f645eb65067848f359fd8369bfec063cc27ae45532d5e31f25f3f15c3d83315f5d12c9544f740553fe1e6592a93f3dc158bfb88127145ffb9560b2873a96cce5d75f25537ce90ba6fa62f283a95e2ae49bd2f82b0f82c93ef385645a6f17ed453d39984aa6fac04c32fdfd5607c1a42ff14a30cdb7b74232e5a76f60e483fe5132cdafb960c4fb5f60c4aba52218ebaf7b30d69fb6e27b9c1f0ceec1d82f962b92c95f1d24537da7148cf93d05239f534f92e9bc8bb81fcefb1547c9544fabc1383fe68af1c67e92f807d3fe43213ff6af7662fcb19fdaa37cc410f5ebfc5e30cd1f6b07ecd2f85a347e06332faa8f1cc0d0efdb17784cf6e91a82499ff44ff004eb318f92693fdebd649adf5f05937efa67c1347fe91618e7bb6e7782112faa60ac8736a1601a8fac00a31ee98c05e37d155bc1347ff8aa647a1fc009bca0f1f21682c99f9ae2fe0b6acf360763fd62bb168cfcb0148cf7790879f1be9ad4954cf53cd17fd8bfe49f24533db1164cfdbd7d07e33cd346fc1efb17b789643a4f300423bf303760bcdfec42f669b27885ee47f38169e1bc977e124cf18d3706e3fd11fa163c22fdda9482a7b43e7805c3ff058660ba9f2b9e87f364d14632d5fb4792e9ef37fe02e33cd926028bf364efe039c9b712f747fdd9ad24d3f58231fee58b601affdb9b648a6f7230dedfe12d25d3fa760a467d3817f218145fd99f9269bda1924cefdf93df23fe7e009b349f98623c2c1a5ffb2298ee97d8609c3f32e6609c3f8b2cc9646f0bc914cf3f4aa6786607c6fe958ee20f8bcdafb43f81e20b165e93fe5c3e25d37e30f13dea3ddd093cc27ede2d18f5983804e3fd1d9a25989ed7168269ff61fa089e223f9e8167d47f862699d6f39e25d3fe68152ce2b70318e7c9ec67c9f4fe12138cf70f252918f1932b9e67507caf08f9f1be9938069b648fc15e308dbf32108cf7df88e7637f627c150cff7a0163ff42f000c6f99c88ec9b4d37a867d1fc62b3f1a3fd3c743f5b8c5ff102463cb2da82117fb4df9269bde12498ec510f25d3fef01c8cfcb8b425d37eaa5232bd5f2506235ed85a9269bda4154ce31d89f6cef17ea8037841f76b447b17d84fb6012fa9fd6b211fea49978b608a4f0c156c423f3bc9b49f3602c31e6f7bc1d0bf4a32c50fe44f6c1bfb3be22918e7e93a6287d907adb70ec063eacfd51b784afdb3d1c0c85f8a5232cd97afe0398ddf652d99fcf75130e5879d09c67c961482c97eae7bb049f74b3ac9349e86649a4f2692b93cb978be8df749b88229be509660eca7f39f24d3f922713dd6afaedf8269bcd690c7c6f9d755001e52bc5b533ceb5a63d29fab2199ce63edc1139a9f82083c25f9f5068cf745dd2cf082c6238d25d3fb1d378229bf503ec178dfce6a0946fce9bd0aa6fe5ccf04e37d0af27aca77ac1bd8a2e747df9229fe2dc136f98ffc4530e9f34a934cf9f10fa6e78be739387f48fde9daa8f7273c3e310716f67b260f9269ffde1318efefb91e24537dcd06e3fd79f6156ca0deb1904cf6a080d1fe6a2199e67b5f303d4fbb801dd8fb0a8cf8f9a611db78ff5dac8211df745f60d413133e7e2c389be17ccc183c27ff97459279ffac4b30de27947e0826f94c4532bd7f5d032fa9fd6d2a784af58e21d8a0f9e1aa48a6f53f5b30d58ffd6730de5f94ad89ed01d9ef86eb2b0b2eb0feac6fc04b92af7525d3fbcd8f6093fccde64532d9cb4d30c57fe1128cfd33eb77c1a41feb028cf7355a1f82e9f9ee1cec62ffea9b60f227892918e785f0bd8dfdafe9b3601a4f270463fda81980f17ea59adbbf3966fd41ef472dc14bf2075b1b6c60fdec4132d50f0bc9944f1cc126c693dad7bf5e9ff2075c6f63bd6b45fd33b1e6549fb8adc0580fdc7682c97fdd5ab035a5f74309c67961e50bec523c1de2f736eaf7f11c3ca4feaba8bfa6d664467fffdc080c7f53b492a97e6f08a6f686776013fab4964cf69982717ed224ff30b5b15fe81608c6fbd3ce60c48b2d8dd78cdd8ff2eb5430c5839b5730f2dff60086be74a4af33d6ff148fdd8391ff6a74bf390b30693de808b6917f64c436ce8fdf1230f6bfb7345e0b6b3a27fbe9c0f319bdaf8bfcc782a5f7e43f0f60cc4705f99f256b3fedf71c826d92ef3625b627349f68dcdf9b2c9f9b927f237d3458ffd1fc5b8327f007241f530f1aaf6b00467cad51ffb2f8674efd41fed5b6711ed0e4fac192cf39b57733022fe97ecf977feda32abf7d8c9f3e26ffa7827fa74fcf0afb9da5daaac3fe58ff6a0be8f3df21cb2f72b9ecf3bb5c0afe9b90afff77f7df5116d62247f5d81ffad87ddba87590cbfd87bfb3f1f9779605f20899fa6be8cfffb79fff167b71e9f393743ffadc1663f4e33aa96fbdedf8eccf3f18b9ffff65e16dfbc90e6009240d1fa9bf2b3bc9439ee0df4d1661eb3f64f9313a3f24f3e4e717cbfa7791e5379fecfefa91d758f05a8e94457a8a7f2b590235542335561335553335570b364ea55aa917b5669f86e951ab76ec7365b2de544dd5d99f15ff9dc67eb1fe379365a3aed827652391a85bf6b963d2ecd43dfbec982c07464726dd91fdfb4e3da9f74cce7bf5817d0c76e53ff4daff5b6479e43dfdc446e699fddb597d515fb94ebda9efea87faa906ec9a9449f8c524f85607ea501da96375a24ed5993a67d2fc1bc9c25a7a5637ec9f91ba607f02d8fd92c9f2cafe6929aafaa4284cc7be15431d2ba662b18fad380af31a8aa7f8ff3d92fcf7cc954aa0844aa4c44aa2a44aa6e44ccf5ca63d2dfbf4b6622a059b45064aa954ca45a9954669954eb92a3745537465a5acffe8b5ff37cab251b6ca9db253cf8aa2ec95036bf1513929f7ca83f2a83c29cfca5979515e9537e55df9503e952ff6dfbf9581325446ca589928d37f23596c65a6cc9505d3b393b26413cd83f261288661b044c0b00dc7700dcff08dc0088dc8888dc4488dccc88dc2288dcab8a87746fddf23c99f9345b58ca6ff23a390df6677a3353ae36adc0ccdd08d95b13636c6d6b83376c69efd391847e364dcb3cf897d8e8c1fd8e7d178329e8db3f162bc1a6fc6bbf1c1b4b0cf02685e757f9b797f9aadfe999ff8af6561527c1a5feccfb7313086c6c818315fd4186363624c8d194b9916c6b2370ad3304dd3326de3683aa68b8fc73ebe19b04f684666c465eaa53a9a31936a6726666a66666e16666956e6c5accdc66ccdcebc9a375333757365aecdcd2f33b1f2eb1cfcd764311a736bde3169becd9db9e7b21ccc8379344fe6bdf9603e9a4fe6b379365fcc57f3cd7c373fcc4ff38b7dbecd8139c467648ed967c23e63736aceccb9b960992a3334e3de322cd3b22cdb722cd7f22cdf0aacd08aacd84aacd4caacdc2aac12b9dc2f91c5ffaa2c56655dac4b3f2e566d0cad5a3d5b8dd55a9d75b56e9666e9d6ca5a5b1bd6d3f7ccd96ead3bd6522689b5b3f61677bfd6019f2393666a9dac7beb817d1ead27ebd93ab351da592fd6abf566bd5b1fd6274b98bf5884b0601e3d61b3e9c0faeea3cf1fd1d1bfa2634cb31a8bfe82f001fff74a89aca135b2c6d6c49a5a336b6e2d7acdb196cc74fa4a9ed18f85b5b34d48f2439643bf4c614e6ddb766cd77ab03ddbb7033bb42326cfc178b4633bb1533bb37336abda766197ea935dd997de92fecce74fc932307756cdc6646055aa67d77663b776675fed9badd9ba71303fec95bdb6376c249ef9676fed9924625414662bcc5e602bf766681bf6d6beb377f6de3eb0cfde3eda27fb9e8debde7eb01fed27fbd93eb319d7b35fec57656fbfb1d1b07efffcafc9f27cb16a66274cb78cc6f8b4df992c1ff6a7fd657fdb037bc8faf3c47a7864bbe6dc1edb137b6a2db924bb7e64fab161ff9cb1f6ce85fd9b91bdb0972c485698ddcc1dc3311d662c8eed384cd2bde33a9ee33b8113b218f5dd89545df17fcdecfe155954d7183ab113333bb1edda499cd4c9ec2f27778a5e0ea7640ff0ed3d6b55653d3b17361acf4cc706cc6216dc6ed8ff3b356b6be3b44ca6b9d3998173756e8e66f7938feeac9cb5b3b1b7ecf78eb365d21c8d9d73e7ec9cbd73708ecec9b9771e7ec9107ecb7a7eb6a03f234b2f09f3c683fe7ecea3f3e43c3b67e7c58cadb33db1ced6b33d6656cc3ece2b6b5dc5dab5c0a7f765ec63cfe9e374f8bc39efbd24f6d20e9d0f66fd47e7d3f9ea7fe954ce379366dffff5f6cec8e9ff5acca933b3eb9fe4f8576599ab9db3b05f9c25fba1e21a6ce2b08c23f34accd3bab6ebb8aebd702a73e17ab66b1f5d9ff9a8931b981fccdacfaca5f76ec86c2ae673e6d18ddcd84d98bde0e3746e6a7acc73b02b594fbcd93336be67377373b7704bb7722f6e6d176e63356e6b358ae67656f3afe8987a70afaaeddeecd6d55cdd5db96b3626cfeec6dd9a43f7ceddb97b3622dbde86dd837bb4576e6031ed331df7e4debb0feea3fbe43e1b817b765fdc472195fbeabeb9efec5707f7c3f9703fdd2ff7db1db84377c474f1c0fe7dec4edca93b73e7eec25daabd2f6091b8a7aa81f70fbdda9f91c533d8f46d79b6e778ae937b9e71b2179eef055ec8e4601fdbf0222ff612e6030eb6d1eb8c977a99977b85577a9577f16aaff15aaff3aedecdd33cdd5b796b36e7c7c6c9db785befce7a70471ebb0b1b5d9dfd3ff36fde8e59cec1db7b07efe89dbc7bb5f01e58467af31ebcc71f5af5bb1ff853b23c79cfded97bf15ebd37a730637362dbde3bd32f2e099368cbe6f229b39ae7de76bd0fefd3fbf2bebd8137f446ded89b78536fe6cdbd85b76441d7a3aff8866ffa966ffb8e71f45ddfb31e7c9ff9e8ad6df8811ff663e547ee8069e4831ffb899ffa198bd6be51bffd523c9189fe75599e2f7eee177ee957fec5af0d6603e6d46f7a49fc967d3aff6acead27ffd6cf77bee6ebfeca5ffb1b7febdff93b7fef1ffca37f62f966a2bef8f78aea3ff88ffe93ffec9ffd17ffd57ff3df8da3bdf03ffc4fff8bf9f485bd30c74ee57ffb037fe88f8cbd3ff627fed49ff9737fa1382c27fd6679f70f597ea97dfc99d8d25f066aa004060b112da65f6aff97c0f7fae5b7811d38fe3570cd0fe31478811f04411844411c24411a64411e14411954c14509839a7d1afb3d68838ee59af3e06a3f07b7400bf460c5fc48ef0d9560ddeb99ad30d906f6c27a0e36ecaedbe02ed8057ba50e0e4a191c8353708f0af54f35ab3f2d8b1d3c048fc153f01c9ccdd829ad73f012bcf6da15bc05ef81137c049fccf38c83afe03b1804c360148c8309fb330d66c19c49b47016c1325443253442d3188416fbc39c71e8865ee88741188651c86cc73a8709f3cb4698f29881c50f61d6fbfc300f8bb00cabf012d661e32fd421d3b41fb2387f94e5e77af6cf63d25f1db661175ec39b19875aa8b3bbafac636f27e13a5c33795e8c7b2f0d37e136bc0b77e13e3c84c7f014de870fe163f8143e8767f52d7c095fc337ab08dfc38ff033fc62d2982c22f6d97ff90e07e1301c8563e3184ed82cb40dd6e1943d63e6ee99fd7c9b53f6dfe7e1225c466aa428456444e68fcacdaf5a46b288ff862c28f1d4c8525fd5d7c88e1c7f19b9e673e41987c8376751c02375a61351c8e2f7cf88e524511c25511a65c62dca8347ab65f369cafe3c4645f01895aa1255d125aaa3266a5910d345d7e8166966678ccc75d4467ab48ad6d126da4677c629da452c82f0039ef778d68ecdb40bf6bc7d74888ed129ba77d2e8217aecefcdabed866af4d1eeaff6f2932c068fb043b77516ca2e7a8a9ea373f4629ea357f6a437e6750d16a79ca37773c2e6e8aad7eae823fa8cbea2ef68a0ce153f1a2aea8f2a2c7f9e1b8da27134096d2b8ca6d1cc8aa379b48896b11a2b56111b319bac629b85166eccbc3d9f73962c7f93b29843e33ef6e3200ea3fb388ae3f081f554cadbcafc5a1f25fe2c0b7ff68f7131d4f8f9e22cd4f73889d3388bf3b888cbb86277bcb0f87111d7d6dedd5b4f7c2639b959dcc46ddcc557ff515dfdb4f662cb3bbaca5875e25bacc5ba3f8b57f13adec4dbf82edec57ba5890fea323ec6a7f83e7e881fe327e3143fb3d866c9bc7380b86e689de373fc120ce2d76011bfc5effd88736b3055a38fdeff992c0ad34726cb6b9cb8adba8a3f4c23fe649db7641ec6b09ee3da665ed3fc0c33f6dcaff83b1ec4c378a456eaca7e51ee94713c862c3c1eecff9dfdb7493c55f57816cfe345bc4c54e3c17e4894c448ccc44aecc449dcc44bfc24484263efde9b3e8bd8d887e7a42c3b65f3d6d17c4da2244e92244db2a84872b1baf07765b1c886f8155b36bbb2fe65914fa2b8499194e69b71f26fd69e8dc9d9b998dff6c13ad953e39054c925a99326d6d5f7beea9db4ccca52f40d55c1d97d95bb385332bb4abae49adc12cd38252ceb4956c93ad924dbe42eba26bb641f1c9243724cd82c657a8ec272014364d94c9b4b2f4dee9387e4d158264f09b34ab146d2e722ff4c96e499f5e198e50e2bf6efe7e4257935dfad3e3f3f276f56ff8afa7df26ece8dfb709c7c249fc957f29d0c143d192a8b64c4abe3bdc7b4fbac8dc9c264b2df93713231de9269324be6c63159d8c76469c6a99a2aa9919aa995daa9e3dfa76eeaa5bef1603a2cbfe1b2f45910cb54b769601cd3308dd2384dd294cbc2d76dfa7cc4180aaff6932c96b0fe3453466e6b97cc8e9d344f8bb4343fd22a4c98f75a5afdfe8687f4621becee75daa46ddaa5d7d451f4a04b6fa996ea91c9fd3f978549c3644957e93adda4dbf42eddb15fedd3837d4c8fe9c9d8a7f7e943fa18fae953642b7a344c9fd373fa92bed2c8902c2ca7db4681719fbea5efe947fa997ef5feb197a56f7f9f5bfd2acb8f91e17a78607dbb5412ff2139a7dfce9069eb673ae86da5f7c54ee5fa696f8f553a4ac7e9249da6b3a4b50b65c3f42c5177fe23ef31361a7d0edad724d379ba4897999a29c63163f971b4efb3e3ccecb3e2649559999d39ea57ea0475e6665ee66781e9fa81a3a06ab0eb675096e1c5599845599c25ce23b3172e8b6af5b9d52fb2889a9add3f99d14efd4a064ccf952c553eb2cc74cc2fe61b077dcecbf477613d982316e37efaeb2ccf8aaccc2a61e7e45b98b34db24b56678d5dc763f53b6bb32ebb662c62f343d6df6ff6c2fd66de9c652c99661ce3a74ccf56d93adb306bd3b36d76e74efa5999c53363a603cf76bfcd8445369691edb23d93e5901db313d31d85db7491ddff268bf28b2ca67a973d3032b24743c99eb82ccc37f67d642ebcc4661146f69c9db397ec357bcbde852c1855577d4bdaec23fb8c9e93419a655fd97736c8d8e866a36cec8eb24936355da7cc66d9bcf7ebacbf17d93257734509552b377233b7723b77d8377d3d6dc29edad74398b7cedddccbfdec900779a828ff4496be024a7dabf8bd36f63edacc23c330ee982cbd97efed70c024619219f7799c27fe364ff32c3c30597eac4172bf95e779919779a556f925aff3266f8d63dee5d75eb7dc613f1ef9cdfdeeb3e25cb316f153aee7ab7cad9eed32dfe4dbfcced67396c1b09879c8729a4bafd9feb7719f29f93e3fe4c73cc88e4c9b1392c52afe812cbd0f559209d332db2ed5263f1926f32baed05ca6678eed5877ecbfbce6f7fe5dfe104cf347a3fd690d92d97afe943f671725cecff94bfe9abfe5ef7dd4937ff49909af719cddaf6cca73628dcd8871fe997fe5dff9404d9cc833f3613ecac7f1579ff1997dbc4c51b4cfee30c9a7f92cc9988e1d59a699f47e377c0bdffe200bb75792259fab7b854d65ea77be302c63cfd2fb1dd5bc481673943bf9b2500b8545f5b3e8814547b6dcabc0575793b1fa919f0ba33059b7d9ac557d2cbfe8f312ebaeb7e4c2e96b1785cb62ad53e1157e111461112923d52ee22229d22233f67d5ec365611ac6aecdd98cb92f8aa22caa3c2459faf6b398f5f597f9e5375958c6b34f6fcc62be8b0b7be4ce74a97227646177ae8ba6688b2e288a6b714bf25f7684303d53fc645268855eac8ab5710835e7b597a5d8b06cabaf6a7ef4d5be60cd243916dbe2aed815fbe2a0d8c5317b284ec57df1503c16cc3efa1a279764614e0b268f7128cec54bf15abcfd248b1aaa7f57164fcab22bde59fe742a3ed894b5efa33c5420875c9645f1597c15dfc5a01806398ba2c90bffd8555114a3625c4c8a692f4931ebd72c989ea8c5bc8f467b5b6677e03163b12cd5ecbb544287c540d7d250c2d22cadd22e9dd2354ebc22c2ae36c7f6a1f498cdc6a55f06e1ae64290dd731f7efc822d654c40cf3adb665c472b053191b2ecbef852cfb5e16f3cb3a9749999659996749745f163f564a7824669465599597b22e9b5e92b2cd34661b565f3b6371dc985bb4e10ffaaca7ecca6b79b3be4acd0a4a9d8d67c4a45995eb72536e992cbabdeda326368e5bebbecf64cabb7257ee7b591425cd7a6d28b552fb45961fd13ef773ea8dcd103b75c56439183e1bebc81c5b7d3d2cb0674e63cfcb63792aefcb87f2b17c6271ce86e527a398c594ca9d5d97cfe5b97c295fcbb7f29d79d12eef32adafee9bb3bebec13f337b5f7eb079bc2c3fcbaff2bb1c985d392c47e5b89c94d3c42d67e5bc5c944be3c45c7d156a7c4c0f665f1939564a655466d06746a7e0d4ef2ab2aadf62fedefb3059d8b7663f36c8d834bbaa2c26cbbd19b2deec97483a264b6b06c6a1b22bc79bc5e3a00996e5c4dc562e538ba86236cfa29545e5574115329fca66bb3ea736471513d73a313946fd9a4515dbdb2aa9d22aabf2aaa84a2bacaaea52d55553b5556745c1b1ba062b362e5ba7a355b57ebda3aff254b74aabf42467b21c83a36ad9f51f641151a5cf6571d488e9e246bd315559556b264bc4662c268b193269f64c96a37bf65a6fae2e2387e9eb5bb5a9b6d55db5abf6cab53a54c7ea54f575e17be6c717d681c5d5233e26a3fe2ebd3d570f4c96c7eaa97af646d5b97ab1aaead5dc556fd57bf5517d565ff128afabef5e966ac07ac2e5f5cf678bddb11a56a36a9ce4ce23c6c5339adf627e4bca6270efba60d1ee539ac5a36a524db98e912c51af654c965335f33a8f656bca3c34ccae9a87af9eaac6ac3f17d5f2a26637f7f5a25cb81fb615f38349d17f26b406c3ee7570377d7e75312fd6c5be38e1cbc5bd78179f8d897f092e6134b8449798c9d2b91fccbadefb159cde673059946a7449823e47f6d9c7fea32ca859283c96225912f549bdbfa4ec9e593fc6fdfa9c6df523d4af3d18a774e75d2fb9925e8ad0c8eefbbcfd525eaacbe5525f9a4b6b9c2edde56a6fcdd1e5165f98bd93244764f10773e445d68e5da55df4cbeab2b6c2cbe6b2bddc5d7655a7b697fde57039ba2fbd2c173633b1d8cde27fd5d684fde2fef27079e4b2a0adfd5add3f95256071f24d29c2faf27479eeb585d61bfb95a07ecd81e9d8a377f35545b3df7975c88ca6feec72bebc5c5ecdc4383afae58daf136d8235f75dbd7e8db92c7c3d96f5f196c5dd5333bebc5f3e2e9f97afcb777cbcf06a13d388e16578195dc66c869ddb6c66cd466c967db5ee7adbbf4c2ed3cb8ccba2f0bcc2fe5d16392f4096545373b5cdcf97f9657159f6eb90bdcdb2d8b85fd50accc08d8c83a7298f8a1fb4c620fca8d55a49b6b5519bc98ac9f9565bb56def1cc38bfaf99ecd8d336ef74cc7b8341e9b3146e6dcdef82cdeac9ddaadbddaaf83484b46e9ad0eeba88eeb84e5ca9fcce3796c6e9db008f4c9dd32590e755a67756e325990875bfd0aeaeff9cbcfb2287eaa2b6e5dd4a5f25557c68149c0bc0fb3dfa8978569716cc69eee2b6aa9cc422bfc8caa9a4590ec7f0d6b5beb7eb84347cdaf2c63af9cd73063f67faa22f6ebdeaff7d27875c746f9cbfc626d5cd6d7fa566bb55eafea35d36ca77c8af27a536fcdd8b9b23cdceb6318d6239bdec2eabb7a57efcb3d932515759e3fe695d8112074cc55efd44370523ae5b13e184cb3597e7f6fdbbc12cfda581f599b4ff57dfde0b6a1556d13b77eac9fea67e3549feb17a65b8bfab59f159cd728b02d1691ceeb37bfb1b7fe376fd994b220ca89acbdfb5abfd71ff56738a8bfeaef7a500fcba01e992ed3c27db17077aec3f29881cb324b63578feb493de5b2507ef20f7264f6a797a59ffb13f6ff0d9bfda7f5ac9ed70b9657b2fc8bc52e5b7b592f9d779bcdc98dda288de13f5a35f3ca1f8dd958c64363db47f6d9374e3f438693be6ed3fbb2c665ff34a2d0def09a9af1cb1ae0d074eb5be3357e1334a1f3d4444ddc244dcafae291e54977eeaec9ac2dfb158b429bbc299ab2a9b8bdd09ca8f42b763fcb42732397c5e4b364aa8cd2cc99c77a7369eaa6316377c3eefb7039352d0b8359d6e186c6aee99a6b738badd0b48a466b74fbc18c9b557aecc7c57c6fd64cdfc76c2c3efa5cbdd9345bebdcdcb9dbbe8283d53fac9c9b5ebfb3a4d935fbe6604d9a63736aee9b0726c363f3d43c3799bbeb6be64c2fe3e6dcbc34afcd9b948559c51f65a1d95ecaa2f1959bb5faa138cd7bf3c1a22ac7ff609e89d973bfa6686f9b4fe3e0dbcd57f31dbae167ad3483669828d60b7bde283359ae356bc66c961b46611f41369366dacc9ab971b296eeb6e1e3815566167d9b9ed3354b63efad5bb5555aa3355bcbe8ebd581396efb15c45d9f2b87ba71689dd66dbdd6ef63181e7719aadfaf09ff365752a5cfa4bdc2fdfa937a8bc76de03dc65d1b1afd4afdb658703fbbed6dba8d8c531bb7499b865ef5de666d9e9fdaa22ddbcad8370fed85595585fce4beaddba66ddbaebd5e5876dfded8bcf3ddd70ee4eabfefed5aaddf1de36baddeaeda755bb35f6dda6df0dede056f5ec89eb7734a63d7eedb437b6c4f52163f38fd41161bd97abff39945bc2c951e313ddbe5b9a2b7f7ed43fbc8b4f7686ffa9d05b5d53ef55adf326fdf9edb97f6d518861f4e5c44ed5bb269df59ccb3cf3b7bc9645ef5f949fbd17eb65fed773b6887eda865b3068b697aed123b19f67e906bf6b69db0acf8d44edb593b6751cb397875ed76d12e3bb59fdbeace38754a67746667c571922779af472c8e39fe4116e75759d84c99a94967770e93e6dab99d67192cd770d89cb063be56ef7c7b5b9f7d3753baa00bbba8da767197746997b1b0b8e8ca7e6dc8db75157bfea5abbbc6df756dd775d7eed6699ddeadfaac8e723b5ec95b326b687b8fe2fb4e65dce75db7ee36eeaedb76776c02d875fbe6397aef0eddb13b75f7dd43f7f8ab2cbfc563b40fdae2fbb87b59fabdb76ef7d43de7cfddb97be95e6bc738b9ae7de8ff1a4166c38eb3eddeba77964f9cba8feeb3fbeabe9d85fad80dba6137eac6d19d195b0b33f6b56ed24dbb5937ef16ddf2aa5e95ab71358d9dfbca7763f9bd1ce6d00ffa99fd6ad97bc7bada4cbe73b7bb322bb18ee1cadd5d5deffdea3109dfaffe35b886d7280fa302b66ffe1d1d13eb0b72bf196a7fdcef5de36b52b2d65d53ebe19ab119ef6c9dddcf7eb5f79ab3ff5a5ccb6bc5e29897ebe55a5bfeb5b9b6d7ee7acd27d7db55bb321d5533b30bdf8da69c5c57d7f57573dde6937efe655aa8f4750ce623a2be06c6f7638dd87c74ecfd38d515ade7de5aaa8171bcde5d77d7bdda3847b5edab2c5993353c07367f9c07f8afd7f89ca7ebe17a8cd953afa7eb3d3dddbf998b6641d1eef5e1fa787dba3e5fcfd797eb6bad3069deaeefd78febe7f5ebfa5d75d74139bc0eafa3eb987d26d7e975769d7b6bd60b8bcccccceb92dba2f5f327f2dd7d73c7fc1c27ebcc52c3a79b7263f955348c4c36f3b9aa6dbf33591cbebef31764b99937eb66df1cd6379ecb66877edf8bad140b2fb9b139d0b8f7b51b0b346f8152ddc25b748bd5db2db9a5b7ec96df8a68d025e15755df4a7377ab6e97f0e3c626c65b5bac6e9db1ef772df0fd16d6af1f5eafb0d86cc4246aee7236b3dcaeb7db4d4bc6d133cb2d44fefb87ddf3ffb52ce6e34dbfad6eeb86c5860d1b0d663515f3f8ecff6d8fc5eecc9fe593dbe6b6bdddd5a5fa62d7cae2b65386b7fdeda0d4ea58dd869f55773bde4eb7fbcbddede1f6787bba3ddfce51623f180fb71733643e7af24759983454afa4fbbfdede54f7f67efb48068a226ac97f7d7d3f2a6e9fb7afdbf76dc02b565f2cb35c58776c86d89a73162f6d6e43e3741bddc6b7c96d9abab759eadce6f1241ef77bf56f8bc80a5fa2eab6d4d4a8d394a85202f5ac199aa9599aadb1b16e5acdedade4e78fbbef3396c82759cc58f3345f0bb4508bf242d1d20ce3f287d3597fc25e1eb5584bb454cbfad981dd7b617e7a119385f624cdedad96f733a75668a5566917ad564325615ed0b65fe289b25322add15aadd3aedacdf84c1dd573979aa6e9da4a5b6b1b7ba16da99af0ebc8b03f2a8bb1ad7667dada9db653bba0b9bddbef2c7f37642dcfa1f8f22fc8926a7beda01db59376af3db008efce9cfa1f2c3bda71eb6451633568f92e43ed517bd29eb5b3f6a2bd46b935d2de8c85f61e4fb40f36269f2c216e94246ccb2767e999da97f6ad0d3436a6edeeefd98bf5dcee2c35f2b59136d6260a8bd955d72eed525db37111f562ef2fcbf2a84db59936d716da52578d7da8318f79673d9993b86e6fecb363518056b6bac26c79a71bbad92a9dab5bc64db77527327457c97596ee844e7fe622ce597e32d4033dd4233dd6133dedc7e0d74f98f5b2447e2f95bbd7333dcfebb2d20bf6fbfe0c84266b797c86ff2b3a16157aa957fa45aff5466ff5aedf11c3f2de39af8f322fa45ffb798faffbfaa6ebbe66817ed3355dd757fa5adfe85bfdcef850bff59dbe77c6d5413fe847fda4dfeb0ffaa3fe14bd07aece722db28dde4ef86e0bf3e78fe9e8e764adbfe8af4aa36ead86cdca34abf4f6eff075c43fbd8724c9f537fdbdb8ea1ffaa7fea57febcc07588affed6ed3ca56a3f7beea637afd3a561f4733895c33d687fa888dd0589fe8537da6cff585be5ca92b6565accc95e5eddd3c7ded778d38d5ca5e39b6e1eec90f0b0ff68b2cae7170dc95bbf2567e3c535f56415f310a4e2cdeea57df6a5a7bfb73b2048fab701505b355bc4a56e92a5be5ed78555807166b6efa5ccb3afe248bc9b28265dee5ceed8565b4b755b9aa5697555dcd568d3e5ab5b1c7f7c23129dcddaaeb76abab395e752c5bbbe3f66e626ef955166f7533e3b261f9d270a5b1f178e335567efeafaf2afd9571311f57fa6ab55a6bb362b8daacb6abbbcbc76ad75767d2a05f79b0b67d0ecf64796372ec983c0adfc570cff7819ef85efea3d8cf6bdcbbdf76e87ff8cd6abf3aac8ead1d7cb84edffa7e9e679aa6b63b6627bfcae2af4eab7b9643ad570fcdfbea919fce727f3a052c4f69fca971795a3dafceab176db67ad5ebd5dbea7df5b1fa8cbff26ef595f615a31fbbddf98749f7c177bc0f9d57f6795b7daf06d17e35147b2cfbbdbccd9339ee7739b58bd5a8d72e173b9358e3acdf65b1ceab717d67ec5693d574355bcd51c3b7708ec1fdf3314c92af16abe55a5d2b6b439badcdb5b5b6d7ceda5d7bc69e45cffb1f7bdefb489eaffb32097a7b62b3105fc7e3fba9f9beea7e36627e6318266b7f1dacc3c0091cbecb91452c6431bd17f85d967e7473dbd8d7efeb681dab77e20c2d9745f9b16be9cff8b1f03198af933c5d5bc1789daeb375be2ed6e5ba5a5fd6b5b5b437741601fbf7fbd5b30fbe57a25f6bb15a16fc34ceba757416dfb3e83e9ce9d77ecd807df6ebceefd6cc62bc50c8d2eeb411f366bfd90bd7d26374b7beadb53573e4b2fee5fed5793f628aba5eaf37ebedfa6ebd5befd787f5717d5adfaf1fd68feba790c5fdd69eef5ac1b8b04fbf9ef76a7e704b3e584bbedb9f5950bffba8f7e2eb7e97fcb1df83b63eaf5f02d736cc28effa73246c8e1feb193f73d2e7373edfafe4b23c69bb7e5dbf35cafa7dfdc1e617c8f2f7f78ffdf38ff3283f69566595d196e7f5e7fa6bfdbd1eac87eb11d335bea38c568b980e4db0afbf8fa6c6acc7cffc04c6b2dfadd7cbe90f7a7bea77569a43967505d5e0a69a713e6171d79d36d1f3f5b8f776eb49bfa3b61f93cb389f38de7aba9eade7eabdd8d32b674be7afc8f2d3d9621ecf798f6a11dcaf179774bdcc5f36ea46d9181bb37faead164ebf368979c230a77db5439cb4602336661ab91436d3dc39174ba1fd0a2caa7f6511e4ae0f0b36569fdfacc6cce59f8ce3c6c9271b77e36dfc4d607da94f56f35b9bfed2b8fc7eb6381a2a9ee2da55972acd26dc449b78936cd24db6c9f9aa0bcb6eac27ffdbf68bbc782effdf76ae6549552488eee733a6f615fdba7dbb6356a899203e5a6db51f3b4444f0c14b1489987f9faa8202a4bd37b457331113b9d010943a661645669d93b6d9e37b5a6207f5ce54d90a7b630ee6244ed8f3c2d4532060d9afca32ad349d280e4d481246103617866ae8b10a11c3b2b36c86248e1fe983506f36cb7bd7f59cde1344592e9dd23decc91c0e90c0115250a0014d680104cf80a691efb672cf7c667bc1191af13a6a6c8d2ed758790ea8a041fba8a546ca6681e23a2c67047dffd9b4a1130fb9e20cbad0833e2ce34747a706bc2c0e85fef98baee722bfd4f4404187dc51957668dcd0c2d0b660004318c12b8c61025378f3347fb13bb0acbe5df0f8ab3a31cdd0e01d3ee0136ee036e9c2ddb1ed7437f7e95459c13d7169c0bcfd003fe0117eb2bb700a4ff08c94def1b9eef5e9337dca1557dfc052a8ea8aefae6ed98c216b9d45ef4ffa485524aebeeaa181333471eeaa5edbb7f71bff47100423b4421517519a70a1686ff7106f632dbe471b97ebe0a027b3a4874ec8a276354cdffc603e255ca59dee228325a4b8c2354b719e8d29bbca113774bcb961e319c8f15c1f6327bd3884873ca043ee1bdcda7dce35430f7d0c30740718e10e636fed2f7ddd7f0cc2861b3aa1161991827b3cecfa8d66ec6112bce2115354f693204dfadb96d559cd6ccab25f967cd21655d61b3627a2d61336b0892d72a03dc20e53978ef868d8fa229f5faee75a7fe935c07eb745b764495b08ec7d0311d5f514356ca3bffd70224ff774bfb3f1822818bb5ad8461d3bd8c5de6e837df6fe0507fb088787258ef015c7d68bd0fa1a7cc79ef3f0a8623d21573237714a0f6bb636061dba66de58d0211dac1b76bfe293ef6039b59ad281736c393795d713791dceebf80ee712f96e3009ddd07544a5d179e13613e6e4967d435ca3ec245389a0cad56bfd58aad7bf7aee9fc122ff178e852391e3f3ba9c7d9399eff23a234758aeb7d96b869def6fe7fb0f468e60216ac18678a2378b9890bd31a42ee18c42f1d27b720dcf09969c1fb0909d7904e76ec356026184f0baafc89d66956e3da5fecbf6f6f369d67545d6b5c5d924df135a7ec542cb5e26e49a7cbfc201afa191da8093df3604f79408ae9ab0ad576031ca9ca3caca1635c83935653d22cfb448ce3bcf6adc752c32e62a9eb9443352aa19aaaae7e288acea1ab4729f2cb50e052bf5d4871cf952b02732ae47d9db635ea9689b453c57bc2062244752ad5f5e84c592fcc3e1ee4c949995795bc152fdbea830d827ffc84c20e9088f91d2fb395e4b665b520152c3422492ebf27dce3a1163b10a2cc60916c11710bad85b6ed69a7320cdc09db863ceee0a1533e20c1ccef6c814cd995eb334f9fc9ecf4b7ebda988b5c23b67b1108e04dff03d63da7fc32f8b9a5f4caeec2fc7c9c7e6f5bc5e154b795ce2e596e3679fca7dd222b624e3bc58134fe3a1e0bbcd199677fcb81c4b3d6a7ea7d6aeb0fb7e71ceb9a3f5738b7cbeda2ba7de3ba79caf57e52fff15fb1fcbbfd3fefcfbaf3ffe0193cc32fd + + + + + + diff --git a/chalk/plugins/viewplugins/colorspaceconversion/Makefile.am b/chalk/plugins/viewplugins/colorspaceconversion/Makefile.am new file mode 100644 index 00000000..cfc849f9 --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/Makefile.am @@ -0,0 +1,27 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = colorspaceconversion.rc + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kde_module_LTLIBRARIES = chalkcolorspaceconversion.la + +chalkcolorspaceconversion_la_SOURCES = wdgconvertcolorspace.ui colorspaceconversion.cc dlg_colorspaceconversion.cc +noinst_HEADERS = wdgconvertcolorspace.h dlg_colorspaceconversion.h colorspaceconversion.h + +chalkcolorspaceconversion_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkcolorspaceconversion_la_LIBADD = ../../../libchalkcommon.la + +chalkcolorspaceconversion_la_METASOURCES = AUTO + +kde_services_DATA = chalkcolorspaceconversion.desktop + diff --git a/chalk/plugins/viewplugins/colorspaceconversion/chalkcolorspaceconversion.desktop b/chalk/plugins/viewplugins/colorspaceconversion/chalkcolorspaceconversion.desktop new file mode 100644 index 00000000..0993dcc7 --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/chalkcolorspaceconversion.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Colorspace Conversion +Name[bg]=Цветово обръщане +Name[ca]=Conversió d'espai de color +Name[da]=Farverumskonvertering +Name[de]=Farbraumumwandlung +Name[el]=Μετατροπή χρωματικού χώρου +Name[en_GB]=Colourspace Conversion +Name[eo]=Kolorspackonvertado +Name[es]=Conversión de espacio de color +Name[et]=Värviruumi teisendus +Name[fa]=تبدیل فاصله رنگ +Name[fr]=Conversion d'espaces de couleurs +Name[fy]=Konversje fan kleurspektrum +Name[gl]=Conversión de Espazos de Cores +Name[hu]=Színtér-konverzió +Name[is]=Litasvæðis umbreyting +Name[it]=Conversione dello spazio dei colori +Name[ja]=カラースペース変換 +Name[km]=បម្លែង​ប្រភេទ​ពណ៌ +Name[nb]=Fargerom-konvertering +Name[nds]=Klörenruum-Ümwanneln +Name[ne]=रङ खालीस्थान रूपानान्तरण +Name[nl]=Conversie van kleurspectrum +Name[pl]=Konwersja przestrzeni barw +Name[pt]=Conversão de Espaços de Cores +Name[pt_BR]=Conversão de Espaços de Cores +Name[ru]=Цветовые пространства +Name[se]=Ivdnegaskkadat-konveršuvdna +Name[sk]=Konverzia farebného priestoru +Name[sl]=Pretvorba barvnega prostora +Name[sr]=Претварање простора боја +Name[sr@Latn]=Pretvaranje prostora boja +Name[sv]=Färgrymdskonvertering +Name[uk]=Перетворення простору кольорів +Name[zh_TW]=色彩空間轉換 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkcolorspaceconversion +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc new file mode 100644 index 00000000..10479a3c --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.cc @@ -0,0 +1,155 @@ +/* + * colorspaceconversion.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "kis_meta_registry.h" +#include +#include +#include +#include +#include + +#include "colorspaceconversion.h" +#include "dlg_colorspaceconversion.h" +#include "wdgconvertcolorspace.h" + +typedef KGenericFactory ColorSpaceConversionFactory; +K_EXPORT_COMPONENT_FACTORY( chalkcolorspaceconversion, ColorSpaceConversionFactory( "chalk" ) ) + + +ColorSpaceConversion::ColorSpaceConversion(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) + { + m_view = (KisView*) tqparent; + + setInstance(ColorSpaceConversionFactory::instance()); + setXMLFile(locate("data","chalkplugins/colorspaceconversion.rc"), true); + + (void) new KAction(i18n("&Convert Image Type..."), 0, 0, this, TQT_SLOT(slotImgColorSpaceConversion()), actionCollection(), "imgcolorspaceconversion"); + (void) new KAction(i18n("&Convert Layer Type..."), 0, 0, this, TQT_SLOT(slotLayerColorSpaceConversion()), actionCollection(), "layercolorspaceconversion"); + + } +} + +ColorSpaceConversion::~ColorSpaceConversion() +{ + m_view = 0; +} + +void ColorSpaceConversion::slotImgColorSpaceConversion() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + + if (image->colorSpace()->willDegrade(TO_LAB16)) { + if (KMessageBox::warningContinueCancel(m_view, + i18n("This conversion will convert your %1 image through 16-bit L*a*b* and back.\n" + "Watercolor and openEXR colorspaces will even be converted through 8-bit RGB.\n") + .tqarg(image->colorSpace()->id().name()), + i18n("Colorspace Conversion"), + KGuiItem(i18n("Continue")), + "lab16degradation") != KMessageBox::Continue) return; + + } + + DlgColorSpaceConversion * dlgColorSpaceConversion = new DlgColorSpaceConversion(m_view, "ColorSpaceConversion"); + Q_CHECK_PTR(dlgColorSpaceConversion); + + dlgColorSpaceConversion->setCaption(i18n("Convert All Layers From ") + image->colorSpace()->id().name()); + + if (dlgColorSpaceConversion->exec() == TQDialog::Accepted) { + // XXX: Do the rest of the stuff + KisID cspace = dlgColorSpaceConversion->m_page->cmbColorSpaces->currentItem(); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace, dlgColorSpaceConversion->m_page->cmbDestProfile->currentText()); + + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + image->convertTo(cs, dlgColorSpaceConversion->m_page->grpIntent->selectedId()); + TQApplication::restoreOverrideCursor(); + } + delete dlgColorSpaceConversion; +} + +void ColorSpaceConversion::slotLayerColorSpaceConversion() +{ + + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + if (dev->colorSpace()->willDegrade(TO_LAB16)) { + if (KMessageBox::warningContinueCancel(m_view, + i18n("This conversion will convert your %1 layer through 16-bit L*a*b* and back.\n" + "Watercolor and openEXR colorspaces will even be converted through 8-bit RGB.\n") + .tqarg(dev->colorSpace()->id().name()), + i18n("Colorspace Conversion"), + KGuiItem(i18n("Continue")), + "lab16degradation") != KMessageBox::Continue) return; + + } + + DlgColorSpaceConversion * dlgColorSpaceConversion = new DlgColorSpaceConversion(m_view, "ColorSpaceConversion"); + Q_CHECK_PTR(dlgColorSpaceConversion); + + dlgColorSpaceConversion->setCaption(i18n("Convert Current Layer From") + dev->colorSpace()->id().name()); + + if (dlgColorSpaceConversion->exec() == TQDialog::Accepted) { + KisID cspace = dlgColorSpaceConversion->m_page->cmbColorSpaces->currentItem(); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry() -> + getColorSpace(cspace, dlgColorSpaceConversion->m_page->cmbDestProfile->currentText()); + + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + dev->convertTo(cs, dlgColorSpaceConversion->m_page->grpIntent->selectedId()); + TQApplication::restoreOverrideCursor(); + } + delete dlgColorSpaceConversion; +} + +#include "colorspaceconversion.moc" diff --git a/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h new file mode 100644 index 00000000..a1f7f5c0 --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.h @@ -0,0 +1,51 @@ +/* + * colorspaceconversion.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COLORSPACECONVERSION_H +#define COLORSPACECONVERSION_H + +#include + +class KisView; + +/** + * Dialog for converting between color models. + */ +class ColorSpaceConversion : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ColorSpaceConversion(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ColorSpaceConversion(); + +private slots: + + void slotImgColorSpaceConversion(); + void slotLayerColorSpaceConversion(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // COLORSPACECONVERSION_H diff --git a/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc new file mode 100644 index 00000000..94f6066d --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/colorspaceconversion.rc @@ -0,0 +1,11 @@ + + + + &Image + + + La&yer + + + + diff --git a/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc b/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc new file mode 100644 index 00000000..616b1714 --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.cc @@ -0,0 +1,91 @@ +/* + * dlg_colorspaceconversion.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_meta_registry.h" +#include +#include "kis_profile.h" +#include "kis_colorspace.h" +#include +#include +#include + +#include "wdgconvertcolorspace.h" +#include "dlg_colorspaceconversion.h" + +DlgColorSpaceConversion::DlgColorSpaceConversion( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Image Size"), Ok | Cancel, Ok) +{ + m_page = new WdgConvertColorSpace(this, "colorspace_conversion"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + m_page->cmbColorSpaces->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + + fillCmbDestProfile(m_page->cmbColorSpaces->currentItem()); + + connect(m_page->cmbColorSpaces, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(fillCmbDestProfile(const KisID &))); + + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + +} + +DlgColorSpaceConversion::~DlgColorSpaceConversion() +{ + delete m_page; +} + +// SLOTS + +void DlgColorSpaceConversion::okClicked() +{ + accept(); +} + + +void DlgColorSpaceConversion::fillCmbDestProfile(const KisID & s) +{ + m_page->cmbDestProfile->clear(); + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor(s); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page->cmbDestProfile->insertItem((*it)->productName()); + + } +} + + +#include "dlg_colorspaceconversion.moc" diff --git a/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h b/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h new file mode 100644 index 00000000..608989ab --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/dlg_colorspaceconversion.h @@ -0,0 +1,50 @@ +/* + * dlg_colorspaceconversion.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_COLORSPACECONVERSION +#define DLG_COLORSPACECONVERSION + +#include + +#include + +class WdgConvertColorSpace; + +/** + * XXX + */ +class DlgColorSpaceConversion: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgColorSpaceConversion(TQWidget * tqparent = 0, const char* name = 0); + ~DlgColorSpaceConversion(); + + WdgConvertColorSpace * m_page; + +public slots: + + void okClicked(); + void fillCmbDestProfile(const KisID &); +}; + +#endif // DLG_COLORSPACECONVERSION diff --git a/chalk/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui b/chalk/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui new file mode 100644 index 00000000..ae183206 --- /dev/null +++ b/chalk/plugins/viewplugins/colorspaceconversion/wdgconvertcolorspace.ui @@ -0,0 +1,218 @@ + +WdgConvertColorSpace + + + WdgConvertColorSpace + + + + 0 + 0 + 399 + 228 + + + + Colorspace Conversion + + + + unnamed + + + + lblConvert + + + &Target color space: + + + cmbColorSpaces + + + + + cmbColorSpaces + + + + 3 + 0 + 0 + 0 + + + + + + + Default + + + + cmbDestProfile + + + + + grpIntent + + + &Rendering Intent + + + + + + + unnamed + + + + radioPerceptual + + + Perceptual + + + + + + true + + + For images + + + Hue hopefully maintained (but not required), +lightness and saturation sacrificed to maintain +the perceived color. White point changed to +result in neutral grays. Intended for images. + + + + + radioRelativeColorimetric + + + Relative colorimetric + + + + + + Within and outside gamut; same as Absolute +Colorimetric. White point changed to result in +neutral grays. + +If adequate table is present in profile, +then, it is used. Else reverts to perceptual +intent. + + + + + radioSaturation + + + Saturation + + + + + + Best for graphs and charts + + + Hue and saturation maintained with lightness +sacrificed to maintain saturation. White point +changed to result in neutral grays. Intended for +business graphics (make it colorful charts, +graphs, overheads, ...) + +If adequate table is present in profile, +then, it is used. Else reverts to perceptual +intent. + + + + + radioAbsoluteColorimetric + + + Absolute colorimetric + + + + + + Best for spot colours + + + Within the destination device gamut; hue, +lightness and saturation are maintained. Outside +the gamut; hue and lightness are maintained, +saturation is sacrificed. White point for source +and destination; unchanged. Intended for spot +colors (Pantone, TruMatch, logo colors, ...) + + + + + + + lblDestICMProfile + + + &Destination ICM profile: + + + cmbDestProfile + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+ + SqueezedComboBox +
squeezedcombobox.h
+ + -1 + i24 + + 0 + + 3 + 0 + 0 + 0 + + image1 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082 + + + +
diff --git a/chalk/plugins/viewplugins/dropshadow/Makefile.am b/chalk/plugins/viewplugins/dropshadow/Makefile.am new file mode 100644 index 00000000..98ba3550 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/Makefile.am @@ -0,0 +1,31 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = dropshadow.rc +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../colorspaces/rgb_u8 \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kde_module_LTLIBRARIES = chalkdropshadow.la + +chalkdropshadow_la_SOURCES = wdg_dropshadow.ui \ + kis_dropshadow.cc dlg_dropshadow.cc \ + kis_dropshadow_plugin.cc + +noinst_HEADERS = wdg_dropshadow.h kis_dropshadow_plugin.h \ + kis_dropshadow.h dlg_dropshadow.h + +chalkdropshadow_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkdropshadow_la_LIBADD = ../../../libchalkcommon.la ../../../colorspaces/rgb_u8/libchalkrgb.la + +kde_services_DATA = chalkdropshadow.desktop + +chalkdropshadow_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/chalk/plugins/viewplugins/dropshadow/chalkdropshadow.desktop b/chalk/plugins/viewplugins/dropshadow/chalkdropshadow.desktop new file mode 100644 index 00000000..a48a477e --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/chalkdropshadow.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Dropshadow +Name[bg]=Сянка +Name[ca]=Gota d'ombra +Name[da]=Faldskygge +Name[de]=Schattenwurf +Name[el]=Ρίψη σκιάς +Name[et]=Varju heitmine +Name[fa]=سایۀ قطره +Name[fr]=Jet d'ombre +Name[fy]=Skaad sette +Name[gl]=Sombreado +Name[hu]=Ejtett árnyék +Name[is]=Undirskuggi +Name[it]=Getta ombra +Name[ja]=影付け +Name[km]=ទម្លាក់​ស្រមោល +Name[nb]=Skygge +Name[nds]=Schaddeneffekt +Name[ne]=छायाँ छोड्नुहोस् +Name[nl]=Schaduw plaatsen +Name[pl]=Dodaj cień +Name[pt]=Sombreado +Name[pt_BR]=Sombreado +Name[ru]=Тень +Name[se]=Suoivvan +Name[sk]=Tieň +Name[sl]=Senca +Name[sr]=Падајућа сенка +Name[sr@Latn]=Padajuća senka +Name[sv]=Fallskugga +Name[uk]=Тінь +Name[uz]=Soya tushirish +Name[uz@cyrillic]=Соя тушириш +Name[zh_CN]=阴影 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkdropshadow +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.cc b/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.cc new file mode 100644 index 00000000..797fc098 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.cc @@ -0,0 +1,117 @@ +/* + * dlg_dropshadow.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2005 Michael Thaler + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "dlg_dropshadow.h" +#include "wdg_dropshadow.h" + +DlgDropshadow::DlgDropshadow( const TQString & /*imageCS*/, + const TQString & /*layerCS*/, + TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Drop Shadow"), Ok | Cancel, Ok) +{ + m_page = new WdgDropshadow(this, "dropshadow"); + Q_CHECK_PTR(m_page); + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + KConfig * cfg = KGlobal::config(); + m_page->xOffsetSpinBox->setValue( cfg->readNumEntry("dropshadow_x", 8) ); + m_page->yOffsetSpinBox->setValue( cfg->readNumEntry("dropshadow_y", 8) ); + m_page->blurRadiusSpinBox->setValue( cfg->readNumEntry("dropshadow_blurRadius", 5) ); + TQColor black(0,0,0); + m_page->shadowColorButton->setColor( cfg->readColorEntry("dropshadow_color", &black) ); + m_page->opacitySlider->setValue( cfg->readNumEntry("dropshadow_opacity", 80 ) ); + m_page->opacitySpinBox->setValue( cfg->readNumEntry("dropshadow_opacity", 80 ) ); + m_page->allowResizingCheckBox->setChecked( cfg->readBoolEntry("dropshadow_resizing", true ) ); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); +} + +DlgDropshadow::~DlgDropshadow() +{ + delete m_page; +} + +TQ_INT32 DlgDropshadow::getXOffset() +{ + return m_page->xOffsetSpinBox->value(); +} + +TQ_INT32 DlgDropshadow::getYOffset() +{ + return m_page->yOffsetSpinBox->value(); +} + +TQ_INT32 DlgDropshadow::getBlurRadius() +{ + return m_page->blurRadiusSpinBox->value(); +} + +TQ_UINT8 DlgDropshadow::getShadowOpacity() +{ + double opacity = (double)m_page->opacitySpinBox->value(); + //convert percent to a 8 bit opacity value + return (TQ_UINT8)(opacity / 100 * 255); +} + +TQColor DlgDropshadow::getShadowColor() +{ + return m_page->shadowColorButton->color(); +} + +bool DlgDropshadow::allowResizingChecked() +{ + return m_page->allowResizingCheckBox->isChecked(); +} + +// SLOTS + +void DlgDropshadow::okClicked() +{ + KConfig * cfg = KGlobal::config(); + cfg->writeEntry("dropshadow_x", m_page->xOffsetSpinBox->value()); + cfg->writeEntry("dropshadow_y", m_page->yOffsetSpinBox->value()); + cfg->writeEntry("dropshadow_blurRadius", m_page->blurRadiusSpinBox->value()); + cfg->writeEntry("dropshadow_color", m_page->shadowColorButton->color()); + cfg->writeEntry("dropshadow_opacity", m_page->opacitySpinBox->value()); + cfg->writeEntry("dropshadow_resizing", m_page->allowResizingCheckBox->isChecked()); + + accept(); +} + +#include "dlg_dropshadow.moc" diff --git a/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.h b/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.h new file mode 100644 index 00000000..9f3ca469 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/dlg_dropshadow.h @@ -0,0 +1,60 @@ +/* + * dlg_dropshadow.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_DROPSHADOW +#define DLG_DROPSHADOW + +#include +#include + +class WdgDropshadow; +class TQColor; + +/** + * This dialog allows the user to configure the decomposition of an image + * into layers: one layer for each color channel. + */ +class DlgDropshadow: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgDropshadow(const TQString & imageCS, const TQString & layerCS, TQWidget * tqparent = 0, + const char* name = 0); + ~DlgDropshadow(); + +public: + + TQ_INT32 getXOffset(); + TQ_INT32 getYOffset(); + TQ_INT32 getBlurRadius(); + TQ_UINT8 getShadowOpacity(); + TQColor getShadowColor(); + bool allowResizingChecked(); +private slots: + void okClicked(); + +private: + + WdgDropshadow * m_page; +}; + +#endif // DLG_DROPSHADOW diff --git a/chalk/plugins/viewplugins/dropshadow/dropshadow.rc b/chalk/plugins/viewplugins/dropshadow/dropshadow.rc new file mode 100644 index 00000000..fcd0be0e --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/dropshadow.rc @@ -0,0 +1,11 @@ + + + + La&yer + + Layer Effects + + + + + diff --git a/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.cc b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.cc new file mode 100644 index 00000000..207c86c3 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.cc @@ -0,0 +1,758 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * The gaussian blur algoithm is ported from gimo + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "kis_meta_registry.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_rgb_colorspace.h" + +#include "kis_dropshadow.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +KisDropshadow::KisDropshadow(KisView * view) + : m_view(view) +{ +} + +void KisDropshadow::dropshadow(KisProgressDisplayInterface * progress, TQ_INT32 xoffset, TQ_INT32 yoffset, TQ_INT32 blurradius, TQColor color, TQ_UINT8 opacity, bool allowResize) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisLayerSP src = image->activeLayer(); + if (!src) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + m_cancelRequested = false; + if ( progress ) + progress->setSubject(this, true, true); + emit notifyProgressStage(i18n("Add drop shadow..."), 0); + + if (image->undo()) { + image->undoAdapter()->beginMacro(i18n("Add Drop Shadow")); + } + + KisPaintDeviceSP shadowDev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"" ), "Shadow"); + KisPaintDeviceSP bShadowDev; + KisRgbColorSpace *rgb8cs = static_cast(shadowDev->colorSpace()); + + TQRect rect = dev->exactBounds(); + + for (TQ_INT32 row = 0; row < rect.height(); ++row) + { + KisHLineIteratorPixel srcIt = dev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), false); + KisHLineIteratorPixel dstIt = shadowDev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), true); + while( ! srcIt.isDone() ) + { + if (srcIt.isSelected()) + { + //set the shadow color + TQ_UINT8 alpha = dev->colorSpace()->getAlpha(srcIt.rawData()); + rgb8cs->setPixel(dstIt.rawData(), color.red(), color.green(), color.blue(), alpha); + } + ++srcIt; + ++dstIt; + } + emit notifyProgress((row * 100) / rect.height() ); + } + + if( blurradius > 0 ) + { + bShadowDev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"" ), "bShadow"); + gaussianblur(shadowDev, bShadowDev, rect, blurradius, blurradius, BLUR_RLE, progress); + shadowDev = bShadowDev; + } + + if (!m_cancelRequested) { + shadowDev->move (xoffset,yoffset); + + KisGroupLayerSP tqparent = image->rootLayer(); + if (image->activeLayer()) + tqparent = image->activeLayer()->tqparent().data(); + + KisPaintLayerSP l = new KisPaintLayer(image, i18n("Drop Shadow"), opacity, shadowDev); + image->addLayer( l.data(), tqparent, src->siblingBelow() ); + + if (allowResize) + { + TQRect shadowBounds = shadowDev->exactBounds(); + + if (!image->bounds().tqcontains(shadowBounds)) { + + TQRect newImageSize = image->bounds() | shadowBounds; + image->resize(newImageSize.width(), newImageSize.height()); + + if (shadowBounds.left() < 0 || shadowBounds.top() < 0) { + + TQ_INT32 newRootX = image->rootLayer()->x(); + TQ_INT32 newRootY = image->rootLayer()->y(); + + if (shadowBounds.left() < 0) { + newRootX += -shadowBounds.left(); + } + if (shadowBounds.top() < 0) { + newRootY += -shadowBounds.top(); + } + + KCommand *moveCommand = image->rootLayer()->moveCommand(TQPoint(image->rootLayer()->x(), image->rootLayer()->y()), + TQPoint(newRootX, newRootY)); + Q_ASSERT(moveCommand != 0); + + if (moveCommand) { + moveCommand->execute(); + if (image->undo()) { + image->undoAdapter()->addCommand(moveCommand); + } else { + delete moveCommand; + } + } + } + } + } + m_view->canvasSubject()->document()->setModified(true); + } + + if (image->undo()) { + image->undoAdapter()->endMacro(); + } + + emit notifyProgressDone(); +} + +void KisDropshadow::gaussianblur (KisPaintDeviceSP srcDev, KisPaintDeviceSP dstDev, TQRect& rect, double horz, double vert, BlurMethod method, KisProgressDisplayInterface *) +{ + TQ_INT32 width, height; + TQ_INT32 bytes; + TQ_UINT8 *dest, *dp; + TQ_UINT8 *src, *sp, *sp_p, *sp_m; + TQ_INT32 *buf = NULL; + TQ_INT32 *bb; + double n_p[5], n_m[5]; + double d_p[5], d_m[5]; + double bd_p[5], bd_m[5]; + double *val_p = NULL; + double *val_m = NULL; + double *vp, *vm; + TQ_INT32 x1, y1, x2, y2; + TQ_INT32 i, j; + TQ_INT32 row, col, b; + TQ_INT32 terms; + double progress, max_progress; + TQ_INT32 initial_p[4]; + TQ_INT32 initial_m[4]; + double std_dev; + TQ_INT32 pixels; + TQ_INT32 total = 1; + TQ_INT32 start, end; + TQ_INT32 *curve; + TQ_INT32 *sum = NULL; + TQ_INT32 val; + TQ_INT32 length; + TQ_INT32 initial_pp, initial_mm; + + x1 = (TQ_INT32)(rect.x() - horz); + y1 = (TQ_INT32)(rect.y() - vert); + width = (TQ_INT32)(rect.width() + 2 * horz); + height = (TQ_INT32)(rect.height() + 2 * vert); + x2 = x1 + width; + y2 = y1 + height; + + if (width < 1 || height < 1) return; + + emit notifyProgressStage(i18n("Blur..."), 0); + + bytes = srcDev->pixelSize(); + + switch (method) + { + case BLUR_IIR: + val_p = new double[MAX (width, height) * bytes]; + val_m = new double[MAX (width, height) * bytes]; + break; + + case BLUR_RLE: + buf = new TQ_INT32[MAX (width, height) * 2]; + break; + } + + src = new TQ_UINT8[MAX (width, height) * bytes]; + dest = new TQ_UINT8[MAX (width, height) * bytes]; + + progress = 0.0; + max_progress = (horz <= 0.0 ) ? 0 : width * height * horz; + max_progress += (vert <= 0.0 ) ? 0 : width * height * vert; + + + /* First the vertical pass */ + if (vert > 0.0) + { + vert = fabs (vert) + 1.0; + std_dev = sqrt (-(vert * vert) / (2 * log (1.0 / 255.0))); + + switch (method) + { + case BLUR_IIR: + /* derive the constants for calculating the gaussian + * from the std dev + */ + find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + break; + + case BLUR_RLE: + curve = make_curve (std_dev, &length); + sum = new TQ_INT32[2 * length + 1]; + + sum[0] = 0; + + for (i = 1; i <= length*2; i++) + sum[i] = curve[i-length-1] + sum[i-1]; + sum += length; + + total = sum[length] - sum[-length]; + break; + } + + for (col = 0; col < width; col++) + { + switch (method) + { + case BLUR_IIR: + memset (val_p, 0, height * bytes * sizeof (double)); + memset (val_m, 0, height * bytes * sizeof (double)); + break; + + case BLUR_RLE: + break; + } + + //gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height); + srcDev->readBytes(src, col+x1, y1, 1, height); + + multiply_alpha (src, height, bytes); + + switch (method) + { + case BLUR_IIR: + sp_p = src; + sp_m = src + (height - 1) * bytes; + vp = val_p; + vm = val_m + (height - 1) * bytes; + + /* Set up the first vals */ + for (i = 0; i < bytes; i++) + { + initial_p[i] = sp_p[i]; + initial_m[i] = sp_m[i]; + } + + for (row = 0; row < height; row++) + { + double *vpptr, *vmptr; + terms = (row < 4) ? row : 4; + + for (b = 0; b < bytes; b++) + { + vpptr = vp + b; vmptr = vm + b; + for (i = 0; i <= terms; i++) + { + *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - + d_p[i] * vp[(-i * bytes) + b]; + *vmptr += n_m[i] * sp_m[(i * bytes) + b] - + d_m[i] * vm[(i * bytes) + b]; + } + for (j = i; j <= 4; j++) + { + *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; + *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; + } + } + + sp_p += bytes; + sp_m -= bytes; + vp += bytes; + vm -= bytes; + } + + transfer_pixels (val_p, val_m, dest, bytes, height); + break; + + case BLUR_RLE: + sp = src; + dp = dest; + + for (b = 0; b < bytes; b++) + { + initial_pp = sp[b]; + initial_mm = sp[(height-1) * bytes + b]; + + /* Determine a run-length encoded version of the row */ + run_length_encode (sp + b, buf, bytes, height); + + for (row = 0; row < height; row++) + { + start = (row < length) ? -row : -length; + end = (height <= (row + length) ? + (height - row - 1) : length); + + val = 0; + i = start; + bb = buf + (row + i) * 2; + + if (start != -length) + val += initial_pp * (sum[start] - sum[-length]); + + while (i < end) + { + pixels = bb[0]; + i += pixels; + if (i > end) + i = end; + val += bb[1] * (sum[i] - sum[start]); + bb += (pixels * 2); + start = i; + } + + if (end != length) + val += initial_mm * (sum[length] - sum[end]); + + dp[row * bytes + b] = val / total; + } + } + break; + } + + separate_alpha (src, height, bytes); + + dstDev->writeBytes(dest, col + x1, y1, 1, height); + + progress += height * vert; + if ((col % 5) == 0) emit notifyProgress( (TQ_UINT32)((progress * 100) / max_progress)); + } + } + + /* Now the horizontal pass */ + if (horz > 0.0) + { + horz = fabs (horz) + 1.0; + + if (horz != vert) + { + std_dev = sqrt (-(horz * horz) / (2 * log (1.0 / 255.0))); + + switch (method) + { + case BLUR_IIR: + /* derive the constants for calculating the gaussian + * from the std dev + */ + find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + break; + + case BLUR_RLE: + curve = make_curve (std_dev, &length); + sum = new TQ_INT32[2 * length + 1]; + + sum[0] = 0; + + for (i = 1; i <= length*2; i++) + sum[i] = curve[i-length-1] + sum[i-1]; + sum += length; + + total = sum[length] - sum[-length]; + break; + } + } + + for (row = 0; row < height; row++) + { + switch (method) + { + case BLUR_IIR: + memset (val_p, 0, width * bytes * sizeof (double)); + memset (val_m, 0, width * bytes * sizeof (double)); + break; + + case BLUR_RLE: + break; + } + + + //gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, width); + dstDev->readBytes(src, x1, row + y1, width, 1); + + multiply_alpha (dest, width, bytes); + + switch (method) + { + case BLUR_IIR: + sp_p = src; + sp_m = src + (width - 1) * bytes; + vp = val_p; + vm = val_m + (width - 1) * bytes; + + /* Set up the first vals */ + for (i = 0; i < bytes; i++) + { + initial_p[i] = sp_p[i]; + initial_m[i] = sp_m[i]; + } + + for (col = 0; col < width; col++) + { + double *vpptr, *vmptr; + terms = (col < 4) ? col : 4; + + for (b = 0; b < bytes; b++) + { + vpptr = vp + b; vmptr = vm + b; + for (i = 0; i <= terms; i++) + { + *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - + d_p[i] * vp[(-i * bytes) + b]; + *vmptr += n_m[i] * sp_m[(i * bytes) + b] - + d_m[i] * vm[(i * bytes) + b]; + } + for (j = i; j <= 4; j++) + { + *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; + *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; + } + } + + sp_p += bytes; + sp_m -= bytes; + vp += bytes; + vm -= bytes; + } + + transfer_pixels (val_p, val_m, dest, bytes, width); + break; + + case BLUR_RLE: + sp = src; + dp = dest; + + for (b = 0; b < bytes; b++) + { + initial_pp = sp[b]; + initial_mm = sp[(width-1) * bytes + b]; + + /* Determine a run-length encoded version of the row */ + run_length_encode (sp + b, buf, bytes, width); + + for (col = 0; col < width; col++) + { + start = (col < length) ? -col : -length; + end = (width <= (col + length)) ? (width - col - 1) : length; + + val = 0; + i = start; + bb = buf + (col + i) * 2; + + if (start != -length) + val += initial_pp * (sum[start] - sum[-length]); + + while (i < end) + { + pixels = bb[0]; + i += pixels; + if (i > end) + i = end; + val += bb[1] * (sum[i] - sum[start]); + bb += (pixels * 2); + start = i; + } + + if (end != length) + val += initial_mm * (sum[length] - sum[end]); + + dp[col * bytes + b] = val / total; + } + } + break; + } + + separate_alpha (dest, width, bytes); + + //gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, width); + dstDev->writeBytes(dest, x1, row + y1, width, 1); + + progress += width * horz; + //if ((row % 5) == 0) gimp_progress_update (progress / max_progress); + if ((row % 5) == 0) emit notifyProgress( (TQ_UINT32)((progress * 100) / max_progress )); + } + } + + /* free up buffers */ + switch (method) + { + case BLUR_IIR: + delete[] val_p; + delete[] val_m; + break; + + case BLUR_RLE: + delete[] buf; + break; + } + + delete[] src; + delete[] dest; +} + +void KisDropshadow::find_constants (double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev) +{ + TQ_INT32 i; + double constants [8]; + double div; + + /* The constants used in the implemenation of a casual sequence + * using a 4th order approximation of the gaussian operator + */ + + div = sqrt(2 * M_PI) * std_dev; + constants [0] = -1.783 / std_dev; + constants [1] = -1.723 / std_dev; + constants [2] = 0.6318 / std_dev; + constants [3] = 1.997 / std_dev; + constants [4] = 1.6803 / div; + constants [5] = 3.735 / div; + constants [6] = -0.6803 / div; + constants [7] = -0.2598 / div; + + n_p [0] = constants[4] + constants[6]; + n_p [1] = exp (constants[1]) * + (constants[7] * sin (constants[3]) - + (constants[6] + 2 * constants[4]) * cos (constants[3])) + + exp (constants[0]) * + (constants[5] * sin (constants[2]) - + (2 * constants[6] + constants[4]) * cos (constants[2])); + n_p [2] = 2 * exp (constants[0] + constants[1]) * + ((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) - + constants[5] * cos (constants[3]) * sin (constants[2]) - + constants[7] * cos (constants[2]) * sin (constants[3])) + + constants[6] * exp (2 * constants[0]) + + constants[4] * exp (2 * constants[1]); + n_p [3] = exp (constants[1] + 2 * constants[0]) * + (constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) + + exp (constants[0] + 2 * constants[1]) * + (constants[5] * sin (constants[2]) - constants[4] * cos (constants[2])); + n_p [4] = 0.0; + + d_p [0] = 0.0; + d_p [1] = -2 * exp (constants[1]) * cos (constants[3]) - + 2 * exp (constants[0]) * cos (constants[2]); + d_p [2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) + + exp (2 * constants[1]) + exp (2 * constants[0]); + d_p [3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) - + 2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]); + d_p [4] = exp (2 * constants[0] + 2 * constants[1]); + + for (i = 0; i <= 4; i++) + d_m [i] = d_p [i]; + + n_m[0] = 0.0; + for (i = 1; i <= 4; i++) + n_m [i] = n_p[i] - d_p[i] * n_p[0]; + + { + double sum_n_p, sum_n_m, sum_d; + double a, b; + + sum_n_p = 0.0; + sum_n_m = 0.0; + sum_d = 0.0; + for (i = 0; i <= 4; i++) + { + sum_n_p += n_p[i]; + sum_n_m += n_m[i]; + sum_d += d_p[i]; + } + + a = sum_n_p / (1.0 + sum_d); + b = sum_n_m / (1.0 + sum_d); + + for (i = 0; i <= 4; i++) + { + bd_p[i] = d_p[i] * a; + bd_m[i] = d_m[i] * b; + } + } +} + + +void KisDropshadow::transfer_pixels (double *src1, double *src2, TQ_UINT8 *dest, TQ_INT32 bytes, TQ_INT32 width) +{ + TQ_INT32 b; + TQ_INT32 bend = bytes * width; + double sum; + + for(b = 0; b < bend; b++) + { + sum = *src1++ + *src2++; + if (sum > 255) sum = 255; + else if(sum < 0) sum = 0; + + *dest++ = (TQ_UINT8) sum; + } +} + +//The equations: g(r) = exp (- r^2 / (2 * sigma^2)), r = sqrt (x^2 + y ^2) +TQ_INT32 * KisDropshadow::make_curve(double sigma, TQ_INT32 *length) +{ + int *curve; + double sigma2; + double l; + int temp; + int i, n; + + sigma2 = 2 * sigma * sigma; + l = sqrt (-sigma2 * log (1.0 / 255.0)); + + n = (int)(ceil (l) * 2); + if ((n % 2) == 0) + n += 1; + + curve = new TQ_INT32[n]; + + *length = n / 2; + curve += *length; + curve[0] = 255; + + for (i = 1; i <= *length; i++) + { + temp = (TQ_INT32) (exp (- (i * i) / sigma2) * 255); + curve[-i] = temp; + curve[i] = temp; + } + + return curve; +} + +void KisDropshadow::run_length_encode (TQ_UINT8 *src, TQ_INT32 *dest, TQ_INT32 bytes, TQ_INT32 width) +{ + TQ_INT32 start; + TQ_INT32 i; + TQ_INT32 j; + TQ_UINT8 last; + + last = *src; + src += bytes; + start = 0; + + for (i = 1; i < width; i++) + { + if (*src != last) + { + for (j = start; j < i; j++) + { + *dest++ = (i - j); + *dest++ = last; + } + start = i; + last = *src; + } + src += bytes; + } + + for (j = start; j < i; j++) + { + *dest++ = (i - j); + *dest++ = last; + } +} + +void KisDropshadow::multiply_alpha (TQ_UINT8 *buf, TQ_INT32 width, TQ_INT32 bytes) +{ + TQ_INT32 i, j; + double alpha; + + for (i = 0; i < width * bytes; i += bytes) + { + alpha = buf[i + bytes - 1] * (1.0 / 255.0); + for (j = 0; j < bytes - 1; j++) { + double a = (double)(buf[i + j]) * alpha; + buf[i + j] = (TQ_UINT8)a; + } + } +} + +void KisDropshadow::separate_alpha (TQ_UINT8 *buf, TQ_INT32 width, TQ_INT32 bytes) +{ + TQ_INT32 i, j; + TQ_UINT8 alpha; + double recip_alpha; + TQ_UINT32 new_val; + + for (i = 0; i < width * bytes; i += bytes) + { + alpha = buf[i + bytes - 1]; + if (alpha != 0 && alpha != 255) + { + recip_alpha = 255.0 / alpha; + for (j = 0; j < bytes - 1; j++) + { + new_val = (TQ_UINT32)(buf[i + j] * recip_alpha); + buf[i + j] = MIN (255, new_val); + } + } + } +} + +#include "kis_dropshadow.moc" diff --git a/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.h b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.h new file mode 100644 index 00000000..94c6decc --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow.h @@ -0,0 +1,72 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_DROPSHADOW_H_ +#define _KIS_DROPSHADOW_H_ + +#include +#include + +typedef enum +{ + BLUR_IIR, + BLUR_RLE +} BlurMethod; + + +class TQColor; +class KisView; +class KisProgressDisplayInterface; + +class KisDropshadow : public KisProgressSubject { + + Q_OBJECT + TQ_OBJECT + +public: + + KisDropshadow(KisView * view); + virtual ~KisDropshadow() {}; + + void dropshadow(KisProgressDisplayInterface * progress, TQ_INT32 xoffset, TQ_INT32 yoffset, TQ_INT32 blurradius, TQColor color, TQ_UINT8 opacity, bool allowResize); + +public: // Implement KisProgressSubject + virtual void cancel() { m_cancelRequested = true; } + +private: + void gaussianblur (KisPaintDeviceSP src, KisPaintDeviceSP dst, + TQRect& rect, double horz, double vert, + BlurMethod method, + KisProgressDisplayInterface * progressDisplay); + //gaussian blur helper functions + void find_constants(double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev); + void transfer_pixels(double *src1, double *src2, TQ_UINT8 *dest, TQ_INT32 bytes, TQ_INT32 width); + TQ_INT32* make_curve(double sigma, TQ_INT32 *length); + void run_length_encode (TQ_UINT8 *src, TQ_INT32 *dest, TQ_INT32 bytes, TQ_INT32 width); + void multiply_alpha (TQ_UINT8 *buf, TQ_INT32 width, TQ_INT32 bytes); + void separate_alpha (TQ_UINT8 *buf, TQ_INT32 width, TQ_INT32 bytes); + +private: + KisView * m_view; + bool m_cancelRequested; + +}; + +#endif diff --git a/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc new file mode 100644 index 00000000..5dc190f1 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc @@ -0,0 +1,91 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_dropshadow_plugin.h" +#include "kis_dropshadow.h" +#include "dlg_dropshadow.h" + +K_EXPORT_COMPONENT_FACTORY( chalkdropshadow, KGenericFactory( "chalk" ) ) + +KisDropshadowPlugin::KisDropshadowPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + if ( tqparent->inherits("KisView") ) { + + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","chalkplugins/dropshadow.rc"), true); + + m_view = (KisView*) tqparent; + (void) new KAction(i18n("Add Drop Shadow..."), 0, 0, this, TQT_SLOT(slotDropshadow()), actionCollection(), "dropshadow"); + } +} + +KisDropshadowPlugin::~KisDropshadowPlugin() +{ +} + +void KisDropshadowPlugin::slotDropshadow() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + DlgDropshadow * dlgDropshadow = new DlgDropshadow(dev->colorSpace()->id().name(), + image->colorSpace()->id().name(), + m_view, "Dropshadow"); + Q_CHECK_PTR(dlgDropshadow); + + dlgDropshadow->setCaption(i18n("Drop Shadow")); + + if (dlgDropshadow->exec() == TQDialog::Accepted) { + + KisDropshadow dropshadow(m_view); + dropshadow.dropshadow(m_view->canvasSubject()->progressDisplay(), + dlgDropshadow->getXOffset(), + dlgDropshadow->getYOffset(), + dlgDropshadow->getBlurRadius(), + dlgDropshadow->getShadowColor(), + dlgDropshadow->getShadowOpacity(), + dlgDropshadow->allowResizingChecked()); + + } + + delete dlgDropshadow; + +} + +#include "kis_dropshadow_plugin.moc" diff --git a/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h new file mode 100644 index 00000000..e2641ed2 --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h @@ -0,0 +1,46 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_DROPSHADOW_PLUGIN_H_ +#define _KIS_DROPSHADOW_PLUGIN_H_ + +#include + +class KisView; + + + +class KisDropshadowPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + KisDropshadowPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisDropshadowPlugin(); + +private slots: + + void slotDropshadow(); + +private: + + KisView * m_view; +}; + +#endif diff --git a/chalk/plugins/viewplugins/dropshadow/wdg_dropshadow.ui b/chalk/plugins/viewplugins/dropshadow/wdg_dropshadow.ui new file mode 100644 index 00000000..4bd2f38c --- /dev/null +++ b/chalk/plugins/viewplugins/dropshadow/wdg_dropshadow.ui @@ -0,0 +1,235 @@ + +WdgDropshadow + + + WdgDropshadow + + + + 0 + 0 + 403 + 258 + + + + + unnamed + + + + textLabel1 + + + Offset X: + + + + + textLabel1_2 + + + Offset Y: + + + + + textLabel2 + + + Blur radius: + + + + + textLabel3 + + + Color: + + + + + textLabel4 + + + Opacity: + + + + + opacitySlider + + + 100 + + + 80 + + + Horizontal + + + + + opacitySpinBox + + + % + + + 100 + + + 80 + + + + + allowResizingCheckBox + + + Allow resizing + + + true + + + + + xOffsetSpinBox + + + -99 + + + 8 + + + + + spacer7 + + + Horizontal + + + Expanding + + + + 200 + 20 + + + + + + yOffsetSpinBox + + + -99 + + + 8 + + + + + spacer8 + + + Horizontal + + + Expanding + + + + 200 + 20 + + + + + + blurRadiusSpinBox + + + 5 + + + + + spacer9 + + + Horizontal + + + Expanding + + + + 190 + 20 + + + + + + shadowColorButton + + + + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 120 + 31 + + + + + + + + + + opacitySpinBox + valueChanged(int) + opacitySlider + setValue(int) + + + opacitySlider + valueChanged(int) + opacitySpinBox + setValue(int) + + + + xOffsetSpinBox + yOffsetSpinBox + blurRadiusSpinBox + shadowColorButton + opacitySlider + opacitySpinBox + allowResizingCheckBox + + + + kcolorbutton.h + + diff --git a/chalk/plugins/viewplugins/filtersgallery/Makefile.am b/chalk/plugins/viewplugins/filtersgallery/Makefile.am new file mode 100644 index 00000000..90ddcfc6 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/Makefile.am @@ -0,0 +1,26 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = chalkfiltersgallery.rc + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkfiltersgallery_la_SOURCES = filters_gallery.cc \ + kis_dlg_filtersgallery.cc kis_wdg_filtersgallery.ui + +kde_module_LTLIBRARIES = chalkfiltersgallery.la +noinst_HEADERS = filters_gallery.h kis_dlg_filtersgallery.h + +kde_services_DATA = chalkfiltersgallery.desktop + +chalkfiltersgallery_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkfiltersgallery_la_LIBADD = ../../../libchalkcommon.la + +chalkfiltersgallery_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.desktop b/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.desktop new file mode 100644 index 00000000..ed1bb5c9 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.desktop @@ -0,0 +1,45 @@ +[Desktop Entry] +Name=Filters Gallery +Name[bg]=Галерия с филтри +Name[ca]=Galeria de filtres +Name[da]=Filtergalleri +Name[de]=Filtergallerie +Name[el]=Συλλογή φίλτρων +Name[eo]=Filtrilgalerio +Name[es]=Galería de filtros +Name[et]=Filtrigalerii +Name[fa]=گالری پالایه‌ها +Name[fr]=Galerie de filtres +Name[fy]=Filtergallerij +Name[ga]=Gailearaí na Scagairí +Name[gl]=Galería de Filtros +Name[he]=גלריית מסננים +Name[hu]=Szűrőgaléria +Name[is]=Síusafn +Name[it]=Galleria dei filtri +Name[ja]=フィルタギャラリー +Name[km]=វិចិត្រសាល​តម្រង +Name[lv]=Filtru galerija +Name[nb]=Filtergalleri +Name[nds]=Filtersammeln +Name[ne]=फिल्टर ग्यालेरी +Name[nl]=Filtergalerij +Name[pl]=Galeria filtrów +Name[pt]=Galeria de Filtros +Name[pt_BR]=Galeria de Filtros +Name[ru]=Галерея фильтров +Name[se]=Sillegalleriija +Name[sk]=Zbierka filtrov +Name[sl]=Galerija filtrov +Name[sr]=Галерија филтера +Name[sr@Latn]=Galerija filtera +Name[sv]=Filtrergalleri +Name[uk]=Галерея фільтрів +Name[uz]=Filterlar toʻplami +Name[uz@cyrillic]=Филтерлар тўплами +Name[zh_CN]=滤镜库 +Name[zh_TW]=濾鏡畫廊 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkfiltersgallery +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.rc b/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.rc new file mode 100644 index 00000000..e5fcfa43 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/chalkfiltersgallery.rc @@ -0,0 +1,9 @@ + + + +&Filter + + + + + diff --git a/chalk/plugins/viewplugins/filtersgallery/filters_gallery.cc b/chalk/plugins/viewplugins/filtersgallery/filters_gallery.cc new file mode 100644 index 00000000..8f70b8f7 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/filters_gallery.cc @@ -0,0 +1,138 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "filters_gallery.h" + +#include + +#include +#include +#include + +#include + +#include +#include "kis_progress_display_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Chalk { +namespace Plugins { +namespace FiltersGallery { + +typedef KGenericFactory ChalkFiltersGalleryFactory; +K_EXPORT_COMPONENT_FACTORY( chalkfiltersgallery, ChalkFiltersGalleryFactory( "chalk" ) ) + +ChalkFiltersGallery::ChalkFiltersGallery(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) + { + setInstance(ChalkFiltersGallery::instance()); + setXMLFile(locate("data","chalkplugins/chalkfiltersgallery.rc"), true); + + m_view = (KisView*) tqparent; + + (void) new KAction(i18n("&Filters Gallery"), 0, 0, this, TQT_SLOT(showFiltersGalleryDialog()), actionCollection(), "chalk_filters_gallery"); + + // Add a docker with the list of filters +// TQImage img; +// if(img.load(locate("data","chalk/images/previewfilter.png"))) +// { +// KisPaintDeviceSP preview = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"")); +// preview->convertFromTQImage(img,""); +// m_view->canvasSubject()->paletteManager()->addWidget(new KisFiltersListView(preview,m_view),"filterslist",chalk::EFFECTSBOX, 0); +// } + + } + + +} + +ChalkFiltersGallery::~ChalkFiltersGallery() +{ +} + +void ChalkFiltersGallery::showFiltersGalleryDialog() +{ + KisDlgFiltersGallery dlg(m_view, m_view); + if (dlg.exec()) + { + TQApplication::setOverrideCursor( TQt::waitCursor ); + + KisFilter* filter = dlg.currentFilter(); + if(filter ) + { + KisImageSP img = m_view->canvasSubject()->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + TQRect r1 = dev->exactBounds(); + TQRect r2 = img->bounds(); + + TQRect rect = r1.intersect(r2); + + if (dev->hasSelection()) { + TQRect r3 = dev->selection()->selectedExactRect(); + rect = rect.intersect(r3); + } + KisFilterConfiguration* config = filter->configuration( dlg.currentConfigWidget()); + + filter->enableProgress(); + m_view->canvasSubject()->progressDisplay()->setSubject(filter, true, true); + filter->setProgressDisplay(m_view->canvasSubject()->progressDisplay()); + + KisTransaction * cmd = new KisTransaction(filter->id().name(), dev); + + filter->process(dev,dev, config, rect); + + delete config; + if (filter->cancelRequested()) { + cmd->unexecute(); + delete cmd; + } else { + dev->setDirty(rect); + if (img->undo()) + img->undoAdapter()->addCommand(cmd); + else + delete cmd; + } + filter->disableProgress(); + TQApplication::restoreOverrideCursor(); + + } + } +} + +} +} +} + +#include "filters_gallery.moc" diff --git a/chalk/plugins/viewplugins/filtersgallery/filters_gallery.h b/chalk/plugins/viewplugins/filtersgallery/filters_gallery.h new file mode 100644 index 00000000..89fed386 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/filters_gallery.h @@ -0,0 +1,54 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KRITA_FILTERS_PREVIEW_H_ +#define _KRITA_FILTERS_PREVIEW_H_ + +#include + +class KisView; + +namespace Chalk { +namespace Plugins { +namespace FiltersGallery { + class ChalkFiltersGallery : public KParts::Plugin + { + Q_OBJECT + TQ_OBJECT + public: + ChalkFiltersGallery(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkFiltersGallery(); + public slots: + void showFiltersGalleryDialog(); + private: + + KisView * m_view; + + + }; + +} +} +} + + + +#endif diff --git a/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc b/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc new file mode 100644 index 00000000..76676177 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.cc @@ -0,0 +1,133 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005-2006 Cyrille Berger + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "kis_dlg_filtersgallery.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_wdg_filtersgallery.h" + +namespace Chalk { +namespace Plugins { +namespace FiltersGallery { + + +KisDlgFiltersGallery::KisDlgFiltersGallery(KisView* view, TQWidget* tqparent,const char *name) + : KDialogBase(tqparent,name, true,i18n("Filters Gallery"), Ok | Cancel), m_view(view),m_currentConfigWidget(0), m_currentFilter(0) +{ + // Initialize main widget + m_widget = new KisWdgFiltersGallery(this); + m_widget->filtersList->setLayer(view->canvasSubject()->currentImg()->activeLayer()); + m_widget->filtersList->setProfile(view->canvasSubject()->monitorProfile()); + + setMainWidget(m_widget); + // Initialize filters list + connect(m_widget->filtersList , TQT_SIGNAL(selectionChanged(TQIconViewItem*)), this, TQT_SLOT(selectionHasChanged(TQIconViewItem* ))); + // Initialize configWidgetHolder + m_widget->configWidgetHolder->setColumnLayout ( 0, Qt::Horizontal ); + //m_widget->configWidgetHolder->tqsetSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Minimum); + // Initialize preview widget + + if (m_view->canvasSubject()->currentImg() && m_view->canvasSubject()->currentImg()->activeDevice()) + { + m_widget->previewWidget->slotSetDevice( m_view->canvasSubject()->currentImg()->activeDevice().data() ); + } + connect( m_widget->previewWidget, TQT_SIGNAL(updated()), this, TQT_SLOT(refreshPreview())); + resize( tqminimumSizeHint()); + m_widget->previewWidget->tqsetSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::MinimumExpanding); + m_labelNoCW = new TQLabel(i18n("No configuration options are available for this filter."), m_widget->configWidgetHolder); + m_widget->configWidgetHolder->tqlayout()->add(m_labelNoCW); + m_labelNoCW->hide(); +} + +KisDlgFiltersGallery::~KisDlgFiltersGallery() +{ +} + +void KisDlgFiltersGallery::selectionHasChanged ( TQIconViewItem * item ) +{ + KisFiltersIconViewItem* kisitem = (KisFiltersIconViewItem*) item; + m_currentFilter = kisitem->filter(); + if(m_currentConfigWidget != 0) + { + m_widget->configWidgetHolder->tqlayout()->remove(m_currentConfigWidget); + delete m_currentConfigWidget; + m_currentConfigWidget = 0; + } else { + m_labelNoCW->hide(); + } + KisImageSP img = m_view->canvasSubject()->currentImg(); + KisPaintLayerSP activeLayer = dynamic_cast(img->activeLayer().data()); + + if (activeLayer) + m_currentConfigWidget = m_currentFilter->createConfigurationWidget(m_widget->configWidgetHolder, activeLayer->paintDevice()); + + if(m_currentConfigWidget != 0) { + //m_currentConfigWidget->tqsetSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Fixed); + m_widget->configWidgetHolder->tqlayout()->add(m_currentConfigWidget); + m_currentConfigWidget->show(); + connect(m_currentConfigWidget, TQT_SIGNAL(sigPleaseUpdatePreview()), this, TQT_SLOT(slotConfigChanged())); + } + else { + m_labelNoCW->show(); + } + + refreshPreview(); +} + +void KisDlgFiltersGallery::slotConfigChanged() +{ + if(m_widget->previewWidget->getAutoUpdate()) + { + refreshPreview(); + } else { + m_widget->previewWidget->needUpdate(); + } +} + + +void KisDlgFiltersGallery::refreshPreview( ) +{ + if(!m_currentFilter) return; + + KisFilterConfiguration* config = m_currentFilter->configuration(m_currentConfigWidget); + + m_widget->previewWidget->runFilter(m_currentFilter, config); +} + +} +} +} + +#include "kis_dlg_filtersgallery.moc" diff --git a/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h b/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h new file mode 100644 index 00000000..09e5cb1f --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/kis_dlg_filtersgallery.h @@ -0,0 +1,69 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005-2006 Cyrille Berger + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KISDLGFILTERSPREVIEW_H +#define KISDLGFILTERSPREVIEW_H + +#include + +class KisView; +class KisFilter; +class TQIconViewItem; +class TQLabel; +class TQHBoxLayout; +class KisPreviewWidget; +class KisWdgFiltersGallery; +class KisFiltersListView; + +namespace Chalk { +namespace Plugins { +namespace FiltersGallery { + +/** +@author Cyrille Berger +*/ +class KisDlgFiltersGallery : public KDialogBase +{ + Q_OBJECT + TQ_OBJECT + public: + KisDlgFiltersGallery(KisView* view, TQWidget* tqparent,const char *name = ""); + ~KisDlgFiltersGallery(); + public: + inline KisFilter* currentFilter() { return m_currentFilter; }; + inline TQWidget* currentConfigWidget() { return m_currentConfigWidget; } + private slots: + void slotConfigChanged(); + void refreshPreview(); + void selectionHasChanged ( TQIconViewItem * item ); + private: + KisWdgFiltersGallery* m_widget; + KisView* m_view; + TQWidget* m_currentConfigWidget; + KisFilter* m_currentFilter; + TQLabel* m_labelNoCW; +}; + +} +} +} + +#endif diff --git a/chalk/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui b/chalk/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui new file mode 100644 index 00000000..488c9564 --- /dev/null +++ b/chalk/plugins/viewplugins/filtersgallery/kis_wdg_filtersgallery.ui @@ -0,0 +1,123 @@ + +KisWdgFiltersGallery + + + KisWdgFiltersGallery + + + + 0 + 0 + 763 + 296 + + + + + unnamed + + + 0 + + + + previewWidget + + + + 5 + 7 + 0 + 0 + + + + + + filtersList + + + + + configWidgetHolder + + + + 1 + 7 + 0 + 0 + + + + + 0 + 0 + + + + Configuration + + + + + + + KisPreviewWidget +
kis_previewwidget.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 + moved(QPoint) + moving(QPoint) + startMoving(QPoint) + zoomIn() + slot() + zoomOut() + slot() + slot() + slotMoving(QPoint) + slotMoved(QPoint) + slot() + slotStartMoving(QPoint) +
+ + KisFiltersListView +
kis_filters_listview.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image1 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000042949444154388db5954d6c545514c77ff7de37eff1a6a550da994e5ba798868f948fc847a2a2911816c436b0a02ed0083161a1981877ee10d90aa94656063491882c5cd4c4b8103f20cd806909a98604da8482341de80cb69de9bcd799799d79efba980f1da3a80b4f727273939bdff99f9b93f3175a6b6a21849080020c4002a29a8f0a5dcd002803bed63a1035f0d0d0504b6f6fef51d7758fa4d3e98d8ee3fc03af128ee3303939399548242eb8aefb09300f78464de9f0f0f0d148cc7caf3d5424de97a7ec17104220242805520a44557bbd4b21f083801d33e63a6d1bc7bf19c6064e0319a35a58b9ae7ba43d54e4d7c54b64dc097c7f09d30ef04b36736983cc7c11b4456b9b492c5e20dc54a6540e00896a8268a7017010f8bcae1830d2e9f4c69ebe3c197782b2ce60d94ddc9b30f9feeb45ae5d7181c5ead35636ef08d3ffe26a76ee3208b4031a56d80aa00768fda362e9380e25bf80ef3b587613d7afc099533380a4b5dda46fcb5aa42998b9eb7173dce5e6788e434763ec7fc942532008ea436003660d2caa7f8d69c3bd8910674e4d033e83877ad8d36fb0aa4d6058658ac5358c5df6383bf480f31fdda5a3632bbbfb6da4ccd5c00a10b2012cc12fd97cfb5516f0187c25cee0619396480ec3ca909d0f3372d1e5f9fe66de3ad605587c712ec55256a2540d5519d19ae24a29057329839f7ecc138944d833102290f3184ae1e6d6f0e98739c61229e6d21eafbed1c9c8c5558c8f3ee4ceed76946a1c43d97091828585223e2eebfbc295f60d45de89707628cb58224577bc85a79e5d4d786581cddb9b0148259711b20145836221400416e0232d1f6595c9ce4538773ac7b54406f0b15784e8e80aa1ac2594190220d021e49f2437960156b70ba095e95f96f18acd8c263cc6122962b1167a7ba34cdd7ec8c977a699bed546722a8fc2a02b6e2185fff78ab586ce78894ddb9ab9f5738ed14b1e030756929d8ff2e4ae5544632b38f96e89a99b298ebd6950cc2d12ed0eb3618b26f520788462ad09877df60db600f0f1fb49c646f21c7ebd836dcf94e9d9b4c0db27d6d3bd36c6426a96bce731703046d7da129a4670836284a054869d4f1b1c7e2dca67676ef3c1898091ef5ad8bc358c3205c93bf7c9a40ad4c660f4728edd7bbb3142ea2fc1da711cfc200011e08b45f6bd1c261adbce9717928c5f9d63fc6a19f0014567773303073790f8214bd6f5282dfbb8b9fa1f6b40d7c1939393533b92e63ad9240990484aec7e41b27d579cbb531e0f67023492d86316ebb768ba1e0f786e6f37e56550c62237aee7011e54abd7c1412291b8a06de378b4d3c0b215da9708e5a3a442192085404a83d4accfecac067c0c43e13a70e3fa12e96409e0325000966bbb354465339d04a6f9dd15fe6dde07ce030780278088d05ad72cc9a6b2f2daaaa74d75a1f0e8d0d5f60b40868a8364ead6248430000b0857a126ffcdf396abf03ce089ffcb4c7f033046c6b4a995e7a00000000049454e44ae426082 + + + + + kis_previewwidget.h + kis_filters_listview.h + +
diff --git a/chalk/plugins/viewplugins/histogram/Makefile.am b/chalk/plugins/viewplugins/histogram/Makefile.am new file mode 100644 index 00000000..149a523b --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/Makefile.am @@ -0,0 +1,25 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = histogram.rc + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkhistogram.la + +chalkhistogram_la_SOURCES = histogram.cc dlg_histogram.cc wdghistogram.ui kis_histogram_widget.cc +noinst_HEADERS = dlg_histogram.h histogram.h wdghistogram.h kis_histogram_widget.h + +kde_services_DATA = chalkhistogram.desktop + +chalkhistogram_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkhistogram_la_LIBADD = ../../../libchalkcommon.la + +chalkhistogram_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/histogram/chalkhistogram.desktop b/chalk/plugins/viewplugins/histogram/chalkhistogram.desktop new file mode 100644 index 00000000..b91e42b6 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/chalkhistogram.desktop @@ -0,0 +1,43 @@ +[Desktop Entry] +Name=Histogram Plugin +Name[bg]=Приставка за Histogram +Name[ca]=Connector d'histograma +Name[da]=Plugin med histogram +Name[de]=Histogramm-Modul +Name[el]=Πρόσθετο ιστογράμματος +Name[eo]=Histograma kromaĵo +Name[es]=Complemento de histograma +Name[et]=Histogrammiplugin +Name[fa]=وصلۀ سابقه‌نما +Name[fr]=Module d'histogramme +Name[fy]=Histogramplugin +Name[gl]=Plugin de Histograma +Name[hu]=Hisztogram modul +Name[is]=Súluritssía +Name[it]=Plugin per gli istogrammi +Name[ja]=ヒストグラムプラグイン +Name[km]=កម្មវិធី​ជំនួយ​អ៊ីស្តូក្រាម​ +Name[lt]=Histogramos įskiepis +Name[nb]=Programtillegg for histogram +Name[nds]=Histogramm-Moduul +Name[ne]=हिस्टोग्राम प्लगइन +Name[nl]=Histogramplugin +Name[pl]=Wtyczka histogramu +Name[pt]='Plugin' do Histograma +Name[pt_BR]=Plugin do Histograma +Name[ru]=Модуль гистограммы +Name[se]=Histogram lassemoduvla +Name[sk]=Modul histogram +Name[sl]=Vstavek za histograme +Name[sr]=Хистограмски прикључак +Name[sr@Latn]=Histogramski priključak +Name[sv]=Insticksprogram med histogram +Name[uk]=Втулок гістограм +Name[uz]=Gistogramma plagini +Name[uz@cyrillic]=Гистограмма плагини +Name[zh_CN]=直方图插件 +Name[zh_TW]=直方圖外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkhistogram +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/histogram/dlg_histogram.cc b/chalk/plugins/viewplugins/histogram/dlg_histogram.cc new file mode 100644 index 00000000..4b781c17 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/dlg_histogram.cc @@ -0,0 +1,68 @@ +/* + * dlg_histogram.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_types.h" +#include "kis_histogram.h" +#include "kis_layer.h" +#include "kis_paint_device.h" + +#include "dlg_histogram.h" +#include "kis_histogram_widget.h" + + +DlgHistogram::DlgHistogram( TQWidget * tqparent, const char * name) + : super (tqparent, name, true, i18n("Histogram"), Ok | Cancel, Ok) +{ + m_page = new KisHistogramWidget(this, "histogram"); + Q_CHECK_PTR(m_page); + + setCaption(i18n("Histogram")); + setMainWidget(m_page); + resize(m_page->tqsizeHint()); +} + +DlgHistogram::~DlgHistogram() +{ + delete m_page; +} + +void DlgHistogram::setPaintDevice(KisPaintDeviceSP dev) +{ + m_page->setPaintDevice(dev); +} + +void DlgHistogram::okClicked() +{ + accept(); +} + +#include "dlg_histogram.moc" diff --git a/chalk/plugins/viewplugins/histogram/dlg_histogram.h b/chalk/plugins/viewplugins/histogram/dlg_histogram.h new file mode 100644 index 00000000..d2568f7a --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/dlg_histogram.h @@ -0,0 +1,58 @@ +/* + * dlg_histogram.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_HISTOGRAM +#define DLG_HISTOGRAM + +#include + +#include "kis_types.h" + +class KisHistogramWidget; + +/** + * This dialog shows the histogram for the (selected) portion + * of the current layer. + * + * XXX: Also for complete image? + */ +class DlgHistogram: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgHistogram(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgHistogram(); + + void setPaintDevice(KisPaintDeviceSP dev); + +private slots: + void okClicked(); + +private: + + KisHistogramWidget * m_page; + KisHistogramSP m_histogram; + KisLayerSP m_layer; +}; + +#endif // DLG_HISTOGRAM diff --git a/chalk/plugins/viewplugins/histogram/histogram.cc b/chalk/plugins/viewplugins/histogram/histogram.cc new file mode 100644 index 00000000..8e6968b9 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/histogram.cc @@ -0,0 +1,105 @@ +/* + * histogram.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "histogram.h" +#include "dlg_histogram.h" +#include "kis_colorspace.h" +#include "kis_histogram.h" + +typedef KGenericFactory HistogramFactory; +K_EXPORT_COMPONENT_FACTORY( chalkhistogram, HistogramFactory( "chalk" ) ) + +Histogram::Histogram(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) { + + setInstance(HistogramFactory::instance()); + setXMLFile(locate("data","chalkplugins/histogram.rc"), true); + + m_action = new KAction(i18n("&Histogram"), 0, 0, this, TQT_SLOT(slotActivated()), actionCollection(), "histogram"); + + m_view = (KisView*) tqparent; + if (KisImageSP img = m_view->canvasSubject()->currentImg()) { + connect(img, TQT_SIGNAL(sigLayersChanged(KisGroupLayerSP)), this, TQT_SLOT(slotLayersChanged())); + connect(img, TQT_SIGNAL(sigLayerAdded(KisLayerSP)), this, TQT_SLOT(slotLayersChanged())); + connect(img, TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayersChanged())); + connect(img, TQT_SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), this, TQT_SLOT(slotLayersChanged())); + connect(img, TQT_SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, TQT_SLOT(slotLayersChanged())); + connect(img, TQT_SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, TQT_SLOT(slotLayersChanged())); + m_img = img; + } + } +} + +Histogram::~Histogram() +{ +} + +void Histogram::slotLayersChanged() { + m_action->setEnabled(m_img && m_img->activeLayer() && m_img->activeLayer()->visible()); +} + +void Histogram::slotActivated() +{ + DlgHistogram * dlgHistogram = new DlgHistogram(m_view, "Histogram"); + Q_CHECK_PTR(dlgHistogram); + + KisPaintDeviceSP dev = m_view->canvasSubject()->currentImg()->activeDevice(); + if (dev) + dlgHistogram->setPaintDevice(dev); + + if (dlgHistogram->exec() == TQDialog::Accepted) { + // Do nothing; this is an informational dialog + } + delete dlgHistogram; +} + +#include "histogram.moc" + diff --git a/chalk/plugins/viewplugins/histogram/histogram.h b/chalk/plugins/viewplugins/histogram/histogram.h new file mode 100644 index 00000000..2425c0c6 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/histogram.h @@ -0,0 +1,50 @@ +/* + * histogram.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + +#include + +class KisView; +class KAction; +class KisImage; + +class Histogram : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + public: + Histogram(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~Histogram(); + + private slots: + void slotActivated(); + void slotLayersChanged(); + + private: + KisImage* m_img; + KisView * m_view; + KisPainter * m_painter; + KAction* m_action; + +}; + +#endif // HISTOGRAM_H diff --git a/chalk/plugins/viewplugins/histogram/histogram.rc b/chalk/plugins/viewplugins/histogram/histogram.rc new file mode 100644 index 00000000..db37b4b7 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/histogram.rc @@ -0,0 +1,10 @@ + + + + &Layer + + + + + + diff --git a/chalk/plugins/viewplugins/histogram/kis_histogram_widget.cc b/chalk/plugins/viewplugins/histogram/kis_histogram_widget.cc new file mode 100644 index 00000000..12005e05 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/kis_histogram_widget.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_channelinfo.h" +#include "kis_histogram_view.h" +#include "kis_histogram_widget.h" +#include "kis_histogram.h" +#include "kis_global.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_colorspace.h" + + +KisHistogramWidget::KisHistogramWidget(TQWidget *tqparent, const char *name) + : super(tqparent, name) +{ + m_from = 0.0; + m_width = 0.0; +} + +KisHistogramWidget::~KisHistogramWidget() +{ +} + +void KisHistogramWidget::setPaintDevice(KisPaintDeviceSP dev) +{ + grpType->disconnect(this); + cmbChannel->disconnect(this); + + m_histogramView->setPaintDevice(dev); + setActiveChannel(0); // So we have the colored one if there are colors + + // The channels + cmbChannel->clear(); + cmbChannel->insertStringList(m_histogramView->channelStrings()); + cmbChannel->setCurrentItem(0); + + // View display + currentView->setMinValue(0); + currentView->setMaxValue(100); + + updateEnabled(); + + m_from = m_histogramView->currentProducer()->viewFrom(); + m_width = m_histogramView->currentProducer()->viewWidth(); + + connect(grpType, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(slotTypeSwitched(int))); + connect(cmbChannel, TQT_SIGNAL(activated(int)), this, TQT_SLOT(setActiveChannel(int))); + connect(zoomIn, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotZoomIn())); + connect(zoomOut, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotZoomOut())); + connect(currentView, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slide(int))); +} + +void KisHistogramWidget::setActiveChannel(int channel) +{ + m_histogramView->setActiveChannel(channel); + updateEnabled(); +} + +void KisHistogramWidget::slotTypeSwitched(int id) +{ + if (id == LINEAR) + m_histogramView->setHistogramType(LINEAR); + else if (id == LOGARITHMIC) + m_histogramView->setHistogramType(LOGARITHMIC); +} + +void KisHistogramWidget::setView(double from, double size) +{ + m_from = from; + m_width = size; + if (m_from + m_width > 1.0) + m_from = 1.0 - m_width; + m_histogramView->setView(m_from, m_width); + updateEnabled(); +} + +void KisHistogramWidget::slotZoomIn() { + if ((m_width / 2) >= m_histogramView->currentProducer()->maximalZoom()) { + setView(m_from, m_width / 2); + } +} + +void KisHistogramWidget::slotZoomOut() { + if (m_width * 2 <= 1.0) { + setView(m_from, m_width * 2); + } +} + +void KisHistogramWidget::slide(int val) { + // Beware: at the END (e.g. 100), we want to still view m_width: + setView((static_cast(val) / 100.0) * (1.0 - m_width), m_width); +} + +void KisHistogramWidget::updateEnabled() { + if (m_histogramView->currentProducer()->maximalZoom() < 1.0) { + if ((m_width / 2) >= m_histogramView->currentProducer()->maximalZoom()) { + zoomIn->setEnabled(true); + } else { + zoomIn->setEnabled(false); + } + if (m_width * 2 <= 1.0) { + zoomOut->setEnabled(true); + } else { + zoomOut->setEnabled(false); + } + if (m_width < 1.0) + currentView->setEnabled(true); + else + currentView->setEnabled(false); + } else { + zoomIn->setEnabled(false); + zoomOut->setEnabled(false); + currentView->setEnabled(false); + } +} + +#include "kis_histogram_widget.moc" + diff --git a/chalk/plugins/viewplugins/histogram/kis_histogram_widget.h b/chalk/plugins/viewplugins/histogram/kis_histogram_widget.h new file mode 100644 index 00000000..f83394e7 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/kis_histogram_widget.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_HISTOGRAM_WIDGET_ +#define KIS_HISTOGRAM_WIDGET_ + +#include "kis_types.h" +#include "wdghistogram.h" + +class KisColorSpace; + +/** + * The histogram widget takes a paint device or an image and + * draws a histogram for the given KisHistogram. + */ +class KisHistogramWidget : public WdgHistogram { + typedef WdgHistogram super; + Q_OBJECT + TQ_OBJECT + +public: + KisHistogramWidget(TQWidget *tqparent, const char *name); + virtual ~KisHistogramWidget(); + + void setPaintDevice(KisPaintDeviceSP dev); + +private slots: + void setActiveChannel(int channel); + void slotTypeSwitched(int id); + void slotZoomIn(); + void slotZoomOut(); + void slide(int val); + +private: + void setView(double from, double size); + void updateEnabled(); + double m_from, m_width; +}; + + +#endif // KIS_HISTOGRAM_WIDGET_ diff --git a/chalk/plugins/viewplugins/histogram/wdghistogram.ui b/chalk/plugins/viewplugins/histogram/wdghistogram.ui new file mode 100644 index 00000000..77c418ed --- /dev/null +++ b/chalk/plugins/viewplugins/histogram/wdghistogram.ui @@ -0,0 +1,229 @@ + +WdgHistogram + + + WdgHistogram + + + + 0 + 0 + 450 + 380 + + + + + unnamed + + + + grpType + + + Method + + + + unnamed + + + + radioLinear + + + &Linear + + + true + + + + + radioLog + + + &Logarithmic + + + + + spacer1 + + + Vertical + + + Preferred + + + + 20 + 20 + + + + + + cmbChannel + + + + 7 + 0 + 0 + 0 + + + + + 200 + 0 + + + + + + lblChannel + + + &Channel: + + + cmbChannel + + + + + spacer2 + + + Vertical + + + Preferred + + + + 20 + 21 + + + + + + + + m_histogramView + + + + 7 + 7 + 0 + 0 + + + + + 256 + 150 + + + + + + tqlayout2 + + + + unnamed + + + + textLabel1 + + + View: + + + + + zoomIn + + + + 5 + 5 + 0 + 0 + + + + + + + + + + zoomOut + + + + 5 + 5 + 0 + 0 + + + + - + + + + + currentView + + + + 7 + 0 + 0 + 0 + + + + Horizontal + + + + + + + + + KisHistogramView +
kis_histogram_view.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + kis_histogram_view.h + +
diff --git a/chalk/plugins/viewplugins/histogram_docker/Makefile.am b/chalk/plugins/viewplugins/histogram_docker/Makefile.am new file mode 100644 index 00000000..64341755 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/Makefile.am @@ -0,0 +1,22 @@ +kde_services_DATA = chalkhistogramdocker.desktop +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = chalkhistogramdocker.rc + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkhistogramdocker_la_SOURCES = histogramdocker.cc kis_imagerasteredcache.cc kis_cachedhistogram.cc kis_accumulating_producer.cc + +kde_module_LTLIBRARIES = chalkhistogramdocker.la +noinst_HEADERS = histogramdocker.h kis_imagerasteredcache.h kis_cachedhistogram.h kis_accumulating_producer.h + +chalkhistogramdocker_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkhistogramdocker_la_LIBADD = ../../../libchalkcommon.la + +chalkhistogramdocker_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.desktop b/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.desktop new file mode 100644 index 00000000..aba9ded8 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Histogram Docker +Name[ca]=Amarrador de l'histograma +Name[cy]=Bachydd Histogram +Name[da]=Histogramdokning +Name[de]=Histogramm-Docker +Name[el]=Προσάρτηση ιστογράμματος +Name[eo]=Histogramdokilo +Name[es]=Anclaje del histograma +Name[et]=Histogrammi dokk +Name[fa]=پیونددهندۀ سابقه‌نما +Name[fr]=Ancrage d'histogramme +Name[fy]=Histogramkomponint +Name[gl]=Acoplador de Histogramas +Name[hu]=Hisztogramdokkoló +Name[is]=Súluritsspjald +Name[it]=Aggancia-istogrammi +Name[ja]=ヒストグラムドッカー +Name[km]=កន្លែង​ចត​អ៊ីស្តូក្រាម +Name[nb]=Histogramdokker +Name[nds]=Histogramm-Docker +Name[ne]=हिस्टोग्राम डकर +Name[nl]=Histogramcomponent +Name[pl]=Doker histogramu +Name[pt]=Acoplador de Histogramas +Name[pt_BR]=Acoplador de Histogramas +Name[ru]=Панель гистограммы +Name[sk]=Histogram +Name[sl]=Histogram +Name[sr]=Сидраш хистограма +Name[sr@Latn]=Sidraš histograma +Name[sv]=Histogramdockning +Name[uk]=Швартувальник гістограм +Name[uz]=Gistogramma paneli +Name[uz@cyrillic]=Гистограмма панели +Name[zh_TW]=直方圖停駐點 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkhistogramdocker +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.rc b/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.rc new file mode 100644 index 00000000..2b6006b9 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/chalkhistogramdocker.rc @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/chalk/plugins/viewplugins/histogram_docker/histogramdocker.cc b/chalk/plugins/viewplugins/histogram_docker/histogramdocker.cc new file mode 100644 index 00000000..df5de24a --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/histogramdocker.cc @@ -0,0 +1,192 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_meta_registry.h" +#include +#include +#include +#include + +#include +#include + +#include "histogramdocker.h" +#include "kis_imagerasteredcache.h" +#include "kis_accumulating_producer.h" + +typedef KGenericFactory ChalkHistogramDockerFactory; +K_EXPORT_COMPONENT_FACTORY( chalkhistogramdocker, ChalkHistogramDockerFactory( "chalk" ) ) + +ChalkHistogramDocker::ChalkHistogramDocker(TQObject *tqparent, const char *name, const TQStringList&) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) { + m_view = dynamic_cast(tqparent); + + setInstance(ChalkHistogramDockerFactory::instance()); + setXMLFile(locate("data","chalkplugins/chalkhistogramdocker.rc"), true); + + KisImageSP img = m_view->canvasSubject()->currentImg(); + if (!img) { + m_cache = 0; + return; + } + + m_hview = 0; // producerChanged wants to setCurrentChannels, prevent that here + m_cache = 0; // we try to delete it in producerChanged + colorSpaceChanged(img->colorSpace()); // calls producerChanged(0) + + + m_hview = new KisHistogramView(m_view); + TQToolTip::add(m_hview, i18n("Right-click to select histogram type")); + m_hview->setHistogram(m_histogram); + m_hview->setColor(true); + m_hview->setCurrentChannels(m_producer, m_producer->channels()); + m_hview->setFixedSize(256, 100); // XXX if not it keeps expanding + m_hview->setCaption(i18n("Histogram")); + + + connect(m_hview, TQT_SIGNAL(rightClicked(const TQPoint&)), + this, TQT_SLOT(popupMenu(const TQPoint&))); + connect(m_cache, TQT_SIGNAL(cacheUpdated()), + new HistogramDockerUpdater(this, m_histogram, m_hview, m_producer), TQT_SLOT(updated())); + connect(&m_popup, TQT_SIGNAL(activated(int)), + this, TQT_SLOT(producerChanged(int))); + connect(img, TQT_SIGNAL(sigColorSpaceChanged(KisColorSpace*)), + this, TQT_SLOT(colorSpaceChanged(KisColorSpace*))); // No need to force updates here + + // Add it to the control palette + m_view->canvasSubject()->paletteManager()->addWidget( + m_hview, "histodocker", chalk::CONTROL_PALETTE); + } else { + m_cache = 0; + } +} + +ChalkHistogramDocker::~ChalkHistogramDocker() +{ + uint count = m_producers . count(); + for (uint i = 0; i < count; i++) { + delete m_producers . at(i); + } + + if (m_cache) + m_cache->deleteLater(); +} + +void ChalkHistogramDocker::producerChanged(int pos) +{ + if (m_cache) + m_cache->deleteLater(); + m_cache = 0; + + if (m_currentProducerPos < m_popup.count()) + m_popup.setItemChecked(m_currentProducerPos, false); + m_currentProducerPos = pos; + m_popup.setItemChecked(m_currentProducerPos, true); + + uint count = m_producers . count(); + for (uint i = 0; i < count; i++) { + delete m_producers . at(i); + } + m_producers.clear(); + + KisIDList keys = KisHistogramProducerFactoryRegistry::instance() -> + listKeysCompatibleWith(m_cs); + + m_factory = KisHistogramProducerFactoryRegistry::instance()->get(*(keys.at(pos))); + + KisCachedHistogramObserver observer(&m_producers, m_factory, 0, 0, 0, 0, false); + + // We can reference observer because it will be only used as a factory to create new + // instances + m_cache = new KisImageRasteredCache(m_view, &observer); + + m_producer = new KisAccumulatingHistogramProducer(&m_producers); + + // use dummy layer as a source; we are not going to actually use or need it + // All of these are SP, no need to delete them afterwards + m_histogram = new KisHistogram( new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), "dummy histogram"), m_producer, LOGARITHMIC); + + if (m_hview) { + m_hview->setHistogram(m_histogram); + m_hview->setColor(true); + m_hview->setCurrentChannels(m_producer, m_producer->channels()); + + connect(m_cache, TQT_SIGNAL(cacheUpdated()), + new HistogramDockerUpdater(this, m_histogram, m_hview, m_producer), TQT_SLOT(updated())); + } +} + +void ChalkHistogramDocker::popupMenu(const TQPoint& pos) +{ + m_popup.popup(pos, m_currentProducerPos); +} + +void ChalkHistogramDocker::colorSpaceChanged(KisColorSpace* cs) +{ + m_cs = cs; + + KisIDList keys = KisHistogramProducerFactoryRegistry::instance() -> + listKeysCompatibleWith(m_cs); + + m_popup.clear(); + m_currentProducerPos = 0; + + for (uint i = 0; i < keys.count(); i++) { + KisID id(*(keys.at(i))); + m_popup . insertItem(id.name(), static_cast(i)); + } + + producerChanged(0); +} + +HistogramDockerUpdater::HistogramDockerUpdater(TQObject* /*tqparent*/, KisHistogramSP h, KisHistogramView* v, + KisAccumulatingHistogramProducer* p) + : m_histogram(h), m_view(v), m_producer(p) +{ + connect(p, TQT_SIGNAL(completed()), this, TQT_SLOT(completed())); +} + +void HistogramDockerUpdater::updated() { + // We don't [!] do m_histogram->updateHistogram();, because that will try to compute + // the histogram synchronously, while we want it asynchronously. + m_producer->addRegionsToBinAsync(); +} + +void HistogramDockerUpdater::completed() { + m_histogram->computeHistogram(); + m_view->updateHistogram(); +} + +#include "histogramdocker.moc" diff --git a/chalk/plugins/viewplugins/histogram_docker/histogramdocker.h b/chalk/plugins/viewplugins/histogram_docker/histogramdocker.h new file mode 100644 index 00000000..ade0650f --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/histogramdocker.h @@ -0,0 +1,81 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _HISTOGRAMDOCKER_H_ +#define _HISTOGRAMDOCKER_H_ + +#include +#include + +#include +#include +#include + +#include "kis_cachedhistogram.h" + +class KisAccumulatingHistogramProducer; +class KisColorSpace; +class KisHistogramView; +class KisView; +class KisColorSpace; + +class ChalkHistogramDocker : public KParts::Plugin +{ +Q_OBJECT + TQ_OBJECT +public: + ChalkHistogramDocker(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkHistogramDocker(); +private slots: + void producerChanged(int pos); + void popupMenu(const TQPoint & pos); + void colorSpaceChanged(KisColorSpace* cs); +private: + KisHistogramProducerFactory* m_factory; + KisCachedHistogramObserver::Producers m_producers; + KisAccumulatingHistogramProducer* m_producer; + KisColorSpace* m_cs; + KisView* m_view; + KisHistogramView* m_hview; + KisImageRasteredCache* m_cache; + TQPopupMenu m_popup; + KisHistogramSP m_histogram; + uint m_currentProducerPos; +}; + +class KisGenericRGBHistogramProducerFactory; + +class HistogramDockerUpdater : public TQObject { +Q_OBJECT + TQ_OBJECT +public: + HistogramDockerUpdater(TQObject* tqparent, KisHistogramSP h, KisHistogramView* v, + KisAccumulatingHistogramProducer* p); +public slots: + void updated(); +private slots: + void completed(); +private: + KisHistogramSP m_histogram; + KisHistogramView* m_view; + KisAccumulatingHistogramProducer* m_producer; +}; + +#endif //_HISTOGRAMDOCKER_H_ diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc b/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc new file mode 100644 index 00000000..217a36d9 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.cc @@ -0,0 +1,102 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "kis_accumulating_producer.h" + +static const int EmitCompletedType = TQEvent::User + 1; + +/** + * The threaded producer definition in c++ file because this is really an internal affair. + * Note that since we _know_ that we'll only have a single instance of it running, at most, + * we don't care too much about locking and synchronization + **/ +class KisAccumulatingHistogramProducer::ThreadedProducer : public TQThread { + KisAccumulatingHistogramProducer* m_source; + bool m_stop; +protected: + virtual void run(); +public: + ThreadedProducer(KisAccumulatingHistogramProducer* source) + : m_source(source), m_stop(false) {} + void cancel() { m_stop = true; } +}; + +KisAccumulatingHistogramProducer::KisAccumulatingHistogramProducer(KisCachedHistogramObserver::Producers* source) + : KisBasicHistogramProducer( + KisID("ACCHISTO", ""), + source->at(0)->channels().count(), + source->at(0)->numberOfBins(), + 0), + m_source(source) +{ + m_thread = new ThreadedProducer(this); +} + +KisAccumulatingHistogramProducer::~KisAccumulatingHistogramProducer() { + m_thread->cancel(); + m_thread->wait(); + delete m_thread; +} + +void KisAccumulatingHistogramProducer::addRegionsToBinAsync() { + m_thread->cancel(); + m_thread->wait(); + clear(); + m_thread->start(); +} + +void KisAccumulatingHistogramProducer::ThreadedProducer::run() { + m_stop = false; + + uint count = m_source->m_source->count(); // Talk about bad naming schemes... + KisCachedHistogramObserver::Producers* source = m_source->m_source; + TQValueVector& bins = m_source->m_bins; + int channels = m_source->m_channels; + int nrOfBins = m_source->m_nrOfBins; + + for (uint i = 0; i < count && !m_stop; i++) { + KisHistogramProducer* p = source->at(i); + m_source->m_count += p->count(); + + for (int j = 0; j < channels && !m_stop; j++) { + for (int k = 0; k < nrOfBins; k++) { + bins.at(j).at(k) += p->getBinAt(j, k); + } + } + } + + if (!m_stop) { + // This function is thread-safe; and it takes ownership of the event + TQApplication::postEvent(m_source, new TQCustomEvent(EmitCompletedType)); + } +} + +void KisAccumulatingHistogramProducer::customEvent(TQCustomEvent* e) { + if (e->type() == EmitCompletedType) { + emit completed(); + } +} + +#include "kis_accumulating_producer.moc" + diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h b/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h new file mode 100644 index 00000000..d74a3ec5 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_accumulating_producer.h @@ -0,0 +1,77 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_ACCUMULATING_PRODUCER_H_ +#define _KIS_ACCUMULATING_PRODUCER_H_ + +#include + +#include +#include "kis_cachedhistogram.h" + +/** + * Kept very minimalistic because all options would require much reiterating which we don't want. + * This class is multithreading! Don't expect it to contain the right data after an + * addRegionsToBinAsync call, but await it's completed() signal. Also beware! This function + * _does_ clear() before addRegionsToBinAsync! (hence not conforming to the regular semantics + * of HistogramProducers if you'd take addRegionsToBinAsync = addRegionToBin, but since that is + * already violated with the asynchronousity of it that is not really an issue anymore, I think) + **/ +class KisAccumulatingHistogramProducer : public TQObject, public KisBasicHistogramProducer { +Q_OBJECT + TQ_OBJECT +public: + KisAccumulatingHistogramProducer(KisCachedHistogramObserver::Producers* source); + ~KisAccumulatingHistogramProducer(); + /// Does _nothing_, use addRegionsToBinAsync + virtual void addRegionToBin(TQ_UINT8 *, TQ_UINT8*, TQ_UINT32, KisColorSpace *) {} + virtual void addRegionsToBinAsync(); + virtual TQString positionToString(double pos) const + { return m_source->at(0)->positionToString(pos); } + + virtual void setView(double, double) {} // No view support + virtual double maximalZoom() const { return 1.0; } + + virtual TQ_INT32 numberOfBins() { return m_source->at(0)->numberOfBins(); } + + virtual TQValueVector channels() { return m_source->at(0)->channels(); } + + /// Call this when the 'source' list has changed colorspace + virtual void changedSourceProducer() { + m_count = m_source->at(0)->channels().count(); + m_external.clear(); + makeExternalToInternal(); + } + +signals: + void completed(); + +protected: + virtual void customEvent(TQCustomEvent* e); + /// source already converts external to internal + virtual int externalToInternal(int ext) { return ext; } + KisCachedHistogramObserver::Producers* m_source; + + class ThreadedProducer; + friend class ThreadedProducer; + ThreadedProducer* m_thread; +}; + +#endif // _KIS_ACCUMULATING_PRODUCER_H_ diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc b/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc new file mode 100644 index 00000000..1ad197f9 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.cc @@ -0,0 +1,37 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "kis_cachedhistogram.h" + +void KisCachedHistogramObserver::regionUpdated(KisPaintDeviceSP dev) { + m_producer->clear(); + KisRectIteratorPixel srcIt = dev->createRectIterator(m_x, m_y, m_w, m_h, false); + int i; + while ( !srcIt.isDone() ) { + i = srcIt.nConseqPixels(); + m_producer->addRegionToBin(srcIt.rawData(), srcIt.selectionMask(), i, dev->colorSpace()); + srcIt += i; + if (i == 0) + ++srcIt; + } +} diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h b/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h new file mode 100644 index 00000000..084ff389 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_cachedhistogram.h @@ -0,0 +1,53 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CACHED_HISTOGRAM_H_ +#define _CACHED_HISTOGRAM_H_ + +#include +#include + +#include "kis_imagerasteredcache.h" + +class KisCachedHistogramObserver : public KisImageRasteredCache::Observer { +public: + typedef TQValueVector Producers; + KisCachedHistogramObserver(Producers* p, KisHistogramProducerFactory* f, + int x, int y, int w, int h, bool add = true) + : m_producers(p), m_factory(f), m_x(x), m_y(y), m_w(w), m_h(h) + { + m_producer = m_factory->generate(); + if (add) + m_producers->append(m_producer); + } + virtual ~KisCachedHistogramObserver() {} + + virtual Observer* createNew(int x, int y, int w, int h) + { return new KisCachedHistogramObserver(m_producers, m_factory, x, y, w, h); } + + virtual void regionUpdated(KisPaintDeviceSP dev); +private: + Producers* m_producers; + KisHistogramProducerFactory* m_factory; + KisHistogramProducerSP m_producer; + int m_x, m_y, m_w, m_h; +}; + +#endif // _CACHED_HISTOGRAM_H_ diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc b/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc new file mode 100644 index 00000000..19599cd9 --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.cc @@ -0,0 +1,162 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +#include "kis_imagerasteredcache.h" + +KisImageRasteredCache::KisImageRasteredCache(KisView* view, Observer* o) + : m_observer(o->createNew(0, 0, 0, 0)), m_view(view) +{ + m_busy = false; + m_imageProjection = 0; + m_rasterSize = 64*4; + m_timeOutMSec = 1000; + + KisImageSP img = view->canvasSubject()->currentImg(); + + if (!img) { + return; + } + + imageSizeChanged(img->width(), img->height()); + + connect(img, TQT_SIGNAL(sigImageUpdated(TQRect)), + this, TQT_SLOT(imageUpdated(TQRect))); + connect(img, TQT_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)), + this, TQT_SLOT(imageSizeChanged(TQ_INT32, TQ_INT32))); + connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(timeOut())); +} + +KisImageRasteredCache::~KisImageRasteredCache() { + cleanUpElements(); +} + +void KisImageRasteredCache::imageUpdated(TQRect rc) { + + if (rc.isValid()) { + TQRect r(0, 0, m_width * m_rasterSize, m_height * m_rasterSize); + r &= rc; + + uint x = static_cast(r.x() / m_rasterSize); + uint y = static_cast(r.y() / m_rasterSize); + uint x2 = static_cast(ceil(float(r.x() + r.width()) / float(m_rasterSize))); + uint y2 = static_cast(ceil(float(r.y() + r.height()) / float(m_rasterSize))); + + if (!m_raster.empty()) { + for ( ; x < x2; x++) { + for (uint i = y; i < y2; i++) { + if (x < m_raster.size()) { + if (i < m_raster.at(x).size()) { + Element* e = m_raster.at(x).at(i); + if (e && e->valid) { + e->valid = false; + m_queue.push_back(e); + } + } + } + } + } + } + } + + if (!m_busy) { + // If the timer is already started, this resets it. That way, we update always + // m_timeOutMSec milliseconds after the lastly monitored activity + m_timer.start(m_timeOutMSec, true); // true->singleshot + } +} + +void KisImageRasteredCache::imageSizeChanged(TQ_INT32 w, TQ_INT32 h) { + + KisImageSP image = m_view->canvasSubject()->currentImg(); + + cleanUpElements(); + m_busy = false; + + m_width = static_cast(ceil(float(w) / float(m_rasterSize))); + m_height = static_cast(ceil(float(h) / float(m_rasterSize))); + + m_raster.resize(m_width); + + int rasterX = 0; + + for (int i = 0; i < m_width * m_rasterSize; i += m_rasterSize) { + int rasterY = 0; + + m_raster.at(rasterX).resize(m_height + 1); + + for (int j = 0; j < m_height * m_rasterSize; j += m_rasterSize) { + Element* e = new Element(m_observer->createNew(i, j, m_rasterSize, m_rasterSize)); + m_raster.at(rasterX).at(rasterY) = e; + rasterY++; + } + rasterX++; + } + + imageUpdated(TQRect(0,0, image->width(), image->height())); +} + +void KisImageRasteredCache::timeOut() { + m_busy = true; + KisImageSP img = m_view->canvasSubject()->currentImg(); + + // Temporary cache: while we are busy, we won't get the mergeImage time and again. + if (!m_imageProjection) + m_imageProjection = img->mergedImage(); + + // Pick one element of the cache, and update it + if (!m_queue.isEmpty()) { + m_queue.front()->observer->regionUpdated(m_imageProjection); + m_queue.front()->valid = true; + m_queue.pop_front(); + } + + // If there are still elements, we need to be called again (this emulates processEvents) + if (!m_queue.isEmpty()) { + TQTimer::singleShot(0, this, TQT_SLOT(timeOut())); + } else { + emit cacheUpdated(); + m_imageProjection = 0; + m_busy = false; + } +} + +void KisImageRasteredCache::cleanUpElements() { + for (uint i = 0; i < m_raster.count(); i++) { + for (uint j = 0; j < m_raster.at(i).count(); j++) { + delete m_raster.at(i).at(j); + } + m_raster.at(i).clear(); + } + m_raster.clear(); + m_queue.clear(); +} + +#include "kis_imagerasteredcache.moc" diff --git a/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h b/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h new file mode 100644 index 00000000..7df7df8f --- /dev/null +++ b/chalk/plugins/viewplugins/histogram_docker/kis_imagerasteredcache.h @@ -0,0 +1,81 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_IMAGE_RASTERED_CACHE_H_ +#define _KIS_IMAGE_RASTERED_CACHE_H_ + +#include +#include +#include +#include + +#include + +class KisView; + +class KisImageRasteredCache : public TQObject { +Q_OBJECT + TQ_OBJECT + +public: + class Observer { + public: + virtual Observer* createNew(int x, int y, int w, int h) = 0; + virtual void regionUpdated(KisPaintDeviceSP dev) = 0; + virtual ~Observer() {} + }; + + KisImageRasteredCache(KisView* view, Observer* o); + virtual ~KisImageRasteredCache(); + +signals: + void cacheUpdated(); + +private slots: + void imageUpdated(TQRect rc); + void imageSizeChanged(TQ_INT32 w, TQ_INT32 h); + void timeOut(); + +private: + class Element { + public: + Element(Observer* o) : observer(o), valid(true) {} + Observer* observer; + bool valid; + }; + typedef TQValueVector< TQValueVector > Raster; + typedef TQValueList Queue; + + void cleanUpElements(); + + Observer* m_observer; + Raster m_raster; + Queue m_queue; + TQTimer m_timer; + int m_timeOutMSec; + int m_rasterSize; + int m_width, m_height; + KisView * m_view; + bool m_busy; + + KisPaintDeviceSP m_imageProjection; +}; + +#endif // _KIS_IMAGE_RASTERED_CACHE_H_ diff --git a/chalk/plugins/viewplugins/history_docker/Makefile.am b/chalk/plugins/viewplugins/history_docker/Makefile.am new file mode 100644 index 00000000..53511b3d --- /dev/null +++ b/chalk/plugins/viewplugins/history_docker/Makefile.am @@ -0,0 +1,18 @@ +#kde_services_DATA = chalkhistorydocker.desktop + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkhistorydocker_la_SOURCES = historydocker.cc + +kde_module_LTLIBRARIES = chalkhistorydocker.la +noinst_HEADERS = historydocker.h + +chalkhistorydocker_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkhistorydocker_la_LIBADD = ../../../libchalkcommon.la + +chalkhistorydocker_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/history_docker/chalkhistorydocker.desktop b/chalk/plugins/viewplugins/history_docker/chalkhistorydocker.desktop new file mode 100644 index 00000000..270393ce --- /dev/null +++ b/chalk/plugins/viewplugins/history_docker/chalkhistorydocker.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Name=History Docker +Name[ca]=Amarrador d'història +Name[cy]=Bachydd Hanes +Name[da]=Historikdokning +Name[de]=Verlauf-Docker +Name[el]=Προσάρτηση ιστορικού +Name[eo]=Historidokilo +Name[es]=Anclaje del histórico +Name[et]=Ajaloo dokk +Name[fa]=پیونددهندۀ سابقه‌نما +Name[fr]=Ancrage d'historique +Name[fy]=Histoarjekomponint +Name[gl]=Acoplador de Histórico +Name[hu]=Előzménydokkoló +Name[is]=Söguspjald +Name[it]=Aggancia-cronologia +Name[ja]=履歴ドックパネル +Name[km]=កន្លែង​ចត​ប្រវត្តិ +Name[nb]=Hiastoriedokker +Name[nds]=Vörgeschicht-Docker +Name[ne]=इतिहास डकर +Name[nl]=Geschiedeniscomponent +Name[pl]=Doker historii +Name[pt]=Acoplador de Histórico +Name[pt_BR]=Acoplador de Histórico +Name[ru]=История команд +Name[sk]=História +Name[sl]=Zgodovina +Name[sr]=Сидраш историјата +Name[sr@Latn]=Sidraš istorijata +Name[sv]=Historikdockning +Name[uk]=Швартувальник історії +Name[zh_TW]=歷史紀錄停駐點 +Comment=Command history docker for Chalk +Comment[bg]=Основната функционалност на Chalk +Comment[ca]=Amarrador d'història d'ordres per a Chalk +Comment[cy]=Bachydd yr hanes gorchmynion ar gyfer Chalk +Comment[da]=Dokning af kommandohistorik for Chalk +Comment[de]=Befehlsverlauf-Docker für Chalk +Comment[el]=Άρθρωμα προσάρτησης ιστορικού εντολών για το Chalk +Comment[es]=Anclaje con el histórico de órdenes para Chalk +Comment[et]=Chalk käskude ajaloo dokk +Comment[fa]=پیونددهنده تاریخچۀ فرمان برای Chalk +Comment[fr]=Ancrage de l'historique des commandes pour Chalk +Comment[fy]=Komponint mei bewurkingshistoarje foar Chalk" +Comment[gl]=Un módulo acoplado co historial de comandos para Chalk +Comment[hu]=Chalk parancselőzmény-dokkoló +Comment[is]=Skipanasöguspjald fyrir Chalk +Comment[it]=Aggancia-cronologia dei comandi di Chalk +Comment[ja]=Chalk コマンド履歴ドックパネル +Comment[km]=កន្លែង​ចត​ប្រវត្តិ​ពាក្យបញ្ជា​សម្រាប់ Chalk +Comment[nb]=Kommandohistorie-dokker for Chalk +Comment[nds]=Befehlsvörgeschicht-Docker för Chalk +Comment[ne]=क्रिताका लागि आदेश इतिहास +Comment[nl]=Component met bewerkingsgeschiedenis voor Chalk +Comment[pl]=Doker historii poleceń dla Chalk +Comment[pt]=Um módulo acoplado de histórico de comandos do Chalk +Comment[pt_BR]=Um módulo acoplado de histórico de comandos do Chalk +Comment[ru]=Панель истории команд Chalk +Comment[sk]=História príkazov pre Chalk +Comment[sl]=Zgodovina ukazov za Krito +Comment[sr]=Сидраш историјата наредби за Chalk-у +Comment[sr@Latn]=Sidraš istorijata naredbi za Chalk-u +Comment[sv]=Dockning av kommandohistorik för Chalk +Comment[uk]=Швартувальник історії команд для Chalk +Comment[uz]=Chalk uchun buyruqlar tarixi paneli +Comment[uz@cyrillic]=Chalk учун буйруқлар тарихи панели +Comment[zh_TW]=Chalk 的指令紀錄停駐點 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkhistorydocker +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/history_docker/historydocker.cc b/chalk/plugins/viewplugins/history_docker/historydocker.cc new file mode 100644 index 00000000..e4f36813 --- /dev/null +++ b/chalk/plugins/viewplugins/history_docker/historydocker.cc @@ -0,0 +1,58 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "historydocker.h" + +typedef KGenericFactory ChalkHistoryDockerFactory; +K_EXPORT_COMPONENT_FACTORY( chalkhistorydocker, ChalkHistoryDockerFactory( "chalk" ) ) + +ChalkHistoryDocker::ChalkHistoryDocker(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + + + if ( tqparent->inherits("KisView") ) + { + setInstance(ChalkHistoryDockerFactory::instance()); + // Create history docker + // Add the docker to the docker manager + // Connect the undo system to the docker + } + +} + +ChalkHistoryDocker::~ChalkHistoryDocker() +{ +} diff --git a/chalk/plugins/viewplugins/history_docker/historydocker.h b/chalk/plugins/viewplugins/history_docker/historydocker.h new file mode 100644 index 00000000..82aee9bf --- /dev/null +++ b/chalk/plugins/viewplugins/history_docker/historydocker.h @@ -0,0 +1,34 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _HISTORYDOCKER_H +#define _HISTORYDOCKER_H + +#include + +class ChalkHistoryDocker : public KParts::Plugin +{ +public: + ChalkHistoryDocker(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ChalkHistoryDocker(); +}; + + +#endif //_HISTORYDOCKER_H diff --git a/chalk/plugins/viewplugins/imagesize/Makefile.am b/chalk/plugins/viewplugins/imagesize/Makefile.am new file mode 100644 index 00000000..cf863888 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/Makefile.am @@ -0,0 +1,25 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = imagesize.rc +EXTRA_DIST = $(chalkrc_DATA) + +kde_services_DATA = chalkimagesize.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkimagesize_la_SOURCES = wdg_imagesize.ui wdg_layersize.ui imagesize.cc dlg_imagesize.cc dlg_layersize.cc wdg_resolution.ui + +noinst_HEADERS = wdg_imagesize.h dlg_imagesize.h imagesize.h dlg_layersize.h + +kde_module_LTLIBRARIES = chalkimagesize.la + +chalkimagesize_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkimagesize_la_LIBADD = ../../../libchalkcommon.la + +chalkimagesize_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/imagesize/chalkimagesize.desktop b/chalk/plugins/viewplugins/imagesize/chalkimagesize.desktop new file mode 100644 index 00000000..8505b94e --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/chalkimagesize.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Image Resize and Scale Plugin +Name[bg]=Приставка за оразмеряване +Name[ca]=Connector de redimensionament i escala d'imatge +Name[da]=Plugin for størrelsesændring og skalering +Name[de]=Bildgrößenänderungs- und Skalierungsmodul +Name[el]=Πρόσθετο αλλαγής μεγέθους και κλιμάκωσης εικόνας +Name[es]=Complemento para cambiar de tamaño y para escalar la imagen +Name[et]=Pildi suuruse muutmise ja skaleerimise plugin +Name[fa]=تغییر اندازۀ تصویر و مقیاس‌بندی وصله +Name[fr]=Module de redimensionnement d'images +Name[fy]=Grutte wizigje en skale fan de ôfbylding +Name[gl]=Plugin de Redimensionamento e Escalado da Imaxe +Name[he]=תוסף לשינוי גודל וזוויות של תמונ +Name[hu]=Képátméretező és -nyújtó modul +Name[is]=Breytingar á stærð og skala mynda íforrit +Name[it]=Plugin di ridimensionamento e riscalamento delle immagini +Name[ja]=画像 リサイズ/スケール プラグイン +Name[km]=កម្មវិធី​ជំនួយ​ដើម្បី​ប្ដូរ​ទំហំ និង​ធ្វើ​មាត្រដ្ឋាន​រូបភាព +Name[nb]=Programtillegg for skalering og endring av bildestørrelse +Name[nds]=Moduul för't Ännern un Topassen vun de Bildgrött +Name[ne]=छवि रिसाइज र स्केल प्लगइन +Name[nl]=Grootte wijzigen en schalen van afbeelding +Name[pl]=Wtyczka skalowania i zmiany rozmiarów obrazków +Name[pt]='Plugin' de Dimensionamento e Escala da Imagem +Name[pt_BR]=Plugin de Redimensionamento e Escala da Imagem +Name[ru]=Модуль масштабирования и изменения размера +Name[se]=Lassemoduvla mii skále ja rievdada govvasturrodaga +Name[sk]=Modul na zmenu veľkosti a škály obrázkov +Name[sl]=Vstavek za spreminjanje velikosti in povečavo slike +Name[sr]=Прикључак за промену величине и скалирање слика +Name[sr@Latn]=Priključak za promenu veličine i skaliranje slika +Name[sv]=Insticksprogram för bildstorleksändring och skalning +Name[uk]=Втулок зміни розміру та масштабування зображень +Name[zh_TW]=圖片大小與縮放外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkimagesize +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/imagesize/configure.in.in b/chalk/plugins/viewplugins/imagesize/configure.in.in new file mode 100644 index 00000000..0875ce32 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/configure.in.in @@ -0,0 +1 @@ +AC_CHECK_DECLS([round], [], [], [#include ]) diff --git a/chalk/plugins/viewplugins/imagesize/dlg_imagesize.cc b/chalk/plugins/viewplugins/imagesize/dlg_imagesize.cc new file mode 100644 index 00000000..a1eba4f3 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/dlg_imagesize.cc @@ -0,0 +1,277 @@ +/* + * dlg_imagesize.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "dlg_imagesize.h" +#include "wdg_imagesize.h" + + +// XXX: I'm really real bad at arithmetic, let alone math. Here +// be rounding errors. (Boudewijn) +DlgImageSize::DlgImageSize( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Image Size"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgImageSize(this, "image_size"); + Q_CHECK_PTR(m_page); + + m_page->cmbFilterType->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); + m_page->cmbFilterType->setCurrentText("Mitchell"); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + unblockAll(); + + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + +} + +DlgImageSize::~DlgImageSize() +{ + delete m_page; +} + +void DlgImageSize::hideScaleBox() +{ + m_page->grpResizeScale->hide(); +} + +void DlgImageSize::setWidth(TQ_UINT32 w) +{ + blockAll(); + + m_page->lblWidthOriginal->setNum((int)w); + m_page->intWidth->setValue(w); + m_oldW = w; + m_origW = w; + + unblockAll(); +} + +void DlgImageSize::setWidthPercent(TQ_UINT32 w) +{ + blockAll(); + + m_page->intWidthPercent->setValue(w); + m_oldWPercent = w; + + unblockAll(); +} + + +void DlgImageSize::setMaximumWidth(TQ_UINT32 w) +{ + m_page->intWidth->setMaxValue(w); + m_maxW = w; +} + +TQ_INT32 DlgImageSize::width() +{ + //return (TQ_INT32)tqRound(m_oldW); + return (TQ_INT32)tqRound(m_page->intWidth->value()); +} + +void DlgImageSize::setHeight(TQ_UINT32 h) +{ + blockAll(); + + m_page->lblHeightOriginal->setNum((int)h); + m_page->intHeight->setValue(h); + m_oldH = h; + m_origH = h; + + unblockAll(); +} + + +void DlgImageSize::setHeightPercent(TQ_UINT32 h) +{ + blockAll(); + + m_page->intHeightPercent->setValue(h); + m_oldHPercent = h; + + unblockAll(); +} + + + +void DlgImageSize::setMaximumHeight(TQ_UINT32 h) +{ + m_page->intHeight->setMaxValue(h); + m_maxH = h; +} + + +TQ_INT32 DlgImageSize::height() +{ + //return (TQ_INT32)tqRound(m_oldH); + return (TQ_INT32)tqRound(m_page->intHeight->value()); +} + +bool DlgImageSize::scale() +{ + return m_page->radioScale->isChecked(); +} + +bool DlgImageSize::cropLayers() +{ + return m_page->chkCrop->isChecked(); +} + +KisFilterStrategy *DlgImageSize::filterType() +{ + KisID filterID = m_page->cmbFilterType->currentItem(); + KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->get(filterID); + return filter; +} + +// SLOTS + +void DlgImageSize::okClicked() +{ + accept(); +} + +void DlgImageSize::slotWidthPixelsChanged(int w) +{ + blockAll(); + + double wPercent = double(w) * 100 / double(m_origW); + + m_page->intWidthPercent->setValue(tqRound(wPercent)); + + // Set height in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(tqRound(wPercent)); + + m_oldH = tqRound(m_origH * wPercent / 100); + m_page->intHeight->setValue(tqRound(m_oldH)); + + } + m_oldW = w; + + unblockAll(); +} + +void DlgImageSize::slotHeightPixelsChanged(int h) +{ + blockAll(); + + double hPercent = double(h) * 100 / double(m_origH); + + m_page->intHeightPercent->setValue(tqRound(hPercent)); + + // Set width in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(tqRound(hPercent)); + + m_oldW = tqRound(m_origW * hPercent / 100); + m_page->intWidth->setValue(tqRound(m_oldW)); + + } + m_oldH = h; + + unblockAll(); +} + +void DlgImageSize::slotWidthPercentChanged(int w) +{ + blockAll(); + + m_page->intWidth->setValue(tqRound(w * m_origW / 100)); + + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(w); + m_page->intHeight->setValue(tqRound( w * m_origH / 100)); + } + + unblockAll(); +} + +void DlgImageSize::slotHeightPercentChanged(int h) +{ + blockAll(); + + m_page->intHeight->setValue(tqRound(h * m_origH / 100)); + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(h); + m_page->intWidth->setValue(tqRound( h * m_origW / 100)); + } + + unblockAll(); + +} + + +void DlgImageSize::blockAll() +{ + // XXX: more efficient to use blockSignals? + m_page->intWidth->disconnect(); + m_page->intHeight->disconnect(); + m_page->intWidthPercent->disconnect(); + m_page->intHeightPercent->disconnect(); + +} + +void DlgImageSize::unblockAll() +{ + // XXX: more efficient to use blockSignals? + connect (m_page->intWidth, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotWidthPixelsChanged(int))); + + connect (m_page->intHeight, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotHeightPixelsChanged(int))); + + connect (m_page->intWidthPercent, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotWidthPercentChanged(int))); + + connect (m_page->intHeightPercent, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotHeightPercentChanged(int))); + + +} + +#include "dlg_imagesize.moc" diff --git a/chalk/plugins/viewplugins/imagesize/dlg_imagesize.h b/chalk/plugins/viewplugins/imagesize/dlg_imagesize.h new file mode 100644 index 00000000..7983e112 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/dlg_imagesize.h @@ -0,0 +1,83 @@ +/* + * dlg_imagesize.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_IMAGESIZE +#define DLG_IMAGESIZE + +#include + +class KisFilterStrategy; +class WdgImageSize; + +/** + * This dialog allows the user to create a selection tqmask based + * on a (range of) colors. + */ +class DlgImageSize: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgImageSize(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgImageSize(); + + void hideScaleBox(); + + void setWidth(TQ_UINT32 w); + void setWidthPercent(TQ_UINT32 w); + void setMaximumWidth(TQ_UINT32 w); + TQ_INT32 width(); + + void setHeight(TQ_UINT32 h); + void setHeightPercent(TQ_UINT32 h); + void setMaximumHeight(TQ_UINT32 h); + TQ_INT32 height(); + + bool scale(); + bool cropLayers(); + + KisFilterStrategy *filterType(); + +private slots: + + void okClicked(); + void slotWidthPixelsChanged(int w); + void slotHeightPixelsChanged(int h); + void slotWidthPercentChanged(int w); + void slotHeightPercentChanged(int h); + +private: + + void blockAll(); + void unblockAll(); + + WdgImageSize * m_page; + double m_oldW, m_oldH; + double m_oldWPercent, m_oldHPercent; + double m_origW, m_origH; + double m_maxW, m_maxH; + + bool m_lock; + +}; + +#endif // DLG_IMAGESIZE diff --git a/chalk/plugins/viewplugins/imagesize/dlg_layersize.cc b/chalk/plugins/viewplugins/imagesize/dlg_layersize.cc new file mode 100644 index 00000000..8289d693 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/dlg_layersize.cc @@ -0,0 +1,261 @@ +/* + * dlg_layersize.cc - part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "dlg_layersize.h" +#include "wdg_layersize.h" + + +// XXX: I'm really real bad at arithmetic, let alone math. Here +// be rounding errors. (Boudewijn) +DlgLayerSize::DlgLayerSize( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Scale Layer"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgLayerSize(this, "layer_size"); + Q_CHECK_PTR(m_page); + + m_page->cmbFilterType->setIDList(KisFilterStrategyRegistry::instance()->listKeys()); + m_page->cmbFilterType->setCurrentText("Mitchell"); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + unblockAll(); + + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + +} + +DlgLayerSize::~DlgLayerSize() +{ + delete m_page; +} + +void DlgLayerSize::setWidth(TQ_UINT32 w) +{ + blockAll(); + + m_page->lblWidthOriginal->setNum((int)w); + m_page->intWidth->setValue(w); + m_oldW = w; + m_origW = w; + + unblockAll(); +} + +void DlgLayerSize::setWidthPercent(TQ_UINT32 w) +{ + blockAll(); + + m_page->intWidthPercent->setValue(w); + m_oldWPercent = w; + + unblockAll(); +} + + +void DlgLayerSize::setMaximumWidth(TQ_UINT32 w) +{ + m_page->intWidth->setMaxValue(w); + m_maxW = w; +} + +TQ_INT32 DlgLayerSize::width() +{ + //return (TQ_INT32)tqRound(m_oldW); + return (TQ_INT32)tqRound(m_page->intWidth->value()); +} + +void DlgLayerSize::setHeight(TQ_UINT32 h) +{ + blockAll(); + + m_page->lblHeightOriginal->setNum((int)h); + m_page->intHeight->setValue(h); + m_oldH = h; + m_origH = h; + + unblockAll(); +} + + +void DlgLayerSize::setHeightPercent(TQ_UINT32 h) +{ + blockAll(); + + m_page->intHeightPercent->setValue(h); + m_oldHPercent = h; + + unblockAll(); +} + +void DlgLayerSize::setMaximumHeight(TQ_UINT32 h) +{ + m_page->intHeight->setMaxValue(h); + m_maxH = h; +} + +TQ_INT32 DlgLayerSize::height() +{ + //return (TQ_INT32)tqRound(m_oldH); + return (TQ_INT32)tqRound(m_page->intHeight->value()); +} + +KisFilterStrategy *DlgLayerSize::filterType() +{ + KisID filterID = m_page->cmbFilterType->currentItem(); + KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->get(filterID); + return filter; +} + + +// SLOTS + +void DlgLayerSize::okClicked() +{ + accept(); +} + +void DlgLayerSize::slotWidthPixelsChanged(int w) +{ + blockAll(); + + double wPercent = double(w) * 100 / double(m_origW); + + m_page->intWidthPercent->setValue(tqRound(wPercent)); + + // Set height in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(tqRound(wPercent)); + + m_oldH = tqRound(m_origH * wPercent / 100); + m_page->intHeight->setValue(tqRound(m_oldH)); + + } + m_oldW = w; + + unblockAll(); +} + +void DlgLayerSize::slotHeightPixelsChanged(int h) +{ + blockAll(); + + double hPercent = double(h) * 100 / double(m_origH); + + m_page->intHeightPercent->setValue(tqRound(hPercent)); + + // Set width in pixels and percent of necessary + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(tqRound(hPercent)); + + m_oldW = tqRound(m_origW * hPercent / 100); + m_page->intWidth->setValue(tqRound(m_oldW)); + + } + m_oldH = h; + + unblockAll(); +} + +void DlgLayerSize::slotWidthPercentChanged(int w) +{ + blockAll(); + + m_page->intWidth->setValue(tqRound(w * m_origW / 100)); + + if (m_page->chkConstrain->isChecked()) { + m_page->intHeightPercent->setValue(w); + m_page->intHeight->setValue(tqRound( w * m_origH / 100)); + } + + unblockAll(); +} + +void DlgLayerSize::slotHeightPercentChanged(int h) +{ + blockAll(); + + m_page->intHeight->setValue(tqRound(h * m_origH / 100)); + if (m_page->chkConstrain->isChecked()) { + m_page->intWidthPercent->setValue(h); + m_page->intWidth->setValue(tqRound( h * m_origW / 100)); + } + + unblockAll(); + +} + + +void DlgLayerSize::blockAll() +{ + // XXX: more efficient to use blockSignals? + m_page->intWidth->disconnect(); + m_page->intHeight->disconnect(); + m_page->intWidthPercent->disconnect(); + m_page->intHeightPercent->disconnect(); + +} + +void DlgLayerSize::unblockAll() +{ + // XXX: more efficient to use blockSignals? + connect (m_page->intWidth, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotWidthPixelsChanged(int))); + + connect (m_page->intHeight, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotHeightPixelsChanged(int))); + + connect (m_page->intWidthPercent, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotWidthPercentChanged(int))); + + connect (m_page->intHeightPercent, TQT_SIGNAL(valueChanged(int)), + this, TQT_SLOT(slotHeightPercentChanged(int))); + + +} + +#include "dlg_layersize.moc" diff --git a/chalk/plugins/viewplugins/imagesize/dlg_layersize.h b/chalk/plugins/viewplugins/imagesize/dlg_layersize.h new file mode 100644 index 00000000..0aaf8445 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/dlg_layersize.h @@ -0,0 +1,74 @@ +/* + * dlg_layersize.h -- part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_LAYERSIZE +#define DLG_LAYERSIZE + +#include + +class WdgLayerSize; +class KisFilterStrategy; + +class DlgLayerSize: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgLayerSize(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgLayerSize(); + + void setWidth(TQ_UINT32 w); + void setWidthPercent(TQ_UINT32 w); + void setMaximumWidth(TQ_UINT32 w); + TQ_INT32 width(); + + void setHeight(TQ_UINT32 h); + void setHeightPercent(TQ_UINT32 h); + void setMaximumHeight(TQ_UINT32 h); + TQ_INT32 height(); + KisFilterStrategy *filterType(); + +private slots: + + void okClicked(); + void slotWidthPixelsChanged(int w); + void slotHeightPixelsChanged(int h); + void slotWidthPercentChanged(int w); + void slotHeightPercentChanged(int h); + +private: + + void blockAll(); + void unblockAll(); + + WdgLayerSize * m_page; + double m_oldW, m_oldH; + double m_oldWPercent, m_oldHPercent; + double m_origW, m_origH; + double m_maxW, m_maxH; + + bool m_lock; + +}; + +#endif // DLG_IMAGESIZE diff --git a/chalk/plugins/viewplugins/imagesize/imagesize.cc b/chalk/plugins/viewplugins/imagesize/imagesize.cc new file mode 100644 index 00000000..c23d2717 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/imagesize.cc @@ -0,0 +1,190 @@ +/* + * imagesize.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "imagesize.h" +#include "dlg_imagesize.h" +#include "dlg_layersize.h" +#include "kis_filter_strategy.h" + +typedef KGenericFactory ImageSizeFactory; +K_EXPORT_COMPONENT_FACTORY( chalkimagesize, ImageSizeFactory( "chalk" ) ) + +ImageSize::ImageSize(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + if ( tqparent->inherits("KisView") ) + { + setInstance(ImageSizeFactory::instance()); + setXMLFile(locate("data","chalkplugins/imagesize.rc"), true); + + (void) new KAction(i18n("Change &Image Size..."), 0, "Shift-s", this, TQT_SLOT(slotImageSize()), actionCollection(), "imagesize"); + (void) new KAction(i18n("&Scale Layer..."), 0, 0, this, TQT_SLOT(slotLayerSize()), actionCollection(), "layerscale"); + + + m_view = (KisView*) tqparent; + // Selection manager takes ownership? + KAction * a = new KAction(i18n("&Scale Selection..."), 0, 0, this, TQT_SLOT(slotSelectionScale()), actionCollection(), "selectionscale"); + Q_CHECK_PTR(a); + m_view ->canvasSubject()-> selectionManager()->addSelectionAction(a); + } +} + +ImageSize::~ImageSize() +{ + m_view = 0; +} + +void ImageSize::slotImageSize() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgImageSize * dlgImageSize = new DlgImageSize(m_view, "ImageSize"); + Q_CHECK_PTR(dlgImageSize); + + dlgImageSize->setCaption(i18n("Image Size")); + + KisConfig cfg; + + dlgImageSize->setWidth(image->width()); + dlgImageSize->setHeight(image->height()); + + if (dlgImageSize->exec() == TQDialog::Accepted) { + TQ_INT32 w = dlgImageSize->width(); + TQ_INT32 h = dlgImageSize->height(); + + if (dlgImageSize->scale()) { + m_view->scaleCurrentImage((double)w / ((double)(image->width())), + (double)h / ((double)(image->height())), + dlgImageSize->filterType()); + } + else { + m_view->resizeCurrentImage(w, h, dlgImageSize->cropLayers()); + } + } + + delete dlgImageSize; +} + +void ImageSize::slotLayerSize() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgLayerSize * dlgLayerSize = new DlgLayerSize(m_view, "LayerSize"); + Q_CHECK_PTR(dlgLayerSize); + + dlgLayerSize->setCaption(i18n("Layer Size")); + + KisConfig cfg; + KisPaintDeviceSP dev = image->activeDevice(); + + TQRect rc = dev->exactBounds(); + + dlgLayerSize->setWidth(rc.width()); + dlgLayerSize->setHeight(rc.height()); + + if (dlgLayerSize->exec() == TQDialog::Accepted) { + TQ_INT32 w = dlgLayerSize->width(); + TQ_INT32 h = dlgLayerSize->height(); + + m_view->scaleLayer((double)w / ((double)(rc.width())), + (double)h / ((double)(rc.height())), + dlgLayerSize->filterType()); + } + delete dlgLayerSize; +} + +void ImageSize::slotSelectionScale() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + KisPaintDeviceSP layer = image->activeDevice(); + + if (!layer) return; + + if (!layer->hasSelection()) return; + + + DlgLayerSize * dlgLayerSize = new DlgLayerSize(m_view, "SelectionScale"); + Q_CHECK_PTR(dlgLayerSize); + + dlgLayerSize->setCaption(i18n("Scale Selection")); + + KisConfig cfg; + TQRect rc = layer->selection()->selectedRect(); + + dlgLayerSize->setWidth(rc.width()); + dlgLayerSize->setHeight(rc.height()); + + if (dlgLayerSize->exec() == TQDialog::Accepted) { + TQ_INT32 w = dlgLayerSize->width(); + TQ_INT32 h = dlgLayerSize->height(); + + KisScaleWorker worker (layer->selection().data(), + (double)w / ((double)(rc.width())), + (double)h / ((double)(rc.height())), + dlgLayerSize->filterType()); + worker.run(); + + m_view->getCanvasController()->updateCanvas(); + + } + delete dlgLayerSize; +} + + +#include "imagesize.moc" diff --git a/chalk/plugins/viewplugins/imagesize/imagesize.h b/chalk/plugins/viewplugins/imagesize/imagesize.h new file mode 100644 index 00000000..989a603f --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/imagesize.h @@ -0,0 +1,49 @@ +/* + * imagesize.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef IMAGESIZE_H +#define IMAGESIZE_H + +#include + +class KisView; +class KisPainter; + +class ImageSize : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ImageSize(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ImageSize(); + +private slots: + + void slotImageSize(); + void slotLayerSize(); + void slotSelectionScale(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // IMAGESIZE_H diff --git a/chalk/plugins/viewplugins/imagesize/imagesize.rc b/chalk/plugins/viewplugins/imagesize/imagesize.rc new file mode 100644 index 00000000..2efb4ed8 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/imagesize.rc @@ -0,0 +1,15 @@ + + + + Image + + + + Layer + + + &Select + + + + diff --git a/chalk/plugins/viewplugins/imagesize/wdg_imagesize.ui b/chalk/plugins/viewplugins/imagesize/wdg_imagesize.ui new file mode 100644 index 00000000..4cdd5c95 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/wdg_imagesize.ui @@ -0,0 +1,365 @@ + +WdgImageSize + + + WdgImageSize + + + + 0 + 0 + 397 + 382 + + + + Image Size + + + + unnamed + + + + grpResizeScale + + + + + + + unnamed + + + + pixmapLabel1_2 + + + image0 + + + true + + + + + spacer2_2 + + + Horizontal + + + Expanding + + + + 65 + 20 + + + + + + spacer1_2 + + + Horizontal + + + Expanding + + + + 65 + 20 + + + + + + pixmapLabel2_2 + + + + 0 + 0 + 0 + 0 + + + + image1 + + + true + + + + + radioResize + + + &Resize + + + + + chkCrop + + + &Crop layers on image resize + + + true + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 121 + 20 + + + + + + radioScale + + + &Scale + + + true + + + + + + + grpPixelDimensions + + + &Pixel Dimensions + + + + unnamed + + + + lblWidth + + + &Width: + + + intWidth + + + + + intHeight + + + 0 + + + + + textLabel2 + + + &Height: + + + intHeight + + + + + lblWidthOriginal + + + WinPanel + + + Sunken + + + + + + AlignVCenter|AlignRight + + + + + lblHeightOriginal + + + WinPanel + + + Sunken + + + + + + AlignVCenter|AlignRight + + + + + lblOrignal + + + Original: + + + + + lblNew + + + &New: + + + intWidth + + + + + intWidth + + + 0 + + + + + intWidthPercent + + + 100 + + + 0 + + + 100 + + + % + + + + + intHeightPercent + + + 100 + + + 0 + + + % + + + + + lblPercent + + + &Percent: + + + intWidthPercent + + + + + chkConstrain + + + &Constrain proportions + + + true + + + + + + + lblFilterType + + + Filter: + + + AlignVCenter|AlignRight + + + cmbFilterType + + + + + cmbFilterType + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image2 +
+
+ + + 89504e470d0a1a0a0000000d494844520000006e0000002e0806000000c9032c97000010fe49444154789ced9b79741455bec73f55bdd0d94893054212c32a10821064095b44458119c1618928038af8e61c78e3783cfee13bcfa7c020eaf00e1c90a3ce24f890454438a0cce8cc1b8808610f04599c17c0b0bcb0042421fbda55d575df1f9dea7477ba4967018ecefb9e53dd55f7debaf7d6ef5bbfe52e256566660aee31de78e38da4f2f2f26b0042dcf3e6bd2049120053a64c99f6d24b2fcda8abab76754880d0759001dd5556a7b1afba2b411702245759d0119ee58c0b570202dd558d68fcf14c6b2ce3be4f074c8de94e5709a70024937cf6ecf9a3595959996680050b1674a028ee8cacac2c2c164b8210e29a21b4fb0d21043367ce1c3b65ca53cf5b2cd6b6d6e2f11fe89c46428d73e17e7185e7b96ebc3b02a10bd7bf10d842ecfc61f97fc6039f995bd5b5c6ca8510e88d6f9defb9bfc3c88b8c8c0440922491959545972e5d5ad3fc5d8549128ef628bf10783cab679a77beeb5a6a2c2b79dc27f994c1230d9c4e1d4b278184e604ac72dbbbda7e582c96fbd9fc7dc5a64d9bda76a370a971ab34aeb2b2124d034992319bcd5cb97295ae5dedd8ed76005455e51fff384f48880db359263a3aaaf1dc7f33aaaab6adf3f719959595389d2049264c261357ae5c253e3ec66d415455e5cc997c424242b0584c74ed1a4b48880d93c9d442cdc12368e284101417979094d4039bcde507745da3aaaaca4d5c6e6e1e13274e70df535454cadebd393cf9e404b739f5447b346e6786940aec03ecc00660fef41d6db775cd7b171825252524262679c9a1babada4ddc9123b93cfef8a3eef24545a51c3efc2d93264d74a7bdf0c20b6dee2bb86226bff0f45d062449c2330ad434dd1d951d3f7e82f1e31ff52affd5573b193870406359ad591bed0c4ea645f64cb58ffab79d58c2ec2f02eb7766b4bd3e4df34f5d70727022cb2e511e3b96c7b871e95ee5fffad7bf909232b0cd7df384ea74fd0724eef0e1a3e4e4e472e2c477ee20c36432a1aa4d0408a1131616c6a54b97494979884e9d9a4cc1575fed2239b92f090909e8baee65163bca445ac2ec74ef7d86f4e72bb0d878917692e70f9e723060369bbde4a0eb82b0b0302e5ebc44fffe03b05a9be4f0f5d7bb193c3899c4c444af7a376ddae415bcf98367bed3e9f4caf34b5c4ece7e060c18c4e38f8fa173e7ae6cdcb88d8b170b5154d9cbbc454444b06fdf615455101d1de94e3f72e43bcaca7e64e8d0a10821d034edee8dd76a7388ec06e97331c83bb53343b2770481be72d8b0612b172ffe2f0d0ec94b0e9d3b87f3cd37fba9afd7888a6a92c3d1a327a9aa2a65d8b0615ef5fa93c59d481442347bd9fd1267b3d9282cbc0140bf7e0ff0e4939349ead58b7e7dba633635dd121e16c6238f3c4a6a6a8a3bede6cddbe4e61e64c68c1900e8ba8ed3d9644a3a1cbaeb888c85f467c1d209b7ef6b2f79fee490d8a3170ff68ef3924358681863c7a6336448b23bede6cddb9c387194679ec970a77912f3fcf3cffb6dd373f8042eb3acaa2abaae7bb916bfc1c9a85169ac5bb789f8f8ae444686939060a7fe87cd545cdc43f8843fba6f33994c8485857addfbe9a79b98376f8edb37a8aa8a2449adf2673b33a447815771051e81d0d3f5844d47642c4c7a090e6e27b5f236fb80c776664815c1042dbaae377be3db23872d5b36f39bdfcc7775d1673c6bc0dfe0db13469aa669cde41730aa9c356b3abb771f2423e397949fde4897ca3d848c7f0fc5d4d4c1eef1b15ef7e4e59da57bf738424242703a9d7e1bf444205f278469677cda54bbbd474f709ef622c7f3088ded09da69b7d6a183c502e9d3e0e04e522b4b5b479e3f3cfbec0c76ed3ad06a392426261212121290904f3ffd94b973e70624d280a669e8badecc620524aea2a29291a3d36828caa3cba53fc2137f42682ac2ac40e3b450e9ed4a6c61a18485b8ec7dbf7e7dd8bb771f0e87c35d4fdb2247c93eeaf5d5503b14d40a70025a80a38e66845a2c903e050e7e4d6a6519fb80e93b33a4c2b690d75639ecdf7f004dd3bc047e271fe69b67a419160b086c2a2b2baba9ad55282baba4b4b49c31e9c350774c064b0d2857118e4244a77877f9db37afa02b95f4199c8e5353e8d44966fcf8f1e4e49c202c2c045d57e9d7af07515151ad16187a21e8152e32749fc357fbfce45b2c903e190efe9dd4ca724ee1d2bcd3c190d7117218376e1cbb761d2222220c703270601fa2a2a2dc8418da168830c3b719e7be0ae0a57f870ee51217174d4a4a6f06a73e447dd975421d27c0741e6a73c079d12b2c359914ba687fa3f8da251c0a5455d592981847dfbe0f327a741afdfba7909777b2451f1730af1544f9cbb79821fd09888b97ed20ed734de5b78c8e9243af5ebd193efc617af6eccbd1a3c75b6cd793444f577347e25455c5643223cb20498dd1a0a31642711d35eb41ca4773368d5f1455c16e3b80f5e6124acbeb70284eeaea1a703a9d5cba7495babafaa08213bf26a40d44f9cb979189eb6e45088b5d88c033359ec1c9dd9083a2285e1ab679f366bfcf6f9c1bfebf45e26a6a6ab87af532efbfbf961d3bb2b978e93ad6d028549b09a281f02a74d39f716a0e340d1c0aa8ce320447e96afb8cba4b1f515ee5a4b6b61e4d7372fb76159b366d2639b95faba3ca2669e29fac2089742a3237ae59f9fe1408216d1022b83edcba7583356b3eee30396cdebc85e4e47ecddaf14718e0652203c14d9c2449cc9a3593a95327101bdb8983fb77610a8da53ee2510807ba8008ed82a2eaa8aac0a180a2e888082016faaa6f71bb20879a3a27d5d575984c269292fa60b158da4e5cb064f9e6e9e0545da49d3c0e9ac60690e6cbb21254b3f3e6cd61eedc19f4ee1dc3f1dc7ded96c3030ff4f29a6817423067ce9c663e4e0881d3e9748fd9fc1d06dcb51989313131c4c4c4d0ad5b37f24ee633a2d7121aae7d8bad0f5033829a6a1587e336d5d555a8ea752c76a01684650c515d92c9bf5c04ba46616121b76e5d253e3e843e7dfa0078459b2da1aea404ab2a7b47943ed1a58c4016a219914e55e6c6152b278f81a6893f03f31f1e2171ea44f093dad1d1d1444747131717c777a7ce31ac1d72282ebe46626238bd7bf7f622c91746e8efef250f388ef3cd50558d9a8a4aaafa8dc512b50dcefe165b3f33f6a8f398cd7d4888fb0eb335072aa1b6280547ff6d5c3dfd2385970b3199ca18336638c9c9bf222222c25da7b1ac11c4aa4045de87efd823a2ad4da4786a5ae37f648c469f215a73f378c5cac95c706ada6959d6e6037c7fca46b0a6d2130e8742754539550fb65e0e66733963c70e2739791ae1e1e14053d4b865cb1666cf9e0d34cd2ef95b41090437712693c96ba47ef9f20d9e7e7a2267ce5c24a6dbafb03184b2efdec71ef337cc09a3a1e67fa8bf7213a779314a8f57d97d209ff8b808626234a033050505141414f86d54b4204149d2a6979ecf7fb5f48e3327a267ec80213dfb8c125079daad6965c556ce9e72912649da6340852cdbd03498f96543c0dafccd9c689a467efe259e7a6a42abe53069523af9f9798c1c39d278e680ed1aa4dd695a30288ddbbbf70053a63c8d2441dfbe496cd9f2df24f54a62d8a095dcae3c8b282802691452e779dcaa0b277bcbdfe999d49dd4d4019c3f7f8ca953a762369bd175dd2d108bc582aeeb2c5dba34bbb8b8f872604260fa0e91f3e54c4bcee40fb760559ff36b2ebf7e47ff3de6c825987091a6c894ddb272f230d4567b9066b2a1a9e28ea405c2eedd7b983871b2971c7af44ee2e1944072d845cfa438525307a0eb3ac78e9de1cc99ef193cf821c09bbcd9b367a3ebba7bb9abb531805fe2c2c343d8b7ef2003060c64edda8f090f97e9da1532d7e5f0d0e03144dafba3282a47fff22d3555579930611c172efcc0f6ede500c4c6c6fa35874b962cd9939999f92f0d0d0dc51b366c68b173791fbe4340734923119ea41d84da2a6fd29c9a862c375f0b0c06e1e1a1e4e41ca27fff643efef8bf888cb4a0392cac5d7f809441a33ce4b097daeaab3cf1443a05052e398c1b379acb97cf9192e29a0ef39cce32b4aca5c8d11341695c7afa38f2f24eb0614316cf3cf34bfaf7ef0fc0a04137c8cfbfc6d0c1432829a9e49b5d452c5dfa1fc8b2cc638f491c3d7a948282db343434b807a856ab6b5a68d1a2457bde7befbdf9353535d783f17592a4517a3e9fd280f98090d11c50fea39593fba1b64a3d2d49cec7808ad0701bb5d51a92a411ec5497e7ac05c0f8f18f70ecd871366f5ec7af7f3d95010306208460d0a0419c3953c8d0c13d2929a964cfee22de7efb4d64d93573949b9bcbba75993cfdf404860f1fee55bf6116b76fdf4e464646fb89f3c58811c3193162b8575a42423cfbf7e761b78770e1c2351e78a09b975d1e397224050505ee7188c562415114962e5dba67f9f2e5f3333333af071a78faa22561efcc90a82a2aa4ac7c3ca7f61fa1ae5a392d49ba8bb4081bb555ad23cde84f4d4d0db22cd3a95327cc6633696923494b1be9b5129e9090c0b7dfe6bae5909414e7b52a9e9696465a5a9abb7ca0e0a33d3b0002469581101e6e66e5ca3f71eb5609191993bc26408d73d72c8c09455178f7dd77f7ac58b1627e5151d1751f5f477171719b3b0e6c70545c7df5d0dacfec92a49d86f691064d2f92c3e14051144c26d766205996ddff0622222cac5c994971b14b0e060c9f6e9842cfb19aa78c67cd9ad5aabe053d1c088469d3a606acd878305996a9abab63e5ca957b56ad5a355f0871ddb3ec92254bc8cccc6c55c77d317d8728dc9921758919f838a3a740f9b9239ccc81da2a154972b69a34dfe730846f987ccf41b02ccbfce21713dd323366f10dd2fc5992f66efe0d38e565369b3be400d72ea8575e7965c3aa55ab5eacafafbfded0d0e08e30df7cf34dde7efbed0edbcae032973d38b91feaaa953693e6cf8cf9ce58782e0eabaa8aa228288a82a6696e0df377af3fd2b66ddbd686a76d825be3eaebebdb254ccf0ebef6da6b6bb2b3b3ffbdb4b4b44151144f5fc7f2e5cb3b74ff89a3e22a87d67e86246980de664d332049925ba8cf3df71c005bb76ef5ba6e293fd8ebd668a16f59e96e7cf4b170e1c2ce999999d5d3a64dc366b301f0eebbefb262c50a2fd27cb7b9dd0f187d983c79f23b3b76ec78539224bf5b09ef372449a273e7ce2c5bb62c7bf1e2c573cc0b172e948410646565b160c102f7f2437b1a98376f1e1b376ef4f475ac5ab5ea9e9154121d4d6c69a081c49d21cbf2dddbd8e481400ba4069a6958e3b5d137b39168040b66b3b9ddc419fea2a4a484c58b17f3c5175ff8edcc3f33645946d3341c0e4750f23648d6755d0624b37153565616d0e1be8eececec7b6e0edba26dc6cbd6e625a856429665aaaaaa3877ee1c56abd53dce332259df0db02693899090100a0b0beb01cd6b006e90d751b81fa4b517f7923887c34174743483070f769b4e7ff2926519555559bd7af5f91d3b767c0054bb89bb1b1f37decb0f263dd11e1f772f2184409665ac56abd7e2a92f545565e3c68d17962d5bf63b87c371005f8dfb67474b014347c268c330d19edbf0dc0148e3b878cd9a353fbcf5d65b2f3b1c8e7d42085d92a4e03fb3fa29a13dda76af89337c9be78e2e5dd7b15aad343434f0c1071f9c5fba74e9ef1c0ec77e219a3e2cff5912d716b466f5b92360f8332320f124ce6c36535757c7faf5eb2f2c5ab4c820cd6b70795f3f25be5b28898ebedf5d080a9ec419e4812b82fce8a38f2ebcfefaebbf6d348fcd6604fe5fe37c702f4da5a7d6699a86c562c1e974f2f9e79fdf5cbd7af56287c371c8d33c7ae26749dc4fc5c719ed18df0fcab2cc975f7e59fcf2cb2fff6b7d7dfd2e2144c06d713f4be2da83fb419c2ccb288ac2279f7cf2c39a356b7edf1269f03325eea7328e03dc0bce5bb76e2d688c1e0fb5441adc07e28cc0c110ecddba6e2d244992434343dd03e27b81b0b030cacacad8b871e30f8b162d7ad9e170e408219c2ddf791f88f3d584bb7d1d2c144569c8ceceae976559ba1743035996a9a9a9e1d0a14317d6af5fff5a63c81f146900d24f6d2eb1a3e1e1cfecb83e4fb601f74a281250015c0682fbb0a111ff075b8fc771a1b0847a0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d494844520000006e0000002e0806000000c9032c970000154149444154789ced9b797014d79dc73fdd3df7a19991348390408045c469a4981b1b13c026ae0427c626c956eda61cb27f381b672b9baaddd42665cc5249586fd965c7760ec9a9d8e0d871126393908a8d09e6306064c020620e21400c022124746b46337dbefd6334c38c90401cb6e38abf552df5bc7efddeebf77dbfb35f4b555555828f183ff8c10f4a3b3b3bcf0208f191779f0349920058ba74e97ddffce637efefebeb4d0d4880b02c90012b55d7a27fac56aac01202a4545db010d9f5d23f520508ac5433a2ff4f76597f9dcc7d16a0f4979ba91aa60024453e7ab46e4f757575950de0a1871eba8953716554575763b7db4b841067d393f6714308c1030f3c70fbd2a55ffcbaddeeb8de56b2fe0f754e3fa1e9739159b822fbdc4aaf1d81b044eabf10b8dc41fef7b1ff2b065eb65dd3d0fa1b174260f5afba81e7831de96b81400000499244757535a150e85abaff50a14842bd11e11782ac67cd2ecbbd9efa2df5d795b2ee9306d421ab0c4cd3c2ee14481826e090af7fa8370ebbddfe7176ffc9844889f135495c7777378601922463b3d93873a69148244830180440d7753ef8a00eb7db85cd26535090df7f3e7837baaedff073fca362d8c40921686dbd4869e9185cae941db02c839e9e9e0c713535fb58b26471e69ea6a676b66eddcedd772fcea8d36cdc88c46d582e5502db8020b01658b16cfdf5ebbacb47f7f78d215565b6ed4a439224b2bd40c3b0325ed9debdfb59b0e07339f5376edcc0e4c913fbeb1a97f57183cec97d81b195c139dfdf80dd1bfc06f0c286e5d7df9e617c78d4f5f6f6a169faa08bf75aa19ba9ff434adceedd7bd034c8cb73327dfa6d08215014055d3770bb9d000861e1f57a3975aa8129536ec5e95432f76fdcb8894993c6535252826559396af166a948bb37c8c85b0e31ffeb5dec5ccb37f4246c582edd90e45d0fb217732cd6475b5b179aa6e376bbb02c8b4442c56e87c2c2104ea713594ec98ba6e9ecdf7f0cbfdf4b3299c4e773130e07f1f93c993ae9b64dd3cce97350e2b66fdfc1d4a99fa5b0308ffafab3ac5bf77be6cd9b8525941cf5e6f7fbd9b66d3753a64ca6a02090297ff7ddf7e9e8b8c08205cb10426018c68717afc5b7131801f3ff0576bec437f424951b964b0b81ae8f92c0f4f3e9ba4e414190bc3c6fe65a47470fc78e1dc3e9b461b7db339ae6f0e10666cf9e86d7eb02e0c28576dadabaa9a9394a45c52d8c185198697be0621f5455ba5c2ea2d1f30094978fe6eebbefa174dc38cacb4662532edde2f37ab9f3cecf5159392553d6dcdc464dcd4eeebfff7e002ccbc234cdcc0abae9b05247200cf3bf06762719db7723aaf35a910e7d4cd3c2b22e5f30f1781c555533049f3c7996d2d29119d2008a8a0a0885fc184692eeee0e20654e743da566b34dcba0123767ce6c7efdeb17292e8e1008f82829099238fe125d27b7e05bfc8bcc6d8aa2e0f57a72eefdcd6f5ee4c107ff396323755d4792a46bb2671b964b9f03be4bcaf1180a63814b31ae4891f7f96fc2ce57a9ec6e631bb070c3726958926759d6756985ec5835fdfb52d09d2ebbd4b61082aeae5e34cd64d4a8484e3d55d578fbed3de4e7cb39fe84611897cddf9036eeab5f5dc65b6fed64f9f22fd059bb8e50f716dc0bd6a02997881a591cceb967dfbea38c1c5984dbedc634cd413bccc650b64e086543f1ec7b83c13163c1accd2127fbf084c782519b913a2cb0db61fe7db0730395ddedd746de7071faf479eaea4e138904993cf9961cf5971b40a790ed93e8bac1b16351162e9c99f5bc00828d1bb7e1f3598442051416a6d4a4611858967599c61a92b8aeae6e66cd9d4db2691fa153bf80bb7e893074844d83feb4507b5b372eaf07af3b65f7cacbcbd8ba751baaaa66dab93ecf510acef9afa720fe59d0bbc0048c218e3e2e23d46e87f94b61e79fa9ecee601bb06cc372297a33c86b68680260d1a299ecd9f301afbcb289850ba7337264049bcd4667672f91c8c0b49940557584101c3c788239736ebd74a59fe8b7dfde871071f2f3f3894422f87cbe8c6d4bcf61f65ce6d0d8ddddcbf9f3ed1c3edc4043430b23471660edfe36c83da0352262b588ace4695bf3191a8fd6a0e9904868389d320b162c60fbf6fdecdb7784f7deaba5b3b3f39a5525005614acae1419d68063a0f40d72dd6e87f9f7402044257010a8bc1936eff0e1939494847138ec2c58701bf3e74fe70f7fd8caae5d07397cf8d4a0c90621c0e1f070e8d019cacbc7e0f5bafbcb536af6e8d1d3343737120af9894422040201ec767bc6a91b6cfe7288dbb5ab86a2a202a64cb9856995b792e8388747dd0f4a1dc4b7837932c72d55148d90f1175acf9e42d5a0a727cea851458c1fff19e6ce9dcd840953d8b7efc055891bf2da351035d875bb0de6df0545c57210a46da954fe8da1a0208f9a9a2399df858521962c99c3fcf9d3a9a828efb74db9f15ada568d193392d1a347f4dbffd4d1dadac9c183870887bd84c36142a1100e8723c7d45c91385dd751141bb20c92d4ef0daa71f0903a622f807404c3bc14486bba46d0f50e8ee655b477f6a16a267d7d494cd3e4d4a946fafa12c3724e06750aae83a8c1aecbc8148d7420843d28c4d0999ae13a27b7dd3691fdfb3fa0b1f1025d5d31baba7aa8ac9c4047470f275ffd1ad21bf730589cadeb3073e694ace47b2abedbb2e55df2f2140a0a0a282828c0e572653c49e0eac4c562311a1b1bf8e94f9f63fdfacd9c3c750e87271fdda54001e0ebc152fe8869a81806a81ae86607823d445c2fd377eae774f698c4e3090cc3a4adad87175f7c894993caaf4f55c2d0640d93485393397fd6c1df0e8210d25a216e5ce29c4e270b174ee7f5d7b7d2d4d4cad8b1c51cfb5b2dd6efa730deefc07fdf1f19e85586427e962c999b1532080cc362e3c61db85c060505f984c3617c3e1fb22ca3eb7a46450e850c719224f1d5af3ec0bdf72e261c76b273c726144f9884ff73e00342203c2134dd42d705aa069a6621fc4018c6eb8fd056bf9d589f496f6f1f8aa2505a5a96f1b8ae8bb8e19235f09a05a69e22edc05e300cd682b44296b56b1fc3004892c4e4c96594978f66ca945b387daa8150ed7f503cf7df61d1cf11b2eb32afd26eb761b7dbb0ac14699665d2d5d54b6beb455a5a7ac9cbcbc3ebf522cb32a6696662b6c18e346cd90302282c2ca4b0b090112346b0efc011668e5b45f2ecdbb8ca80d84c62bd3aaada466f6f0fba7e0e7b108883b0cf233f3489230d4d601944a3515a5a1a292e765356560690e36d5e0d7d172fe2d0e55c8f72807729239085b88c485397397fc6c181f7c030c41f8115b7cd9438b8ffe6bc468ac51254544c2099d4481efe35e312e760dc17a1bb0111d720303e535708c1c58b5df4f4c4282d2dea4f4808dc6e27b7dd36852d5bf6108f27b02c2be3fa0fb6c8878ce3065ed075835857373de5b763cfff3d1cfd36ae721bc1fc3a6cb6324a8adec7e6d80edd106f9a823ae1f734d65e20da1045513a98376f0693267d19bfdf9f69535152b9cc61bc15e8daf7b31f07fd058e4ba4644b5affff40a141598571b97a3ce3e0400d9886512bcbc60a80bf1d7471a3aa5208414b4b3bcdcd6d54549473fce04e269daf8611b320d690da6e909411796599d8ccb204c9a4ca3b3bdee3fe07eec16653300c13d3b49830612c0d0de73870e00489844924924f4141004551aeaaa132c4298a9213a937349ce74b5f5ac2a14327291cf1655c54d0f1fe4f0916fe055bc95c881d2671a619d3f628da98eff2d63b47282ef25358680079d4d7d7535f5f3fd4045c715492642c6baf3bf2ddf62b664ec4d8f0c48ab165730474d76624ada3d5c1d18329d224c9580874c9b20bc380075e4f0ed9da50ce89ae1b1c39728ae6e68bb4b474e0f57a282a2a484d6ce36fa0b3038a7b403d033610ba3bd3961016a669611826e3020d6cddb293858befe827ce44d70de6ce9dc65b6fd5609a360e1d8ad2d6d6452492c71d77dc8ac77329d9312c89dbbaf51d962efd129204e3c797f2dbdfbe41e9b852a64f7d82b6eea388fa2690e620e53d484b9f8fcdbf7d93b1a523a9ac9c485ddd7bdc7befbdd86c362ccbca3c84dd6ec7b22c56af5ebdb9b5b5b5e14ac42d5b2fb6bffe807dfb3d3ffb2d0efd9f0655977ffeb1f53fd802ab504891a6c974b43838b01be2bd59a4292e0c5d5c91b42ba1a3a31b97cbc1a245b37038529ae2fdf78f01201adf49d9ff9e0360cc00c012a17e5b662184d5af022dfcce0b947863d4d6869930610c8691224e089832a58c8e8e1eeeba6b168661b2756b0d6d6d6d9496960e39ae4189f3f9dc6cdbb693891327f3dc73bfc2e7938944a0ead7dbb975da3c02c109689ace9e3fbd4daca791c58befe0c489e3bcfa6a2700e170785075b86ad5aa2d555555ff9a4c265bd7ae5d7bd549dbf7b31f33a4baa49f886cd27642bc279734d33090e5cbdf050e17ba6ee0f77b33a4c1a5fd237629095ec09584f657a1682ea0f62f5813cb4a798fa6698068a73cd2c8b1fd161de115381c0e745def6fdf43347a9ebaba28e3c615a3aa0962b1580e27c392b8f9f3ef60dfbefdac5d5bcd57bef205264c9800c0d4a9e73972e42c9f9d56c1c58bddfc755313ab57ff10599659b85062cf9e3dd4d7b7914c263381bac3914affac5cb972cb9a356b56c462b173c3b1759264d05e7784f621af0342c650a1f38283033b20dea3d74a92b910e8f2f85cc47b0d24c960b8a9aeb4bb9e3d17866170f8f069dadb7b2829091308f8323196092989f3034a33a86f20a4b91886d94f58ca96e9ba8910a7207188cf8fd8c8baed6398b76011baaea3693aaaaa535a3a929a9a0f3870e018f1782fe5e545c3236e2066ce9cc1cc993372ca4a4a8ad9b1631fc1a09b1327ce327af4889ce4e7ac59b3a8afafcfc42176bb1d4dd358bd7af596c71e7b6c455555d5b9975e7a2967a286c2d5267bc372899ea6281d9d0b38b8e35dfa7ab55a49b252a4f95dc47bae8db4f47862b118b22ce3743ab1d96c8c1a358296968becdd7b8053a79a48262deebcf3368400dd3f013c6753090a3fe04b226227310c0b5d37fadf8e182995289f01571c5700ee8eac66776d316565a35155ad9f3c8dd1a38b387ab49e193346e3743aaf38d621bdcaa1e0f3d978e2895fd2d27291e5cb3f9f93004d9fa7b2300a9aa6f1939ffc64cbe38f3fbea2a9a9e9dc005b476b6bebb0277510ac55bb1abfbbebb997839264d4c28d9106971692aaaa689a86a228c8b2ccf8f1a3894402cc9e3d894422c1e9d3eda8aa86145e8c2eb660f792923c1f08358069a6c84aa7ad745d47764aa93a26dc12394fedfb3fe382f7fb389d2995994c6ae8ba4e7e7e8868b483f1e3c75fbbaabc12eebbefde41cb2549ca489f2ccbf4f5f5f1c4134f6c79f2c927570821ce65d75db56a15555555c3ea6f282c5b2fa21b964ba1c2c98b98bb143a8fbdcb81ed10efd19124f39a491bf81ca90c879951f93e9f0fa7d389699ac4e32667cfb65072fbc39c5dff14b78c6b053760cf03a9045d33d1753de380689a8ec3e64bd55101274c0eaabc113d47696909aaaa914caa24931af17882e6e6362a2bbb183d7a74ceb8b29121ce66b3ddd0f6024992329b612e5ebcc8a38f3ebaf6b5d75e7b249148342593c96c5bc79a356bae9ad2192e06a84b24c9ba2ed206db189586a22828caa56d1b93268d63f7eec32c59328fbecf3c4b4fe3d7c88b48a0e423a40867cfb6108d9ea7a7bb1387a31b35719cb99536b02b6037397fc28967f61aa69e879a9a0f70b91cc46271ec764138ec63dab4a9b8dd578e7533c42512891b262efdb0dffbdef79edebc79f37fb7b7b727354dcbb6753cf6d8633775ff89dad5c8aee75e46920ce0fa48cbc670d27389848e65a5c2823973be4c74cb4a8c236bc89fee62444441b30e533062066ea70f97bd15cce65428a3cbb41eb3a14dde80e519454dcd9b4812381c0633668cc2e7f3e1f57af1783cf8fdfeababcaeaeaea1b7ad881d8bc79f3caaaaaaae4005bc7e38f3f7e5349fba87773413a208f72c71d951c3f1ee5fdf7ebf8eca21f12dd5bc1c53ffc276316b732fe9638d862a91b8c38584962d15e5a8f4ec236b90ad3338a975f7a83b2b252c2e1207bf71e22180c52545484cfe7c3e1700cb989380ddbb7bef52d4908417575350f3df4109aa6ddb0e43df8e083ac5bb72edbd6f1e4934f7eec5fe60c07b22c5f7163d3c993e7282d1d4928e467f6eca9ecde7d88b7dedac3bc790b51a61e205af322e6aefdb8f38ee00a87e96bacc73083d84b7e8cf3f6bb696ebec89b1b52a4cd993315d3141c3f7e86baba26c68e1d8bdfef4796e5cb242cfd3b3d365bba30ed2c7c08b68ed75e7b2da7f34f2ababa7a89c5542a2a2666623e97cbc9a64dbb3975aa91a9533fc3b8cfdc47b8e01b5896891002dfb8d4a6a933679a39f0a7ed44a38d949414535e3e3af3a6e0f6db2b79fef9d799366d5c7f9baecbfa4eab70cbb26440b2a5494aabcb9b6cebd8bc79f32742d2d28bed4a362e10f0a169492e5ce8c0eff7b07efd5f696838cdd4a9c5141515d0d6769ea347eb89c7351c0e278a22d1dd1da7bbbb07b75ba1ac2cc25d77dd8aaec3b66dfb2829194138ace0703858b66c16bdbdbd747575e578b369288a82dbed261a8d26002347917e08b6ee13415a36ae449c2ccb4c9f3e814d9bdee5f8f1b31417fb59b4e85682c120a15088f2723badad1d3435f5306fde342ccb4255759e79e6156ebfbd9cc2c242f2f3f3713a9d8c19338a37dfdccdc489d399366d5ac6cb1e6cbed22f579f7aeaa9baf5ebd73f0bf46688fb303e6efc283f98fc282049126eb79bc58b67525131ae7fdbb88f502884d7eb4551140281007bf7fe359364eee8e8c1b2343c1e0f914884c2c2421445213f3f9f050b2a90651987c391f3f27420745d67ddba75277ef4a31f7d4755d577182871ffe8186a4755366c361b81400097cb856118381c0e1c0e47c66970b95cc8f2a5d744a74f9f2714f2e076bbf17abd9978d6e17010080488c7e30039dbf0320e48bf67f9f4d34f1f7fe491471e5655759b10c2922469f89f59fda36038719ccd661bd25d972489bc3c2f7bf71e2114f2535f1f251209e0f1787236ce4a9284a22899ad0ad93bba2ccbc2e170904c2679f6d967eb56af5efd1d55557788aced631feb17a97f4fb8199f40a5b178f10cfc7e85d6d67394947899366d3c7ebf3f236d70e993b5f4b7158661640e21047d7d7dfcea57bf3ab172e5caefc4e3f11d42889c77539f4adc8780fcfc2077de39fbaaf5b2894b7b9176bb1d455178e699674eac5ab5eadb69f538f0de4f891b80ebde91769dfda4c9330c03bbdd8e699abcf2ca2bcd4f3df5d4a3aaaaee1a8c34f894b8cbf051130764d4a32ccbbcfefaebad0f3ffcf0bf2512894d428821b7c57d4adc007c1cc4c9b28ca6693cfffcf3c79f7efae9ffb91a69f029711f3bd249f8dffdee77f5fddee3aeab91069f1297812449b2c7e3c904c41f05bc5e2f1d1d1dac5bb7eef8ca952b1f565575bb10c2bcfa9d9f129781a669c9cd9b37276459966e66683014645926168bb16bd7ae132fbcf0c2f7fae3b4619106207dd27289371b59f62c48eaf3641703bfdaf810bb07ba8006e09a3e6cf87fd8857d4933e0288e0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + intWidth + intHeight + intWidthPercent + intHeightPercent + chkConstrain + radioScale + + + + knuminput.h + +
diff --git a/chalk/plugins/viewplugins/imagesize/wdg_layersize.ui b/chalk/plugins/viewplugins/imagesize/wdg_layersize.ui new file mode 100644 index 00000000..fb7547d2 --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/wdg_layersize.ui @@ -0,0 +1,234 @@ + +WdgLayerSize + + + WdgLayerSize + + + + 0 + 0 + 391 + 224 + + + + Image Size + + + + unnamed + + + 0 + + + + grpPixelDimensions + + + &Pixel Dimensions + + + + unnamed + + + + lblWidth + + + &Width: + + + intWidth + + + + + intHeight + + + 0 + + + + + textLabel2 + + + &Height: + + + intHeight + + + + + lblWidthOriginal + + + WinPanel + + + Sunken + + + + + + AlignVCenter|AlignRight + + + + + lblHeightOriginal + + + WinPanel + + + Sunken + + + + + + AlignVCenter|AlignRight + + + + + lblOrignal + + + Original: + + + + + lblNew + + + &New: + + + intWidth + + + + + intWidth + + + 0 + + + + + intWidthPercent + + + 100 + + + 0 + + + 100 + + + % + + + + + intHeightPercent + + + 100 + + + 0 + + + % + + + + + lblPercent + + + &Percent: + + + intWidthPercent + + + + + chkConstrain + + + &Constrain proportions + + + true + + + + + + + lblFilterType + + + &Filter: + + + cmbFilterType + + + + + cmbFilterType + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + intWidth + intHeight + intWidthPercent + intHeightPercent + chkConstrain + + + + knuminput.h + +
diff --git a/chalk/plugins/viewplugins/imagesize/wdg_resolution.ui b/chalk/plugins/viewplugins/imagesize/wdg_resolution.ui new file mode 100644 index 00000000..df0e010d --- /dev/null +++ b/chalk/plugins/viewplugins/imagesize/wdg_resolution.ui @@ -0,0 +1,152 @@ + +WdgResolution + + + WdgResolution + + + + 0 + 0 + 487 + 265 + + + + Image Resolution + + + + unnamed + + + + grpSize + + + Print Size + + + + unnamed + + + + lblHeight + + + Height: + + + + + lblWidth + + + Width: + + + + + intWidth + + + " + + + + + intHeight + + + " + + + + + + + grpResolution + + + Image Resolution + + + + unnamed + + + + lblScreen + + + Screen resolution: + + + + + lblScreenResolution + + + Panel + + + Sunken + + + 100 + + + AlignVCenter|AlignRight + + + + + lblYResolution + + + Image Y resolution: + + + + + lblImageXRes + + + Image X resolution: + + + + + intXRes + + + dpi + + + + + intYRes + + + dpi + + + + + + + + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/viewplugins/modify_selection/Makefile.am b/chalk/plugins/viewplugins/modify_selection/Makefile.am new file mode 100644 index 00000000..6e0f14c5 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/Makefile.am @@ -0,0 +1,27 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = modify_selection.rc +EXTRA_DIST = $(chalkrc_DATA) + +kde_services_DATA = chalkmodifyselection.desktop + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkmodifyselection_la_SOURCES = wdg_grow_selection.ui wdg_shrink_selection.ui wdg_border_selection.ui \ +dlg_grow_selection.cc dlg_shrink_selection.cc dlg_border_selection.cc modify_selection.cc + +noinst_HEADERS = wdg_grow_selection.h wdg_shrink_selection.h wdg_border_selection.h dlg_grow_selection.h \ +dlg_shrink_selection.h dlg_border_selection.h modify_selection.h + +kde_module_LTLIBRARIES = chalkmodifyselection.la + +chalkmodifyselection_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkmodifyselection_la_LIBADD = ../../../libchalkcommon.la + +chalkmodifyselection_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/modify_selection/chalkmodifyselection.desktop b/chalk/plugins/viewplugins/modify_selection/chalkmodifyselection.desktop new file mode 100644 index 00000000..aa4a9d58 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/chalkmodifyselection.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Modify Selection +Name[bg]=Промяна на маркираното +Name[br]=Kemmañ an dibab +Name[ca]=Selecció de modificació +Name[da]=Ændr markering +Name[de]=Auswahl verändern +Name[el]=Τροποποίηση επιλογής +Name[eo]=Modifi elekton +Name[es]=Modificar selección +Name[et]=Valiku muutmine +Name[fa]=تغییر گزینش +Name[fr]=Modifier la sélection +Name[fy]=Seleksje oanpasse +Name[ga]=Athraigh an Roghnúchán +Name[gl]=Modificación da Selección +Name[hu]=A kijelölés módosítása +Name[it]=Modifica la selezione +Name[ja]=選択領域を変更 +Name[km]=កែប្រែ​ការ​ជ្រើស +Name[lv]=Mainīt izvēli +Name[nb]=Endre utvalg +Name[nds]=Utwahl ännern +Name[ne]=चयन परिमार्जन गर्नुहोस् +Name[nl]=Selectie aanpassen +Name[pl]=Zmiana wyboru +Name[pt]=Modificar a Selecção +Name[pt_BR]=Modificar a Seleção +Name[ru]=Выделение +Name[sk]=Zmeniť výber +Name[sl]=Spremeni izbiro +Name[sr]=Измена избора +Name[sr@Latn]=Izmena izbora +Name[sv]=Ändra markering +Name[uk]=Зміна виділення +Name[zh_TW]=變更選取 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkmodifyselection +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.cc b/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.cc new file mode 100644 index 00000000..dcda5c7e --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.cc @@ -0,0 +1,76 @@ +/* + * dlg_border_selection.cc - part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_border_selection.h" +#include "wdg_border_selection.h" + +DlgBorderSelection::DlgBorderSelection( TQWidget * tqparent, const char * name) : super (tqparent, name, true, i18n("Border Selection"), Ok | Cancel, Ok) +{ + m_page = new WdgBorderSelection(this, "border_selection"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), this, TQT_SLOT(okClicked())); +} + +DlgBorderSelection::~DlgBorderSelection() +{ + delete m_page; +} + +TQ_INT32 DlgBorderSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +TQ_INT32 DlgBorderSelection::yradius() +{ + return m_page->radiusSpinBox->value(); +} + + +// SLOTS + +void DlgBorderSelection::okClicked() +{ + accept(); +} + +#include "dlg_border_selection.moc" diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.h b/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.h new file mode 100644 index 00000000..472f01ef --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_border_selection.h @@ -0,0 +1,49 @@ +/* + * dlg_border_selection.h -- part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_BORDER_SELECTION_H +#define DLG_BORDER_SELECTION_H + +#include + +class WdgBorderSelection; + +class DlgBorderSelection: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgBorderSelection(TQWidget * tqparent = 0, const char* name = 0); + ~DlgBorderSelection(); + + TQ_INT32 xradius(); + TQ_INT32 yradius(); + +private slots: + + void okClicked(); + +private: + + WdgBorderSelection * m_page; +}; + +#endif // DLG_BORDER_SELECTION_H diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.cc b/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.cc new file mode 100644 index 00000000..b889ccde --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.cc @@ -0,0 +1,76 @@ +/* + * dlg_grow_selection.cc - part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_grow_selection.h" +#include "wdg_grow_selection.h" + +DlgGrowSelection::DlgGrowSelection( TQWidget * tqparent, const char * name) : super (tqparent, name, true, i18n("Grow Selection"), Ok | Cancel, Ok) +{ + m_page = new WdgGrowSelection(this, "grow_selection"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), this, TQT_SLOT(okClicked())); +} + +DlgGrowSelection::~DlgGrowSelection() +{ + delete m_page; +} + +TQ_INT32 DlgGrowSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +TQ_INT32 DlgGrowSelection::yradius() +{ + return m_page->radiusSpinBox->value(); +} + + +// SLOTS + +void DlgGrowSelection::okClicked() +{ + accept(); +} + +#include "dlg_grow_selection.moc" diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.h b/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.h new file mode 100644 index 00000000..61785b20 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_grow_selection.h @@ -0,0 +1,49 @@ +/* + * dlg_grow_selection.h -- part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_GROW_SELECTION_H +#define DLG_GROW_SELECTION_H + +#include + +class WdgGrowSelection; + +class DlgGrowSelection: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgGrowSelection(TQWidget * tqparent = 0, const char* name = 0); + ~DlgGrowSelection(); + + TQ_INT32 xradius(); + TQ_INT32 yradius(); + +private slots: + + void okClicked(); + +private: + + WdgGrowSelection * m_page; +}; + +#endif // DLG_GROW_SELECTION_H diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc b/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc new file mode 100644 index 00000000..eb50c6cf --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.cc @@ -0,0 +1,81 @@ +/* + * dlg_shrink_selection.cc - part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_shrink_selection.h" +#include "wdg_shrink_selection.h" + +DlgShrinkSelection::DlgShrinkSelection( TQWidget * tqparent, const char * name) : super (tqparent, name, true, i18n("Shrink Selection"), Ok | Cancel, Ok) +{ + m_page = new WdgShrinkSelection(this, "shrink_selection"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), this, TQT_SLOT(okClicked())); +} + +DlgShrinkSelection::~DlgShrinkSelection() +{ + delete m_page; +} + +TQ_INT32 DlgShrinkSelection::xradius() +{ + return m_page->radiusSpinBox->value(); +} + +TQ_INT32 DlgShrinkSelection::yradius() +{ + return m_page->radiusSpinBox->value(); +} + +bool DlgShrinkSelection::shrinkFromImageBorder() +{ + return m_page->shrinkFromImageBorderCheckBox->isChecked(); +} + + +// SLOTS + +void DlgShrinkSelection::okClicked() +{ + accept(); +} + +#include "dlg_shrink_selection.moc" diff --git a/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.h b/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.h new file mode 100644 index 00000000..53ce386b --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/dlg_shrink_selection.h @@ -0,0 +1,50 @@ +/* + * dlg_shrink_selection.h -- part of Chalk + * + * Copyright (c) 2006 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_SHRINK_SELECTION_H +#define DLG_SHRINK_SELECTION_H + +#include + +class WdgShrinkSelection; + +class DlgShrinkSelection: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgShrinkSelection(TQWidget * tqparent = 0, const char* name = 0); + ~DlgShrinkSelection(); + + TQ_INT32 xradius(); + TQ_INT32 yradius(); + bool shrinkFromImageBorder(); + +private slots: + + void okClicked(); + +private: + + WdgShrinkSelection * m_page; +}; + +#endif // DLG_SHRINK_SELECTION_H diff --git a/chalk/plugins/viewplugins/modify_selection/modify_selection.cc b/chalk/plugins/viewplugins/modify_selection/modify_selection.cc new file mode 100644 index 00000000..78a75778 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/modify_selection.cc @@ -0,0 +1,158 @@ +/* + * modify_selection.cc -- Part of Chalk + * + * Copyright (c) 2006 Michael Thaler (michael.thaler@physik.tu-muenchen.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "modify_selection.h" +#include "dlg_grow_selection.h" +#include "dlg_shrink_selection.h" +#include "dlg_border_selection.h" + +typedef KGenericFactory ModifySelectionFactory; +K_EXPORT_COMPONENT_FACTORY( chalkmodifyselection, ModifySelectionFactory( "chalk" ) ) + +ModifySelection::ModifySelection(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + if ( tqparent->inherits("KisView") ) + { + setInstance(ModifySelectionFactory::instance()); + setXMLFile(locate("data","chalkplugins/modify_selection.rc"), true); + + m_view = (KisView*) tqparent; + + // Selection manager takes ownership? + KAction* a = new KAction(i18n("Grow Selection..."), 0, 0, this, TQT_SLOT(slotGrowSelection()), actionCollection(), "growselection"); + KAction* b = new KAction(i18n("Shrink Selection..."), 0, 0, this, TQT_SLOT(slotShrinkSelection()), actionCollection(), "shrinkselection"); + KAction* c = new KAction(i18n("Border Selection..."), 0, 0, this, TQT_SLOT(slotBorderSelection()), actionCollection(), "borderselection"); + + Q_CHECK_PTR(a); + Q_CHECK_PTR(b); + Q_CHECK_PTR(c); + + m_view ->canvasSubject()-> selectionManager()->addSelectionAction(a); + m_view ->canvasSubject()-> selectionManager()->addSelectionAction(b); + m_view ->canvasSubject()-> selectionManager()->addSelectionAction(c); + } +} + +ModifySelection::~ModifySelection() +{ + m_view = 0; +} + +void ModifySelection::slotGrowSelection() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgGrowSelection * dlgGrowSelection = new DlgGrowSelection(m_view, "GrowSelection"); + Q_CHECK_PTR(dlgGrowSelection); + + dlgGrowSelection->setCaption(i18n("Grow Selection")); + + KisConfig cfg; + + if (dlgGrowSelection->exec() == TQDialog::Accepted) { + TQ_INT32 xradius = dlgGrowSelection->xradius(); + TQ_INT32 yradius = dlgGrowSelection->yradius(); + + m_view ->canvasSubject()-> selectionManager()->grow(xradius, yradius); + } + + delete dlgGrowSelection; +} + +void ModifySelection::slotShrinkSelection() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgShrinkSelection * dlgShrinkSelection = new DlgShrinkSelection(m_view, "ShrinkSelection"); + Q_CHECK_PTR(dlgShrinkSelection); + + dlgShrinkSelection->setCaption(i18n("Shrink Selection")); + + KisConfig cfg; + + if (dlgShrinkSelection->exec() == TQDialog::Accepted) { + TQ_INT32 xradius = dlgShrinkSelection->xradius(); + TQ_INT32 yradius = dlgShrinkSelection->yradius(); + bool shrinkFromImageBorder = dlgShrinkSelection->shrinkFromImageBorder(); + + m_view ->canvasSubject()-> selectionManager()->shrink(xradius, yradius, shrinkFromImageBorder); + } + + delete dlgShrinkSelection; +} + +void ModifySelection::slotBorderSelection() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgBorderSelection * dlgBorderSelection = new DlgBorderSelection(m_view, "BorderSelection"); + Q_CHECK_PTR(dlgBorderSelection); + + dlgBorderSelection->setCaption(i18n("Border Selection")); + + KisConfig cfg; + + if (dlgBorderSelection->exec() == TQDialog::Accepted) { + TQ_INT32 xradius = dlgBorderSelection->xradius(); + TQ_INT32 yradius = dlgBorderSelection->yradius(); + + m_view ->canvasSubject()-> selectionManager()->border(xradius, yradius); + } + + delete dlgBorderSelection; +} + +#include "modify_selection.moc" diff --git a/chalk/plugins/viewplugins/modify_selection/modify_selection.h b/chalk/plugins/viewplugins/modify_selection/modify_selection.h new file mode 100644 index 00000000..db5dd1b7 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/modify_selection.h @@ -0,0 +1,47 @@ +/* + * modify_selection.h -- Part of Chalk + * + * Copyright (c) 2006 Michael Thaler (michael.thaler@physik.tu-muenchen.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef MODIFY_SELECTION_H +#define MODIFY_SELECTION_H + +#include + +class KisView; + +class ModifySelection : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ModifySelection(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ModifySelection(); + +private slots: + + void slotGrowSelection(); + void slotShrinkSelection(); + void slotBorderSelection(); + +private: + + KisView * m_view; + +}; + +#endif // MODIFY_SELECTION_H diff --git a/chalk/plugins/viewplugins/modify_selection/modify_selection.rc b/chalk/plugins/viewplugins/modify_selection/modify_selection.rc new file mode 100644 index 00000000..999aaaaa --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/modify_selection.rc @@ -0,0 +1,10 @@ + + + + &Select + + + + + + diff --git a/chalk/plugins/viewplugins/modify_selection/wdg_border_selection.ui b/chalk/plugins/viewplugins/modify_selection/wdg_border_selection.ui new file mode 100644 index 00000000..06d01e9f --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/wdg_border_selection.ui @@ -0,0 +1,57 @@ + +WdgBorderSelection + + + WdgBorderSelection + + + + 0 + 0 + 255 + 101 + + + + + unnamed + + + + textLabel1 + + + Border selection by + + + + + radiusSpinBox + + + 10000 + + + 1 + + + 1 + + + + + + pixels + + + + comboBox1 + + + + + + radiusSpinBox + + + diff --git a/chalk/plugins/viewplugins/modify_selection/wdg_grow_selection.ui b/chalk/plugins/viewplugins/modify_selection/wdg_grow_selection.ui new file mode 100644 index 00000000..d1180803 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/wdg_grow_selection.ui @@ -0,0 +1,57 @@ + +WdgGrowSelection + + + WdgGrowSelection + + + + 0 + 0 + 255 + 101 + + + + + unnamed + + + + textLabel1 + + + Grow selection by + + + + + radiusSpinBox + + + 10000 + + + 1 + + + 1 + + + + + + pixels + + + + comboBox1 + + + + + + radiusSpinBox + + + diff --git a/chalk/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui b/chalk/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui new file mode 100644 index 00000000..28429d72 --- /dev/null +++ b/chalk/plugins/viewplugins/modify_selection/wdg_shrink_selection.ui @@ -0,0 +1,68 @@ + +WdgShrinkSelection + + + WdgShrinkSelection + + + + 0 + 0 + 255 + 117 + + + + + unnamed + + + + textLabel1 + + + Shrink selection by + + + + + radiusSpinBox + + + 10000 + + + 1 + + + 1 + + + + + + pixels + + + + comboBox1 + + + + + shrinkFromImageBorderCheckBox + + + Shrink from image border + + + true + + + + + + radiusSpinBox + + + diff --git a/chalk/plugins/viewplugins/performancetest/Makefile.am b/chalk/plugins/viewplugins/performancetest/Makefile.am new file mode 100644 index 00000000..e2d7dfac --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/Makefile.am @@ -0,0 +1,25 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = perftest.rc + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkperftest.la + +chalkperftest_la_SOURCES = wdg_perftest.ui perftest.cc dlg_perftest.cc +noinst_HEADERS = wdg_perftest.h dlg_perftest.h perftest.h + +chalkperftest_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkperftest_la_LIBADD = ../../../libchalkcommon.la + +kde_services_DATA = chalkperftest.desktop + +chalkperftest_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/performancetest/chalkperftest.desktop b/chalk/plugins/viewplugins/performancetest/chalkperftest.desktop new file mode 100644 index 00000000..74aee7ed --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/chalkperftest.desktop @@ -0,0 +1,41 @@ +[Desktop Entry] +Name=Performance Test +Name[bg]=Тест за производителност +Name[ca]=Prova d'execució +Name[da]=Ydelsestest +Name[de]=Leistungstest +Name[el]=Δοκιμή επίδοσης +Name[es]=Prueba de rendimiento +Name[et]=Jõudlustest +Name[fa]=آزمون کارایی +Name[fr]=Test de performances +Name[fy]=Prestaasjemjitting +Name[gl]=Probas de Rendemento +Name[he]=בדיקת ביצועים +Name[hu]=Teljesítményteszt +Name[is]=Afkastapróf +Name[it]=Prova delle prestazioni +Name[ja]=パフォーマンステスト +Name[km]=សាកល្បង​ការ​សម្ដែង +Name[lv]=Veiktspējas tests +Name[nb]=Ytelsestest +Name[nds]=Leistenprööv +Name[ne]=कार्य सम्पादन परीक्षण +Name[nl]=Prestatiemeting +Name[pl]=Test wydajności +Name[pt]=Teste de Performance +Name[pt_BR]=Teste de Desempenho +Name[ru]=Модуль производительности +Name[sk]=Test výkonnosti +Name[sl]=Preizkus zmogljivosti +Name[sr]=Проба перформанси +Name[sr@Latn]=Proba performansi +Name[sv]=Prestandatest +Name[uk]=Тест швидкодії +Name[uz]=Unumdorilkni tekshirish +Name[uz@cyrillic]=Унумдорилкни текшириш +Name[zh_TW]=效能測試 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkperftest +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/performancetest/dlg_perftest.cc b/chalk/plugins/viewplugins/performancetest/dlg_perftest.cc new file mode 100644 index 00000000..12e3f42c --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/dlg_perftest.cc @@ -0,0 +1,110 @@ +/* + * dlg_perftest.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_perftest.h" +#include "wdg_perftest.h" + + +DlgPerfTest::DlgPerfTest( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Performance Test"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgPerfTest(this, "perf_test"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + + connect(m_page->btnSelectAll, TQT_SIGNAL(clicked()), this, TQT_SLOT(selectAllClicked())); + connect(m_page->btnDeselectAll, TQT_SIGNAL(clicked()), this, TQT_SLOT(deselectAllClicked())); +} + +DlgPerfTest::~DlgPerfTest() +{ + delete m_page; +} + +WdgPerfTest * DlgPerfTest::page() +{ + return m_page; +} + +// SLOTS + +void DlgPerfTest::okClicked() +{ + accept(); +} + +void DlgPerfTest::setAllTestCheckBoxes(bool checked) +{ + m_page->chkBitBlt->setChecked(checked); + m_page->chkFill->setChecked(checked); + m_page->chkGradient->setChecked(checked); + m_page->chkPixel->setChecked(checked); + m_page->chkShape->setChecked(checked); + m_page->chkLayer->setChecked(checked); + m_page->chkScale->setChecked(checked); + m_page->chkRotate->setChecked(checked); + m_page->chkRender->setChecked(checked); + m_page->chkSelection->setChecked(checked); + m_page->chkColorConversion->setChecked(checked); + m_page->chkFilter->setChecked(checked); + m_page->chkReadBytes->setChecked(checked); + m_page->chkWriteBytes->setChecked(checked); + m_page->chkIterators->setChecked(checked); + m_page->chkPaintView->setChecked(checked); + m_page->chkPaintViewFPS->setChecked(checked); +} + +void DlgPerfTest::selectAllClicked() +{ + setAllTestCheckBoxes(true); +} + +void DlgPerfTest::deselectAllClicked() +{ + setAllTestCheckBoxes(false); +} + + +#include "dlg_perftest.moc" diff --git a/chalk/plugins/viewplugins/performancetest/dlg_perftest.h b/chalk/plugins/viewplugins/performancetest/dlg_perftest.h new file mode 100644 index 00000000..aae398fa --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/dlg_perftest.h @@ -0,0 +1,56 @@ +/* + * dlg_perftest.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_PERFTEST_H_ +#define DLG_PERFTEST_H_ + +#include + +class WdgPerfTest; + +class DlgPerfTest: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgPerfTest(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgPerfTest(); + + WdgPerfTest * page(); + +private slots: + + void okClicked(); + void selectAllClicked(); + void deselectAllClicked(); + + void setAllTestCheckBoxes(bool checked); + +private: + + WdgPerfTest * m_page; + double m_oldAngle; + bool m_lock; + +}; + +#endif // DLG_PERFTEST_H diff --git a/chalk/plugins/viewplugins/performancetest/perftest.cc b/chalk/plugins/viewplugins/performancetest/perftest.cc new file mode 100644 index 00000000..88a50e85 --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/perftest.cc @@ -0,0 +1,1198 @@ +/* + * perftest.cc -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_meta_registry.h" +#include +#include "kis_cursor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "perftest.h" +#include "kis_filter_config_widget.h" +#include "kis_factory.h" + +#include "dlg_perftest.h" +#include "wdg_perftest.h" + +#define USE_CALLGRIND 0 + +#if USE_CALLGRIND +#include +#endif + + +typedef KGenericFactory PerfTestFactory; +K_EXPORT_COMPONENT_FACTORY( chalkperftest, PerfTestFactory( "chalk" ) ) + +PerfTest::PerfTest(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + if ( tqparent->inherits("KisView") ) + { + setInstance(PerfTestFactory::instance()); + setXMLFile(locate("data","chalkplugins/perftest.rc"), true); + + (void) new KAction(i18n("&Performance Test..."), 0, 0, this, TQT_SLOT(slotPerfTest()), actionCollection(), "perf_test"); + + m_view = (KisView*) tqparent; + } +} + +PerfTest::~PerfTest() +{ + m_view = 0; +} + +void PerfTest::slotPerfTest() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgPerfTest * dlgPerfTest = new DlgPerfTest(m_view, "PerfTest"); + Q_CHECK_PTR(dlgPerfTest); + + dlgPerfTest->setCaption(i18n("Performance Test")); + + TQString report = TQString(""); + + if (dlgPerfTest->exec() == TQDialog::Accepted) { + + TQ_INT32 testCount = (TQ_INT32)tqRound(dlgPerfTest->page()->intTestCount->value()); + + if (dlgPerfTest->page()->chkBitBlt->isChecked()) { + kdDebug() << "bltTest:\n"; + TQString s = bltTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkFill->isChecked()) { + kdDebug() << "Filltest\n"; + TQString s= fillTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkGradient->isChecked()) { + kdDebug() << "Gradienttest\n"; + TQString s = gradientTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPixel->isChecked()) { + kdDebug() << "Pixeltest\n"; + TQString s = pixelTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkShape->isChecked()) { + kdDebug() << "Shapetest\n"; + TQString s = tqshapeTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkLayer->isChecked()) { + kdDebug() << "LayerTest\n"; + TQString s = layerTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkScale->isChecked()) { + kdDebug() << "Scaletest\n"; + TQString s = scaleTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkRotate->isChecked()) { + kdDebug() << "Rotatetest\n"; + TQString s = rotateTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkRender->isChecked()) { + kdDebug() << "Rendertest\n"; + TQString s = renderTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkSelection->isChecked()) { + kdDebug() << "Selectiontest\n"; + TQString s = selectionTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkColorConversion->isChecked()) { + kdDebug() << "Colorconversiontest\n"; + TQString s = colorConversionTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkFilter-> isChecked()) { + kdDebug() << "filtertest\n"; + TQString s = filterTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkReadBytes->isChecked()) { + kdDebug() << "Readbytes test\n"; + TQString s = readBytesTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkWriteBytes-> isChecked()) { + kdDebug() << "Writebytes test\n"; + TQString s = writeBytesTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkIterators->isChecked()) { + kdDebug() << "Iterators test\n"; + TQString s = iteratorTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPaintView->isChecked()) { + kdDebug() << "paintview test\n"; + TQString s = paintViewTest(testCount); + report = report.append(s); + kdDebug() << s << "\n"; + } + if (dlgPerfTest->page()->chkPaintViewFPS->isChecked()) { + kdDebug() << "paint current view (fps) test\n"; + TQString s = paintViewFPSTest(); + report = report.append(s); + kdDebug() << s << "\n"; + } + KDialogBase * d = new KDialogBase(m_view, "", true, "", KDialogBase::Ok); + Q_CHECK_PTR(d); + + d->setCaption("Performance test results"); + TQTextEdit * e = new TQTextEdit(d); + Q_CHECK_PTR(e); + d->setMainWidget(e); + e->setText(report); + e->setMinimumWidth(600); + e->setMinimumHeight(600); + d->exec(); + delete d; + + } + delete dlgPerfTest; +} + +TQString PerfTest::bltTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* bitBlt test\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + + kdDebug() << "Image->" << (*it).name() << "\n"; + + report = report.append( " Testing blitting on " + (*it).name() + "\n"); + + KisImageSP img = doc->newImage("blt-" + (*it).name(), 1000, 1000, + KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + + report = report.append(doBlit(COMPOSITE_OVER, *it, OPACITY_OPAQUE, testCount, img)); + report = report.append( "\n"); + report = report.append(doBlit(COMPOSITE_OVER, *it, OPACITY_OPAQUE / 2, testCount, img)); + report = report.append( "\n"); + report = report.append(doBlit(COMPOSITE_COPY, *it, OPACITY_OPAQUE, testCount, img)); + report = report.append( "\n"); + report = report.append(doBlit(COMPOSITE_COPY, *it, OPACITY_OPAQUE / 2, testCount, img)); + report = report.append( "\n"); + } + + return report; + + +} + + +TQString PerfTest::doBlit(const KisCompositeOp& op, + KisID cspace, + TQ_UINT8 opacity, + TQ_UINT32 testCount, + KisImageSP img) +{ + + TQTime t; + TQString report; + + // ------------------------------------------------------------------------------ + // Small + + KisPaintDeviceSP small = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace,""), "small blit"); + Q_CHECK_PTR(small); + + KisFillPainter pf(small.data()) ; + pf.fillRect(0, 0, 32, 32, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + KisPainter p(img->activeDevice()); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, small.data(),0,0,32, 32); + } + p.end(); + + report = report.append(TQString(" %1 blits of rectangles < tilesize with opacity %2 and composite op %3: %4ms\n") + .tqarg(testCount) + .tqarg(opacity) + .tqarg(op.id().name()) + .tqarg(t.elapsed())); + + + // ------------------------------------------------------------------------------ + // Medium + KisPaintDeviceSP medium = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace,""), "medium blit"); + Q_CHECK_PTR(medium); + + pf.begin(medium.data()) ; + pf.fillRect(0, 0, 64 * 3, 64 * 3, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, medium.data(),0,0,96, 96); + } + p.end(); + + report = report.append(TQString(" %1 blits of rectangles 3 * tilesize with opacity %2 and composite op %3: %4ms\n") + .tqarg(testCount) + .tqarg(opacity) + .tqarg(op.id().name()) + .tqarg(t.elapsed())); + + + // ------------------------------------------------------------------------------ + // Big + KisPaintDeviceSP big = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace,""), "big blit"); + Q_CHECK_PTR(big); + + pf.begin(big.data()) ; + pf.fillRect(0, 0, 800, 800, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, big.data(),0,0,800,800); + + } + p.end(); + report = report.append(TQString(" %1 blits of rectangles 800 x 800 with opacity %2 and composite op %3: %4ms\n") + .tqarg(testCount) + .tqarg(opacity) + .tqarg(op.id().name()) + .tqarg(t.elapsed())); + + + // ------------------------------------------------------------------------------ + // Outside + + KisPaintDeviceSP outside = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace,""), "outside blit"); + Q_CHECK_PTR(outside); + pf.begin(outside.data()) ; + pf.fillRect(0, 0, 500, 500, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(600, 600, op, outside.data(),0,0,500,500); + + } + p.end(); + report = report.append(TQString(" %1 blits of rectangles 500 x 500 at 600,600 with opacity %2 and composite op %3: %4ms\n") + .tqarg(testCount) + .tqarg(opacity) + .tqarg(op.id().name()) + .tqarg(t.elapsed())); + + // ------------------------------------------------------------------------------ + // Small with varied source opacity + + KisPaintDeviceSP small_with_alpha = new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getColorSpace(cspace,""), "small blit with alpha"); + Q_CHECK_PTR(small_with_alpha); + + pf.begin(small_with_alpha.data()) ; + pf.fillRect(0, 0, 32, 32, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_TRANSPARENT); + pf.fillRect(4, 4, 24, 24, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + pf.fillRect(8, 8, 16, 16, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE); + pf.end(); + + t.restart(); + p.begin(img->activeDevice().data()); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.bitBlt(0, 0, op, small_with_alpha.data(), 0, 0, 32, 32); + } + p.end(); + + report = report.append(TQString(" %1 blits of rectangles < tilesize with source alpha, with opacity %2 and composite op %3: %4ms\n") + .tqarg(testCount) + .tqarg(opacity) + .tqarg(op.id().name()) + .tqarg(t.elapsed())); + + return report; + +} + +TQString PerfTest::fillTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* Fill test\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + kdDebug() << "Filltest on " << (*it).name() + "\n"; + + report = report.append( " Testing blitting on " + (*it).name() + "\n"); + + KisImageSP img = doc->newImage("fill-" + (*it).name(), 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + KisPaintDeviceSP l = img->activeDevice(); + + // Rect fill + KisFillPainter p(l.data()); + TQTime t; + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); + } + report = report.append(TQString(" Erased 1000 x 1000 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(50, 50, 500, 500); + } + report = report.append(TQString(" Erased 500 x 500 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(-50, -50, 1100, 1100); + } + report = report.append(TQString(" Erased rect bigger than layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + // Opaque Rect fill + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(TQString(" Opaque fill 1000 x 1000 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(50, 50, 500, 500, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(TQString(" Opaque fill 500 x 500 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(-50, -50, 1100, 1100, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + } + report = report.append(TQString(" Opaque fill rect bigger than layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + // Transparent rect fill + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(TQString(" Opaque fill 1000 x 1000 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(50, 50, 500, 500, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(TQString(" Opaque fill 500 x 500 layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.fillRect(-50, -50, 1100, 1100, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8()), OPACITY_OPAQUE / 2); + } + report = report.append(TQString(" Opaque fill rect bigger than layer %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + // Colour fill + + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); +// p.paintEllipse(500, 1000, 100, 0, 0); + p.setPaintColor(KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.setFillThreshold(15); + p.setCompositeOp(COMPOSITE_OVER); + p.fillColor(0,0); + } + report = report.append(TQString(" Opaque floodfill of whole circle (incl. erase and painting of circle) %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + // Pattern fill + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + p.eraseRect(0, 0, 1000, 1000); +// p.paintEllipse(500, 1000, 100, 0, 0); + p.setPaintColor(KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + KisResourceServerBase* r = KisResourceServerRegistry::instance()->get("PatternServer"); + Q_CHECK_PTR(r); + p.setPattern((KisPattern*)r->resources().first()); + p.setFillThreshold(15); + p.setCompositeOp(COMPOSITE_OVER); + p.fillPattern(0,0); + } + report = report.append(TQString(" Opaque patternfill of whole circle (incl. erase and painting of circle) %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + + + } + + + + return report; + +} + +TQString PerfTest::gradientTest(TQ_UINT32 testCount) +{ + return TQString("Gradient test\n"); +} + +TQString PerfTest::pixelTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* pixel/setpixel test\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + + + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + report = report.append( " Testing pixel/setpixel on " + (*it).name() + "\n"); + + KisImageSP img = doc->newImage("fill-" + (*it).name(), 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + TQColor c = TQt::black; + TQ_UINT8 opacity = OPACITY_OPAQUE; + for (TQ_UINT32 i = 0; i < testCount; ++i) { + for (TQ_UINT32 x = 0; x < 1000; ++x) { + for (TQ_UINT32 y = 0; y < 1000; ++y) { + l->pixel(x, y, &c, &opacity); + } + } + } + report = report.append(TQString(" read 1000 x 1000 pixels %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + c= TQt::black; + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + for (TQ_UINT32 x = 0; x < 1000; ++x) { + for (TQ_UINT32 y = 0; y < 1000; ++y) { + l->setPixel(x, y, c, 128); + } + } + } + report = report.append(TQString(" written 1000 x 1000 pixels %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + } + + + + + return report; + +} + +TQString PerfTest::tqshapeTest(TQ_UINT32 testCount) +{ + return TQString("Shape test\n"); +} + +TQString PerfTest::layerTest(TQ_UINT32 testCount) +{ + return TQString("Layer test\n"); +} + +TQString PerfTest::scaleTest(TQ_UINT32 testCount) +{ + return TQString("Scale test\n"); +} + +TQString PerfTest::rotateTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* Rotate test\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + + doc->undoAdapter()->setUndo( false ); + TQTime t; + + for (uint i = 0; i < testCount; ++i) { + for (double angle = 0; angle < 360; ++angle) { + kdDebug() << "Rotating " << (*it).name() << " at " << angle << " degrees\n"; + KisImage * img = doc->newImage("cs-" + (*it).name(), 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + img->rotate(angle, m_view->canvasSubject()->progressDisplay()); + kdDebug() << "Size: " << img->projection()->extent() << endl; + delete img; + } + } + report = report.append(TQString(" rotated 1000 x 1000 pixels over 360 degrees, degree by degree, %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + } + return report; +} + +TQString PerfTest::renderTest(TQ_UINT32 restCount) +{ + return TQString("Render test\n"); +} + +TQString PerfTest::selectionTest(TQ_UINT32 testCount) +{ + return TQString("Selection test\n"); +} + +TQString PerfTest::colorConversionTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* Colorspace conversion test\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + + KisImage * img = doc->newImage("cs-" + (*it).name(), 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + + TQTime t; + + KisIDList l2 = KisMetaRegistry::instance()->csRegistry()->listKeys(); + for (KisIDList::Iterator it2 = l2.begin(); it2 != l2.end(); ++it2) { + kdDebug() << "test conversion from " << (*it).name() << " to " << (*it2).name() << endl; + + t.restart(); + for (uint i = 0; i < testCount; ++i) { + KisImage * img2 = new KisImage(*img); + img2->convertTo(KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it2,"")); + delete img2; + } + report = report.append(TQString(" converted from " + (*it).name() + " to " + (*it2).name() + " 1000 x 1000 pixels %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + } + + delete img; + + } + return report; + +} + +TQString PerfTest::filterTest(TQ_UINT32 testCount) +{ + + TQString report = TQString("* Filter test\n"); + + KisIDList filters = KisFilterRegistry::instance()->listKeys(); + KisDoc * doc = m_view->canvasSubject()->document(); + KisIDList l = KisMetaRegistry::instance()->csRegistry()->listKeys(); + + for (KisIDList::Iterator it = l.begin(); it != l.end(); ++it) { + report = report.append( " Testing filtering on " + (*it).name() + "\n"); + + KisImageSP img = doc->newImage("filter-" + (*it).name(), 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(*it,"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + + for (KisIDList::Iterator it = filters.begin(); it != filters.end(); ++it) { + + KisFilterSP f = KisFilterRegistry::instance()->get(*it); + t.restart(); + kdDebug() << "test filter " << f->id().name() << " on " << img->colorSpace()->id().name() << endl; + for (TQ_UINT32 i = 0; i < testCount; ++i) { + f->enableProgress(); + f->process(l.data(), l.data(), f->configuration(f->createConfigurationWidget(m_view, l.data())), TQRect(0, 0, 1000, 1000)); + f->disableProgress(); + } + report = report.append(TQString(" filtered " + (*it).name() + "1000 x 1000 pixels %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + } + + } + return report; + +} + +TQString PerfTest::readBytesTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* Read bytes test\n\n"); + + // On default tiles + KisDoc * doc = m_view->canvasSubject()->document(); + KisImageSP img = doc->newImage("Readbytes ", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + TQ_UINT8 * newData = new TQ_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(newData); + l->readBytes(newData, 0, 0, 1000, 1000); + delete[] newData; + } + + report = report.append(TQString(" read 1000 x 1000 pixels %1 times from empty image: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + // On tiles with data + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + TQ_UINT8 * newData = new TQ_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(newData); + l->readBytes(newData, 0, 0, 1000, 1000); + delete[] newData; + } + + report = report.append(TQString(" read 1000 x 1000 pixels %1 times from filled image: %2\n").tqarg(testCount).tqarg(t.elapsed())); + + return report; +} + + +TQString PerfTest::writeBytesTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* Write bytes test"); + + // On default tiles + KisDoc * doc = m_view->canvasSubject()->document(); + KisImageSP img = doc->newImage("Writebytes ", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + TQ_UINT8 * data = new TQ_UINT8[1000 * 1000 * l->pixelSize()]; + Q_CHECK_PTR(data); + l->readBytes(data, 0, 0, 1000, 1000); + + TQTime t; + t.restart(); + for (TQ_UINT32 i = 0; i < testCount; ++i) { + l->writeBytes(data, 0, 0, 1000, 1000); + } + delete[] data; + report = report.append(TQString(" written 1000 x 1000 pixels %1 times: %2\n").tqarg(testCount).tqarg(t.elapsed())); + return report; + + +} + +/////// Iterator tests + + +TQString hlineRODefault(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, false); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return TQString(" hline iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + + +} + +TQString hlineRO(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, false); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return TQString(" hline iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString hlineWRDefault(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + int adv; + + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, true); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return TQString(" hline iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString hlineWR(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + int adv; + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(0, y2, 1000, true); + while(! hiter.isDone()) + { + adv = hiter.nConseqHPixels(); + hiter += adv; + } + } + + } + + return TQString(" hline iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + + +TQString vlineRODefault(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return TQString(" vline iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString vlineRO(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return TQString(" vline iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString vlineWRDefault(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisVLineIterator hiter = l->createVLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return TQString(" vline iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); +} + +TQString vlineWR(KisDoc * doc, TQ_UINT32 testCount) +{ + + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + for(TQ_INT32 y2 = 0; y2 < 0 + 1000; y2++) + { + KisHLineIterator hiter = l->createHLineIterator(y2, 0, 1000, true); + while(! hiter.isDone()) + { + ++hiter; + } + } + + } + + return TQString(" vline iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString rectRODefault(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); +; + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, false); + while(! r.isDone()) + { + ++r; + } + } + + return TQString(" rect iterated read-only 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + + +} + +TQString rectRO(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, false); + while(! r.isDone()) + { + ++r; + } + } + + return TQString(" rect iterated read-only 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString rectWRDefault(KisDoc * doc, TQ_UINT32 testCount) +{ + + + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + TQTime t; + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, true); + while(! r.isDone()) + { + ++r; + } + } + + return TQString(" rect iterated writable 1000 x 1000 pixels %1 times over default tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + +} + +TQString rectWR(KisDoc * doc, TQ_UINT32 testCount) +{ + KisImageSP img = doc->newImage("", 1000, 1000, KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""),"")); + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 1000, 1000, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + + TQTime t; + t.restart(); + + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + KisRectIterator r = l->createRectIterator(0, 0, 1000, 1000, true); + while(! r.isDone()) + { + ++r; + } + } + + + return TQString(" rect iterated writable 1000 x 1000 pixels %1 times over existing tile: %2\n").tqarg(testCount).tqarg(t.elapsed()); + + +} +TQString PerfTest::iteratorTest(TQ_UINT32 testCount) +{ + TQString report = "Iterator test"; + + KisDoc * doc = m_view->canvasSubject()->document(); + + report = report.append(hlineRODefault(doc, testCount)); + report = report.append(hlineRO(doc, testCount)); + report = report.append(hlineWRDefault(doc, testCount)); + report = report.append(hlineWR(doc, testCount)); + + report = report.append(vlineRODefault(doc, testCount)); + report = report.append(vlineRO(doc, testCount)); + report = report.append(vlineWRDefault(doc, testCount)); + report = report.append(vlineWR(doc, testCount)); + + report = report.append(rectRODefault(doc, testCount)); + report = report.append(rectRO(doc, testCount)); + report = report.append(rectWRDefault(doc, testCount)); + report = report.append(rectWR(doc, testCount)); + + return report; + + +} + +TQString PerfTest::paintViewTest(TQ_UINT32 testCount) +{ + TQString report = TQString("* paintView test\n\n"); + + KisDoc * doc = m_view->canvasSubject()->document(); + + KisImageSP img = doc->currentImage(); + img->resize(512,512); + + + KisPaintDeviceSP l = img->activeDevice(); + + KisFillPainter p(l.data()); + p.fillRect(0, 0, 512, 512, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + TQTime t; + t.restart(); + +#if USE_CALLGRIND + CALLGRIND_ZERO_STATS(); +#endif + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + m_view->getCanvasController()->updateCanvas(TQRect(0, 0, 512, 512)); + } + +#if USE_CALLGRIND + CALLGRIND_DUMP_STATS(); +#endif + + report = report.append(TQString(" painted a 512 x 512 image %1 times: %2 ms\n").tqarg(testCount).tqarg(t.elapsed())); + + img->newLayer("layer 2", OPACITY_OPAQUE); + l = img->activeDevice(); + + p.begin(l.data()); + p.fillRect(0, 0, 512, 512, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + img->newLayer("layer 3", OPACITY_OPAQUE); + l = img->activeDevice(); + + p.begin(l.data()); + p.fillRect(0, 0, 512, 512, KisColor(TQt::black, KisMetaRegistry::instance()->csRegistry()->getRGB8())); + p.end(); + + t.restart(); + + for (TQ_UINT32 i = 0; i < testCount; ++i) { + m_view->getCanvasController()->updateCanvas(TQRect(0, 0, 512, 512)); + } + + report = report.append(TQString(" painted a 512 x 512 image with 3 layers %1 times: %2 ms\n").tqarg(testCount).tqarg(t.elapsed())); + + return report; +} + +TQString PerfTest::paintViewFPSTest() +{ + TQString report = TQString("* paintView (fps) test\n\n"); + + TQTime t; + t.restart(); + +#if USE_CALLGRIND + CALLGRIND_ZERO_STATS(); +#endif + + int numViewsPainted = 0; + const int millisecondsPerSecond = 1000; + + while (t.elapsed() < millisecondsPerSecond) { + m_view->getCanvasController()->updateCanvas(); + numViewsPainted++; + } + +#if USE_CALLGRIND + CALLGRIND_DUMP_STATS(); +#endif + + report = report.append(TQString(" painted current view at %1 frames per second\n").tqarg(numViewsPainted)); + + return report; +} + +#include "perftest.moc" diff --git a/chalk/plugins/viewplugins/performancetest/perftest.h b/chalk/plugins/viewplugins/performancetest/perftest.h new file mode 100644 index 00000000..5bae3c8c --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/perftest.h @@ -0,0 +1,76 @@ +/* + * perftest.h -- Part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PERFTEST_H_ +#define PERFTEST_H_ + +#include +#include +#include + +class KisView; +class KisID; + +class PerfTest : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + PerfTest(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~PerfTest(); + +private slots: + + void slotPerfTest(); + +private: + + TQString bltTest(TQ_UINT32 testCount); + TQString fillTest(TQ_UINT32 testCount); + TQString gradientTest(TQ_UINT32 testCount); + TQString pixelTest(TQ_UINT32 testCount); + TQString tqshapeTest(TQ_UINT32 testCount); + TQString layerTest(TQ_UINT32 testCount); + TQString scaleTest(TQ_UINT32 testCount); + TQString rotateTest(TQ_UINT32 testCount); + TQString renderTest(TQ_UINT32 restCount); + TQString selectionTest(TQ_UINT32 testCount); + TQString colorConversionTest(TQ_UINT32 testCount); + TQString filterTest(TQ_UINT32 testCount); + TQString readBytesTest(TQ_UINT32 testCount); + TQString writeBytesTest(TQ_UINT32 testCount); + TQString iteratorTest(TQ_UINT32 testCount); + TQString paintViewTest(TQ_UINT32 testCount); + TQString paintViewFPSTest(); + + TQString doBlit(const KisCompositeOp& op, + KisID cspace, + TQ_UINT8 opacity, + TQ_UINT32 testCount, + KisImageSP img); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // PERFTEST_H_ diff --git a/chalk/plugins/viewplugins/performancetest/perftest.rc b/chalk/plugins/viewplugins/performancetest/perftest.rc new file mode 100644 index 00000000..de404a34 --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/perftest.rc @@ -0,0 +1,9 @@ + + + + &Tools + + + + + \ No newline at end of file diff --git a/chalk/plugins/viewplugins/performancetest/wdg_perftest.ui b/chalk/plugins/viewplugins/performancetest/wdg_perftest.ui new file mode 100644 index 00000000..7dc14f17 --- /dev/null +++ b/chalk/plugins/viewplugins/performancetest/wdg_perftest.ui @@ -0,0 +1,283 @@ + +WdgPerfTest + + + WdgPerfTest + + + + 0 + 0 + 377 + 566 + + + + Image Size + + + + unnamed + + + + grpPerfTest + + + &Performance Test + + + + unnamed + + + + lblTests + + + Number of tests: + + + intWidth + + + + + chkBitBlt + + + bitBlt + + + true + + + + + chkFill + + + Fill + + + true + + + + + chkGradient + + + Gradients + + + true + + + + + chkPixel + + + setPixel/getPixel + + + true + + + + + chkShape + + + Shapes + + + true + + + + + chkLayer + + + Layers + + + true + + + + + chkScale + + + Scaling + + + true + + + + + chkRotate + + + Rotating + + + true + + + + + chkRender + + + Rendering + + + true + + + + + chkSelection + + + Selection + + + true + + + + + chkColorConversion + + + Color conversion + + + true + + + + + chkFilter + + + Filters + + + true + + + + + intTestCount + + + 10 + + + 0 + + + 1000000 + + + + + chkReadBytes + + + Read bytes + + + true + + + + + chkWriteBytes + + + Write bytes + + + true + + + + + chkIterators + + + Iterators + + + true + + + + + chkPaintView + + + PaintView + + + true + + + + + tqlayout5 + + + + unnamed + + + + btnSelectAll + + + &Select All + + + + + btnDeselectAll + + + &Deselect All + + + + + + + chkPaintViewFPS + + + PaintView (fps) + + + true + + + + + + + + intTestCount + + + + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/viewplugins/rotateimage/Makefile.am b/chalk/plugins/viewplugins/rotateimage/Makefile.am new file mode 100644 index 00000000..d4ff4e63 --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/Makefile.am @@ -0,0 +1,25 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = rotateimage.rc + +EXTRA_DIST = $(chalkrc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkrotateimage.la + +chalkrotateimage_la_SOURCES = wdg_rotateimage.ui rotateimage.cc dlg_rotateimage.cc +noinst_HEADERS = wdg_rotateimage.h dlg_rotateimage.h rotateimage.h + +chalkrotateimage_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkrotateimage_la_LIBADD = ../../../libchalkcommon.la + +kde_services_DATA = chalkrotateimage.desktop + +chalkrotateimage_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/rotateimage/chalkrotateimage.desktop b/chalk/plugins/viewplugins/rotateimage/chalkrotateimage.desktop new file mode 100644 index 00000000..e855492e --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/chalkrotateimage.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Rotate Image Plugin +Name[bg]=Приставка за въртене на изображение +Name[ca]=Connector de rotació d'imatge +Name[da]=Plugin for rotering af billede +Name[de]="Bild rotieren"-Modul +Name[el]=Πρόσθετο περιστροφής εικόνας +Name[es]=Complemento para girar la imagen +Name[et]=Pildi pööramise plugin +Name[fa]=چرخش وصلۀ تصویر +Name[fr]=Module de rotation d'images +Name[fy]=Plugin foar ôfbyldingsrotaasje +Name[gl]=Plugin para Rodar a Imaxe +Name[he]=תוסף לשינוי גודל של תמונה +Name[hu]=Képelforgató modul +Name[is]=Snúa mynd íforrit +Name[it]=Plugin per ruotare le immagini +Name[ja]=画像回転プラグイン +Name[km]=កម្មវិធី​ត្រឡប់​រូបភាព +Name[nb]=Programtillegg for bilderotering +Name[nds]=Moduul för't Bilddreihen +Name[ne]=छवि प्लगइन परिक्रमा गर्नुहोस् +Name[nl]=Plugin voor afbeeldingrotatie +Name[pl]=Wtyczka obrotu obrazków +Name[pt]='Plugin' para Rodar a Imagem +Name[pt_BR]=Plugin para Rodar a Imagem +Name[ru]=Модуль вращения +Name[sk]=Modul rotácia obrázkov +Name[sl]=Vstavek za vrtenje slike +Name[sr]=Прикључак за ротирање слике +Name[sr@Latn]=Priključak za rotiranje slike +Name[sv]=Insticksprogram för rotera bild +Name[uk]=Втулок обертання зображень +Name[uz]=Rasmni burish plagini +Name[uz@cyrillic]=Расмни буриш плагини +Name[zh_TW]=旋轉圖片外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkrotateimage +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.cc b/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.cc new file mode 100644 index 00000000..6e3cc9f7 --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.cc @@ -0,0 +1,147 @@ +/* + * dlg_rotateimage.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_rotateimage.h" +#include "wdg_rotateimage.h" + + +DlgRotateImage::DlgRotateImage( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Rotate Image"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgRotateImage(this, "rotate_image"); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + connect( m_page->doubleCustom, TQT_SIGNAL( valueChanged ( double ) ), + this, TQT_SLOT( slotAngleValueChanged( double ) ) ); + +} + +DlgRotateImage::~DlgRotateImage() +{ + delete m_page; +} + +void DlgRotateImage::slotAngleValueChanged( double ) +{ + m_page->radioCustom->setChecked(true); +} + +void DlgRotateImage::setAngle(double angle) +{ + if (angle == 90) { + m_page->radio90->setChecked(true); + } + else if (angle == 180) { + m_page->radio180->setChecked(true); + } + else if (angle == 270) { + m_page->radio270->setChecked(true); + } + else { + m_page->radioCustom->setChecked(true); + m_page->doubleCustom->setValue(angle); + } + + if (m_oldAngle != angle) + resetPreview(); + + m_oldAngle = angle; + +} + +double DlgRotateImage::angle() +{ + double angle = 0; + if (m_page->radio90->isChecked()) { + angle = 90; + } + else if (m_page->radio180->isChecked()) { + angle = 180; + } + else if (m_page->radio270->isChecked()) { + angle = 270; + } + else { + angle = tqRound(m_page->doubleCustom->value()); + } + if (m_page->radioCW->isChecked()) { + return angle; + } + else { + return -angle; + } +} + +void DlgRotateImage::setDirection (enumRotationDirection direction) +{ + if (direction == CLOCKWISE) { + m_page->radioCW->setChecked(true); + } + else if (direction== COUNTERCLOCKWISE) { + m_page->radioCCW->setChecked(true); + } +} + +enumRotationDirection DlgRotateImage::direction() +{ + if (m_page->radioCCW->isChecked()) { + return COUNTERCLOCKWISE; + } + else { + return CLOCKWISE; + } +} + +void DlgRotateImage::okClicked() +{ + accept(); +} + +void DlgRotateImage::resetPreview() +{ + // Code to update preview here. +} + +#include "dlg_rotateimage.moc" diff --git a/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.h b/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.h new file mode 100644 index 00000000..47ddd344 --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/dlg_rotateimage.h @@ -0,0 +1,66 @@ +/* + * dlg_rotateimage.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_ROTATEIMAGE +#define DLG_ROTATEIMAGE + +#include + +#include + +class WdgRotateImage; + +enum enumRotationDirection { + CLOCKWISE, + COUNTERCLOCKWISE +}; + + +class DlgRotateImage: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgRotateImage(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgRotateImage(); + + void setAngle(double w); + double angle(); + + void setDirection (enumRotationDirection direction); + enumRotationDirection direction(); + +private slots: + + void okClicked(); + void resetPreview(); + void slotAngleValueChanged( double ); + +private: + + WdgRotateImage * m_page; + double m_oldAngle; + bool m_lock; + +}; + +#endif // DLG_ROTATEIMAGE diff --git a/chalk/plugins/viewplugins/rotateimage/rotateimage.cc b/chalk/plugins/viewplugins/rotateimage/rotateimage.cc new file mode 100644 index 00000000..e8961cec --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/rotateimage.cc @@ -0,0 +1,134 @@ +/* + * rotateimage.cc -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rotateimage.h" +#include "dlg_rotateimage.h" + +typedef KGenericFactory RotateImageFactory; +K_EXPORT_COMPONENT_FACTORY( chalkrotateimage, RotateImageFactory( "chalk" ) ) + +// XXX: this plugin could also provide layer scaling/resizing +RotateImage::RotateImage(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) { + setInstance(RotateImageFactory::instance()); + setXMLFile(locate("data","chalkplugins/rotateimage.rc"), true); + m_view = (KisView*) tqparent; + (void) new KAction(i18n("&Rotate Image..."), 0, 0, TQT_TQOBJECT(this), TQT_SLOT(slotRotateImage()), actionCollection(), "rotateimage"); + (void) new KAction(i18n("Rotate Image CW"), "rotate_cw", 0, TQT_TQOBJECT(this), TQT_SLOT(slotRotateImage90()), actionCollection(), "rotateImageCW90"); + (void) new KAction(i18n("Rotate Image 1&80"), 0, 0, TQT_TQOBJECT(this), TQT_SLOT(slotRotateImage180()), actionCollection(), "rotateImage180"); + (void) new KAction(i18n("Rotate Image CCW"), "rotate_ccw", 0, TQT_TQOBJECT(this), TQT_SLOT(slotRotateImage270()), actionCollection(), "rotateImageCCW90"); + + (void) new KAction(i18n("&Rotate Layer..."), 0, 0, TQT_TQOBJECT(this), TQT_SLOT(slotRotateLayer()), actionCollection(), "rotatelayer"); + + (void)new KAction(i18n("Rotate 1&80"), 0, TQT_TQOBJECT(m_view), TQT_SLOT(rotateLayer180()), actionCollection(), "rotateLayer180"); + (void)new KAction(i18n("Rotate CCW"), "rotate_ccw", 0, TQT_TQOBJECT(m_view), TQT_SLOT(rotateLayerLeft90()), actionCollection(), "rotateLayerCCW90"); + (void)new KAction(i18n("Rotate CW"), "rotate_cw", 0, TQT_TQOBJECT(m_view), TQT_SLOT(rotateLayerRight90()), actionCollection(), "rotateLayerCW90"); + } +} + +RotateImage::~RotateImage() +{ + m_view = 0; +} + +void RotateImage::slotRotateImage() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgRotateImage * dlgRotateImage = new DlgRotateImage(m_view, "RotateImage"); + Q_CHECK_PTR(dlgRotateImage); + + dlgRotateImage->setCaption(i18n("Rotate Image")); + + if (dlgRotateImage->exec() == TQDialog::Accepted) { + double angle = dlgRotateImage->angle(); + angle *= M_PI/180; + m_view->rotateCurrentImage(angle); + } + delete dlgRotateImage; +} + +void RotateImage::slotRotateImage90() +{ + m_view->rotateCurrentImage( M_PI/2); +} + +void RotateImage::slotRotateImage180() +{ + m_view->rotateCurrentImage( M_PI ); +} + + +void RotateImage::slotRotateImage270() +{ + m_view->rotateCurrentImage( - M_PI/2 + M_PI*2 ); +} + +void RotateImage::slotRotateLayer() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgRotateImage * dlgRotateImage = new DlgRotateImage(m_view, "RotateLayer"); + Q_CHECK_PTR(dlgRotateImage); + + dlgRotateImage->setCaption(i18n("Rotate Layer")); + + if (dlgRotateImage->exec() == TQDialog::Accepted) { + double angle = dlgRotateImage->angle(); + angle *= M_PI/180; + m_view->rotateLayer(angle); + } + delete dlgRotateImage; +} + +#include "rotateimage.moc" diff --git a/chalk/plugins/viewplugins/rotateimage/rotateimage.h b/chalk/plugins/viewplugins/rotateimage/rotateimage.h new file mode 100644 index 00000000..6b262608 --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/rotateimage.h @@ -0,0 +1,50 @@ +/* + * rotateimage.h -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler (michael.thaler@physik.tu-muenchen.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef ROTATEIMAGE_H +#define ROTATEIMAGE_H + +#include + +class KisView; + +class RotateImage : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + RotateImage(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~RotateImage(); + +private slots: + + void slotRotateImage(); + void slotRotateImage90(); + void slotRotateImage180(); + void slotRotateImage270(); + void slotRotateLayer(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // ROTATEIMAGE_H diff --git a/chalk/plugins/viewplugins/rotateimage/rotateimage.rc b/chalk/plugins/viewplugins/rotateimage/rotateimage.rc new file mode 100644 index 00000000..78ae6f4f --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/rotateimage.rc @@ -0,0 +1,25 @@ + + + + &Image + &Rotate + + + + + + + + + La&yer + &Rotate + + + + + + + + + + diff --git a/chalk/plugins/viewplugins/rotateimage/wdg_rotateimage.ui b/chalk/plugins/viewplugins/rotateimage/wdg_rotateimage.ui new file mode 100644 index 00000000..d58c458d --- /dev/null +++ b/chalk/plugins/viewplugins/rotateimage/wdg_rotateimage.ui @@ -0,0 +1,245 @@ + +WdgRotateImage + + + WdgRotateImage + + + + 0 + 0 + 489 + 447 + + + + Rotate Image + + + + unnamed + + + + grpDirection + + + Direction + + + + unnamed + + + + tqlayout6 + + + + unnamed + + + + spacer3 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + pixmapLabel1 + + + image0 + + + false + + + AlignCenter + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 41 + 20 + + + + + + pixmapLabel2 + + + image1 + + + false + + + AlignCenter + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + + + radioCW + + + C&lockwise + + + true + + + + + radioCCW + + + Cou&nter-clockwise + + + + + + + grpAngle + + + Angle + + + + unnamed + + + + radio90 + + + 90 &degrees + + + + + radio180 + + + 180 d&egrees + + + + + radio270 + + + 270 de&grees + + + + + tqlayout1 + + + + unnamed + + + + radioCustom + + + &Custom: + + + true + + + + + doubleCustom + + + 360 + + + 1 + + + + + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 91 + + + + + + + + + + 89504e470d0a1a0a0000000d494844520000002c0000002e0806000000534cfb0a0000013a494441545885ed994b0ec330084487aaf7bf32dd5689297f9b489d6d24fc3c02db106266a445c460a67c205daf7404a2821ddb9503de0c0b64800fc00251e043b00040eea28bc21615a50fb8cad904bc1db8230d02e0671cbeca01ee2bbaaecbc16184bfe8a405b4cd58a00c86c48eb588d3cc54b1a9f8c5114d0f0d5c81ce5dcd999c0e42e71f3f5dd0826245572dc9d1c586f20e57a8ed1cdead85f373808d2ecf01366a16f0cae54b5acc0236e80fdcadc701bfc52f99c77ae35065edf0c1ae58d31d78302c302d870d9dcc2c6083e4a2bbaa7b3a694cc5bbc39bc6a626a5dec39dc5e888bd06965cee8076741b40a4e82aa103b164e0442b6ed2af183fd6d69b500dce5ba4c978b6aeb962cc5434aa3a3b6efd56794fd7793e3b62d74d2f23da3ef939f0bfa36e54557d9a48cb8c98ad39f4b8e7e5e3803f91a1a32701eeec170000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d494844520000002c0000002e0806000000534cfb0a00000132494441545885ed994b12032108449b54ee7f65b3cd5440f92a56a5f7326f5a11451a63608b8806c6a0689857068b5a446177f6020361e8fdc04008fa0c30e086a6b4a4f3ba664cc418704212013041fb80b340bfa5847e9b825680022687f549d70016d03aac815d7d988be1a87c6be015acb7dc3ac7cd8167b091734160acbc861bc2029e4a77101690f661c9dd840f46a577b8012cc00157edb749d239dcc45de0e4f1d2a927705235aad4e50e5fa03f70b56c0778ab227bba90ec7d1d167eb62f30c0423f81b9696856aa7b3bcc487fa7f3543ccb18e54cfe3adca914332ce7aff9c6d83cb0e47205b4f176634fba4c68472c1978b69633a09db7f2753330bb91128ca7eb5e56b5aaac316069b756573ce54cf5b8e65fd3d0769870e6c920305bfb1e659296541ef0265d77bcbc0ef803779f9c39421cd9b50000000049454e44ae426082 + + + + + knuminput.h + + diff --git a/chalk/plugins/viewplugins/screenshot/Makefile.am b/chalk/plugins/viewplugins/screenshot/Makefile.am new file mode 100644 index 00000000..9887b7a2 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/Makefile.am @@ -0,0 +1,27 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = screenshot-chalk.rc + +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkscreenshot.la + +chalkscreenshot_la_SOURCES = screenshot.cpp ksnapshot.cpp regiongrabber.cpp ksnapshotwidget.ui +noinst_HEADERS = screenshot.h ksnapshot.h regiongrabber.h ksnapshotwidget.h ksnapshotwidget.ui.h + +chalkscreenshot_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui -lkdeprint +chalkscreenshot_la_LIBADD = ../../../libchalkcommon.la + +kde_services_DATA = chalkscreenshot.desktop + +chalkscreenshot_la_METASOURCES = AUTO + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/kscreenshot_plugin.pot diff --git a/chalk/plugins/viewplugins/screenshot/chalkscreenshot.desktop b/chalk/plugins/viewplugins/screenshot/chalkscreenshot.desktop new file mode 100644 index 00000000..7b9b0d4b --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/chalkscreenshot.desktop @@ -0,0 +1,47 @@ +[Desktop Entry] +Name=Screenshot +Name[bg]=Снимка на екрана +Name[br]=Skrammpaker +Name[ca]=Captura de pantalla +Name[cy]=Sgrinlun +Name[da]=Skærmaftryk +Name[de]=Bildschirmphoto +Name[el]=Στιγμιότυπο οθόνης +Name[eo]=Ekrankopio +Name[es]=Captura de pantalla +Name[et]=Ekraanipilt +Name[fa]=تصویر پرده +Name[fr]=Capture d'écran +Name[fy]=Skermôfbylding +Name[ga]=Seat den Scáileán +Name[gl]=Captura de Pantalla +Name[he]=תמונת מסך +Name[hu]=Képernyőfelvétel +Name[is]=Skjámynd +Name[it]=Schermata +Name[ja]=スクリーンショット +Name[km]=រូបថត​អេក្រង់ +Name[lv]=Ekrānattēls +Name[nb]=Skjermbilde +Name[nds]=Schirmbild +Name[ne]=स्क्रिनसट +Name[nl]=Schermafbeelding +Name[pl]=Zrzut ekranu +Name[pt]=Captura +Name[pt_BR]=Captura de Tela +Name[ru]=Снимок экрана +Name[se]=Šearbmagovva +Name[sk]=Snímač obrazovky +Name[sl]=Posnetek zaslona +Name[sr]=Снимак екрана +Name[sr@Latn]=Snimak ekrana +Name[sv]=Skärmdump +Name[uk]=Знімок екрана +Name[uz]=Skrinshot +Name[uz@cyrillic]=Скриншот +Name[zh_CN]=抓图 +Name[zh_TW]=螢幕快照 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkscreenshot +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp b/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp new file mode 100644 index 00000000..f9887821 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/ksnapshot.cpp @@ -0,0 +1,499 @@ +/* + * KSnapshot + * + * (c) Richard J. Moore 1997-2002 + * (c) Matthias Ettrich 2000 + * (c) Aaron J. Seigo 2002 + * (c) Nadeem Hasan 2003 + * This adaptation: (c) Boudewijn Rempt 2005 + * + * Released under the GPL see file LICENSE for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ksnapshot.h" +#include "regiongrabber.h" +#include "ksnapshotwidget.h" + +#include +#include + +#include + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H +#include +#endif + +#include + +KSnapshot::KSnapshot(TQWidget *tqparent, const char *name) + : super(tqparent, name, false, TQString(), Ok|Cancel) +{ + grabber = new TQWidget( 0, 0, WStyle_Customize | WX11BypassWM ); + Q_CHECK_PTR(grabber); + grabber->move( -1000, -1000 ); + grabber->installEventFilter( this ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + int tmp1, tmp2; + //Check whether the extension is available + haveXShape = XShapeQueryExtension( qt_xdisplay(), &tmp1, &tmp2 ); +#endif + + TQVBox *vbox = makeVBoxMainWidget(); + mainWidget = new KSnapshotWidget( vbox, "mainWidget" ); + Q_CHECK_PTR(mainWidget); + + mainWidget->btnSave->hide(); + mainWidget->btnPrint->hide(); + connect(mainWidget, TQT_SIGNAL(startImageDrag()), TQT_SLOT(slotDragSnapshot())); + + connect( mainWidget, TQT_SIGNAL( newClicked() ), TQT_SLOT( slotGrab() ) ); + connect( mainWidget, TQT_SIGNAL( printClicked() ), TQT_SLOT( slotPrint() ) ); + + grabber->show(); + grabber->grabMouse( waitCursor ); + + snapshot = TQPixmap::grabWindow( qt_xrootwin() ); + updatePreview(); + grabber->releaseMouse(); + grabber->hide(); + + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + mainWidget->setDelay(conf->readNumEntry("delay",0)); + mainWidget->setMode( conf->readNumEntry( "mode", 0 ) ); + mainWidget->setIncludeDecorations(conf->readBoolEntry("includeDecorations",true)); + + connect( &grabTimer, TQT_SIGNAL( timeout() ), this, TQT_SLOT( grabTimerDone() ) ); + + KAccel* accel = new KAccel(this); + Q_CHECK_PTR(accel); + accel->insert(KStdAccel::Print, TQT_TQOBJECT(this), TQT_SLOT(slotPrint())); + accel->insert(KStdAccel::New, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + + accel->insert( "Print2", TQt::Key_P, TQT_TQOBJECT(this), TQT_SLOT(slotPrint())); + accel->insert( "New2", TQt::Key_N, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + accel->insert( "New3", TQt::Key_Space, TQT_TQOBJECT(this), TQT_SLOT(slotGrab())); + + mainWidget->btnNew->setFocus(); + +} + +KSnapshot::~KSnapshot() +{ +} + +bool KSnapshot::save( const TQString &filename ) +{ + return save( KURL::fromPathOrURL( filename )); +} + +bool KSnapshot::save( const KURL& url ) +{ + TQString type( KImageIO::type(url.path()) ); + if ( type.isNull() ) + type = "PNG"; + + bool ok = false; + + if ( url.isLocalFile() ) { + KSaveFile saveFile( url.path() ); + if ( saveFile.status() == 0 ) { + if ( snapshot.save( saveFile.file(), type.latin1() ) ) + ok = saveFile.close(); + } + } + else { + KTempFile tmpFile; + tmpFile.setAutoDelete( true ); + if ( tmpFile.status() == 0 ) { + if ( snapshot.save( tmpFile.file(), type.latin1() ) ) { + if ( tmpFile.close() ) + ok = KIO::NetAccess::upload( tmpFile.name(), url, this ); + } + } + } + + TQApplication::restoreOverrideCursor(); + if ( !ok ) { + kdWarning() << "KSnapshot was unable to save the snapshot" << endl; + + TQString caption = i18n("Unable to Save Image"); + TQString text = i18n("KSnapshot was unable to save the image to\n%1.") + .tqarg(url.prettyURL()); + KMessageBox::error(this, text, caption); + } + + return ok; +} + +void KSnapshot::slotCopy() +{ + TQClipboard *cb = TQApplication::tqclipboard(); + cb->setPixmap( snapshot ); +} + +void KSnapshot::slotDragSnapshot() +{ + TQDragObject *drobj = new TQImageDrag(snapshot.convertToImage(), this); + Q_CHECK_PTR(drobj); + drobj->setPixmap(mainWidget->preview()); + drobj->dragCopy(); +} + +void KSnapshot::slotGrab() +{ + hide(); + if ( mainWidget->mode() == Region ) + { + rgnGrab = new RegionGrabber(); + Q_CHECK_PTR(rgnGrab); + connect( rgnGrab, TQT_SIGNAL( regionGrabbed( const TQPixmap & ) ), + TQT_SLOT( slotRegionGrabbed( const TQPixmap & ) ) ); + } + else + { + if ( mainWidget->delay() ) + grabTimer.start( mainWidget->delay() * 1000, true ); + else { + grabber->show(); + grabber->grabMouse( crossCursor ); + } + } +} + +void KSnapshot::slotPrint() +{ + KPrinter printer; + if (snapshot.width() > snapshot.height()) + printer.setOrientation(KPrinter::Landscape); + else + printer.setOrientation(KPrinter::Portrait); + + tqApp->processEvents(); + + if (printer.setup(this, i18n("Print Screenshot"))) + { + tqApp->processEvents(); + + TQPainter painter(&printer); + TQPaintDeviceMetrics metrics(painter.device()); + + float w = snapshot.width(); + float dw = w - metrics.width(); + float h = snapshot.height(); + float dh = h - metrics.height(); + bool scale = false; + + if ( (dw > 0.0) || (dh > 0.0) ) + scale = true; + + if ( scale ) { + + TQImage img = snapshot.convertToImage(); + tqApp->processEvents(); + + float newh, neww; + if ( dw > dh ) { + neww = w-dw; + newh = neww/w*h; + } + else { + newh = h-dh; + neww = newh/h*w; + } + + img = img.smoothScale( int(neww), int(newh), TQ_ScaleMin ); + tqApp->processEvents(); + + int x = (metrics.width()-img.width())/2; + int y = (metrics.height()-img.height())/2; + + painter.drawImage( x, y, img); + } + else { + int x = (metrics.width()-snapshot.width())/2; + int y = (metrics.height()-snapshot.height())/2; + painter.drawPixmap( x, y, snapshot ); + } + } + + tqApp->processEvents(); +} + +void KSnapshot::slotRegionGrabbed( const TQPixmap &pix ) +{ + if ( !pix.isNull() ) + { + snapshot = pix; + updatePreview(); + modified = true; + } + + delete rgnGrab; + TQApplication::restoreOverrideCursor(); + show(); +} + +bool KSnapshot::eventFilter( TQObject* o, TQEvent* e) +{ + if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(grabber) && e->type() == TQEvent::MouseButtonPress ) { + TQMouseEvent* me = (TQMouseEvent*) e; + if ( TQWidget::mouseGrabber() != grabber ) + return false; + if ( me->button() == Qt::LeftButton ) + performGrab(); + } + return false; +} + +void KSnapshot::updatePreview() +{ + TQImage img = snapshot.convertToImage(); + double r1 = ((double) snapshot.height() ) / snapshot.width(); + if ( r1 * mainWidget->previewWidth() < mainWidget->previewHeight() ) + img = img.smoothScale( mainWidget->previewWidth(), + int( mainWidget->previewWidth() * r1 )); + else + img = img.smoothScale( (int) (((double)mainWidget->previewHeight()) / r1), + (mainWidget->previewHeight() ) ); + + TQPixmap pm; + pm.convertFromImage( img ); + mainWidget->setPreview( pm ); +} + +void KSnapshot::grabTimerDone() +{ + performGrab(); + KNotifyClient::beep(i18n("The screen has been successfully grabbed.")); +} + +static +Window findRealWindow( Window w, int depth = 0 ) +{ + if( depth > 5 ) + return None; + static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False ); + Atom type; + int format; + unsigned long nitems, after; + unsigned char* prop; + if( XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType, + &type, &format, &nitems, &after, &prop ) == Success ) { + if( prop != NULL ) + XFree( prop ); + if( type != None ) + return w; + } + Window root, tqparent; + Window* tqchildren; + unsigned int ntqchildren; + Window ret = None; + if( XQueryTree( qt_xdisplay(), w, &root, &tqparent, &tqchildren, &ntqchildren ) != 0 ) { + for( unsigned int i = 0; + i < ntqchildren && ret == None; + ++i ) + ret = findRealWindow( tqchildren[ i ], depth + 1 ); + if( tqchildren != NULL ) + XFree( tqchildren ); + } + return ret; +} + +void KSnapshot::performGrab() +{ + grabber->releaseMouse(); + grabber->hide(); + grabTimer.stop(); + XGrabServer( qt_xdisplay()); + if ( mainWidget->mode() == WindowUnderCursor ) { + Window root; + Window child; + uint tqmask; + int rootX, rootY, winX, winY; + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, + &rootX, &rootY, &winX, &winY, + &tqmask); + if( child == None ) + child = qt_xrootwin(); + if( !mainWidget->includeDecorations()) { + Window real_child = findRealWindow( child ); + if( real_child != None ) // test just in case + child = real_child; + } + int x, y; + unsigned int w, h; + unsigned int border; + unsigned int depth; + XGetGeometry( qt_xdisplay(), child, &root, &x, &y, + &w, &h, &border, &depth ); + w += 2 * border; + h += 2 * border; + + Window tqparent; + Window* tqchildren; + unsigned int ntqchildren; + if( XQueryTree( qt_xdisplay(), child, &root, &tqparent, + &tqchildren, &ntqchildren ) != 0 ) { + if( tqchildren != NULL ) + XFree( tqchildren ); + int newx, newy; + Window dummy; + if( XTranslateCoordinates( qt_xdisplay(), tqparent, qt_xrootwin(), + x, y, &newx, &newy, &dummy )) { + x = newx; + y = newy; + } + } + + snapshot = TQPixmap::grabWindow( qt_xrootwin(), x, y, w, h ); + +#ifdef HAVE_X11_EXTENSIONS_SHAPE_H + //No XShape - no work. + if (haveXShape) { + TQBitmap tqmask(w, h); + //As the first step, get the tqmask from XShape. + int count, order; + XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child, + ShapeBounding, &count, &order); + //The ShapeBounding region is the outermost tqshape of the window; + //ShapeBounding - ShapeClipping is defined to be the border. + //Since the border area is part of the window, we use bounding + // to limit our work region + if (rects) { + //Create a TQRegion from the rectangles describing the bounding tqmask. + TQRegion contents; + for (int pos = 0; pos < count; pos++) + contents += TQRegion(rects[pos].x, rects[pos].y, + rects[pos].width, rects[pos].height); + XFree(rects); + + //Create the bounding box. + TQRegion bbox(0, 0, snapshot.width(), snapshot.height()); + + if( border > 0 ) { + contents.translate( border, border ); + contents += TQRegion( 0, 0, border, h ); + contents += TQRegion( 0, 0, w, border ); + contents += TQRegion( 0, h - border, w, border ); + contents += TQRegion( w - border, 0, border, h ); + } + + //Get the tqmasked away area. + TQRegion tqmaskedAway = bbox - contents; + TQMemArray tqmaskedAwayRects = tqmaskedAway.rects(); + + //Construct a bitmap tqmask from the rectangles + TQPainter p(&tqmask); + p.fillRect(0, 0, w, h, TQt::color1); + for (uint pos = 0; pos < tqmaskedAwayRects.count(); pos++) + p.fillRect(tqmaskedAwayRects[pos], TQt::color0); + p.end(); + + snapshot.setMask(tqmask); + } + } +#endif + } + else { + snapshot = TQPixmap::grabWindow( qt_xrootwin() ); + } + XUngrabServer( qt_xdisplay()); + updatePreview(); + TQApplication::restoreOverrideCursor(); + modified = true; +// show(); + slotOk(); +} + +void KSnapshot::setTime(int newTime) +{ + mainWidget->setDelay(newTime); +} + +void KSnapshot::setURL( const TQString &url ) +{ + KURL newURL = KURL::fromPathOrURL( url ); + if ( newURL == filename ) + return; + + filename = newURL; +} + +void KSnapshot::setGrabMode( int m ) +{ + mainWidget->setMode( m ); +} + +void KSnapshot::slotMovePointer(int x, int y) +{ + TQCursor::setPos( x, y ); +} + +void KSnapshot::exit() +{ + + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + conf->writeEntry("delay",mainWidget->delay()); + conf->writeEntry("mode",mainWidget->mode()); + conf->writeEntry("includeDecorations",mainWidget->includeDecorations()); + KURL url = filename; + url.setPass( TQString() ); + conf->writePathEntry("filename",url.url()); + + reject(); +} + +void KSnapshot::slotOk() +{ + + KConfig *conf=KGlobal::config(); + conf->setGroup("GENERAL"); + conf->writeEntry("delay",mainWidget->delay()); + conf->writeEntry("mode",mainWidget->mode()); + conf->writeEntry("includeDecorations",mainWidget->includeDecorations()); + KURL url = filename; + url.setPass( TQString() ); + conf->writePathEntry("filename",url.url()); + + emit screenGrabbed(); + + accept(); +} + +#include "ksnapshot.moc" diff --git a/chalk/plugins/viewplugins/screenshot/ksnapshot.h b/chalk/plugins/viewplugins/screenshot/ksnapshot.h new file mode 100644 index 00000000..030cad12 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/ksnapshot.h @@ -0,0 +1,137 @@ +// -*- c++ -*- +/* + * (c) Richard J. Moore 1997-2002 + * (c) Matthias Ettrich 2000 + * (c) Aaron J. Seigo 2002 + * (c) Nadeem Hasan 2003 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KSNAPSHOT_H +#define KSNAPSHOT_H + +#include +#include +#include + +#include +#include +#include +#include + +class RegionGrabber; +class KSnapshotWidget; + +class KSnapshotThumb : public TQLabel +{ + Q_OBJECT + TQ_OBJECT + +public: + KSnapshotThumb(TQWidget *tqparent, const char *name = 0) + : TQLabel(tqparent, name) + { + tqsetAlignment(AlignHCenter | AlignVCenter); + } + virtual ~KSnapshotThumb() {} + +signals: + void startDrag(); + +protected: + void mousePressEvent(TQMouseEvent * e) + { + mClickPt = e->pos(); + } + + void mouseMoveEvent(TQMouseEvent * e) + { + if (mClickPt != TQPoint(0, 0) && + (e->pos() - mClickPt).manhattanLength() > KGlobalSettings::dndEventDelay()) + { + mClickPt = TQPoint(0, 0); + emit startDrag(); + } + } + + void mouseReleaseEvent(TQMouseEvent * /*e*/) + { + mClickPt = TQPoint(0, 0); + } + + TQPoint mClickPt; +}; + +class KSnapshot : public KDialogBase +{ + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + KSnapshot(TQWidget *tqparent= 0, const char *name= 0); + ~KSnapshot(); + + enum CaptureMode { FullScreen=0, WindowUnderCursor=1, Region=2 }; + + bool save( const TQString &filename ); + bool save( const KURL& url ); + + TQString url() const { return filename.url(); } + +signals: + void screenGrabbed(); + +protected slots: + void slotGrab(); + void slotCopy(); + void slotPrint(); + void slotMovePointer( int x, int y ); + + void setTime(int newTime); + void setURL(const TQString &newURL); + void setGrabMode( int m ); + void exit(); + + void slotOk(); + + +protected: + void reject() { close(); } + bool eventFilter( TQObject*, TQEvent* ); + +private slots: + void grabTimerDone(); + void slotDragSnapshot(); + void slotRegionGrabbed( const TQPixmap & ); + +private: + void updatePreview(); + void performGrab(); + void autoincFilename(); + + TQPixmap snapshot; + TQTimer grabTimer; + TQWidget* grabber; + KURL filename; + KSnapshotWidget *mainWidget; + RegionGrabber *rgnGrab; + bool modified; + bool haveXShape; +}; + +#endif // KSNAPSHOT_H + diff --git a/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui b/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui new file mode 100644 index 00000000..0672215e --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui @@ -0,0 +1,335 @@ + +KSnapshotWidget + + + KSnapshotWidget + + + + 0 + 0 + 358 + 241 + + + + + unnamed + + + 0 + + + + lblImage + + + + 200 + 130 + + + + Thumbnail of the current snapshot + + + This is a thumbnail of the current snapshot. + +The image can be dragged to another application or document to copy the full screenshot there. Try it with the Konqueror file manager. + + + + + btnNew + + + &New Snapshot + + + "tool_screenshot" + + + Click this button to take a new snapshot. + + + + + btnSave + + + &Save As... + + + "filesave" + + + Click this button to save the current snapshot. To quickly save the snapshot without showing the file dialog, press Ctrl+Shift+S. The filename is automatically incremented after each save. + + + + + Spacer6 + + + Vertical + + + Expanding + + + + 16 + 16 + + + + + + btnPrint + + + &Print... + + + "fileprint" + + + Click this button to print the current screenshot. + + + + + line1 + + + HLine + + + Sunken + + + Horizontal + + + + + spinDelay + + + sec + + + No delay + + + Snapshot delay in seconds + + + <qt> +This is the number of seconds to wait after clicking the <i>New Snapshot</i> button before taking the snapshot. +<p> +This is very useful for getting windows, menus and other items on the screen set up just the way you want. +<p> +If <i>no delay</i> is set, the program will wait for a mouse click before taking a snapshot. +</p> +</qt> + + + + + lblDelay + + + Snapshot &delay: + + + spinDelay + + + + + textLabel1 + + + Cap&ture mode: + + + comboMode + + + + + Spacer1 + + + Horizontal + + + Expanding + + + + 156 + 16 + + + + + + cbIncludeDecorations + + + Include &window decorations + + + true + + + When enabled, snapshot of a window will also include the window decorations + + + + + + Full Screen + + + + + Window Under Cursor + + + + + Region + + + + comboMode + + + <qt>Using this menu, you can select from the three following snapshot modes: +<p> +<b>Full Screen</b> - captures the entire desktop.<br> +<b>Window Under Cursor</b> - captures only the window (or menu) that is under the mouse cursor when the snapshot is taken.<br> +<b>Region</b> - captures only the region of the desktop that you specify. When taking a new snapshot in this mode you will be able to select any area of the screen by clicking and dragging the mouse.</p></qt> + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 31 + + + + + + + + KSnapshotThumb +
ksnapshot.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 + startDrag() +
+
+ + + 789c9597db4e1d4b0e86eff31428be8b46b5fb54dd551acd051020211c4320c0682eecaa5e9ccf90005bf3ee53cbbfe9d9c9c548a38ea27c2977b5cbfe6dd7fae3c3c2e1cee6c2873fde3d3cf2e3595a48a77cbff0213f5d5dbdfcf35ffff8f3ddfba65998fff161a179ffb777ef771f17d2c2d6cdf53807c705a889cdac6ee72c47736eebd637b5f2b672d70ecd30e744ca7d9b9a4ad7579587363433e527e5d072abefbb03636978ceb4a31c5bc13a91716ad41f89e0aec2fe74abcc6d6ad5f9e4945357375ef75f997357751dd61d19c71afb61bdef421b951f274ebaffb6716cb3f2b2f230f18d3183dd95b1b441d7d59f2e94757ccf1b27eceff69563618d0f5dcfd9d7beeb7a5dd7f3fac6fb4ee32b87c619f1168d976f7d6ff6df26d6ef4b301e1bac7f54f63e747a5e87f5c173276aff605c22a8fefc540e5e3af5972f956359577bf2c6d978cb78d6697edc9eb2f8b143fed7945359d778b0e6c3e7be81bf7465dce23cf4ac3c16567f19fecefaae53bd081b7baccbb131b7d05f679ca03f27c6b9d1f388c6bbaffab7f80dca4d1fed7bfafdbeedb9533d490f1e2ae8d5693ccacb83d77cd027e3d4416faa97beefa3d7f8f086f168f9d9020f43a3f5c5aa877e28eb88f74fe319becfaa873e0c15de775f95639f3dec37c143d361bf2be3cef4b76bdcb7d84ff5d2cbd0227facf1ecd360fa67d54b9f078ffcd10f636e11ff53e3847853ad3c1b668837e9fe43358c2df45a81430b3db2e6676842d368fd48abdc068b87e0fd2e788bf792b21f861e7afd0e0e5ce37dcdd7d0872218e5d789f57b3218a71ae7bb501eca3af67b510e21c05fd27a1b6218ac3ef17d0ed68fe8cb1be3fc6e5159863ca0bfed824340fe687d62c4838c23f677f0370de380fcdd2be7e03dfab1d6cf300bcd80fa80bfb358dbf9547fa18abe413d68fe421d63ade7737aded094cf63fdcc38f4d0bfee17dac2d08380a3a0dff24cb90bdc23ffaa87e0636c912fed87612e38d4df1e982bc4dbdd29872001f14aca319413eb793e83cbfbe8af27606e4c0f5f8d3bcb7763ec6b8da73b57e69083d61f9d82b9b5fada31f635fcaf8d7b7b5ffb41f16e34ff34fe214dfc0c8e1ef1a22330bfcdc345e31e4c33e3c1e6e181b1609e3ac43f8759803e8cd9f2e7e0ff18ab80ef5d8239e2fc0ef129f90ff0bf0773347fee8d13ce279bc6b34af5c61abf58157bf4b765b05435f4abfec726968c2b67e536fa80fe388279067f680d2c750dff75fe9766da07e44bc02521ba4e1d584c1fb261dcc23fd97f63f8c3af136bfc687362c4e76962ed8fac7a2ecdb7853f7c63ec6bf467bd3fc421c680780c60b6f9275fc045aea84fadaf18a2e0fc04ff0237bd9e8fefc0d236e8ef3f8d83c57fdd38daf94edeb886be74fec618b3ed7f3731e66b0fe67a403e76c0454ef8de9231dbfe9f8dc5fc47be38a6887ad2f950964d2fdc1a27d3c7b6710693f6ef9864b4fdb4ffc6cc5540fea0972c339c87afc1c9f4443a5fe2c84d40bd2f82cb3ae6c7b1716dbc37b1e68bf5be118b7e3dead78125d87d0bfa99bd7d8fb78c1bdb4fcfcfd51bcb9d716bebda3fb8966cf7cf57709103f2e327c6fe5a2fdc4ab4fb01deef5283fa65d50ffb54c13fd67ec37d61e845fb070f8571df7c341eec7e7a691c6ae453fb771937d1fa999ebfa43358bf573d3327c6fdd0a9de59b87414e59f60911ef3ff07380d16bf0b63b6fbb8ce0f4e523a80ee8ff8a5f21fe83f384f2e8cf9d419db7d4bb4bff32cb1dd871ae38c79417962dd9f8f2786bfaa3fa992ddbf68d5d8d6797d62dc27b4bf4a9bdeee5be7c619efbb169c2b9bb7aa67e972857a67d59bf8943cf4a6f5237dae3b9c3f4f8cef5713637e6a3c6548e546a7eb87e0b28e7cf7c68ddd2fb15f28acf166bd2f484c19f921f8cbc57de84ff52c397b8f7e178d7bbb7f7e9f18f743d593ccd210d12f9e8c05fd8417c1e5e704e2afefa7aa5cf850ff4fc6a1473debfc4d7561c4ebd3c48897f69fd4e4d8eb7e4efb736a0b23fe9adfd465bb3f388d6ff22933fa1df6f7597ad483c62371f6e6ff8671b6f89e198fb8cfb0ea3f49619c6f6562cc27d5474a7906e6b589d1df549f29e78479450fe0b1c2fc67d5731a0ba33ffc97a167fd7d92ebb1b1f9a87acdcdd8a23ff2e3c4a81fed0fb91bbb88f8e9f772f9b9c6b8bfac187bd41febbcc8c35831f4bb6edc227eeec8b847bc58ef0f398d91a1179d6f391746bdebfd60ac4716b0180bd8a97e473f8ea2dfdb7d9c3f8e1cff8f8760057b27e57f92cb6e743377e24efff29cb97377e12edd55b190c99eddb5bb71b7eeceddbb07f7e89edc0ff7d33dbb17f7ea16dd925b761fdd8a63d8174f52b15e756bee93fbecd6dd17b7e136dd96db763b6ed77d2dd67bee9bdb77078ed49e8b27b7c5fabb3b7447eed855ae768d6bcbd339ef7a37b8e022392a2734fbd1dd119350a24c23cde8844ee98ccee9c2f9c2977445d77443b793fd8ceee89e1ee8919ee807fdb4e7995ee8b5d82fd252b15ffe8bfd097da4155aa535fa34597fa6f5f2f717da28f69bb445dbb433d99fd22e7da53dfa3659efd3017da7c3f2af233aa68aeadfec1b6aa9236fd63d0d14ca15c0719913737b965fedcbf0c83cc29a677cc2a77cc6e77cc1977cc5d7c5fee637fbdbb2db9d5adff343b17ee427fec1737ee69762fffa9bfd222ff17259fdc82bbcca6bfc893ff33a7fe10ddee42ddee69ddfec77f92beff137dee703fece877cc4c7aee58a6b6ee8b8fc10ed7eb13f635f9a4bc5e54719477152ba671977a505c84845c57222a7bfd89fcb999ccb855cca955cbfc5546ee456ee68b14cf67b799047799aec2fdc92fc28999cef567224cff222afb2c85b32e36d599265f9282bb23ad95fba6559934f2593f3e798b74acc8fd5f6b3accb17d9904dd9926db3a7520d1fdd37d9915df95a72599e1291566df7e49beccb817c974339829eb55e56dc7e51ec0d2dcbb1545297a791563af1c5eff2d3beb4faf8562f568f0744745b9e9d5f1f7992d5e412a186ffef7afff7dfdffd077c99ae99 + + + + + comboMode + activated(int) + KSnapshotWidget + slotModeChanged(int) + + + btnNew + clicked() + KSnapshotWidget + slotNewClicked() + + + btnPrint + clicked() + KSnapshotWidget + slotPrintClicked() + + + btnSave + clicked() + KSnapshotWidget + slotSaveClicked() + + + lblImage + startDrag() + KSnapshotWidget + slotStartDrag() + + + + btnNew + btnSave + btnPrint + comboMode + spinDelay + cbIncludeDecorations + + + kdialog.h + kiconloader.h + kglobalsettings.h + ksnapshotwidget.ui.h + + + newClicked() + saveClicked() + printClicked() + startImageDrag() + + + slotModeChanged( int mode ) + slotNewClicked() + slotSaveClicked() + slotPrintClicked() + slotStartDrag() + previewWidth() + previewHeight() + + + setPreview( const TQPixmap & pm ) + setDelay( int i ) + setIncludeDecorations( bool b ) + setMode( int mode ) + delay() + includeDecorations() + mode() + preview() + +SmallIconSet + + +
diff --git a/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h b/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h new file mode 100644 index 00000000..3c552868 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/ksnapshotwidget.ui.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** TQt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + + +void KSnapshotWidget::slotModeChanged( int mode ) +{ + switch ( mode ) + { + case 0: + lblDelay->setEnabled(true); + spinDelay->setEnabled(true); + cbIncludeDecorations->setEnabled(false); + break; + case 1: + lblDelay->setEnabled(true); + spinDelay->setEnabled(true); + cbIncludeDecorations->setEnabled(true); + break; + case 2: + lblDelay->setEnabled(false); + spinDelay->setEnabled(false); + cbIncludeDecorations->setEnabled(false); + default: + break; + } +} + + +void KSnapshotWidget::setPreview( const TQPixmap &pm ) +{ + lblImage->setPixmap(pm); +} + + +void KSnapshotWidget::setDelay( int i ) +{ + spinDelay->setValue(i); +} + + +void KSnapshotWidget::setIncludeDecorations( bool b ) +{ + cbIncludeDecorations->setChecked(b); +} + + +void KSnapshotWidget::setMode( int mode ) +{ + comboMode->setCurrentItem(mode); + slotModeChanged(mode); +} + + +int KSnapshotWidget::delay() +{ + return spinDelay->value(); +} + + +bool KSnapshotWidget::includeDecorations() +{ + return cbIncludeDecorations->isChecked(); +} + + +int KSnapshotWidget::mode() +{ + return comboMode->currentItem(); +} + + +void KSnapshotWidget::slotNewClicked() +{ + emit newClicked(); +} + + +void KSnapshotWidget::slotSaveClicked() +{ + emit saveClicked(); +} + + +void KSnapshotWidget::slotPrintClicked() +{ + emit printClicked(); +} + + +void KSnapshotWidget::slotStartDrag() +{ + emit startImageDrag(); +} + + +TQPixmap KSnapshotWidget::preview() +{ + return *lblImage->pixmap(); +} + + +int KSnapshotWidget::previewWidth() +{ + return lblImage->width(); +} + + +int KSnapshotWidget::previewHeight() +{ + return lblImage->height(); +} + diff --git a/chalk/plugins/viewplugins/screenshot/main.cpp b/chalk/plugins/viewplugins/screenshot/main.cpp new file mode 100644 index 00000000..70f61349 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/main.cpp @@ -0,0 +1,38 @@ +#include +#include "ksnapshot.h" +#include +#include +#include +#include +#include + +static const char description[] = + I18N_NOOP("KDE Screenshot Utility"); + +int main(int argc, char **argv) +{ + KAboutData aboutData( "ksnapshot", I18N_NOOP("KSnapshot"), + KSNAPVERSION, description, KAboutData::License_GPL, + "(c) 1997-2003, Richard J. Moore,\n(c) 2000, Matthias Ettrich,\n(c) 2002-2003 Aaron J. Seigo"); + aboutData.addAuthor("Richard J. Moore",0, "rich@kde.org"); + aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org"); + aboutData.addAuthor("Aaron J. Seigo", 0, "aseigo@kde.org"); + aboutData.addCredit( "Nadeem Hasan", "Region Grabbing\nReworked GUI", + "nhasan@kde.org" ); + KCmdLineArgs::init( argc, argv, &aboutData ); + + KApplication app; + + KImageIO::registerFormats(); + + // Create top level window + KSnapshot *toplevel= new KSnapshot(); + Q_CHECK_PTR(toplevel); + app.dcopClient()->setDefaultObject( toplevel->objId() ); + toplevel->setCaption( app.makeStdCaption("") ); + toplevel->setIcon(SmallIcon("tool_screenshot")); + app.setMainWidget(toplevel); + toplevel->show(); + return app.exec(); +} + diff --git a/chalk/plugins/viewplugins/screenshot/regiongrabber.cpp b/chalk/plugins/viewplugins/screenshot/regiongrabber.cpp new file mode 100644 index 00000000..1d3a451d --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/regiongrabber.cpp @@ -0,0 +1,170 @@ +/* + * This file was copied from ksnapshot + * + * Copyright (C) 2003 Nadeem Hasan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "regiongrabber.h" + +#include +#include +#include +#include +#include + +#include + +SizeTip::SizeTip( TQWidget *tqparent, const char *name ) + : TQLabel( tqparent, name, WStyle_Customize | WX11BypassWM | + WStyle_StaysOnTop | WStyle_NoBorder | WStyle_Tool ) +{ + setMargin( 2 ); + setIndent( 0 ); + setFrameStyle( TQFrame::Plain | TQFrame::Box ); + + setPalette( TQToolTip::palette() ); +} + +void SizeTip::setTip( const TQRect &rect ) +{ + TQString tip = TQString( "%1x%2" ).tqarg( rect.width() ) + .tqarg( rect.height() ); + + setText( tip ); + adjustSize(); + + positionTip( rect ); +} + +void SizeTip::positionTip( const TQRect &rect ) +{ + TQRect tipRect = tqgeometry(); + tipRect.moveTopLeft( TQPoint( 0, 0 ) ); + + if ( rect.intersects( tipRect ) ) + { + TQRect deskR = KGlobalSettings::desktopGeometry( TQPoint( 0, 0 ) ); + + tipRect.moveCenter( TQPoint( deskR.width()/2, deskR.height()/2 ) ); + if ( !rect.tqcontains( tipRect, true ) && rect.intersects( tipRect ) ) + tipRect.moveBottomRight( tqgeometry().bottomRight() ); + } + + move( tipRect.topLeft() ); +} + +RegionGrabber::RegionGrabber() + : TQWidget( 0, 0 ), + mouseDown( false ), sizeTip( 0L ) +{ + sizeTip = new SizeTip( ( TQWidget * )0L ); + + tipTimer = new TQTimer( this ); + Q_CHECK_PTR(tipTimer); + connect( tipTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( updateSizeTip() ) ); + + TQTimer::singleShot( 200, this, TQT_SLOT( initGrabber() ) ); +} + +RegionGrabber::~RegionGrabber() +{ + delete sizeTip; +} + +void RegionGrabber::initGrabber() +{ + pixmap = TQPixmap::grabWindow( qt_xrootwin() ); + setPaletteBackgroundPixmap( pixmap ); + + showFullScreen(); + + grabMouse( crossCursor ); +} + +void RegionGrabber::mousePressEvent( TQMouseEvent *e ) +{ + if ( e->button() == Qt::LeftButton ) + { + mouseDown = true; + grabRect = TQRect( e->pos(), e->pos() ); + } +} + +void RegionGrabber::mouseMoveEvent( TQMouseEvent *e ) +{ + if ( mouseDown ) + { + sizeTip->hide(); + tipTimer->start( 250, true ); + + drawRubber(); + grabRect.setBottomRight( e->pos() ); + drawRubber(); + } +} + +void RegionGrabber::mouseReleaseEvent( TQMouseEvent *e ) +{ + mouseDown = false; + drawRubber(); + sizeTip->hide(); + + grabRect.setBottomRight( e->pos() ); + grabRect = grabRect.normalize(); + + TQPixmap region = TQPixmap::grabWindow( winId(), grabRect.x(), grabRect.y(), + grabRect.width(), grabRect.height() ); + + releaseMouse(); + + emit regionGrabbed( region ); +} + +void RegionGrabber::keyPressEvent( TQKeyEvent *e ) +{ + if ( e->key() == TQt::Key_Escape ) + { + releaseMouse(); + emit regionGrabbed( TQPixmap() ); + } + else + e->ignore(); +} + +void RegionGrabber::updateSizeTip() +{ + TQRect rect = grabRect.normalize(); + + sizeTip->setTip( rect ); + sizeTip->show(); +} + +void RegionGrabber::drawRubber() +{ + TQPainter p; + p.begin( this ); + p.setRasterOp( NotROP ); + p.setPen( TQPen( color0, 1 ) ); + p.setBrush( NoBrush ); + + tqstyle().tqdrawPrimitive( TQStyle::PE_FocusRect, &p, grabRect, tqcolorGroup(), + TQStyle::Style_Default, TQStyleOption( tqcolorGroup().base() ) ); + + p.end(); +} + +#include "regiongrabber.moc" diff --git a/chalk/plugins/viewplugins/screenshot/regiongrabber.h b/chalk/plugins/viewplugins/screenshot/regiongrabber.h new file mode 100644 index 00000000..b1da1049 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/regiongrabber.h @@ -0,0 +1,72 @@ +/* + * This file is copied from ksnapshot. + * + * Copyright (C) 2003 Nadeem Hasan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or ( at your option ) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef REGIONGRABBER_H +#define REGIONGRABBER_H + +#include +#include + +class TQTimer; + +class SizeTip : public TQLabel +{ +public: + SizeTip( TQWidget *tqparent, const char *name=0 ); + ~SizeTip() {} + + void setTip( const TQRect &rect ); + void positionTip( const TQRect &rect ); +}; + +class RegionGrabber : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + +public: + RegionGrabber(); + ~RegionGrabber(); + +protected slots: + void initGrabber(); + void updateSizeTip(); + + signals: + void regionGrabbed( const TQPixmap & ); + +protected: + void mousePressEvent( TQMouseEvent *e ); + void mouseReleaseEvent( TQMouseEvent *e ); + void mouseMoveEvent( TQMouseEvent *e ); + void keyPressEvent( TQKeyEvent *e ); + + void drawRubber(); + + bool mouseDown; + TQRect grabRect; + TQPixmap pixmap; + + SizeTip *sizeTip; + TQTimer *tipTimer; +}; + +#endif // REGIONGRABBER_H + diff --git a/chalk/plugins/viewplugins/screenshot/screenshot-chalk.rc b/chalk/plugins/viewplugins/screenshot/screenshot-chalk.rc new file mode 100644 index 00000000..ec96bf11 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/screenshot-chalk.rc @@ -0,0 +1,9 @@ + + + + &Tools + + + + + diff --git a/chalk/plugins/viewplugins/screenshot/screenshot-kpresenter.rc b/chalk/plugins/viewplugins/screenshot/screenshot-kpresenter.rc new file mode 100644 index 00000000..8f1f2033 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/screenshot-kpresenter.rc @@ -0,0 +1,9 @@ + + + + &Insert + + + + + diff --git a/chalk/plugins/viewplugins/screenshot/screenshot-kword.rc b/chalk/plugins/viewplugins/screenshot/screenshot-kword.rc new file mode 100644 index 00000000..f923f87f --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/screenshot-kword.rc @@ -0,0 +1,9 @@ + + + + &Insert + + + + + diff --git a/chalk/plugins/viewplugins/screenshot/screenshot.cpp b/chalk/plugins/viewplugins/screenshot/screenshot.cpp new file mode 100644 index 00000000..ff762925 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/screenshot.cpp @@ -0,0 +1,78 @@ +/* + * This file is part of the KDE project + * + * This file was copied from ksnapshot + * + * Copyright (C) 2001 Nikolas Zimmermann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ksnapshot.h" +#include +#include +#include +#include "screenshot.moc" + + +K_EXPORT_COMPONENT_FACTORY( chalkscreenshot, KGenericFactory( "chalk" ) ) + +Screenshot::Screenshot(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + KGlobal::locale()->insertCatalogue("kscreenshot_plugin"); + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","chalkplugins/screenshot-chalk.rc"), true); + KImageIO::registerFormats(); + + snapshot = new KSnapshot(); + Q_CHECK_PTR(snapshot); + connect( snapshot, TQT_SIGNAL( screenGrabbed() ), TQT_SLOT( slotScreenGrabbed() ) ); + + (void) new KAction(i18n("&Screenshot..."), SmallIcon("tool_screenshot"), 0, this, TQT_SLOT(slotScreenshot()), actionCollection(), "screenshot"); + +} + +Screenshot::~Screenshot() +{ + delete snapshot; +} + +void Screenshot::slotScreenshot() +{ + snapshot->show(); +} + +void Screenshot::slotScreenGrabbed() +{ + KTempFile temp(locateLocal("tmp", "screenshot"), ".png"); + snapshot->save(temp.name()); + + KisView *view = dynamic_cast(tqparent()); + if(view) + view->importImage(temp.name()); +} diff --git a/chalk/plugins/viewplugins/screenshot/screenshot.h b/chalk/plugins/viewplugins/screenshot/screenshot.h new file mode 100644 index 00000000..d1100836 --- /dev/null +++ b/chalk/plugins/viewplugins/screenshot/screenshot.h @@ -0,0 +1,43 @@ +/* This file is part of the KDE project + * Copyright (C) 2001 Nikolas Zimmermann + * Copyright (C) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef SCREENSHOT_H +#define SCREENSHOT_H + +#include + +class KSnapshot; + +class Screenshot : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + Screenshot(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~Screenshot(); + +private slots: + void slotScreenshot(); + void slotScreenGrabbed(); + +private: + KSnapshot * snapshot; +}; + +#endif diff --git a/chalk/plugins/viewplugins/scripting/Makefile.am b/chalk/plugins/viewplugins/scripting/Makefile.am new file mode 100644 index 00000000..2bc6c1fd --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/Makefile.am @@ -0,0 +1,29 @@ +SUBDIRS = chalkscripting chalkcore samples + +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = scripting.rc + +kde_services_DATA = chalkscripting.desktop + + +INCLUDES = -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/chalkcolor/ \ + -I$(top_srcdir)/chalk/ui \ + -I$(top_builddir)/lib/kross/main \ + $(KROSS_INCLUDES) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +chalkscripting_la_SOURCES = scripting.cc + +kde_module_LTLIBRARIES = chalkscripting.la +noinst_HEADERS = scripting.h + +chalkscripting_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkscripting_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la $(top_builddir)/lib/kross/main/libkrossmain.la ./chalkscripting/libchalkscripting.la + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +chalkscripting_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/Makefile.am b/chalk/plugins/viewplugins/scripting/chalkcore/Makefile.am new file mode 100644 index 00000000..448c7c59 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/Makefile.am @@ -0,0 +1,30 @@ + +INCLUDES = -I$(top_srcdir)/core -I$(top_srcdir)/chalk/plugins/viewplugins/scripting/chalkscripting \ + -I$(top_srcdir)/chalk $(KOFFICECORE_INCLUDES) $(KROSS_INCLUDES) \ + -I$(top_srcdir)/chalk/ui -I$(top_srcdir)/chalk/core -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/chalkcolor $(all_includes) + +kde_module_LTLIBRARIES = krosschalkcore.la + +krosschalkcore_la_SOURCES = chalkcoremodule.cpp krs_doc.cpp krs_paint_layer.cpp \ + krs_image.cpp krs_histogram.cpp krs_script_progress.cpp krs_painter.cpp krs_color.cpp \ + krs_brush.cpp krs_pattern.cpp krs_filter.cpp krs_filter_configuration.cpp \ + krs_wavelet.cpp + +krosschalkcore_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../../chalk/core/.libs -lchalkimage \ + -L../../../../../chalk/ui/.libs -lchalkui -L../../../../../lib/kofficeui/.libs -lkofficeui -L../../../../../lib/kofficecore/.libs -lkofficecore +krosschalkcore_la_LIBADD = \ + $(LIB_QT) \ + $(LIB_KDECORE) \ + $(top_builddir)/lib/kross/api/libkrossapi.la \ + $(top_builddir)/lib/kross/main/libkrossmain.la \ + $(top_builddir)/chalk/libchalkcommon.la \ + $(top_builddir)/chalk/plugins/viewplugins/scripting/chalkscripting/libchalkscripting.la + +METASOURCES = AUTO +SUBDIRS = . + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_HEADERS = krs_doc.h krs_iterator.h krs_painter.h krs_color.h krs_brush.h \ + krs_filter.h krs_filter_configuration.h krs_wavelet.h diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.cpp new file mode 100644 index 00000000..04f7b653 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "chalkcoremodule.h" + +#include + +//#include +#include +#include
+ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_script_progress.h" + +#include "krs_brush.h" +#include "krs_color.h" +#include "krs_doc.h" +#include "krs_filter.h" +#include "krs_image.h" +#include "krs_pattern.h" +#include "krs_script_progress.h" + +extern "C" +{ + /** + * Exported an loadable function as entry point to use + * the \a KexiAppModule. + */ + Kross::Api::Object* KDE_EXPORT init_module(Kross::Api::Manager* manager) + { + return new Kross::ChalkCore::ChalkCoreModule(manager); + } +} + + +using namespace Kross::ChalkCore; + +ChalkCoreFactory::ChalkCoreFactory(TQString packagePath) : Kross::Api::Event("ChalkCoreFactory"), m_packagePath(packagePath) +{ + addFunction("newRGBColor", &ChalkCoreFactory::newRGBColor); + addFunction("newHSVColor", &ChalkCoreFactory::newHSVColor); + addFunction("getPattern", &ChalkCoreFactory::getPattern); + addFunction("loadPattern", &ChalkCoreFactory::loadPattern); + addFunction("getBrush", &ChalkCoreFactory::getBrush); + addFunction("loadBrush", &ChalkCoreFactory::loadBrush); + addFunction("getFilter", &ChalkCoreFactory::getFilter); + addFunction("newCircleBrush", &ChalkCoreFactory::newCircleBrush); + addFunction("newRectBrush", &ChalkCoreFactory::newRectBrush); + addFunction("newImage", &ChalkCoreFactory::newImage); + addFunction("getPackagePath", &ChalkCoreFactory::getPackagePath); +} + +Kross::Api::Object::Ptr ChalkCoreFactory::newRGBColor(Kross::Api::List::Ptr args) +{ + Color* c = new Color(Kross::Api::Variant::toUInt(args->item(0)), Kross::Api::Variant::toUInt(args->item(1)), Kross::Api::Variant::toUInt(args->item(2)), TQColor::Rgb); + return c; +} +Kross::Api::Object::Ptr ChalkCoreFactory::newHSVColor(Kross::Api::List::Ptr args) +{ + return new Color(Kross::Api::Variant::toUInt(args->item(0)), Kross::Api::Variant::toUInt(args->item(1)), Kross::Api::Variant::toUInt(args->item(2)), TQColor::Hsv); +} + +Kross::Api::Object::Ptr ChalkCoreFactory::getPattern(Kross::Api::List::Ptr args) +{ + KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("PatternServer"); + TQValueList resources = rServer->resources(); + + TQString name = Kross::Api::Variant::toString(args->item(0)); + + for (TQValueList::iterator it = resources.begin(); it != resources.end(); ++it ) + { + if((*it)->name() == name) + { + return new Pattern(dynamic_cast(*it), true); + } + } + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown pattern") ) ); + return 0; + +} + +Kross::Api::Object::Ptr ChalkCoreFactory::loadPattern(Kross::Api::List::Ptr args) +{ + TQString filename = Kross::Api::Variant::toString(args->item(0)); + KisPattern* pattern = new KisPattern(filename); + if(pattern->load()) + { + return new Pattern( pattern, false ); + } else { + delete pattern; + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown pattern") ) ); + return 0; + } +} + +Kross::Api::Object::Ptr ChalkCoreFactory::getBrush(Kross::Api::List::Ptr args) +{ + KisResourceServerBase* rServer = KisResourceServerRegistry::instance()->get("BrushServer"); + TQValueList resources = rServer->resources(); + + TQString name = Kross::Api::Variant::toString(args->item(0)); + + for (TQValueList::iterator it = resources.begin(); it != resources.end(); ++it ) + { + if((*it)->name() == name) + { + return new Brush(dynamic_cast(*it), true); + } + } + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown brush") ) ); + return 0; +} + +Kross::Api::Object::Ptr ChalkCoreFactory::loadBrush(Kross::Api::List::Ptr args) +{ + TQString filename = Kross::Api::Variant::toString(args->item(0)); + KisBrush* brush = new KisBrush(filename); + if(brush->load()) + { + return new Brush( brush, false ); + } else { + delete brush; + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Unknown brush") ) ); + return 0; + } +} + +Kross::Api::Object::Ptr ChalkCoreFactory::getFilter(Kross::Api::List::Ptr args) +{ + TQString name = Kross::Api::Variant::toString(args->item(0)); + KisFilter* filter = KisFilterRegistry::instance()->get(name); + if(filter) + { + return new Filter(filter); + } else { + return 0; + } +} + +Kross::Api::Object::Ptr ChalkCoreFactory::newCircleBrush(Kross::Api::List::Ptr args) +{ + uint w = TQMAX(1, Kross::Api::Variant::toUInt(args->item(0))); + uint h = TQMAX(1, Kross::Api::Variant::toUInt(args->item(1))); + uint hf = 0; + uint vf = 0; + if( args.count() > 2) + { + hf = Kross::Api::Variant::toUInt(args->item(2)); + vf = Kross::Api::Variant::toUInt(args->item(3)); + } + KisAutobrushShape* kas = new KisAutobrushCircleShape(w, h, hf, vf); + TQImage* brsh = new TQImage(); + kas->createBrush(brsh); + return new Brush(new KisAutobrushResource(*brsh), false); +} +Kross::Api::Object::Ptr ChalkCoreFactory::newRectBrush(Kross::Api::List::Ptr args) +{ + uint w = TQMAX(1, Kross::Api::Variant::toUInt(args->item(0))); + uint h = TQMAX(1, Kross::Api::Variant::toUInt(args->item(1))); + uint hf = 0; + uint vf = 0; + if( args.count() > 2) + { + hf = Kross::Api::Variant::toUInt(args->item(2)); + vf = Kross::Api::Variant::toUInt(args->item(3)); + } + KisAutobrushShape* kas = new KisAutobrushRectShape(w, h, hf, vf); + TQImage* brsh = new TQImage(); + kas->createBrush(brsh); + return new Brush(new KisAutobrushResource(*brsh), false);; +} + +Kross::Api::Object::Ptr ChalkCoreFactory::newImage(Kross::Api::List::Ptr args) +{ + int w = Kross::Api::Variant::toInt(args->item(0)); + int h = Kross::Api::Variant::toInt(args->item(1)); + TQString csname = Kross::Api::Variant::toString(args->item(2)); + TQString name = Kross::Api::Variant::toString(args->item(3)); + if( w < 0 || h < 0) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Invalid image size") ) ); + return 0; + } + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csname, ""), ""); + if(!cs) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Colorspace %0 is not available, please check your installation.").tqarg(csname ) ) ); + return 0; + } + + return new Image(new KisImage(0,w,h, cs, name)); +} + +Kross::Api::Object::Ptr ChalkCoreFactory::getPackagePath(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_packagePath); +} + +ChalkCoreModule::ChalkCoreModule(Kross::Api::Manager* manager) + : Kross::Api::Module("chalkcore") , m_manager(manager), m_factory(0) +{ + + TQMap tqchildren = manager->getChildren(); + kdDebug(41011) << " there are " << tqchildren.size() << endl; + for(TQMap::const_iterator it = tqchildren.begin(); it != tqchildren.end(); it++) + { + kdDebug(41011) << it.key() << " " << it.data() << endl; + } + + // Wrap doc + Kross::Api::Object::Ptr chalkdocument = manager->getChild("ChalkDocument"); + if(chalkdocument) { + Kross::Api::QtObject* chalkdocumentqt = (Kross::Api::QtObject*)( chalkdocument.data() ); + if(chalkdocumentqt) { + ::KisDoc* document = (::KisDoc*)( chalkdocumentqt->getObject() ); + if(document) { + addChild( new Doc(document) ); + } else { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'ChalkDocument' published.") ); + } + } + } + // Wrap ChalkScriptProgress + TQString packagePath; + Kross::Api::Object::Ptr chalkscriptprogress = manager->getChild("ChalkScriptProgress"); + if(chalkdocument) { + Kross::Api::QtObject* chalkscriptprogressqt = (Kross::Api::QtObject*)( chalkscriptprogress.data() ); + if(chalkscriptprogressqt) { + ::KisScriptProgress* scriptprogress = (::KisScriptProgress*)( chalkscriptprogressqt->getObject() ); + scriptprogress->activateAsSubject(); + packagePath = scriptprogress->packagePath(); + if(scriptprogress) { + addChild( new ScriptProgress(scriptprogress) ); + } else { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("There was no 'ChalkScriptProgress' published.") ); + } + } + } + m_factory = new ChalkCoreFactory(packagePath); +} + +ChalkCoreModule::~ChalkCoreModule() +{ + if(m_factory) + delete m_factory; +} + + +const TQString ChalkCoreModule::getClassName() const +{ + return "Kross::ChalkCore::ChalkCoreModule"; +} + +Kross::Api::Object::Ptr ChalkCoreModule::call(const TQString& name, Kross::Api::List::Ptr arguments) +{ + kdDebug(41011) << "ChalkCoreModule::call = " << name << endl; + if( m_factory->isAFunction(name)) + { + return m_factory->call(name, arguments); + } else { + return Kross::Api::Module::call(name, arguments); + } +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.h b/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.h new file mode 100644 index 00000000..d719edd6 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/chalkcoremodule.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KRITA_KROSS_KRITACOREMODULE_H +#define KRITA_KROSS_KRITACOREMODULE_H + +#include +#include + +#define KROSS_MAIN_EXPORT KDE_EXPORT + +#include +#include + +namespace Kross { namespace Api { + class Manager; +}} + +namespace Kross { namespace ChalkCore { + /** + * This class contains functions use to create new Kross object in a script + */ + class ChalkCoreFactory : public Kross::Api::Event + { + public: + ChalkCoreFactory(TQString packagePath); + private: + /** + * This function return a new Image. + * It takes four arguments : + * - width + * - height + * - colorspace id + * - name of the image + * + * And in return you get an Image object. + * + * For example (in ruby) : + * @code + * Krosschalkcore::newImage(10,20, "RGBA", "kikoo") + * @endcode + */ + Kross::Api::Object::Ptr newImage(Kross::Api::List::Ptr); + /** + * This function return a new Color with the given RGB triplet + * It takes three arguments : + * - red color (0 to 255) + * - blue color (0 to 255) + * - green color (0 to 255) + * + * For example (in ruby) : + * @code + * Krosschalkcore::newRGBColor(255,0,0) # create a red color + * Krosschalkcore::newRGBColor(255,255,255) # create a white color + * @endcode + */ + Kross::Api::Object::Ptr newRGBColor(Kross::Api::List::Ptr); + /** + * This function return a new Color with the given HSV triplet + * It takes three arguments : + * - hue color (0 to 255) + * - saturation color (0 to 255) + * - value color (0 to 255) + * + * For example (in ruby) : + * @code + * Krosschalkcore::newRGBColor(255,125,0) + * @endcode + */ + Kross::Api::Object::Ptr newHSVColor(Kross::Api::List::Ptr); + /** + * This function return a Pattern taken from the list of ressources + * of chalk + * It takes one argument : + * - the name of the pattern + * + * For example (in ruby) : + * @code + * Krosschalkcore::getPattern("Bricks") + * @endcode + */ + Kross::Api::Object::Ptr getPattern(Kross::Api::List::Ptr); + /** + * This function return a Brush taken from the list of ressources + * of chalk + * It takes one argument : + * - the name of the pattern + * + * For example (in ruby) : + * @code + * Krosschalkcore::getBrush("Circle (05)") + * @endcode + */ + Kross::Api::Object::Ptr getBrush(Kross::Api::List::Ptr); + /** + * This function return a Brush with a circular tqshape + * It takes at least two arguments : + * - width + * - height + * + * It can takes two other arguments : + * - width of the shading + * - height of the shading + * + * If the shading isn't specified, no shading will be used. + * + * For example (in ruby) : + * @code + * Krosschalkcore::newCircleBrush(10,20) # create a plain circle + * Krosschalkcore::newCircleBrush(10,20,5,10) # create a gradient + * @endcode + */ + Kross::Api::Object::Ptr newCircleBrush(Kross::Api::List::Ptr); + /** + * This function return a Brush with a rectangular tqshape + * It takes at least two arguments : + * - width + * - height + * + * It can takes two other arguments : + * - width of the shading + * - height of the shading + * + * If the shading isn't specified, no shading will be used. + * + * For example (in ruby) : + * @code + * Krosschalkcore::newRectBrush(10,20) # create a plain rectangle + * Krosschalkcore::newRectBrush(10,20,5,10) # create a gradient + * @endcode + */ + Kross::Api::Object::Ptr newRectBrush(Kross::Api::List::Ptr); + /** + * This function return a Filter taken from the list of ressources + * of chalk + * It takes one argument : + * - the name of the filter + * + * For example (in ruby) : + * @code + * Krosschalkcore::getFilter("invert") + * @endcode + */ + Kross::Api::Object::Ptr getFilter(Kross::Api::List::Ptr); + /** + * This function loads a Brush and then returns it. + * It takes one argument: the filename of the brush. + */ + Kross::Api::Object::Ptr loadBrush(Kross::Api::List::Ptr); + /** + * This function loads a Pattern and then returns it. + * It takes one argument: the filename of the pattern. + */ + Kross::Api::Object::Ptr loadPattern(Kross::Api::List::Ptr); + /** + * This function return the directory where the script is located. + */ + Kross::Api::Object::Ptr getPackagePath(Kross::Api::List::Ptr); + private: + TQString m_packagePath; + }; + /** + * + */ + class ChalkCoreModule : public Kross::Api::Module + { + public: + /** + * Constructor. + */ + ChalkCoreModule(Kross::Api::Manager* manager); + + /** + * Destructor. + */ + virtual ~ChalkCoreModule(); + + /// \see Kross::Api::Object::getClassName + virtual const TQString getClassName() const; + virtual Kross::Api::Object::Ptr call(const TQString& name, Kross::Api::List::Ptr arguments); + private: + Kross::Api::Manager* m_manager; + ChalkCoreFactory* m_factory; + }; + + +}} + +#endif + diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.cpp new file mode 100644 index 00000000..d3f1cb8a --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_brush.h" + +#include + +namespace Kross { + +namespace ChalkCore { + +Brush::Brush(KisBrush* brush, bool sharedBrush) : Kross::Api::Class("ChalkBrush"), m_brush(brush), m_sharedBrush(sharedBrush) +{ +} + +Brush::~Brush() +{ + if(!m_sharedBrush) + { + delete m_brush; + } +} + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.h new file mode 100644 index 00000000..7a6bdef5 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_brush.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_BRUSH_H +#define KROSS_KRITACOREKRS_BRUSH_H + +#include + +class KisBrush; + +namespace Kross { + +namespace ChalkCore { + +class Brush : public Kross::Api::Class{ + public: + /** + * @param sharedBrush tell if the brush should be deleted or not when this object is deleted + */ + Brush(KisBrush*, bool sharedBrush ); + ~Brush(); + public: + inline KisBrush* getBrush() { return m_brush; } + private: + KisBrush* m_brush; + bool m_sharedBrush; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.cpp new file mode 100644 index 00000000..b02a36f0 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_color.h" + +namespace Kross { + +namespace ChalkCore { + +Color::Color ( int x, int y, int z, TQColor::Spec colorSpec ) + : Kross::Api::Class("ChalkColor"), m_color(x,y,z,colorSpec) +{ +} + +Color::Color() + : Kross::Api::Class("ChalkColor") +{ +} + +Color::~Color() +{ +} + + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.h new file mode 100644 index 00000000..7955dc92 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_color.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_APIKRS_COLOR_H +#define KROSS_APIKRS_COLOR_H + +#include + +#include + +namespace Kross { + +namespace ChalkCore { + +class Color : public Kross::Api::Class +{ + public: + Color ( int x, int y, int z, TQColor::Spec colorSpec ); + Color (); + + ~Color(); + public: + inline const TQString getClassName() const + { return "Kross::Chalk::Color"; }; + inline TQColor toTQColor() { return m_color; }; + private: + TQColor m_color; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.cpp new file mode 100644 index 00000000..4fc37fab --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_doc.h" + +#include +#include + +#include "krs_image.h" + +namespace Kross { namespace ChalkCore { + +Doc::Doc(::KisDoc* doc) : Kross::Api::Class("ChalkDocument"), m_doc(doc) { + addFunction("getImage", &Doc::getImage); +} + +Doc::~Doc() { + +} + +const TQString Doc::getClassName() const { + return "Kross::ChalkCore::Doc"; +} + +Kross::Api::Object::Ptr Doc::getImage(Kross::Api::List::Ptr) +{ + return new Image(m_doc->currentImage(), m_doc); +} + +} +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.h new file mode 100644 index 00000000..c06e530a --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_doc.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KROSS_KRS_DOC_H_ +#define _KROSS_KRS_DOC_H_ + +class KisDoc; + +#include + +namespace Kross { namespace ChalkCore { + +class Doc : public Kross::Api::Class +{ + public: + explicit Doc(::KisDoc* doc); + virtual ~Doc(); + virtual const TQString getClassName() const; + private: + /** + * This function return the Image associated with this Doc. + * + * Example (in Ruby) : + * @code + * doc = krosschalkcore::get("ChalkDocument") + * image = doc.getImage() + * @endcode + */ + Kross::Api::Object::Ptr getImage(Kross::Api::List::Ptr); + private: + KisDoc* m_doc; + +}; +} +} + + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.cpp new file mode 100644 index 00000000..ecac5501 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_filter.h" + +#include +#include + +#include "krs_filter_configuration.h" +#include "krs_paint_layer.h" + +namespace Kross { +namespace ChalkCore { + +Filter::Filter(KisFilter* filter) + : Kross::Api::Class("ChalkFilter"), m_filter(filter), m_config( new FilterConfiguration(filter->configuration()) ) +{ + addFunction("process", &Filter::process); + addFunction("getFilterConfiguration", &Filter::getFilterConfiguration); + +} + +Filter::~Filter() +{ +} + +const TQString Filter::getClassName() const { + return "Kross::ChalkCore::Filter"; +} + +Kross::Api::Object::Ptr Filter::getFilterConfiguration(Kross::Api::List::Ptr ) +{ + return m_config; +} + +Kross::Api::Object::Ptr Filter::process(Kross::Api::List::Ptr args) +{ + PaintLayer* src = (PaintLayer*)args->item(0).data(); + if(!m_filter->workWith( src->paintLayer()->paintDevice()->colorSpace())) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("process") ) ); + } + TQRect rect; + if( args->count() >1) + { + uint x = Kross::Api::Variant::toVariant(args->item(1)).toUInt(); + uint y = Kross::Api::Variant::toVariant(args->item(2)).toUInt(); + uint w = Kross::Api::Variant::toVariant(args->item(3)).toUInt(); + uint h = Kross::Api::Variant::toVariant(args->item(4)).toUInt(); + rect = TQRect(x, y, w, h); + } else { + TQRect r1 = src->paintLayer()->paintDevice()->extent(); + TQRect r2 = src->paintLayer()->image()->bounds(); + rect = r1.intersect(r2); + } + m_filter->process( src->paintLayer()->paintDevice(), src->paintLayer()->paintDevice(), m_config->filterConfiguration(), rect ); + return 0; +} + +} +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.h new file mode 100644 index 00000000..1576574b --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_FILTER_H +#define KROSS_KRITACOREKRS_FILTER_H + +#include + +class KisFilter; + +namespace Kross { +namespace ChalkCore { + class FilterConfiguration; + +class Filter : public Kross::Api::Class +{ + public: + Filter(KisFilter*); + ~Filter(); + private: + /** + * This function return the FilterConfiguration associated with this filter. + */ + Kross::Api::Object::Ptr getFilterConfiguration(Kross::Api::List::Ptr args); + /** + * This function will apply the filter. + * It takes one argument : + * - the source layer + * You can also use this four aguments : + * - x + * - y + * - width + * - height + * + * (x,y, width, height) defines the rectangular area on which the filter will be computed. + * If the rectangle is not defined, then the filter will be apply on alll the source layer. + * + * For example (in ruby) + * @code + * doc = Krosschalkcore::get("ChalkDocument") + * image = doc.getImage() + * layer = image.getActivePaintLayer() + * width = layer.getWidth() + * height = layer.getHeight() + * filter = Krosschalkcore::getFilter("invert") + * filter.process(layer, layer) + * filter.process(layer, layer, 10, 10, 20, 20 ) + * @endcode + */ + Kross::Api::Object::Ptr process(Kross::Api::List::Ptr args); + public: + virtual const TQString getClassName() const; + private: + KisFilter* m_filter; + FilterConfiguration* m_config; +}; + +} +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.cpp new file mode 100644 index 00000000..976af321 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_filter_configuration.h" + +#include + +#include + +namespace Kross { +namespace ChalkCore { + + FilterConfiguration::FilterConfiguration(KisFilterConfiguration* fConfig) + : Kross::Api::Class("ChalkFilterConfiguration"), m_fConfig(fConfig) +{ + addFunction("setProperty", &FilterConfiguration::setProperty); + addFunction("getProperty", &FilterConfiguration::getProperty); + addFunction("fromXML", &FilterConfiguration::fromXML); +} + +FilterConfiguration::~FilterConfiguration() +{ +} + +const TQString FilterConfiguration::getClassName() const { + return "Kross::ChalkCore::FilterConfiguration"; +} + + +Kross::Api::Object::Ptr FilterConfiguration::setProperty(Kross::Api::List::Ptr args) +{ + TQString name = Kross::Api::Variant::toString(args->item(0)); + TQVariant value = Kross::Api::Variant::toVariant(args->item(1)); + m_fConfig->setProperty(name, value); + return 0; +} +Kross::Api::Object::Ptr FilterConfiguration::getProperty(Kross::Api::List::Ptr args) +{ + TQString name = Kross::Api::Variant::toString(args->item(0)); + TQVariant value; + if(m_fConfig->getProperty( name, value)) + { + return new Kross::Api::Variant(value); + } else { + return 0; + } +} + +Kross::Api::Object::Ptr FilterConfiguration::fromXML(Kross::Api::List::Ptr args) +{ + TQString xml = Kross::Api::Variant::toString(args->item(0)); + m_fConfig->fromXML( xml ); + return 0; +} + +} +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.h new file mode 100644 index 00000000..61378cf4 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_filter_configuration.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_FILTER_CONFIGURATION_H +#define KROSS_KRITACOREKRS_FILTER_CONFIGURATION_H + +#include + +class KisFilterConfiguration; + +namespace Kross { +namespace ChalkCore { + +/** + @author Cyrille Berger +*/ +class FilterConfiguration : public Kross::Api::Class +{ + public: + FilterConfiguration(KisFilterConfiguration*); + ~FilterConfiguration(); + public: + virtual const TQString getClassName() const; + inline KisFilterConfiguration* filterConfiguration() { return m_fConfig; }; + private: + /** + * This function define a parameter of the associated Filter. + * It takes two arguments : + * - the name of the parameter + * - the value, whose type depends of the Filter + */ + Kross::Api::Object::Ptr setProperty(Kross::Api::List::Ptr args); + /** + * This function return the value of a parameter of the associated Filter. + * It takes one argument : + * - the name of the parameter + */ + Kross::Api::Object::Ptr getProperty(Kross::Api::List::Ptr args); + /** + * Deserialize + */ + Kross::Api::Object::Ptr fromXML(Kross::Api::List::Ptr args); + private: + KisFilterConfiguration* m_fConfig; +}; + +} +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.cpp new file mode 100644 index 00000000..ea121d7c --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_histogram.h" + +#include + +namespace Kross { + +namespace ChalkCore { + +Histogram::Histogram(KisPaintLayerSP layer, + KisHistogramProducerSP producer, + const enumHistogramType type) + : Kross::Api::Class("ChalkHistogram") +{ + m_histogram = new KisHistogram(layer, producer, type); + addFunction("getMax", &Histogram::getMax); + addFunction("getMin", &Histogram::getMin); + addFunction("getHighest", &Histogram::getHighest); + addFunction("getLowest", &Histogram::getLowest); + addFunction("getMean", &Histogram::getMean); + addFunction("getCount", &Histogram::getCount); + addFunction("getTotal", &Histogram::getTotal); + addFunction("setChannel", &Histogram::setChannel); + addFunction("getChannel", &Histogram::getChannel); + addFunction("getValue", &Histogram::getValue); + addFunction("getNumberOfBins", &Histogram::getNumberOfBins); +} + +Histogram::~Histogram() +{ +} + +const TQString Histogram::getClassName() const { + return "Kross::ChalkCore::Histogram"; +} + +Kross::Api::Object::Ptr Histogram::setChannel(Kross::Api::List::Ptr args) +{ + m_histogram->setChannel(Kross::Api::Variant::toUInt(args->item(0))); + return 0; +} +Kross::Api::Object::Ptr Histogram::getChannel(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->channel()); +} +Kross::Api::Object::Ptr Histogram::getMax(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getMax()); +} +Kross::Api::Object::Ptr Histogram::getMin(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getMin() ); +} +Kross::Api::Object::Ptr Histogram::getHighest(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getHighest() ); +} +Kross::Api::Object::Ptr Histogram::getLowest(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getLowest() ); +} +Kross::Api::Object::Ptr Histogram::getMean(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getMean() ); +} +Kross::Api::Object::Ptr Histogram::getCount(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getCount() ); +} +Kross::Api::Object::Ptr Histogram::getTotal(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->calculations().getTotal() ); +} +Kross::Api::Object::Ptr Histogram::getValue(Kross::Api::List::Ptr args) +{ + return new Kross::Api::Variant( m_histogram->getValue( Kross::Api::Variant::toUInt(args->item(0)) ) ); +} + +Kross::Api::Object::Ptr Histogram::getNumberOfBins(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant( m_histogram->producer()->numberOfBins() ); +} + + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.h new file mode 100644 index 00000000..50b66ca4 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_histogram.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREHISTOGRAM_H +#define KROSS_KRITACOREHISTOGRAM_H + +#include + +#include +#include + +namespace Kross { + +namespace ChalkCore { + +/** + * This class allow to access the histogram of a PaintLayer. + * + * Example (in Ruby) : + * @code + * doc = krosschalkcore::get("ChalkDocument") + * image = doc.getImage() + * layer = image.getActiveLayer() + * histo = layer.createHistogram("RGB8HISTO",0) + * min = layer.getMin() * 255 + * max = layer.getMax() * 255 + * for i in min..max + * print layer.getValue(i) + * print "\n" + * end + * @endcode + */ +class Histogram : public Kross::Api::Class +{ + public: + Histogram(KisPaintLayerSP layer, KisHistogramProducerSP producer, const enumHistogramType type); + ~Histogram(); + virtual const TQString getClassName() const; + private: + /** + * This function return the maximum bound of the histogram + * (values at greater position than the maximum are null). + * The value is in the range 0.0 - 1.0. + */ + Kross::Api::Object::Ptr getMax(Kross::Api::List::Ptr); + /** + * This function return the minimum bound of the histogram + * (values at smaller position than the minimum are null) + * The value is in the range 0.0 - 1.0. + */ + Kross::Api::Object::Ptr getMin(Kross::Api::List::Ptr); + /** + * This function return the highest value of the histogram + */ + Kross::Api::Object::Ptr getHighest(Kross::Api::List::Ptr); + /** + * This function return the lowest value of the histogram + */ + Kross::Api::Object::Ptr getLowest(Kross::Api::List::Ptr); + /** + * This function return the mean of the histogram + */ + Kross::Api::Object::Ptr getMean(Kross::Api::List::Ptr); + /** + * This function return the number of pixels used by the histogram + */ + Kross::Api::Object::Ptr getCount(Kross::Api::List::Ptr); + /** + * This function return the sum of all values of the histogram + */ + Kross::Api::Object::Ptr getTotal(Kross::Api::List::Ptr); + /** + * Select the channel of the layer on which to get the result of the histogram. + * This function takes one argument : + * - channel number + */ + Kross::Api::Object::Ptr setChannel(Kross::Api::List::Ptr); + /** + * Return the selected channel + */ + Kross::Api::Object::Ptr getChannel(Kross::Api::List::Ptr); + /** + * Return the value of a bin of the histogram. + * This function takes one argument : + * - index, in the range [0..255], + */ + Kross::Api::Object::Ptr getValue(Kross::Api::List::Ptr); + /** + * Return the number of bins of this histogram. + */ + Kross::Api::Object::Ptr getNumberOfBins(Kross::Api::List::Ptr); + private: + KisHistogram* m_histogram; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.cpp new file mode 100644 index 00000000..c93d6e88 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_image.h" + +#include + +#include +#include +#include +#include +#include +#include + + +#include "krs_paint_layer.h" + +namespace Kross { + +namespace ChalkCore { + + Image::Image(KisImageSP image, KisDoc* doc) + : Kross::Api::Class("ChalkImage"), m_image(image), m_doc(doc) +{ + addFunction("getActivePaintLayer", &Image::getActivePaintLayer); + addFunction("getWidth", &Image::getWidth); + addFunction("getHeight", &Image::getHeight); + addFunction("convertToColorspace", &Image::convertToColorspace); + addFunction("createPaintLayer", &Image::createPaintLayer); + addFunction("colorSpaceId", &Image::colorSpaceId); + addFunction("scale", &Image::scale); + addFunction("resize", &Image::resize); +} + + +Image::~Image() +{ +} + +const TQString Image::getClassName() const { + return "Kross::ChalkCore::Image"; +} + +Kross::Api::Object::Ptr Image::getActivePaintLayer(Kross::Api::List::Ptr) +{ + KisPaintLayer* activePaintLayer = dynamic_cast(m_image->activeLayer().data()); + if(activePaintLayer ) + { + return new PaintLayer(activePaintLayer, m_doc); + } else { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("The active layer is not paintable.") ); + return 0; + } +} +Kross::Api::Object::Ptr Image::getWidth(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_image->width()); +} +Kross::Api::Object::Ptr Image::getHeight(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_image->height()); +} +Kross::Api::Object::Ptr Image::convertToColorspace(Kross::Api::List::Ptr args) +{ + KisColorSpace * dstCS = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(Kross::Api::Variant::toString(args->item(0)), ""), ""); + if(!dstCS) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("Colorspace %0 is not available, please check your installation.").tqarg(Kross::Api::Variant::toString(args->item(0))) ) ); + return 0; + } + m_image->convertTo(dstCS); + return 0; +} + +Kross::Api::Object::Ptr Image::colorSpaceId(Kross::Api::List::Ptr ) +{ + return new Kross::Api::Variant( m_image->colorSpace()->id().id() ); +} + + +Kross::Api::Object::Ptr Image::createPaintLayer(Kross::Api::List::Ptr args) +{ + TQString name = Kross::Api::Variant::toString(args->item(0)); + int opacity = Kross::Api::Variant::toInt(args->item(1)); + opacity = CLAMP(opacity, 0, 255); + TQString csname; + if(args->count() > 2) + { + csname = Kross::Api::Variant::toString(args->item(2)); + } else { + csname = m_image->colorSpace()->id().id(); + } + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csname, ""), ""); + KisPaintLayer* layer; + if(cs) + { + layer = new KisPaintLayer(m_image, name, opacity, cs); + } else { + layer = new KisPaintLayer(m_image, name, opacity); + } + layer->setVisible(true); + + m_image->addLayer(layer, m_image->rootLayer(), 0); + return new PaintLayer(layer); + +} + +Kross::Api::Object::Ptr Image::scale(Kross::Api::List::Ptr args) +{ + double cw = Kross::Api::Variant::toDouble(args->item(0)); + double ch = Kross::Api::Variant::toDouble(args->item(1)); + m_image->scale( cw, ch, 0, KisFilterStrategyRegistry::instance()->get( "Mitchell") ); + return 0; +} +Kross::Api::Object::Ptr Image::resize(Kross::Api::List::Ptr args) +{ + int nw = Kross::Api::Variant::toInt(args->item(0)); + int nh = Kross::Api::Variant::toInt(args->item(1)); + int x = 0; + int y = 0; + if(args->count() > 2) + { + x = Kross::Api::Variant::toInt(args->item(2)); + y = Kross::Api::Variant::toInt(args->item(3)); + } + m_image->resize( nw, nh, x, y ); + return 0; +} + + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.h new file mode 100644 index 00000000..91314f3f --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_image.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRSIMAGE_H +#define KROSS_KRITACOREKRSIMAGE_H + +#include + +#include + +class KisDoc; + +namespace Kross { + +namespace ChalkCore { + +class Image : public Kross::Api::Class +{ + public: + Image(KisImageSP image, KisDoc* doc = 0); + ~Image(); + virtual const TQString getClassName() const; + private: + /** + * Return the active PaintLayer, if any. + */ + Kross::Api::Object::Ptr getActivePaintLayer(Kross::Api::List::Ptr); + /** + * Return the width of the image. + */ + Kross::Api::Object::Ptr getWidth(Kross::Api::List::Ptr); + /** + * Return the height of the image. + */ + Kross::Api::Object::Ptr getHeight(Kross::Api::List::Ptr); + /** + * Resize an image + */ + Kross::Api::Object::Ptr resize(Kross::Api::List::Ptr); + /** + * Scale an image + */ + Kross::Api::Object::Ptr scale(Kross::Api::List::Ptr); + /** + * Convert the image to a colorspace. + * This function takes one argument : + * - the name of the destination colorspace + * + * For example (in Ruby) : + * @code + * image.convertToColorspace("CMYK") + * @endcode + */ + Kross::Api::Object::Ptr convertToColorspace(Kross::Api::List::Ptr args); + /** + * Return the id of the colorspace of this image. + */ + Kross::Api::Object::Ptr colorSpaceId(Kross::Api::List::Ptr ); + /** + * Create a new PaintLayer for this image, and return it. + * This function takes at least two arguments : + * - the name of the layer + * - the opacity of the layer (between 0 and 255) + * + * This function can take one optional argument : + * - the id of the colorSpace (if this is not specified, the new PaintLayer + * will have the same colorspace as the image) + */ + Kross::Api::Object::Ptr createPaintLayer(Kross::Api::List::Ptr args); + private: + KisImageSP m_image; + KisDoc* m_doc; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_iterator.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_iterator.h new file mode 100644 index 00000000..2e17ed98 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_iterator.h @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_ITERATOR_H +#define KROSS_KRITACOREKRS_ITERATOR_H + +#include +#include +//#include +//#include + +#include + +#include +#include +#include + +#include + +namespace Kross { + +namespace ChalkCore { + +// stupid TQt which doesn't support templated TQObject +class IteratorMemoryManaged { + public: + virtual void tqinvalidateIterator() = 0; +}; + +class IteratorMemoryManager : public TQObject { + Q_OBJECT + TQ_OBJECT + public: + IteratorMemoryManager(IteratorMemoryManaged* it) : m_it(it) + { + // Connect the Monitor to know when the invalidating of iterator is needed + connect(KisScriptMonitor::instance(), TQT_SIGNAL(executionFinished(const Kross::Api::ScriptAction* )), this, TQT_SLOT(tqinvalidateIterator())); + + } + public slots: + void tqinvalidateIterator() + { + m_it->tqinvalidateIterator(); + } + private: + IteratorMemoryManaged* m_it; +}; +// +/** + * This object allow to change the value of pixel one by one. + * The name of some function depends of the colorspace, for instance, if + * the colorspace of the layer is RGB, you will have setR, setG, setB... and for CMYK, + * setC, setM, setY, setK. In the doc bellow we will consider the colorspace is called ABC with + * three channels : A, B and C. + * + * Function: setA setB setC + * Those functions take one argument: + * - the new value of one of the channel of this pixel + * + * Function: setABC + * Set the value of all channels. + * This function take one argument: + * - an array with the new value for all channels + */ +template +class Iterator : public Kross::Api::Class >, private IteratorMemoryManaged +{ + public: + Iterator(_T_It it, KisPaintLayerSP layer) : Kross::Api::Class >("ChalkIterator"), m_itmm (new IteratorMemoryManager(this)), m_it(new _T_It(it)), nchannels(layer->paintDevice()->nChannels()), m_layer(layer) + { + // navigate in the iterator + this->addFunction("next", + new Kross::Api::ProxyFunction< + Iterator<_T_It>, // instance + bool (Iterator<_T_It>::*)(), // method + Kross::Api::Variant // return-value + >(this, &Iterator<_T_It>::next)); + this->addFunction("isDone", + new Kross::Api::ProxyFunction< + Iterator<_T_It>, // instance + bool (Iterator<_T_It>::*)(), // method + Kross::Api::Variant // return-value + >(this, &Iterator<_T_It>::isDone)); + + // get/set value + TQValueVector channels = layer->paintDevice()->colorSpace()->channels(); + TQString initiales = ""; + for(TQValueVector::iterator itC = channels.begin(); itC != channels.end(); itC++) + { + KisChannelInfo * ci = *itC; + initiales += ci->name().left(1); + switch(ci->channelValueType()) + { + case KisChannelInfo::UINT8: + this->addFunction("get"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::getChannelUINT8, ci->pos() ) ); + this->addFunction("set"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::setChannelUINT8, ci->pos() ) ); + break; + case KisChannelInfo::UINT16: + this->addFunction("get"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::getChannelUINT16, ci->pos() ) ); + this->addFunction("set"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::setChannelUINT16, ci->pos() ) ); + break; + case KisChannelInfo::FLOAT32: + this->addFunction("get"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::getChannelFLOAT, ci->pos() ) ); + this->addFunction("set"+ci->name(), + new Kross::Api::Function1< Iterator<_T_It> , uint >( + this, &Iterator<_T_It>::setChannelFLOAT, ci->pos() ) ); + break; + default: + kdDebug(41011) << "unsupported data format in scripts" << endl; + break; + } + } + initiales = initiales.upper(); + // set/get general + addFunction("set" + initiales, &Iterator::setPixel); + addFunction("get" + initiales, &Iterator::getPixel); + kdDebug(41011) << ( "get" + initiales ) << endl; + // Various colorSpace + addFunction("invertColor", &Iterator::invertColor); + addFunction("darken", &Iterator::darken); + } + + ~Iterator() + { + tqinvalidateIterator(); + delete m_itmm; + } + virtual const TQString getClassName() const { + return "Kross::ChalkCore::KrsDoc"; + }; + private: + /** + * Darken a pixel. + * This functions at least one argument: + * - shade amount use to darken all color channels + * + * This function can take the following optional argument: + * - compensation to limit the darkening + */ + Kross::Api::Object::Ptr darken(Kross::Api::List::Ptr args) + { + TQ_INT32 shade = Kross::Api::Variant::toUInt( args->item(0) ); + bool compensate = (args->count() == 2); + double compensation = compensate ? Kross::Api::Variant::toDouble( args->item(2) ) : 0.; + m_layer->paintDevice()->colorSpace()->darken(m_it->rawData(), m_it->rawData(), shade, compensate, compensation, 1); + return 0; + } + /** + * Invert the color of a pixel. + */ + Kross::Api::Object::Ptr invertColor(Kross::Api::List::Ptr ) + { + m_layer->paintDevice()->colorSpace()->invertColor(m_it->rawData(), 1); + return 0; + } + /** + * Increment the positon, and go to the next pixel. + */ + bool next() + { + ++(*m_it); + return m_it->isDone(); + } + /** + * Return true if the iterator is at the end, and that no more pixels are available. + */ + bool isDone() + { + return m_it->isDone(); + } + Kross::Api::Object::Ptr getChannelUINT8(Kross::Api::List::Ptr, uint channelpos) + { + TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + channelpos); + return new Kross::Api::Variant( * data); + } + Kross::Api::Object::Ptr setChannelUINT8(Kross::Api::List::Ptr args, uint channelpos) + { + TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + channelpos); //*(uint*)channelpos); + *data = Kross::Api::Variant::toUInt( args->item(0) ); + return 0; + } + Kross::Api::Object::Ptr getChannelUINT16(Kross::Api::List::Ptr, uint channelpos) + { + TQ_UINT16* data = (TQ_UINT16*)(m_it->rawData() + channelpos); + return new Kross::Api::Variant( * data); + } + Kross::Api::Object::Ptr setChannelUINT16(Kross::Api::List::Ptr args, uint channelpos) + { + TQ_UINT16* data = (TQ_UINT16*)(m_it->rawData() + channelpos); + *data = Kross::Api::Variant::toUInt( args->item(0) ); + return 0; + } + Kross::Api::Object::Ptr getChannelFLOAT(Kross::Api::List::Ptr, uint channelpos) + { + float* data = (float*)(m_it->rawData() + channelpos); + return new Kross::Api::Variant( * data); + } + Kross::Api::Object::Ptr setChannelFLOAT(Kross::Api::List::Ptr args, uint channelpos) + { + float* data = (float*)(m_it->rawData() + channelpos); + *data = Kross::Api::Variant::toUInt( args->item(0) ); + return 0; + } + Kross::Api::Object::Ptr getPixel(Kross::Api::List::Ptr) + { + TQValueVector channels = m_layer->paintDevice()->colorSpace()->channels(); + TQValueList pixel; + for(TQValueVector::iterator itC = channels.begin(); itC != channels.end(); itC++) + { + KisChannelInfo * ci = *itC; + TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + ci->pos()); + switch(ci->channelValueType()) + { + case KisChannelInfo::UINT8: + pixel.push_back( *data); + break; + case KisChannelInfo::UINT16: + pixel.push_back( *((TQ_UINT16*) data) ); + break; + case KisChannelInfo::FLOAT32: + pixel.push_back( *((float*) data) ); + break; + default: + kdDebug(41011) << i18n("An error has occurred in %1").tqarg("getPixel") << endl; + kdDebug(41011) << i18n("unsupported data format in scripts") << endl; + break; + } + } + return new Kross::Api::Variant( pixel); + } + Kross::Api::Object::Ptr setPixel(Kross::Api::List::Ptr args) + { + TQValueList pixel = Kross::Api::Variant::toList( args->item(0) ); + TQValueVector channels = m_layer->paintDevice()->colorSpace()->channels(); + uint i = 0; + for(TQValueVector::iterator itC = channels.begin(); itC != channels.end(); itC++, i++) + { + KisChannelInfo * ci = *itC; + TQ_UINT8* data = (TQ_UINT8*)(m_it->rawData() + ci->pos()); + switch(ci->channelValueType()) + { + case KisChannelInfo::UINT8: + *data = pixel[i].toUInt(); + break; + case KisChannelInfo::UINT16: + *((TQ_UINT16*) data) = pixel[i].toUInt(); + break; + case KisChannelInfo::FLOAT32: + *((float*) data) = pixel[i].toDouble(); + break; + default: + kdDebug(41011) << i18n("An error has occurred in %1").tqarg("setPixel") << endl; + kdDebug(41011) << i18n("unsupported data format in scripts") << endl; + break; + } + } + return 0; + } + private: + virtual void tqinvalidateIterator() + { + kdDebug(41011) << "invalidating iterator" << endl; + if(m_it) + { + kdDebug(41011) << "deleting iterator" << endl; + delete m_it; + } + m_it = 0; + kdDebug() << " Iterator = " << m_it << endl; + } + private: + IteratorMemoryManager* m_itmm; + _T_It* m_it; + int nchannels; + KisPaintLayerSP m_layer; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.cpp new file mode 100644 index 00000000..5f800f6a --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_paint_layer.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "krs_iterator.h" +#include "krs_histogram.h" +#include "krs_painter.h" +#include "krs_wavelet.h" + +namespace Kross { + +namespace ChalkCore { + +PaintLayer::PaintLayer(KisPaintLayerSP layer, KisDoc* doc) + : Kross::Api::Class("ChalkLayer"), m_layer(layer), m_doc(doc), m_cmd(0) +{ + addFunction("createRectIterator", &PaintLayer::createRectIterator); + addFunction("createHLineIterator", &PaintLayer::createHLineIterator); + addFunction("createVLineIterator", &PaintLayer::createVLineIterator); + addFunction("getWidth", &PaintLayer::getWidth); + addFunction("getHeight", &PaintLayer::getHeight); + addFunction("createHistogram", &PaintLayer::createHistogram); + addFunction("createPainter", &PaintLayer::createPainter); + addFunction("beginPainting", &PaintLayer::beginPainting); + addFunction("endPainting", &PaintLayer::endPainting); + addFunction("convertToColorspace", &PaintLayer::convertToColorspace); + addFunction("fastWaveletTransformation", &PaintLayer::fastWaveletTransformation); + addFunction("fastWaveletUntransformation", &PaintLayer::fastWaveletUntransformation); + addFunction("colorSpaceId", &PaintLayer::colorSpaceId); +} + + +PaintLayer::~PaintLayer() +{ +} + +const TQString PaintLayer::getClassName() const { + return "Kross::ChalkCore::PaintLayer"; +} + +Kross::Api::Object::Ptr PaintLayer::createRectIterator(Kross::Api::List::Ptr args) +{ + return new Iterator( + paintLayer()->paintDevice()->createRectIterator(Kross::Api::Variant::toUInt(args->item(0)), + Kross::Api::Variant::toUInt(args->item(1)), + Kross::Api::Variant::toUInt(args->item(2)), + Kross::Api::Variant::toUInt(args->item(3)), true), + paintLayer()); +} +Kross::Api::Object::Ptr PaintLayer::createHLineIterator(Kross::Api::List::Ptr args) +{ + return new Iterator( + paintLayer()->paintDevice()->createHLineIterator(Kross::Api::Variant::toUInt(args->item(0)), + Kross::Api::Variant::toUInt(args->item(1)), + Kross::Api::Variant::toUInt(args->item(2)), true), + paintLayer()); +} +Kross::Api::Object::Ptr PaintLayer::createVLineIterator(Kross::Api::List::Ptr args) +{ + return new Iterator( + paintLayer()->paintDevice()->createVLineIterator(Kross::Api::Variant::toUInt(args->item(0)), + Kross::Api::Variant::toUInt(args->item(1)), + Kross::Api::Variant::toUInt(args->item(2)), true), + paintLayer()); +} +Kross::Api::Object::Ptr PaintLayer::getWidth(Kross::Api::List::Ptr) +{ + TQRect r1 = paintLayer()->extent(); + TQRect r2 = paintLayer()->image()->bounds(); + TQRect rect = r1.intersect(r2); + return new Kross::Api::Variant(rect.width()); +} +Kross::Api::Object::Ptr PaintLayer::getHeight(Kross::Api::List::Ptr) +{ + TQRect r1 = paintLayer()->extent(); + TQRect r2 = paintLayer()->image()->bounds(); + TQRect rect = r1.intersect(r2); + return new Kross::Api::Variant(rect.height()); +} + +Kross::Api::Object::Ptr PaintLayer::createHistogram(Kross::Api::List::Ptr args) +{ + TQString histoname = Kross::Api::Variant::toString(args->item(0)); + KisHistogramProducerFactory* factory = KisHistogramProducerFactoryRegistry::instance()->get(histoname); + +/* KisIDList listID = KisHistogramProducerFactoryRegistry::instance()->listKeys(); + for(KisIDList::iterator it = listID.begin(); it != listID.end(); it++) + { + kdDebug(41011) << (*it).name() << " " << (*it).id() << endl; + }*/ + + enumHistogramType type ; + switch( Kross::Api::Variant::toUInt(args->item(1)) ) + { + case 1: + type = LOGARITHMIC; + break; + case 0: + default: + type = LINEAR; + break; + } + if(factory && factory->isCompatibleWith( paintLayer()->paintDevice()->colorSpace() )) + { + return new Histogram( paintLayer().data(), factory->generate() , type); + } else { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("createHistogram") + "\n" + i18n("The histogram %1 is not available").tqarg(histoname) ) ); + } + return 0; +} + +Kross::Api::Object::Ptr PaintLayer::createPainter(Kross::Api::List::Ptr ) +{ + return new Painter(paintLayer()); +} + +Kross::Api::Object::Ptr PaintLayer::beginPainting(Kross::Api::List::Ptr args) +{ + TQString name = Kross::Api::Variant::toString(args->item(0)); + if(m_cmd != 0) + { + delete m_cmd; + } + m_cmd = new KisTransaction(name, paintLayer()->paintDevice()); + Q_CHECK_PTR(m_cmd); + return 0; +} + +Kross::Api::Object::Ptr PaintLayer::endPainting(Kross::Api::List::Ptr) +{ + if(doc() !=0) + { + doc()->setModified(true); + doc()->currentImage()->activeLayer()->setDirty(); + } + if(m_cmd != 0) + { + paintLayer()->image()->undoAdapter()->addCommand(m_cmd); + } + return 0; +} + +Kross::Api::Object::Ptr PaintLayer::convertToColorspace(Kross::Api::List::Ptr args) +{ + KisColorSpace * dstCS = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(Kross::Api::Variant::toString(args->item(0)), ""), ""); + if(!dstCS) + { + // FIXME: inform user + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("convertToColorspace") + "\n" + i18n("Colorspace %1 is not available, please check your installation.").tqarg(Kross::Api::Variant::toString(args->item(0))) ) ); + return 0; + } + paintLayer()->paintDevice()->convertTo(dstCS); + return 0; +} + +Kross::Api::Object::Ptr PaintLayer::colorSpaceId(Kross::Api::List::Ptr ) +{ + return new Kross::Api::Variant( paintLayer()->paintDevice()->colorSpace()->id().id() ); +} + + +Kross::Api::Object::Ptr PaintLayer::fastWaveletTransformation(Kross::Api::List::Ptr ) +{ + KisMathToolbox* mathToolbox = KisMetaRegistry::instance()->mtRegistry()->get( paintLayer()->paintDevice()->colorSpace()->mathToolboxID() ); + TQRect rect = paintLayer()->exactBounds(); + KisMathToolbox::KisWavelet* wav = mathToolbox->fastWaveletTransformation(paintLayer()->paintDevice(), rect); + return new Wavelet(wav); +} +Kross::Api::Object::Ptr PaintLayer::fastWaveletUntransformation(Kross::Api::List::Ptr args) +{ + Wavelet* wav = (Wavelet*)args->item(0).data(); + KisMathToolbox* mathToolbox = KisMetaRegistry::instance()->mtRegistry()->get( paintLayer()->paintDevice()->colorSpace()->mathToolboxID() ); + TQRect rect = paintLayer()->exactBounds(); + mathToolbox->fastWaveletUntransformation( paintLayer()->paintDevice(), rect, wav->wavelet() ); + return 0; +} + + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.h new file mode 100644 index 00000000..18ac5088 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_paint_layer.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRSLAYER_H +#define KROSS_KRITACOREKRSLAYER_H + +#include + +#include +#include + +class KisDoc; +class KisTransaction; + +namespace Kross { + +namespace ChalkCore { + +/** +@author Cyrille Berger +*/ +class PaintLayer : public Kross::Api::Class +{ + public: + explicit PaintLayer(KisPaintLayerSP layer, KisDoc* doc = 0); + virtual ~PaintLayer(); + virtual const TQString getClassName() const; + private: + /** + * Create an iterator over a layer, it will iterate on a rectangle area. + * This function takes four arguments : + * - x + * - y + * - width of the rectangle + * - height of the rectangle + */ + Kross::Api::Object::Ptr createRectIterator(Kross::Api::List::Ptr); + /** + * Create an iterator over a layer, it will iterate on a row. + * This function takes three arguments : + * - x start in the row + * - y vertical position of the row + * - width of the row + */ + Kross::Api::Object::Ptr createHLineIterator(Kross::Api::List::Ptr); + /** + * Create an iterator over a layer, it will iterate on a column. + * This function takes three arguments : + * - x horizontal position of the column + * - y start in the column + * - height of the column + */ + Kross::Api::Object::Ptr createVLineIterator(Kross::Api::List::Ptr); + /** + * Return the width of the layer + */ + Kross::Api::Object::Ptr getWidth(Kross::Api::List::Ptr); + /** + * Return the height of the layer + */ + Kross::Api::Object::Ptr getHeight(Kross::Api::List::Ptr); + /** + * This function creates an Histogram for this layer. + * It takes two arguments : + * - the type of the histogram ("RGB8HISTO") + * - 0 if the histogram is linear, or 1 if it is logarithmic + */ + Kross::Api::Object::Ptr createHistogram(Kross::Api::List::Ptr); + /** + * This function create a Painter which will allow you to some painting on the layer. + */ + Kross::Api::Object::Ptr createPainter(Kross::Api::List::Ptr); + /** + * Uses this function to create a new undo entry. + */ + Kross::Api::Object::Ptr beginPainting(Kross::Api::List::Ptr args); + /** + * Uses this function to close the current undo entry and add it to the history. + */ + Kross::Api::Object::Ptr endPainting(Kross::Api::List::Ptr args); + /** + * Convert the image to a colorspace. + * This function takes one argument : + * - the name of the destination colorspace + * + * For example (in Ruby) : + * @code + * image.convertToColorspace("CMYK") + * @endcode + */ + Kross::Api::Object::Ptr convertToColorspace(Kross::Api::List::Ptr args); + /** + * Return the id of the colorspace of this paint layer. + */ + Kross::Api::Object::Ptr colorSpaceId(Kross::Api::List::Ptr ); + /** + * Return the fast wavelet transformed of the layer + */ + Kross::Api::Object::Ptr fastWaveletTransformation(Kross::Api::List::Ptr args); + /** + * Untransform a fast wavelet into this layer + * It takes one argument : + * - a wavelet object + * + * For example (in Ruby) : + * @code + * wavelet = layer.fastWaveletTransformation() + * layer.fastWaveletUntransformation(wavelet) + * @endcode + */ + Kross::Api::Object::Ptr fastWaveletUntransformation(Kross::Api::List::Ptr args); + public: + inline KisPaintLayerSP paintLayer() { return m_layer; } + inline KisDoc* doc() { return m_doc; } + private: + KisPaintLayerSP m_layer; + KisDoc* m_doc; + KisTransaction* m_cmd; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.cpp new file mode 100644 index 00000000..44991303 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_painter.h" + +#include +#include +#include +#include +#include + +#include "krs_brush.h" +#include "krs_color.h" +#include "krs_pattern.h" + +namespace Kross { + +namespace ChalkCore { + +Painter::Painter(KisPaintLayerSP layer) + : Kross::Api::Class("ChalkPainter"), m_layer(layer),m_painter(new KisPainter(layer->paintDevice())),m_threshold(1) +{ + // convolution + addFunction("convolve", &Painter::convolve); + // Fill specific + addFunction("setFillThreshold", &Painter::setFillThreshold); + addFunction("fillColor", &Painter::fillColor); + addFunction("fillPattern", &Painter::fillPattern); + + // Painting operations + addFunction("paintPolyline", &Painter::paintPolyline); + addFunction("paintLine", &Painter::paintLine); + addFunction("paintBezierCurve", &Painter::paintBezierCurve); + addFunction("paintEllipse", &Painter::paintEllipse); + addFunction("paintPolygon", &Painter::paintPolygon); + addFunction("paintRect", &Painter::paintRect); + addFunction("paintAt", &Painter::paintAt); + addFunction("setBackgroundColor", &Painter::setBackgroundColor); + addFunction("setPaintColor", &Painter::setPaintColor); + + // Color operations + addFunction("setPattern", &Painter::setPattern); + addFunction("setBrush", &Painter::setBrush); + + // How is painting done operations + addFunction("setPaintOp", &Painter::setPaintOp); + // Special settings + addFunction("setDuplicateOffset", &Painter::setDuplicateOffset); + + // Style operation + addFunction("setOpacity", &Painter::setOpacity); + addFunction("setStrokeStyle", &Painter::setStrokeStyle); + addFunction("setFillStyle", &Painter::setFillStyle); +} + + +Painter::~Painter() +{ + delete m_painter; +} + +Kross::Api::Object::Ptr Painter::convolve(Kross::Api::List::Ptr args) +{ + KisConvolutionPainter* cp = new KisConvolutionPainter(m_painter->device()); + TQRect rect; + KisKernel kernel; + kernel.factor = Kross::Api::Variant::toInt(args->item(1)); + kernel.offset = Kross::Api::Variant::toInt(args->item(2)); + + uint borderop = 3; + if( args.count() > 3 ) + { + borderop = Kross::Api::Variant::toUInt(args->item(3)); + } + uint channelsFlag = KisChannelInfo::FLAG_COLOR; + if( args.count() > 4 ) + { + channelsFlag = Kross::Api::Variant::toUInt(args->item(4)); + } + if( args.count() > 5) + { + uint x = Kross::Api::Variant::toUInt(args->item(5)); + uint y = Kross::Api::Variant::toUInt(args->item(6)); + uint w = Kross::Api::Variant::toUInt(args->item(7)); + uint h = Kross::Api::Variant::toUInt(args->item(8)); + rect = TQRect(x,y,w,h); + } else { + TQRect r1 = paintLayer()->paintDevice()->extent(); + TQRect r2 = paintLayer()->image()->bounds(); + rect = r1.intersect(r2); + } + + TQValueList kernelH = Kross::Api::Variant::toList( args->item(0) ); + + TQVariant firstlineVariant = *kernelH.begin(); + if(firstlineVariant.type() != TQVariant::List) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").tqarg("applyConvolution")) ); + } + + TQValueList firstline = firstlineVariant.toList(); + + kernel.height = kernelH.size(); + kernel.width = firstline.size(); + + kernel.data = new TQ_INT32[kernel.height * kernel.width]; + + uint i = 0; + for(TQValueList::iterator itK = kernelH.begin(); itK != kernelH.end(); itK++, i ++ ) + { + TQVariant lineVariant = *kernelH.begin(); + if(lineVariant.type() != TQVariant::List) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").tqarg("applyConvolution")) ); + } + TQValueList line = firstlineVariant.toList(); + if(line.size() != kernel.width) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception(i18n("An error has occured in %1").tqarg("applyConvolution")) ); + } + uint j = 0; + for(TQValueList::iterator itLine = line.begin(); itLine != line.end(); itLine++, j ++ ) + { + kernel.data[ j + i * kernel.width ] = (*itLine).toInt(); + } + } + cp->applyMatrix(&kernel, rect.x(), rect.y(), rect.width(), rect.height(), (KisConvolutionBorderOp)borderop, (KisChannelInfo::enumChannelFlags) channelsFlag); + + delete[] kernel.data; + return 0; +} + + +KisFillPainter* Painter::createFillPainter() +{ + KisFillPainter* fp = new KisFillPainter(m_painter->device()); + fp->setBrush( m_painter->brush() ); + fp->setFillColor( m_painter->fillColor() ); + fp->setPaintColor( m_painter->paintColor() ); + fp->setFillStyle( m_painter->fillStyle() ); + fp->setOpacity( m_painter->opacity() ); + fp->setPattern( m_painter->pattern() ); + return fp; +} + +Kross::Api::Object::Ptr Painter::setFillThreshold(Kross::Api::List::Ptr args) +{ + m_threshold = Kross::Api::Variant::toInt(args->item(0)); + return 0; +} +Kross::Api::Object::Ptr Painter::fillColor(Kross::Api::List::Ptr args) +{ + KisFillPainter* fp = createFillPainter(); + uint x = Kross::Api::Variant::toUInt(args->item(0)); + uint y = Kross::Api::Variant::toUInt(args->item(1)); + + fp->fillColor( x, y ); + return 0; +} +Kross::Api::Object::Ptr Painter::fillPattern(Kross::Api::List::Ptr args) +{ + KisFillPainter* fp = createFillPainter(); + uint x = Kross::Api::Variant::toUInt(args->item(0)); + uint y = Kross::Api::Variant::toUInt(args->item(1)); + fp->fillPattern(x, y); + return 0; +} + +Kross::Api::Object::Ptr Painter::setStrokeStyle(Kross::Api::List::Ptr args) +{ + uint style = Kross::Api::Variant::toVariant(args->item(0)).toUInt(); + KisPainter::StrokeStyle strokestyle; + switch(style) + { + case 1: + strokestyle = KisPainter::StrokeStyleBrush; + break; + default: + strokestyle = KisPainter::StrokeStyleNone; + } + m_painter->setStrokeStyle(strokestyle); + return 0; +} + +Kross::Api::Object::Ptr Painter::setFillStyle(Kross::Api::List::Ptr args) +{ + uint style = Kross::Api::Variant::toVariant(args->item(0)).toUInt(); + KisPainter::FillStyle fillstyle; + switch(style) + { + case 1: + fillstyle = KisPainter::FillStyleForegroundColor; + break; + case 2: + fillstyle = KisPainter::FillStyleBackgroundColor; + break; + case 3: + fillstyle = KisPainter::FillStylePattern; + break; + default: + fillstyle = KisPainter::FillStyleNone; + } + m_painter->setFillStyle(fillstyle); + return 0; +} + +Kross::Api::Object::Ptr Painter::setOpacity(Kross::Api::List::Ptr args) +{ + TQ_UINT8 opacity = Kross::Api::Variant::toVariant(args->item(0)).toUInt(); + m_painter->setOpacity(opacity); + return 0; +} + +Kross::Api::Object::Ptr Painter::setDuplicateOffset(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + m_painter->setDuplicateOffset(KisPoint(x1,y1)); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintPolyline(Kross::Api::List::Ptr args) +{ + TQValueList pointsX = Kross::Api::Variant::toList( args->item(0) ); + TQValueList pointsY = Kross::Api::Variant::toList( args->item(1) ); + if(pointsX.size() != pointsY.size()) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("the two lists should have the same size.") ); + } + m_painter->paintPolyline( createPointsVector( pointsX, pointsY)); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintLine(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + double p1 = Kross::Api::Variant::toVariant(args->item(2)).toDouble(); + double x2 = Kross::Api::Variant::toVariant(args->item(3)).toDouble(); + double y2 = Kross::Api::Variant::toVariant(args->item(4)).toDouble(); + double p2 = Kross::Api::Variant::toVariant(args->item(5)).toDouble(); + m_painter->paintLine(KisPoint( x1, y1), p1, 0.0, 0.0, KisPoint( x2, y2 ), p2, 0.0, 0.0 ); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintBezierCurve(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + double p1 = Kross::Api::Variant::toVariant(args->item(2)).toDouble(); + double cx1 = Kross::Api::Variant::toVariant(args->item(3)).toDouble(); + double cy1 = Kross::Api::Variant::toVariant(args->item(4)).toDouble(); + double cx2 = Kross::Api::Variant::toVariant(args->item(5)).toDouble(); + double cy2 = Kross::Api::Variant::toVariant(args->item(6)).toDouble(); + double x2 = Kross::Api::Variant::toVariant(args->item(7)).toDouble(); + double y2 = Kross::Api::Variant::toVariant(args->item(8)).toDouble(); + double p2 = Kross::Api::Variant::toVariant(args->item(9)).toDouble(); + m_painter->paintBezierCurve( KisPoint(x1,y1), p1, 0.0, 0.0, KisPoint(cx1,cy1), KisPoint(cx2,cy2), KisPoint(x2,y2), p2, 0.0, 0.0); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintEllipse(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + double x2 = Kross::Api::Variant::toVariant(args->item(2)).toDouble(); + double y2 = Kross::Api::Variant::toVariant(args->item(3)).toDouble(); + double p1 = Kross::Api::Variant::toVariant(args->item(4)).toDouble(); + m_painter->paintEllipse( KisPoint(x1,y1), KisPoint(x2,y2), p1, 0.0, 0.0 ); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintPolygon(Kross::Api::List::Ptr args) +{ + TQValueList pointsX = Kross::Api::Variant::toList( args->item(0) ); + TQValueList pointsY = Kross::Api::Variant::toList( args->item(1) ); + if(pointsX.size() != pointsY.size()) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception("the two lists should have the same size.") ); + } + m_painter->paintPolygon( createPointsVector(pointsX, pointsY)); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintRect(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + double x2 = Kross::Api::Variant::toVariant(args->item(2)).toDouble(); + double y2 = Kross::Api::Variant::toVariant(args->item(3)).toDouble(); + double p1 = Kross::Api::Variant::toVariant(args->item(4)).toDouble(); + m_painter->paintRect( KisPoint(x1, y1), KisPoint(x2,y2), p1, 0, 0); + return 0; +} + +Kross::Api::Object::Ptr Painter::paintAt(Kross::Api::List::Ptr args) +{ + double x1 = Kross::Api::Variant::toVariant(args->item(0)).toDouble(); + double y1 = Kross::Api::Variant::toVariant(args->item(1)).toDouble(); + double p1 = Kross::Api::Variant::toVariant(args->item(2)).toDouble(); + m_painter->paintAt( KisPoint( x1, y1 ), p1, 0.0, 0.0); + return 0; +} + +Kross::Api::Object::Ptr Painter::setBackgroundColor(Kross::Api::List::Ptr args) +{ + Color* c = (Color*)args->item(0).data(); + m_painter->setBackgroundColor( KisColor(c->toTQColor(), paintLayer()->paintDevice()->colorSpace() )); + return 0; +} + +Kross::Api::Object::Ptr Painter::setPaintColor(Kross::Api::List::Ptr args) +{ + Color* c = (Color*)args->item(0).data(); + m_painter->setPaintColor( KisColor(c->toTQColor(), paintLayer()->paintDevice()->colorSpace() )); + return 0; +} + +Kross::Api::Object::Ptr Painter::setPattern(Kross::Api::List::Ptr args) +{ + Pattern* p = (Pattern*)args->item(0).data(); + m_painter->setPattern( p->getPattern()); + return 0; +} + + +Kross::Api::Object::Ptr Painter::setBrush(Kross::Api::List::Ptr args) +{ + Brush* b = (Brush*)args->item(0).data(); + m_painter->setBrush( b->getBrush()); + return 0; +} +Kross::Api::Object::Ptr Painter::setPaintOp(Kross::Api::List::Ptr args) +{ + TQString id = Kross::Api::Variant::toString(args->item(0)); + KisPaintOp* op = KisPaintOpRegistry::instance()->paintOp( id, 0, m_painter ); + m_painter->setPaintOp( op ); + return 0; +} + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.h new file mode 100644 index 00000000..f4e2c06a --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_painter.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_PAINTER_H +#define KROSS_KRITACOREKRS_PAINTER_H + +#include + +#include +#include +#include + +class KisPainter; +class KisFillPainter; + +namespace Kross { + +namespace ChalkCore { + +class Painter : public Kross::Api::Class +{ + public: + explicit Painter(KisPaintLayerSP layer); + ~Painter(); + private: + // Convolution + /** + * This function apply a convolution kernel to an image. + * It takes at least three arguments : + * - a list of a list with the kernel (all lists need to have the same size) + * - factor + * - offset + * + * The value of a pixel will be given by the following function K*P/factor + offset, + * where K is the kernel and P is the neighbourhood. + * + * It can takes the following optional arguments : + * - borderOp control how to convolve the pixels on the border of an image ( 0 use the default color + * 1 use the pixel on the opposite side of the image 2 use the border pixel 3 avoid border pixels) + * - channel ( 1 for color 2 for alpha 3 for both) + * - x + * - y + * - width + * - height + */ + Kross::Api::Object::Ptr convolve(Kross::Api::List::Ptr args); + // Fill specific + /** + * Set the threshold the fill threshold. + * It takes one argument : + * - threshold + */ + Kross::Api::Object::Ptr setFillThreshold(Kross::Api::List::Ptr args); + /** + * Start filling color. + * It takes two argument : + * - x + * - y + */ + Kross::Api::Object::Ptr fillColor(Kross::Api::List::Ptr args); + /** + * start filling a pattern + * It takes two argument : + * - x + * - y + */ + Kross::Api::Object::Ptr fillPattern(Kross::Api::List::Ptr args); + // Painting operations + /** + * This function will paint a polyline. + * It takes two arguments : + * - a list of x position + * - a list of y position + */ + Kross::Api::Object::Ptr paintPolyline(Kross::Api::List::Ptr args); + /** + * This function will paint a line. + * It takes five arguments : + * - x1 + * - y1 + * - x2 + * - y2 + * - pressure + */ + Kross::Api::Object::Ptr paintLine(Kross::Api::List::Ptr args); + /** + * This function will paint a Bezier curve. + * It takes ten arguments : + * - x1 + * - y1 + * - p1 + * - cx1 + * - cy1 + * - cx2 + * - cx2 + * - x2 + * - y2 + * - p2 + * + * Where (x1,y1) is the start position, p1 is the pressure at the start, + * (x2,y2) is the ending position, p2 is the pressure at the end. (cx1,cy1) and (cx2,cy2) + * are the position of the control points. + */ + Kross::Api::Object::Ptr paintBezierCurve(Kross::Api::List::Ptr args); + /** + * This function will paint an ellipse. + * It takes five arguments : + * - x1 + * - y1 + * - x2 + * - y2 + * - pressure + * + * Where (x1,y1) and (x2,y2) are the position of the two centers. + */ + Kross::Api::Object::Ptr paintEllipse(Kross::Api::List::Ptr args); + /** + * This function will paint a polygon. + * It takes two arguments : + * - a list of x position + * - a list of y position + */ + Kross::Api::Object::Ptr paintPolygon(Kross::Api::List::Ptr args); + /** + * This function will paint a rectangle. + * It takes five arguments : + * - x + * - y + * - width + * - height + * - pressure + */ + Kross::Api::Object::Ptr paintRect(Kross::Api::List::Ptr args); + /** + * This function will paint at a given position. + * It takes three arguments : + * - x + * - y + * - pressure + */ + Kross::Api::Object::Ptr paintAt(Kross::Api::List::Ptr args); + // Color operations + /** + * This functions set the paint color (also called foreground color). + * It takes one argument : + * - a Color + */ + Kross::Api::Object::Ptr setPaintColor(Kross::Api::List::Ptr args); + /** + * This functions set the background color. + * It takes one argument : + * - a Color + */ + Kross::Api::Object::Ptr setBackgroundColor(Kross::Api::List::Ptr args); + // How is painting done operations + /** + * This functions set the pattern used for filling. + * It takes one argument : + * - a Pattern object + */ + Kross::Api::Object::Ptr setPattern(Kross::Api::List::Ptr args); + /** + * This functions set the brush used for painting. + * It takes one argument : + * - a Brush object + */ + Kross::Api::Object::Ptr setBrush(Kross::Api::List::Ptr args); + /** + * This function define the paint operation. + * It takes one argument : + * - the name of the paint operation + */ + Kross::Api::Object::Ptr setPaintOp(Kross::Api::List::Ptr args); + // Special settings + /** + * This function define the duplicate offset. + * It takes two arguments : + * - horizontal offset + * - vertical offset + */ + Kross::Api::Object::Ptr setDuplicateOffset(Kross::Api::List::Ptr args); + // Style operation + /** + * This function set the opacity of the painting + * It takes one argument : + * - opacity in the range 0 to 255 + */ + Kross::Api::Object::Ptr setOpacity(Kross::Api::List::Ptr args); + /** + * This function set the style of the stroke. + * It takes one argument : + * - 0 for none 1 for brush + */ + Kross::Api::Object::Ptr setStrokeStyle(Kross::Api::List::Ptr args); + /** + * This function set the fill style of the Painter. + * It takes one argument : + * - 0 for none 1 for fill with foreground color 2 for fill with background color + * 3 for fill with a pattern + */ + Kross::Api::Object::Ptr setFillStyle(Kross::Api::List::Ptr args); + protected: + inline KisPaintLayerSP paintLayer() { return m_layer; } + private: + inline vKisPoint createPointsVector( TQValueList xs, TQValueList ys) + { + vKisPoint a; + TQValueList::iterator itx = xs.begin(); + TQValueList::iterator ity = ys.begin(); + for(; itx != xs.end(); ++itx, ++ity) + { + a.push_back(KisPoint( (*itx).toDouble(), (*ity).toDouble())); + } + return a; + } + inline KisFillPainter* createFillPainter(); + private: + KisPaintLayerSP m_layer; + KisPainter* m_painter; + int m_threshold; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.cpp new file mode 100644 index 00000000..8ee4f909 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_pattern.h" + +#include + +namespace Kross { + +namespace ChalkCore { + +Pattern::Pattern(KisPattern* pattern, bool sharedPattern) : Kross::Api::Class("ChalkPattern"), m_pattern(pattern), m_sharedPattern(sharedPattern) +{ +} + +Pattern::~Pattern() +{ + if(!m_sharedPattern) + delete m_pattern; +} + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.h new file mode 100644 index 00000000..be39cf31 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_pattern.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_PATTERN_H +#define KROSS_KRITACOREKRS_PATTERN_H + +#include + +class KisPattern; + +namespace Kross { + +namespace ChalkCore { + +class Pattern : public Kross::Api::Class{ + public: + /** + * @param sharedPattern tell if the pattern should be deleted or not when this object is deleted + */ + Pattern(KisPattern*, bool sharedPattern); + ~Pattern(); + public: + inline KisPattern* getPattern() { return m_pattern; } + private: + KisPattern* m_pattern; + bool m_sharedPattern; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.cpp new file mode 100644 index 00000000..b36076c4 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_script_progress.h" + +#include "kis_script_progress.h" + +namespace Kross { + +namespace ChalkCore { + +ScriptProgress::ScriptProgress(KisScriptProgress* script): Kross::Api::Class("ChalkScript"), m_script(script) +{ + addFunction("setProgressTotalSteps", &ScriptProgress::setProgressTotalSteps); + addFunction("setProgressTotalSteps", &ScriptProgress::setProgressTotalSteps); + addFunction("setProgress", &ScriptProgress::setProgress); + addFunction("incProgress", &ScriptProgress::incProgress); + addFunction("setProgressStage", &ScriptProgress::setProgressStage); +} + + +ScriptProgress::~ScriptProgress() +{ +} + +Kross::Api::Object::Ptr ScriptProgress::setProgressTotalSteps(Kross::Api::List::Ptr args) +{ + m_script->setProgressTotalSteps( Kross::Api::Variant::toUInt(args->item(0)) ); + return 0; +} + +Kross::Api::Object::Ptr ScriptProgress::setProgress(Kross::Api::List::Ptr args) +{ + m_script->setProgress( Kross::Api::Variant::toUInt(args->item(0)) ); + return 0; +} + +Kross::Api::Object::Ptr ScriptProgress::incProgress(Kross::Api::List::Ptr) +{ + m_script->incProgress(); + return 0; +} + +Kross::Api::Object::Ptr ScriptProgress::setProgressStage(Kross::Api::List::Ptr args) +{ + m_script->setProgressStage( Kross::Api::Variant::toString(args->item(0)), Kross::Api::Variant::toUInt(args->item(1)) ); + return 0; +} + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.h new file mode 100644 index 00000000..b2ae7e44 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_script_progress.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_SCRIPTPROGRESS_H +#define KROSS_KRITACOREKRS_SCRIPTPROGRESS_H + +#include + +class KisScriptProgress; + +namespace Kross { + +namespace ChalkCore { + +/** + * ScriptProgress is used to manage the progress bar of the status bar in chalk + * + * For example (in ruby) : + * @code + * script = Krosschalkcore::get("ChalkScript") + * script.setProgressTotalSteps(1000) + * script.setProgressStage("progressive", 0) + * for i in 1..900 + * script.incProgress() + * end + * script.setProgressStage("brutal", 1000) + * @endcode + */ +class ScriptProgress : public Kross::Api::Class { + public: + ScriptProgress(KisScriptProgress* Script); + ~ScriptProgress(); + private: + /** + * This function set the number of steps that the script will require. + * It takes one argument : + * - maximum value of the progress + */ + Kross::Api::Object::Ptr setProgressTotalSteps(Kross::Api::List::Ptr); + /** + * This function set the value of progress. + * It takes one argument : + * - value of the progress + */ + Kross::Api::Object::Ptr setProgress(Kross::Api::List::Ptr); + /** + * This function increment of one step the position of the progress. + */ + Kross::Api::Object::Ptr incProgress(Kross::Api::List::Ptr); + /** + * This function set the value of the progress and display the text + */ + Kross::Api::Object::Ptr setProgressStage(Kross::Api::List::Ptr); + private: + KisScriptProgress* m_script; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.cpp b/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.cpp new file mode 100644 index 00000000..e166de7c --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.cpp @@ -0,0 +1,114 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "krs_wavelet.h" + +#include + +#include + +namespace Kross { + +namespace ChalkCore { + +Wavelet::Wavelet(KisMathToolbox::KisWavelet* kwl) + : Kross::Api::Class("ChalkWavelet"), m_wavelet(kwl) +{ + addFunction("getNCoeff", &Wavelet::getNCoeff); + addFunction("setNCoeff", &Wavelet::setNCoeff); + addFunction("getXYCoeff", &Wavelet::getXYCoeff); + addFunction("setXYCoeff", &Wavelet::setXYCoeff); + addFunction("getDepth", &Wavelet::getDepth); + addFunction("getSize", &Wavelet::getSize); + addFunction("getNumCoeffs", &Wavelet::getNumCoeffs); + m_numCoeff = m_wavelet->size*m_wavelet->size*m_wavelet->depth; +} + + +Wavelet::~Wavelet() +{ +} + + +Kross::Api::Object::Ptr Wavelet::getNCoeff(Kross::Api::List::Ptr args) +{ + TQ_UINT32 n = Kross::Api::Variant::toUInt(args->item(0)); + if( n > m_numCoeff) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("getNCoeff") + "\n" + i18n("Index out of bound") ) ); + } + return new Kross::Api::Variant(*(m_wavelet->coeffs + n )); +} + +Kross::Api::Object::Ptr Wavelet::setNCoeff(Kross::Api::List::Ptr args) +{ + TQ_UINT32 n = Kross::Api::Variant::toUInt(args->item(0)); + double v = Kross::Api::Variant::toDouble(args->item(1)); + if( n > m_numCoeff) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("setNCoeff") + "\n" + i18n("Index out of bound") ) ); + } + *(m_wavelet->coeffs + n ) = v; + return 0; +} + +Kross::Api::Object::Ptr Wavelet::getXYCoeff(Kross::Api::List::Ptr args) +{ + TQ_UINT32 x = Kross::Api::Variant::toUInt(args->item(0)); + TQ_UINT32 y = Kross::Api::Variant::toUInt(args->item(1)); + if( x > m_wavelet->size && y > m_wavelet->size) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("getXYCoeff") + "\n" + i18n("Index out of bound") ) ); + } + return new Kross::Api::Variant(*(m_wavelet->coeffs + (x + y * m_wavelet->size ) * m_wavelet->depth )); +} + +Kross::Api::Object::Ptr Wavelet::setXYCoeff(Kross::Api::List::Ptr args) +{ + TQ_UINT32 x = Kross::Api::Variant::toUInt(args->item(0)); + TQ_UINT32 y = Kross::Api::Variant::toUInt(args->item(1)); + double v = Kross::Api::Variant::toDouble(args->item(2)); + if( x > m_wavelet->size && y > m_wavelet->size) + { + throw Kross::Api::Exception::Ptr( new Kross::Api::Exception( i18n("An error has occured in %1").tqarg("setXYCoeff") + "\n" + i18n("Index out of bound") )); + } + *(m_wavelet->coeffs + (x + y * m_wavelet->size ) * m_wavelet->depth ) = v; + return 0; +} + +Kross::Api::Object::Ptr Wavelet::getDepth(Kross::Api::List::Ptr /*args*/) +{ + return new Kross::Api::Variant(m_wavelet->depth); +} + +Kross::Api::Object::Ptr Wavelet::getSize(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_wavelet->size); +} + +Kross::Api::Object::Ptr Wavelet::getNumCoeffs(Kross::Api::List::Ptr) +{ + return new Kross::Api::Variant(m_numCoeff); +} + + +} + +} diff --git a/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.h b/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.h new file mode 100644 index 00000000..8a9a0889 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkcore/krs_wavelet.h @@ -0,0 +1,92 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KROSS_KRITACOREKRS_WAVELET_H +#define KROSS_KRITACOREKRS_WAVELET_H + +#include + +#include + +namespace Kross { + +namespace ChalkCore { + +/** + @author Cyrille Berger +*/ +class Wavelet : public Kross::Api::Class +{ + public: + Wavelet(KisMathToolbox::KisWavelet* wavelet); + ~Wavelet(); + private: + /** + * Return the value of the Nth coefficient + * The function takes one argument : + * - the index of the coefficient + */ + Kross::Api::Object::Ptr getNCoeff(Kross::Api::List::Ptr); + /** + * Set the value of the Nth coefficient + * The function takes two arguments : + * - the index of the coefficient + * - the new value of the coefficient + */ + Kross::Api::Object::Ptr setNCoeff(Kross::Api::List::Ptr); + /** + * Return the value of a coefficient + * The function takes two arguments : + * - x + * - y + */ + Kross::Api::Object::Ptr getXYCoeff(Kross::Api::List::Ptr); + /** + * Set the value of a coefficient + * The function takes three arguments : + * - x + * - y + * - the new value of the coefficient + */ + Kross::Api::Object::Ptr setXYCoeff(Kross::Api::List::Ptr); + /** + * Return the depth of the layer + */ + Kross::Api::Object::Ptr getDepth(Kross::Api::List::Ptr); + /** + * Return the size of the wavelet (size = width = height) + */ + Kross::Api::Object::Ptr getSize(Kross::Api::List::Ptr); + /** + * Return the number of coefficients in this wavelet (= size * size * depth) + */ + Kross::Api::Object::Ptr getNumCoeffs(Kross::Api::List::Ptr); + public: + KisMathToolbox::KisWavelet* wavelet() { return m_wavelet; } + private: + KisMathToolbox::KisWavelet* m_wavelet; + uint m_numCoeff; +}; + +} + +} + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting.desktop b/chalk/plugins/viewplugins/scripting/chalkscripting.desktop new file mode 100644 index 00000000..511e76a0 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Name=Scripting plugin +Name[bg]=Приставка за скриптове +Name[ca]=Connector de seqüenciació +Name[da]=Scriptplugin +Name[de]=Skripting-Modul +Name[el]=Πρόσθετο γραφής σεναρίων +Name[eo]=Skriptad-kromaĵo +Name[es]=Complemento para guiones +Name[et]=Skriptiplugin +Name[fa]=وصلۀ دست‌نوشته +Name[fr]=Module de scriptage +Name[fy]=Skriptplugin +Name[ga]=Breiseán scriptithe +Name[gl]=Plugin de programación +Name[he]=תוסף לתסריטים +Name[hu]=Szkript modul +Name[is]=Skriftu íforrit +Name[it]=Plugin di scripting +Name[ja]=スクリプトプラグイン +Name[km]=កម្មវិធី​ជំនួយ​សម្រាប់​ស្គ្រីប +Name[nb]=Programtillegg for skripting +Name[nds]=Skriptmoduul +Name[ne]=प्लगइन स्क्रिप्ट गर्दै +Name[nl]=Scriptplugin +Name[pl]=Wtyczka obsługi języków skryptowych +Name[pt]='Plugin' de programação +Name[pt_BR]=Plugin de programação +Name[ru]=Модуль поддержки сценариев +Name[sk]=Modul pre skripty +Name[sl]=Vstavek za skripte +Name[sr]=Прикључак за скриптовање +Name[sr@Latn]=Priključak za skriptovanje +Name[sv]=Skriptinsticksprogram +Name[uk]=Втулок для скриптів +Name[uz]=Skriptlash plagini +Name[uz@cyrillic]=Скриптлаш плагини +Name[zh_CN]=脚本插件 +Name[zh_TW]=命令稿外掛程式 +Comment=Allow execution of scripts +Comment[bg]=Изпълнение на скриптове +Comment[ca]=Permet l'execució de seqüències +Comment[da]=Tillad kørsel af script +Comment[de]=Ermöglicht das Ausführen von Skripten +Comment[el]=Επιτρέπει την εκτέλεση σεναρίων +Comment[eo]=Permesi ruligon de skriptoj +Comment[es]=Permite la ejecución de guiones +Comment[et]=Võimaldab skriptide käivitamist +Comment[fa]=اجازۀ اجرای دست‌نوشته‌ها +Comment[fr]=Permet d'exécuter des scripts +Comment[fy]=Hjirmei kinne skripts útfierd wurde +Comment[gl]=Permite executar guións +Comment[he]=אפשרות להרצת תסריטים +Comment[hu]=Lehetővé teszi szkriptek végrehajtását +Comment[is]=Leyfa að skriftur séu keyrðar +Comment[it]=Permette di eseguire script +Comment[ja]=スクリプトの実行を可能にします +Comment[km]=អនុញ្ញាត​ឲ្យ​ប្រតិបត្តិ​ស្គ្រីប +Comment[lv]=Atļaut skriptu izpildi +Comment[nb]=Tillater skriptkjøring +Comment[nds]=Skripten utföhren +Comment[ne]=स्क्रिप्टको कार्यान्वयनलाई अनुमति दिनुहोस् +Comment[nl]=Hiermee kunnen scripts uitgevoerd worden +Comment[pl]=Zezwala na wykonywanie skryptów +Comment[pt]=Permitir executar programas ou 'scripts' +Comment[pt_BR]=Permitir executar programas ou 'scripts' +Comment[ru]=Возможность выполнения сценариев +Comment[sk]=Povoliť vykonávanie skriptov +Comment[sl]=Dovoli izvedbo skriptov +Comment[sr]=Омогући извршавање скрипти +Comment[sr@Latn]=Omogući izvršavanje skripti +Comment[sv]=Tillåt körning av skript +Comment[uk]=Дає змогу виконувати скрипти +Comment[uz]=Skriptlarni ishga tushirishga ruxsat berish +Comment[uz@cyrillic]=Скриптларни ишга туширишга рухсат бериш +Comment[zh_CN]=允许执行脚本 +Comment[zh_TW]=允許執行命令稿 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkscripting +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting/Makefile.am b/chalk/plugins/viewplugins/scripting/chalkscripting/Makefile.am new file mode 100644 index 00000000..b805ef18 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/chalkcolor/ \ + -I$(top_srcdir)/chalk/ui \ + $(KROSS_INCLUDES) \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +lib_LTLIBRARIES = libchalkscripting.la +libchalkscripting_la_SOURCES = kis_script_progress.cpp kis_script_monitor.cpp +noinst_HEADERS = kis_script_progress.h + +libchalkscripting_la_LDFLAGS = -no-undefined $(all_libraries) +libchalkscripting_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la $(top_builddir)/lib/kross/main/libkrossmain.la + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +libchalkscripting_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.cpp b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.cpp new file mode 100644 index 00000000..3967ffe7 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_script_monitor.h" + +#include
+#include
+ + +KisScriptMonitor::KisScriptMonitor() +{ +} + + +KisScriptMonitor::~KisScriptMonitor() +{ + s_instance = 0; +} + +void KisScriptMonitor::monitor(Kross::Api::ScriptGUIClient* guiClient) +{ + connect(guiClient, TQT_SIGNAL(executionFinished( const Kross::Api::ScriptAction* )), TQT_SIGNAL(executionFinished( const Kross::Api::ScriptAction* ))); + connect(guiClient, TQT_SIGNAL(executionStarted( const Kross::Api::ScriptAction* )), TQT_SIGNAL(executionStarted( const Kross::Api::ScriptAction* ))); +} + +KisScriptMonitor* KisScriptMonitor::s_instance = 0; + +KisScriptMonitor* KisScriptMonitor::instance() +{ + if(s_instance == 0) + s_instance = new KisScriptMonitor(); + return s_instance; +} + +#include "kis_script_monitor.moc" + diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.h b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.h new file mode 100644 index 00000000..c1ee64c0 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_monitor.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SCRIPT_MONITOR_H +#define KIS_SCRIPT_MONITOR_H + +#include + +namespace Kross { + namespace Api { + class ScriptGUIClient; + class ScriptAction; + } +} + +/** + @author Cyrille Berger +*/ +class KisScriptMonitor : public TQObject { + Q_OBJECT + TQ_OBJECT + private: + KisScriptMonitor(); + ~KisScriptMonitor(); + public: + static KisScriptMonitor* instance(); + void monitor(Kross::Api::ScriptGUIClient* guiClient); + signals: + void executionFinished(const Kross::Api::ScriptAction* ); + void executionStarted(const Kross::Api::ScriptAction* ); + private: + static KisScriptMonitor* s_instance; + +}; + +#endif diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.cpp b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.cpp new file mode 100644 index 00000000..d7af4eb4 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_script_progress.h" + +#include +#include + +void KisScriptProgress::activateAsSubject() +{ + m_view->canvasSubject()->progressDisplay()->setSubject( this, true, false /* TODO: how to cancel a script ? */ ); +} + +void KisScriptProgress::setProgressTotalSteps(TQ_INT32 totalSteps) +{ + m_progressTotalSteps = totalSteps; + m_progressSteps = 0; + m_lastProgressPerCent = 0; + emit notifyProgress(0); +} + +void KisScriptProgress::setProgress(TQ_INT32 progress) +{ + m_progressSteps = progress; + TQ_INT32 progressPerCent = (m_progressSteps * 100) / (m_progressTotalSteps > 0 ? m_progressTotalSteps : 1); + + if (progressPerCent != m_lastProgressPerCent) { + + m_lastProgressPerCent = progressPerCent; + emit notifyProgress(progressPerCent); + } +} + +void KisScriptProgress::incProgress() +{ + setProgress( ++m_progressSteps ); +} + +void KisScriptProgress::setProgressStage(const TQString& stage, TQ_INT32 progress) +{ + TQ_INT32 progressPerCent = (progress * 100) / (m_progressTotalSteps > 0 ? m_progressTotalSteps : 1); + m_lastProgressPerCent = progress; + emit notifyProgressStage( stage, progressPerCent); +} + +void KisScriptProgress::progressDone() +{ + emit notifyProgressDone(); +} diff --git a/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.h b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.h new file mode 100644 index 00000000..48af433c --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/chalkscripting/kis_script_progress.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_SCRIPT_PROGRESS_H_ +#define _KIS_SCRIPT_PROGRESS_H_ + +#include + +class KisView; + +/** + * TODO: clarify the situation, while, in the future, multiple scripts could be running at a same time, + * some of the functions are global to all script and some aren't. + */ +class KisScriptProgress : public KisProgressSubject +{ + public: + KisScriptProgress(KisView* view) : m_view(view) {}; + public: + /** + * This function will set this class as the KisProgressSubject in view + */ + void activateAsSubject(); + virtual void cancel() {}; + public: + void setProgressTotalSteps(TQ_INT32 totalSteps); + void setProgress(TQ_INT32 progress); + void incProgress(); + void setProgressStage(const TQString& stage, TQ_INT32 progress); + void progressDone(); + inline void setPackagePath(TQString path) { m_packagePath = path; }; + inline TQString packagePath() { return m_packagePath; } + private: + TQ_INT32 m_progressSteps, m_progressTotalSteps, m_lastProgressPerCent; + KisView * m_view; + TQString m_packagePath; +}; + +#endif diff --git a/chalk/plugins/viewplugins/scripting/samples/Makefile.am b/chalk/plugins/viewplugins/scripting/samples/Makefile.am new file mode 100644 index 00000000..0f0c383d --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/Makefile.am @@ -0,0 +1,3 @@ +INCLUDES = -I$(srcdir)/../../../sdk -I$(srcdir)/../../../core -I$(srcdir)/../../../chalkcolor/ -I$(srcdir)/../../../ui -I$(top_srcdir)/kexi/scriptingcore/main $(KOFFICE_INCLUDES) $(all_includes) +METASOURCES = AUTO +SUBDIRS = python ruby diff --git a/chalk/plugins/viewplugins/scripting/samples/python/Makefile.am b/chalk/plugins/viewplugins/scripting/samples/python/Makefile.am new file mode 100644 index 00000000..c15a3b3b --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/python/Makefile.am @@ -0,0 +1,5 @@ +scriptinvertdir = $(kde_datadir)/chalk/scripts/invertpython +scriptinvert_SCRIPTS = invert.py invertpython.rc + +scriptreshapedir = $(kde_datadir)/chalk/scripts/reshapehisto +scriptreshape_SCRIPTS = reshapehisto.py reshapehisto.rc diff --git a/chalk/plugins/viewplugins/scripting/samples/python/invert.py b/chalk/plugins/viewplugins/scripting/samples/python/invert.py new file mode 100644 index 00000000..7a642760 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/python/invert.py @@ -0,0 +1,48 @@ +# This file is part of Chalk +# +# Copyright (c) 2005-2006 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Inverter: + def __init__(self): + try: + import krosschalkcore + except: + raise "Import of the ChalkCore module failed." + doc = krosschalkcore.get("ChalkDocument") + script = krosschalkcore.get("ChalkScript") + image = doc.getImage() + layer = image.getActivePaintLayer() + if(layer.colorSpaceId() != "RGBA" ): + raise("This script works only for 8bit RGBA layers") + width = layer.getWidth() + height = layer.getHeight() + script.setProgressTotalSteps(width * height) + layer.beginPainting("invert") + it = layer.createRectIterator( 0, 0, width, height ) + print "kikoo\n" + finesh = it.isDone() + while (not finesh) : + p = it.getRGBA() + p[0] = 255 - p[0] + p[1] = 255 - p[1] + p[2] = 255 - p[2] + it.setRGBA(p) + script.incProgress() + finesh = it.next() + layer.endPainting() + +Inverter() diff --git a/chalk/plugins/viewplugins/scripting/samples/python/invertpython.rc b/chalk/plugins/viewplugins/scripting/samples/python/invertpython.rc new file mode 100644 index 00000000..d2224311 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/python/invertpython.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.py b/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.py new file mode 100644 index 00000000..4ef66965 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.py @@ -0,0 +1,300 @@ +# This file is part of Chalk +# +# Copyright (c) 2005 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import math + +# it's an experimental script to try to reshape.histogram, while the results are far to be convincing yet +# it is still an example on how to use histogram in a script + +def sign(a): + if a < 0: + return -1 + else: + return 1 +#def abs(a): + #if a < + +def computeDiff(histo, histoTarget): + diff = [ ] + histoMax = histo.getHighest() + count = 0 + while( count < 256 ) : + v = histo.getValue(count) + diff.append( v / histoMax - histoTarget[count]) + count += 1 + derivdiff = [ ] + derivdiff.append(diff[1] - diff[0] ) + count = 1 + while( count < 255 ) : + derivdiff.append((diff[count+1] - diff[count - 1])/2.0) + print count + print " " + print derivdiff[count] + print " " + count += 1 + derivdiff.append(diff[255] - diff[254] ) + return diff + +try: + import krosschalkcore +except: + raise "Import of the ChalkCore module failed." + +#histoTarget = [ 0.0, 0.01226531745085, 0.024528789662323, 0.0367885716726463, 0.049042819075215, 0.0612896882960706, 0.0735273368712555, 0.0857539237239997, 0.0979676094416996, 0.110166556552646, 0.122348929802458, 0.13451289643019, 0.146656626444054, 0.158778292896733, 0.170876072160234, 0.18294814420024, 0.194992692849922, 0.207007906083172, 0.218991976287209, 0.230943100534525, 0.242859480854121, 0.254739324502003, 0.266580844230888, 0.278382258559083, 0.290141792038499, 0.301857675521758, 0.313528146428344, 0.325151449009778, 0.336725834613756, 0.348249561947225, 0.359720897338346, 0.371138114997318, 0.38249949727601, 0.393803334926368, 0.405047927357568, 0.416231582891849, 0.427352619019025, 0.4384093626496, 0.449400150366478, 0.460323328675215, 0.471177254252771, 0.481960294194744, 0.492670826261026, 0.50330723911986, 0.513867932590253, 0.524351317882718, 0.534755817838293, 0.545079867165813, 0.555321912677404, 0.565480413522147, 0.575553841417885, 0.585540680881154, 0.595439429455167, 0.605248597935856, 0.614966710595909, 0.624592305406788, 0.634123934258679, 0.643560163178352, 0.652899572544893, 0.662140757303275, 0.671282327175744, 0.680322906870975, 0.689261136290974, 0.698095670735701, 0.706825181105366, 0.715448354100387, 0.723963892418968, 0.732370514952268, 0.740666956977137, 0.748851970346384, 0.756924323676554, 0.764882802533185, 0.772726209613504, 0.780453364926561, 0.788063105970749, 0.795554287908693, 0.802925783739486, 0.810176484468239, 0.817305299272921, 0.824311155668464, 0.83119299966812, 0.837949795942015, 0.84458052797292, 0.851084198209167, 0.857459828214736, 0.863706458816447, 0.869823150248263, 0.875808982292675, 0.881663054419139, 0.887384485919556, 0.892972416040772, 0.898426004114068, 0.903744429681637, 0.908926892620016, 0.913972613260457, 0.918880832506229, 0.923650811946811, 0.928281833968988, 0.93277320186481, 0.937124239936404, 0.941334293597632, 0.945402729472569, 0.949328935490789, 0.953112320979447, 0.956752316752142, 0.960248375194552, 0.963599970346811, 0.966806597982642, 0.969867775685214, 0.972783042919718, 0.97555196110265, 0.978174113667795, 0.980649106128898, 0.982976566139007, 0.985156143546496, 0.987187510447739, 0.989070361236445, 0.990804412649628, 0.99238940381023, 0.993825096266363, 0.995111274027184, 0.99624774359539, 0.997234333996328, 0.998070896803715, 0.998757306161974, 0.99929345880516, 0.999679274072503, 0.999914693920536, 0.999999682931835, 0.99993422832034, 0.999718339933283, 0.999352050249705, 0.998835414375572, 0.998168510035481, 0.997351437560967, 0.996384319875413, 0.995267302475555, 0.994000553409588, 0.992584263251893, 0.991018645074359, 0.989303934414332, 0.987440389239176, 0.985428289907469, 0.983267939126818, 0.980959661908326, 0.978503805517689, 0.975900739422957, 0.973150855238948, 0.970254566668332, 0.967212309439392, 0.964024541240472, 0.960691741651122, 0.957214412069943, 0.953593075639162, 0.949828277165924, 0.945920583040329, 0.941870581150226, 0.937678880792763, 0.933346112582728, 0.928872928357675, 0.924260001079857, 0.919508024734984, 0.914617714227821, 0.909589805274631, 0.90442505429249, 0.899124238285494, 0.89368815472786, 0.888117621443952, 0.882413476485242, 0.876576578004235, 0.870607804125365, 0.86450805281288, 0.858278241735758, 0.851919308129644, 0.845432208655849, 0.83881791925743, 0.832077435012361, 0.825211769983833, 0.818221957067693, 0.811109047837053, 0.803874112384084, 0.796518239159033, 0.789042534806467, 0.781448123998789, 0.773736149267035, 0.76590777082899, 0.757964166414642, 0.749906531088995, 0.741736077072283, 0.733454033557598, 0.725061646525966, 0.716560178558895, 0.707950908648432, 0.699235132004742, 0.690414159861254, 0.681489319277395, 0.672461952938941, 0.663333418956019, 0.654105090658787, 0.644778356390828, 0.635354619300277, 0.625835297128734, 0.616221821997965, 0.606515640194456, 0.596718211951823, 0.586831011231134, 0.576855525499155, 0.566793255504575, 0.556645715052225, 0.546414430775338, 0.536100941905873, 0.525706800042952, 0.515233568919429, 0.504682824166636, 0.49405615307734, 0.483355154366944, 0.472581437932973, 0.461736624612871, 0.450822345940161, 0.439840243898986, 0.428791970677089, 0.417679188417244, 0.406503568967204, 0.39526679362818, 0.383970552901897, 0.372616546236274, 0.361206481769749, 0.349742076074299, 0.338225053897198, 0.326657147901536, 0.315040098405551, 0.303375653120808, 0.291665566889271, 0.279911601419294, 0.268115525020586, 0.256279112338177, 0.244404144085436, 0.232492406776176, 0.220545692455878, 0.208565798432095, 0.196554527004056, 0.184513685191523, 0.172445084462932, 0.160350540462877, 0.148231872738948, 0.136090904468, 0.123929462181863, 0.111749375492553, 0.0995524768170189, 0.0873406011014653, 0.0751155855452987, 0.0628792693247314, 0.0506334933160884, 0.0383800998188613, 0.0261209322785436, 0.0138578350092972 ] + +histoTarget = [ 0.0, 0.00392156862745098, 0.00784313725490196, 0.0117647058823529, 0.0156862745098039, 0.0196078431372549, 0.0235294117647059, 0.0274509803921569, 0.0313725490196078, 0.0352941176470588, 0.0392156862745098, 0.0431372549019608, 0.0470588235294118, 0.0509803921568627, 0.0549019607843137, 0.0588235294117647, 0.0627450980392157, 0.0666666666666667, 0.0705882352941176, 0.0745098039215686, 0.0784313725490196, 0.0823529411764706, 0.0862745098039216, 0.0901960784313725, 0.0941176470588235, 0.0980392156862745, 0.101960784313725, 0.105882352941176, 0.109803921568627, 0.113725490196078, 0.117647058823529, 0.12156862745098, 0.125490196078431, 0.129411764705882, 0.133333333333333, 0.137254901960784, 0.141176470588235, 0.145098039215686, 0.149019607843137, 0.152941176470588, 0.156862745098039, 0.16078431372549, 0.164705882352941, 0.168627450980392, 0.172549019607843, 0.176470588235294, 0.180392156862745, 0.184313725490196, 0.188235294117647, 0.192156862745098, 0.196078431372549, 0.2, 0.203921568627451, 0.207843137254902, 0.211764705882353, 0.215686274509804, 0.219607843137255, 0.223529411764706, 0.227450980392157, 0.231372549019608, 0.235294117647059, 0.23921568627451, 0.243137254901961, 0.247058823529412, 0.250980392156863, 0.254901960784314, 0.258823529411765, 0.262745098039216, 0.266666666666667, 0.270588235294118, 0.274509803921569, 0.27843137254902, 0.282352941176471, 0.286274509803922, 0.290196078431373, 0.294117647058824, 0.298039215686275, 0.301960784313725, 0.305882352941176, 0.309803921568627, 0.313725490196078, 0.317647058823529, 0.32156862745098, 0.325490196078431, 0.329411764705882, 0.333333333333333, 0.337254901960784, 0.341176470588235, 0.345098039215686, 0.349019607843137, 0.352941176470588, 0.356862745098039, 0.36078431372549, 0.364705882352941, 0.368627450980392, 0.372549019607843, 0.376470588235294, 0.380392156862745, 0.384313725490196, 0.388235294117647, 0.392156862745098, 0.396078431372549, 0.4, 0.403921568627451, 0.407843137254902, 0.411764705882353, 0.415686274509804, 0.419607843137255, 0.423529411764706, 0.427450980392157, 0.431372549019608, 0.435294117647059, 0.43921568627451, 0.443137254901961, 0.447058823529412, 0.450980392156863, 0.454901960784314, 0.458823529411765, 0.462745098039216, 0.466666666666667, 0.470588235294118, 0.474509803921569, 0.47843137254902, 0.482352941176471, 0.486274509803922, 0.490196078431373, 0.494117647058824, 0.498039215686275, 0.501960784313725, 0.505882352941176, 0.509803921568627, 0.513725490196078, 0.517647058823529, 0.52156862745098, 0.525490196078431, 0.529411764705882, 0.533333333333333, 0.537254901960784, 0.541176470588235, 0.545098039215686, 0.549019607843137, 0.552941176470588, 0.556862745098039, 0.56078431372549, 0.564705882352941, 0.568627450980392, 0.572549019607843, 0.576470588235294, 0.580392156862745, 0.584313725490196, 0.588235294117647, 0.592156862745098, 0.596078431372549, 0.6, 0.603921568627451, 0.607843137254902, 0.611764705882353, 0.615686274509804, 0.619607843137255, 0.623529411764706, 0.627450980392157, 0.631372549019608, 0.635294117647059, 0.63921568627451, 0.643137254901961, 0.647058823529412, 0.650980392156863, 0.654901960784314, 0.658823529411765, 0.662745098039216, 0.666666666666667, 0.670588235294118, 0.674509803921569, 0.67843137254902, 0.682352941176471, 0.686274509803922, 0.690196078431373, 0.694117647058824, 0.698039215686274, 0.701960784313725, 0.705882352941177, 0.709803921568627, 0.713725490196078, 0.717647058823529, 0.72156862745098, 0.725490196078431, 0.729411764705882, 0.733333333333333, 0.737254901960784, 0.741176470588235, 0.745098039215686, 0.749019607843137, 0.752941176470588, 0.756862745098039, 0.76078431372549, 0.764705882352941, 0.768627450980392, 0.772549019607843, 0.776470588235294, 0.780392156862745, 0.784313725490196, 0.788235294117647, 0.792156862745098, 0.796078431372549, 0.8, 0.803921568627451, 0.807843137254902, 0.811764705882353, 0.815686274509804, 0.819607843137255, 0.823529411764706, 0.827450980392157, 0.831372549019608, 0.835294117647059, 0.83921568627451, 0.843137254901961, 0.847058823529412, 0.850980392156863, 0.854901960784314, 0.858823529411765, 0.862745098039216, 0.866666666666667, 0.870588235294118, 0.874509803921569, 0.87843137254902, 0.882352941176471, 0.886274509803922, 0.890196078431372, 0.894117647058824, 0.898039215686275, 0.901960784313726, 0.905882352941176, 0.909803921568627, 0.913725490196078, 0.917647058823529, 0.92156862745098, 0.925490196078431, 0.929411764705882, 0.933333333333333, 0.937254901960784, 0.941176470588235, 0.945098039215686, 0.949019607843137, 0.952941176470588, 0.956862745098039, 0.96078431372549, 0.964705882352941, 0.968627450980392, 0.972549019607843, 0.976470588235294, 0.980392156862745, 0.984313725490196, 0.988235294117647, 0.992156862745098, 0.996078431372549, 1.0 ] + +doc = krosschalkcore.get("ChalkDocument") +image = doc.getImage() +layer = image.getActivePaintLayer() +if (layer.colorSpaceId() != "RGBA" ): + raise("This script works only for 8bit RGBA layers") + +width = layer.getWidth() +height = layer.getHeight() + +countreshaping = 0 +while countreshaping < 1: + histo = layer.createHistogram("RGB8HISTO",0) + print "################################### histogram reshaping ##################################################" + if histo == 0: + raise "Uncompatible histogram\n" + print "Max : " + str( histo.getMax() ) + " Min : " + str( histo.getMin() ) + + #Compute the area of the target histogram + aireHistoTarget = 0.0 + count = 0 + while( count < 256 ) : + aireHistoTarget += histoTarget[count] + count += 1 + + #compute the table for the blue channel + histo.setChannel(0) + tableb = [ ] + histoMax = histo.getHighest() + aireHisto = width * height + coeff = aireHistoTarget / aireHisto + count = 0 + position = 0 + residu = 0. + while( count < 256 ) : + residu += histo.getValue(count) * coeff + while residu > 0.0: + residu -= histoTarget[position] + position += 1 + tableb.append( position ) + count += 1 + #compute the table for the green channel + histo.setChannel(1) + tableg = [ ] + histoMax = histo.getHighest() + aireHisto = width * height + coeff = aireHistoTarget / aireHisto + count = 0 + position = 0 + residu = 0. + while( count < 256 ) : + residu += histo.getValue(count) * coeff + while residu > 0.0: + residu -= histoTarget[position] + position += 1 + tableg.append( position ) + count += 1 + #compute the table for the red channel + histo.setChannel(2) + tabler = [ ] + histoMax = histo.getHighest() + aireHisto = width * height + coeff = aireHistoTarget / aireHisto + count = 0 + position = 0 + residu = 0. + while( count < 256 ) : + residu += histo.getValue(count) * coeff + while residu > 0.0: + residu -= histoTarget[position] + position += 1 + tabler.append( position ) + count += 1 + + it = layer.createRectIterator( 0, 0, width, height ) + print "kikoo : " + str(countreshaping) + while (not it.isDone()) : + r = it.getRed() + g = it.getGreen() + b = it.getBlue() + #var = ( tabler[r] - r + tableg[g] - g + tableb[b] - b ) / 3 + #ng = g + var + #nr = r + var + #nb = b + var + it.setRed(tabler[r]) + it.setGreen(tableg[g]) + it.setBlue(tableb[b]) + it.next() + + #histo.setChannel(0) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffb = [ ] + #diffb.append(diff[1] - diff[0] ) + #count = 1 + #while( count < 255 ) : + #diffb.append((diff[count+1] - diff[count - 1])/2.0) + #count += 1 + #diffb.append(diff[255] - diff[254] ) + + #histo.setChannel(1) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffg = [ ] + #diffg.append(diff[1] - diff[0] ) + #count = 1 + #while( count < 255 ) : + #diffg.append((diff[count+1] - diff[count - 1])/2.0) + #count += 1 + #diffg.append(diff[255] - diff[254] ) + + #histo.setChannel(2) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffr = [ ] + #diffr.append(diff[1] - diff[0] ) + #count = 1 + #while( count < 255 ) : + #diffr.append((diff[count+1] - diff[count - 1])/2.0) + #count += 1 + #diffr.append(diff[255] - diff[254] ) + + + #histo.setChannel(0) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffb = [ ] + #diffb.append( sign(diff[1] - diff[0] ) * abs(diff[0]) ) + #count = 1 + #while( count < 255 ) : + #diffb.append( sign(diff[count+1] - diff[count - 1]) * abs(diff[count]) ) + #count += 1 + #diffb.append( sign(diff[255] - diff[254] ) * abs(diff[255]) ) + + #histo.setChannel(1) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffg = [ ] + #diffg.append( sign(diff[1] - diff[0] ) * abs(diff[0]) ) + #count = 1 + #while( count < 255 ) : + #diffg.append( sign(diff[count+1] - diff[count - 1]) * abs(diff[count]) ) + #count += 1 + #diffg.append( sign(diff[255] - diff[254] ) * abs(diff[255]) ) + + #histo.setChannel(2) + #diff = [ ] + #histoMax = histo.getHighest() + #count = 0 + #while( count < 256 ) : + #v = histo.getValue(count) + #diff.append( v / histoMax - histoTarget[count]) + #count += 1 + #diffr = [ ] + #diffr.append( sign(diff[1] - diff[0] ) * abs(diff[0]) ) + #count = 1 + #while( count < 255 ) : + #diffr.append( sign(diff[count+1] - diff[count - 1]) * abs(diff[count]) ) + #count += 1 + #diffr.append( sign(diff[255] - diff[254] ) * abs(diff[255]) ) + + + #print str(diffr) + " " + str(diff[count+1]) + " " + str(diff[count-1]) + + #histo.setChannel(0) + #diffb = computeDiff(histo, histoTarget) + #print "##########################" + #count = 0 + #while( count < 256 ) : + #print count + #print " " + #print diffb[count] + #print "\n" + #count += 1 + + #histo.setChannel(1) + #diffg = computeDiff(histo, histoTarget) + #print "##########################" + #count = 0 + #while( count < 256 ) : + #print count + #print " " + #print diffg[count] + #print "\n" + #count += 1 + + #histo.setChannel(2) + #diffr = computeDiff(histo, histoTarget) + #print "##########################" + #count = 0 + #while( count < 256 ) : + #print count + #print " " + #print diffr[count] + #print "\n" + #count += 1 + + #it = layer.createRectIterator( 0, 0, width, height ) + #print "kikoo : " + str(countreshaping) + #while (not it.isDone()) : + #r = it.getRed() + #g = it.getGreen() + #b = it.getBlue() + #coeff = 1.0 - ( diffr[r] + diffg[g] + diffb[b] ) / 3.0 + ##print str(r) + " = " + str(diffr[r]) + " " + str(g) + " = " + str(diffg[g]) + " " + str(b) + " = " + str(diffb[b]) + " coeff = " + str(coeff) + #ng = g * coeff + #nr = r * coeff + #nb = b * coeff + #it.setRed(nr) + #it.setGreen(ng) + #it.setBlue(nb) + #it.next() + countreshaping += 1 + +doc.notifyModification() diff --git a/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.rc b/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.rc new file mode 100644 index 00000000..481f5764 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/python/reshapehisto.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/Makefile.am b/chalk/plugins/viewplugins/scripting/samples/ruby/Makefile.am new file mode 100644 index 00000000..bebd4a71 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/Makefile.am @@ -0,0 +1,18 @@ +scriptsinvertdir = $(kde_datadir)/chalk/scripts/invertruby +scriptsinvert_SCRIPTS = invert.rb invertruby.rc + +scriptschangecsdir = $(kde_datadir)/chalk/scripts/changecs +scriptschangecs_SCRIPTS = changecs.rb changecs.rc + +scriptsrandompaintdir = $(kde_datadir)/chalk/scripts/randompaint +scriptsrandompaint_SCRIPTS = randompaint.rb randompaint.rc + +scriptsfilterstestdir = $(kde_datadir)/chalk/scripts/filterstest +scriptsfilterstest_SCRIPTS = filterstest.rb filterstest.rc + +scriptstorturefiltersdir = $(kde_datadir)/chalk/scripts/torturefilters +scriptstorturefilters_SCRIPTS = torture-filters.rb torture-filters.rc + +scriptstorturepaintingdir = $(kde_datadir)/chalk/scripts/torturepainting +scriptstorturepainting_SCRIPTS = torture-painting.rb torture-painting.rc + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rb new file mode 100644 index 00000000..be7c0d89 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rb @@ -0,0 +1,5 @@ +require "krosschalkcore" + +doc = Krosschalkcore::get("ChalkDocument") +image = doc.getImage() +image.convertToColorspace("LABA") diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rc new file mode 100644 index 00000000..4121693d --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/changecs.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rb new file mode 100644 index 00000000..bf76b018 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rb @@ -0,0 +1,31 @@ +# This file is part of Chalk +# +# Copyright (c) 2005-2006 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "krosschalkcore" + +doc = Krosschalkcore::get("ChalkDocument") + +image = doc.getImage() +layer = image.getActivePaintLayer() +width = layer.getWidth() +height = layer.getHeight() + +filter = Krosschalkcore::getFilter("invert") + +filter.process(layer ) +filter.process(layer, 10, 10, 20, 20 ) diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rc new file mode 100644 index 00000000..2f8dfb98 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/filterstest.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/invert.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/invert.rb new file mode 100644 index 00000000..d9ad32f7 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/invert.rb @@ -0,0 +1,45 @@ +# This file is part of Chalk +# +# Copyright (c) 2005-2006 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "krosschalkcore" + +doc = Krosschalkcore::get("ChalkDocument") +script = Krosschalkcore::get("ChalkScript") +image = doc.getImage() +layer = image.getActivePaintLayer() + +if(layer.colorSpaceId() != "RGBA" ) + raise("This script works only for 8bit RGBA layers") +end + +width = layer.getWidth() +height = layer.getHeight() +script.setProgressTotalSteps(width * height) +layer.beginPainting("invert") +it = layer.createRectIterator( 0, 0, width, height ) +while (it.isDone() == 0) + p = it.getRGBA() + p[0] = 255 - p[0] + p[1] = 255 - p[1] + p[2] = 255 - p[2] + it.setRGBA(p) + script.incProgress() + it.next() +end + +layer.endPainting() diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/invertruby.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/invertruby.rc new file mode 100644 index 00000000..9cc7bd6a --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/invertruby.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rb new file mode 100644 index 00000000..1ec25dcd --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rb @@ -0,0 +1,98 @@ +def randomizeStyle(painter) + painter.setFillStyle(4 *rand) + painter.setStrokeStyle(2 *rand) +end + +require "krosschalkcore" + +doc = Krosschalkcore::get("ChalkDocument") +script = Krosschalkcore::get("ChalkScript") + +image = doc.getImage() +layer = image.getActivePaintLayer() +width = layer.getWidth() +height = layer.getHeight() + +script.setProgressTotalSteps(110) +layer.beginPainting("random paint") + +painter = layer.createPainter() + +# create painting color +blackcolor = Krosschalkcore::newRGBColor(0,0,0) + +# set painting color +painter.setPaintColor( blackcolor ) + +# get the brush +brush = Krosschalkcore::getBrush("Circle (05)") + +# define the brush +painter.setBrush(brush) + +# get the pattern +pattern = Krosschalkcore::getPattern("Bricks") + +# set the pattern +painter.setPattern(pattern) + +# define the paint operation +painter.setPaintOp("paintbrush") + +# randomly paint +for i in 1..10 + # set painting color + painter.setPaintColor( Krosschalkcore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.paintAt(rand * width , rand * height,1.1) + script.incProgress() +end + +# randomly rect or circle paint +for i in 1..100 + # set painting color + painter.setPaintColor( Krosschalkcore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setBackgroundColor( Krosschalkcore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setOpacity( rand*255 ) +# set the brush + if(rand < 0.5) + painter.setBrush( Krosschalkcore::newRectBrush(rand*20,rand*20,rand*10,rand*10) ) + else + painter.setBrush( Krosschalkcore::newCircleBrush(rand*20,rand*20,rand*10,rand*10) ) + end + # paint a point + tqshape = rand * 7 + painter.setStrokeStyle(1) + if( tqshape < 1 ) + painter.paintAt(rand * width , rand * height,1.1) + elsif(tqshape < 2 ) + xs = Array.new + ys = Array.new + for i in 0..6 + xs[i] = rand*width + ys[i] = rand*height + end + painter.paintPolyline(xs,ys) + elsif(tqshape < 3) + painter.paintLine(rand * width, rand * height, 1.1, rand * width, rand * height,1.1) + elsif(tqshape < 4) + painter.paintBezierCurve(rand * width, rand * height, 1.1, rand * width, rand * height, rand * width , rand * height, rand * width, rand * height, 1.1) + elsif(tqshape < 5) + randomizeStyle(painter) + painter.paintEllipse(rand * width, rand * height, rand * width, rand * height, 1.1) + elsif(tqshape < 6) + xs = Array.new + ys = Array.new + for i in 0..6 + xs[i] = rand*width + ys[i] = rand*height + end + randomizeStyle(painter) + painter.paintPolygon(xs, ys) + elsif(tqshape < 7) + randomizeStyle(painter) + painter.paintRect(rand * width, rand * height, rand * width, rand * height, 1.1) + end + script.incProgress() +end + +layer.endPainting() diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rc new file mode 100644 index 00000000..3697f700 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/randompaint.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb new file mode 100644 index 00000000..b92a67e0 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rb @@ -0,0 +1,70 @@ +# This file is part of Chalk +# +# Copyright (c) 2006 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "krosschalkcore" + +doc = Krosschalkcore::get("ChalkDocument") + +image = doc.getImage() +layer = image.getActivePaintLayer() + +def testFilter(layer, filterid) + print " applying filter ", filterid, "\n" + begin + filter = Krosschalkcore::getFilter(filterid) + filter.process(layer) + rescue + print " WARNING: this filter is incompatible with this colorspace\n" + end +end + + +def testColorspace(layer, colorspaceid) + print "Testing for ", colorspaceid, "\n" + if (layer.colorSpaceId() != colorspaceid) + layer.convertToColorspace(colorspaceid) + end + testFilter(layer, "invert") + testFilter(layer, "bumpmap") + testFilter(layer, "cimg") + testFilter(layer, "desaturate") + testFilter(layer, "autocontrast") + testFilter(layer, "brightnesscontrast") + testFilter(layer, "gaussian blur") + testFilter(layer, "cubism") + testFilter(layer, "emboss") + testFilter(layer, "simplenoisereducer") + testFilter(layer, "waveletnoisereducer") + testFilter(layer, "oilpaint") + testFilter(layer, "pixelize") + testFilter(layer, "raindrops") + testFilter(layer, "roundcorners") + testFilter(layer, "smalltiles") + testFilter(layer, "sobel") +end + +testColorspace(layer, "RGBA") +testColorspace(layer, "RGBA16") +testColorspace(layer, "RGBAF16HALF") +testColorspace(layer, "RGBAF32") +testColorspace(layer, "CMYK") +testColorspace(layer, "CMYKA16") +testColorspace(layer, "CMYK") +testColorspace(layer, "CMYKA16") +testColorspace(layer, "LABA") +testColorspace(layer, "LMSAF32") diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc new file mode 100644 index 00000000..b3abde5b --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-filters.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb new file mode 100644 index 00000000..b7c784fc --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rb @@ -0,0 +1,133 @@ +# This file is part of Chalk +# +# Copyright (c) 2006 Cyrille Berger +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "krosschalkcore" + +class TorturePainting + + def initialize() + + doc = Krosschalkcore::get("ChalkDocument") + @script = Krosschalkcore::get("ChalkScript") + + @image = doc.getImage() + @width = @image.getWidth() + @height = @image.getHeight() + + @script.setProgressTotalSteps(30 * 10) + + testColorspace("RGBA") + testColorspace("RGBA16") + testColorspace("RGBAF16HALF") + testColorspace("RGBAF32") + testColorspace("CMYK") + testColorspace("CMYKA16") + testColorspace("CMYK") + testColorspace("CMYKA16") + testColorspace("LABA") + testColorspace("LMSAF32") + + + end + + def randomizeStyle(painter) + painter.setFillStyle(4 *rand) + painter.setStrokeStyle(2 *rand) + end + + + def testColorspace(cs) + print "Torturing for ", cs, "\n" + layer = @image.createPaintLayer("torture", 255 * rand, "RGBA" ); + torture(layer) + end + + + def torture(layer) + layer.beginPainting("torture painting") + + painter = layer.createPainter() + + # create painting color + blackcolor = Krosschalkcore::newRGBColor(0,0,0) + + # set painting color + painter.setPaintColor( blackcolor ) + + # get the pattern + pattern = Krosschalkcore::getPattern("Bricks") + + # set the pattern + painter.setPattern(pattern) + + # define the paint operation + painter.setPaintOp("paintbrush") + + # randomly rect or circle paint + for i in 1..30 + # set painting color + painter.setPaintColor( Krosschalkcore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setBackgroundColor( Krosschalkcore::newRGBColor(rand*255,rand*255,rand*255) ) + painter.setOpacity( rand*255 ) + # set the brush + if(rand < 0.5) + painter.setBrush( Krosschalkcore::newRectBrush(rand*20,rand*20,rand*10,rand*10) ) + else + painter.setBrush( Krosschalkcore::newCircleBrush(rand*20,rand*20,rand*10,rand*10) ) + end + # paint a point + tqshape = rand * 7 + painter.setStrokeStyle(1) + if( tqshape < 1 ) + painter.paintAt(rand * @width , rand * @height,1.1) + elsif(tqshape < 2 ) + xs = Array.new + ys = Array.new + for i in 0..6 + xs[i] = rand*@width + ys[i] = rand*@height + end + painter.paintPolyline(xs,ys) + elsif(tqshape < 3) + painter.paintLine(rand * @width, rand * @height, 1.1, rand * @width, rand * @height,1.1) + elsif(tqshape < 4) + painter.paintBezierCurve(rand * @width, rand * @height, 1.1, rand * @width, rand * @height, rand * @width , rand * @height, rand * @width, rand * @height, 1.1) + elsif(tqshape < 5) + randomizeStyle(painter) + painter.paintEllipse(rand * @width, rand * @height, rand * @width, rand * @height, 1.1) + elsif(tqshape < 6) + xs = Array.new + ys = Array.new + for i in 0..6 + xs[i] = rand*@width + ys[i] = rand*@height + end + randomizeStyle(painter) + painter.paintPolygon(xs, ys) + elsif(tqshape < 7) + randomizeStyle(painter) + painter.paintRect(rand * @width, rand * @height, rand * @width, rand * @height, 1.1) + end + @script.incProgress() + end + layer.endPainting() + end + +end + +TorturePainting.new() \ No newline at end of file diff --git a/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc new file mode 100644 index 00000000..51f2eee4 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/samples/ruby/torture-painting.rc @@ -0,0 +1,9 @@ + + + diff --git a/chalk/plugins/viewplugins/scripting/scripting.cc b/chalk/plugins/viewplugins/scripting/scripting.cc new file mode 100644 index 00000000..34b4d1d8 --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/scripting.cc @@ -0,0 +1,111 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Cyrille Berger + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "scripting.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KROSS_MAIN_EXPORT KDE_EXPORT +#include
+#include
+#include
+ +#include + +#include +#include +#include +#include +#include +#include + +#include "chalkscripting/kis_script_progress.h" +#include "chalkscripting/kis_script_monitor.h" + +typedef KGenericFactory ChalkScriptingFactory; +K_EXPORT_COMPONENT_FACTORY( chalkscripting, ChalkScriptingFactory( "chalk" ) ) + +Scripting::Scripting(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(ChalkScriptingFactory::instance()); + + + if ( tqparent->inherits("KisView") ) + { + setInstance(Scripting::instance()); + m_view = (KisView*) tqparent; + m_scriptguiclient = new Kross::Api::ScriptGUIClient( m_view, m_view ); +// m_scriptguiclient ->setXMLFile(locate("data","chalkplugins/scripting.rc"), true); + //BEGIN TODO: understand why the ScriptGUIClient doesn't "link" its actions to the menu + setXMLFile(locate("data","chalkplugins/scripting.rc"), true); + new KAction(i18n("Execute Script File..."), 0, 0, m_scriptguiclient, TQT_SLOT(executeScriptFile()), actionCollection(), "executescriptfile"); + new KAction(i18n("Script Manager..."), 0, 0, m_scriptguiclient, TQT_SLOT(showScriptManager()), actionCollection(), "configurescripts"); + //END TODO + + TQWidget * w = new Kross::Api::WdgScriptsManager(m_scriptguiclient, m_view); + + m_view->canvasSubject()->paletteManager()->addWidget(w, "Scripts Manager", chalk::LAYERBOX, 10, PALETTE_DOCKER, false); + + connect(m_scriptguiclient, TQT_SIGNAL(executionFinished( const Kross::Api::ScriptAction* )), this, TQT_SLOT(executionFinished(const Kross::Api::ScriptAction*))); + connect(m_scriptguiclient, TQT_SIGNAL(executionStarted( const Kross::Api::ScriptAction* )), this, TQT_SLOT(executionStarted(const Kross::Api::ScriptAction*))); + KisScriptMonitor::instance()->monitor( m_scriptguiclient ); + + Kross::Api::Manager::scriptManager()->addTQObject(m_view->canvasSubject()->document(), "ChalkDocument"); + Kross::Api::Manager::scriptManager()->addTQObject(TQT_TQOBJECT(m_view), "ChalkView"); + m_scriptProgress = new KisScriptProgress(m_view); + Kross::Api::Manager::scriptManager()->addTQObject(m_scriptProgress, "ChalkScriptProgress"); + + } + +} + +Scripting::~Scripting() +{ +} + +void Scripting::executionFinished(const Kross::Api::ScriptAction*) +{ + m_view->canvasSubject()->document()->setModified(true); + m_view->canvasSubject()->document()->currentImage()->activeLayer()->setDirty(); + m_scriptProgress->progressDone(); + TQApplication::restoreOverrideCursor(); +} + +void Scripting::executionStarted(const Kross::Api::ScriptAction* act) +{ + kdDebug(41011) << act->getPackagePath() << endl; + m_scriptProgress->setPackagePath( act->getPackagePath() ); +} + + +#include "scripting.moc" diff --git a/chalk/plugins/viewplugins/scripting/scripting.h b/chalk/plugins/viewplugins/scripting/scripting.h new file mode 100644 index 00000000..a981175d --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/scripting.h @@ -0,0 +1,54 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SCRIPTING_H +#define SCRIPTING_H + +#include + +class KisView; +class KisScript; +class KisScriptProgress; + +namespace Kross { + namespace Api { + class ScriptGUIClient; + class ScriptAction; + } +} + +class Scripting : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + public: + Scripting(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~Scripting(); + private slots: + void executionFinished(const Kross::Api::ScriptAction*); + void executionStarted(const Kross::Api::ScriptAction*); + private: + KisView * m_view; + Kross::Api::ScriptGUIClient* m_scriptguiclient; + KisScriptProgress* m_scriptProgress; +}; + + +#endif diff --git a/chalk/plugins/viewplugins/scripting/scripting.rc b/chalk/plugins/viewplugins/scripting/scripting.rc new file mode 100644 index 00000000..1b4999df --- /dev/null +++ b/chalk/plugins/viewplugins/scripting/scripting.rc @@ -0,0 +1,10 @@ + + + + S&cripts + + + + + + diff --git a/chalk/plugins/viewplugins/selectopaque/Makefile.am b/chalk/plugins/viewplugins/selectopaque/Makefile.am new file mode 100644 index 00000000..7f83e3c6 --- /dev/null +++ b/chalk/plugins/viewplugins/selectopaque/Makefile.am @@ -0,0 +1,25 @@ +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkselectopaque.la + +chalkselectopaque_la_SOURCES = selectopaque.cc +noinst_HEADERS = selectopaque.h + +chalkselectopaque_la_LIBADD = ../../../libchalkcommon.la +chalkselectopaque_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui + +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = selectopaque.rc +EXTRA_DIST = $(chalkrc_DATA) + +kde_services_DATA = chalkselectopaque.desktop + +chalkselectopaque_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/chalk/plugins/viewplugins/selectopaque/chalkselectopaque.desktop b/chalk/plugins/viewplugins/selectopaque/chalkselectopaque.desktop new file mode 100644 index 00000000..049c6a40 --- /dev/null +++ b/chalk/plugins/viewplugins/selectopaque/chalkselectopaque.desktop @@ -0,0 +1,26 @@ +[Desktop Entry] +Name=SelectOpaque +Name[bg]=Негатив +Name[da]=Markér ugennemsigtig +Name[de]=UndurchsichtigeAuswählen +Name[et]=Läbipaistmatute pikslite valik +Name[fy]=Untrochsichtige selektearje +Name[it]=Seleziona i pixel opachi +Name[km]=ជ្រើស​ស្រអាប់ +Name[nds]=Decken utsöken +Name[ne]=अपारदर्शी चयन +Name[nl]=Ondoorzichtige selecteren +Name[pl]=Zaznaczanie nieprzezroczystości +Name[pt]=Selecção Opaca +Name[pt_BR]=Seleção Opaca +Name[ru]=Выделение непрозрачных областей +Name[sk]=Invertovať Výber +Name[sr]=Избор непрозирног +Name[sr@Latn]=Izbor neprozirnog +Name[sv]=Markera ogenomskinliga +Name[uk]=Виділення непрозорих ділянок +Name[zh_TW]=選擇不透明 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkselectopaque +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/selectopaque/selectopaque.cc b/chalk/plugins/viewplugins/selectopaque/selectopaque.cc new file mode 100644 index 00000000..a5717a97 --- /dev/null +++ b/chalk/plugins/viewplugins/selectopaque/selectopaque.cc @@ -0,0 +1,116 @@ +/* + * selectopague.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "selectopaque.h" + +typedef KGenericFactory SelectOpaqueFactory; +K_EXPORT_COMPONENT_FACTORY( chalkselectopaque, SelectOpaqueFactory( "chalk" ) ) + +SelectOpaque::SelectOpaque(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if (tqparent->inherits("KisView")) { + setInstance(SelectOpaqueFactory::instance()); + setXMLFile(locate("data","chalkplugins/selectopaque.rc"), true); + m_view = dynamic_cast(tqparent); + m_view->canvasSubject()->selectionManager()->addSelectionAction( new KAction(i18n("&Select All Opaque Pixels..."), 0, 0, this, TQT_SLOT(slotActivated()), actionCollection(), "selectopaque") ); + + } +} + +SelectOpaque::~SelectOpaque() +{ +} + +void SelectOpaque::slotActivated() +{ + KisSelectedTransaction *transaction; + + KisPaintDeviceSP layer = m_view->canvasSubject()->currentImg()->activeDevice(); + if (!layer) return; + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + + if (layer->image()->undo()) transaction = new KisSelectedTransaction(i18n("Select Opaque Pixels"), layer); + // XXX: Multithread this! + TQ_INT32 x, y, w, h; + layer->exactBounds(x, y, w, h); + + KisColorSpace * cs = layer->colorSpace(); + + if(! layer->hasSelection()) + layer->selection()->clear(); + KisSelectionSP selection = layer->selection(); + + KisHLineIterator hiter = layer->createHLineIterator(x, y, w, false); + KisHLineIterator selIter = selection ->createHLineIterator(x, y, w, true); + + for (int row = 0; row < h; ++row) { + while (!hiter.isDone()) { + // Don't try to select transparent pixels. + if (cs->getAlpha( hiter.rawData() ) > OPACITY_TRANSPARENT) { + *(selIter.rawData()) = MAX_SELECTED; + } + ++hiter; + ++selIter; + } + hiter.nextRow(); + selIter.nextRow(); + } + TQApplication::restoreOverrideCursor(); + layer->setDirty(); + layer->emitSelectionChanged(); + + if (layer->image()->undo()) m_view->canvasSubject()->undoAdapter()->addCommand(transaction); + +} + +#include "selectopaque.moc" + diff --git a/chalk/plugins/viewplugins/selectopaque/selectopaque.h b/chalk/plugins/viewplugins/selectopaque/selectopaque.h new file mode 100644 index 00000000..47614e30 --- /dev/null +++ b/chalk/plugins/viewplugins/selectopaque/selectopaque.h @@ -0,0 +1,45 @@ +/* + * selectopaque.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SELECTOPAQUE_H +#define SELECTOPAQUE_H + +#include + +class KisView; + +class SelectOpaque : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT + public: + SelectOpaque(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~SelectOpaque(); + + private slots: + void slotActivated(); + + private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SELECTOPAQUE_H diff --git a/chalk/plugins/viewplugins/selectopaque/selectopaque.rc b/chalk/plugins/viewplugins/selectopaque/selectopaque.rc new file mode 100644 index 00000000..a4809d59 --- /dev/null +++ b/chalk/plugins/viewplugins/selectopaque/selectopaque.rc @@ -0,0 +1,10 @@ + + + + Select + + + + + + diff --git a/chalk/plugins/viewplugins/separate_channels/Makefile.am b/chalk/plugins/viewplugins/separate_channels/Makefile.am new file mode 100644 index 00000000..9b28a89d --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/Makefile.am @@ -0,0 +1,27 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = imageseparate.rc +EXTRA_DIST = $(chalkrc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkseparatechannels.la + +chalkseparatechannels_la_SOURCES = wdg_separations.ui \ + kis_channel_separator.cc dlg_separate.cc \ + kis_separate_channels_plugin.cc + +noinst_HEADERS = wdg_separations.h kis_separate_channels_plugin.h \ + kis_channel_separator.h dlg_separate.h + +kde_services_DATA = chalkseparatechannels.desktop + +chalkseparatechannels_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui -L../../../../lib/kofficecore/.libs -lkofficecore +chalkseparatechannels_la_LIBADD = ../../../libchalkcommon.la + +chalkseparatechannels_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/separate_channels/chalkseparatechannels.desktop b/chalk/plugins/viewplugins/separate_channels/chalkseparatechannels.desktop new file mode 100644 index 00000000..efb596b8 --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/chalkseparatechannels.desktop @@ -0,0 +1,42 @@ +[Desktop Entry] +Name=Separate Channels Plugin +Name[bg]=Приставка за отделен канал +Name[ca]=Connector de canals separats +Name[da]=Plugin for separate kanaler +Name[de]="Kanäle trennen"-Modul +Name[el]=Πρόσθετο διαχωρισμού καναλιών +Name[eo]=Apartkanal-kromaĵo +Name[es]=Complemento para canales separados +Name[et]=Kanalite lahutamise plugin +Name[fa]=جدا کردن وصلۀ مجراها +Name[fr]=Module de séparation des canaux +Name[fy]=Plugin foar aparte kanalen +Name[gl]=Plugin de Separación de Canais +Name[he]=תוסף לריבוי ערוצים +Name[hu]=Csatornaszétválasztó modul +Name[is]=Aðgreindar rásir íforrit +Name[it]=Plugin per la separazione dei canali +Name[ja]=チャンネル分離プラグイン +Name[km]=កម្មវិធី​ជំនួយ​ដើម្បី​បំបែក​ឆានែល +Name[nb]=Programtillegg for atskilte kanaler +Name[nds]=Kanaaltrenn-Moduul +Name[ne]=च्यानल प्लगइन छुट्याउनुहोस् +Name[nl]=Plugin voor aparte kanalen +Name[pl]=Wtyczka oddzielania kanałów +Name[pt]='Plugin' de Separação de Canais +Name[pt_BR]=Plugin de Separação de Canais +Name[ru]=Разбор изображения по каналам +Name[sk]=Modul oddelenie kanálov +Name[sl]=Vstavek za ločevanje kanalov +Name[sr]=Прикључак за раздвајање канала +Name[sr@Latn]=Priključak za razdvajanje kanala +Name[sv]=Insticksprogram för separata kanaler +Name[uk]=Втулок розділення каналів +Name[uz]=Kanallarni ajratish uchun plagin +Name[uz@cyrillic]=Каналларни ажратиш учун плагин +Name[zh_CN]=独立通道插件 +Name[zh_TW]=分離色頻外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkseparatechannels +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/separate_channels/dlg_separate.cc b/chalk/plugins/viewplugins/separate_channels/dlg_separate.cc new file mode 100644 index 00000000..e6124046 --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/dlg_separate.cc @@ -0,0 +1,110 @@ +/* + * dlg_separate.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_separate.h" +#include "wdg_separations.h" + +DlgSeparate::DlgSeparate( const TQString & imageCS, + const TQString & layerCS, + TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Separate Image"), Ok | Cancel, Ok), + m_imageCS(imageCS), + m_layerCS(layerCS) +{ + m_page = new WdgSeparations(this, "separate_image"); + Q_CHECK_PTR(m_page); + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + m_page->lblColormodel->setText(layerCS); + m_page->grpOutput->hide(); + connect(m_page->grpSource, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(slotSetColorSpaceLabel(int))); + connect(m_page->chkColors, TQT_SIGNAL(toggled(bool)), m_page->chkDownscale, TQT_SLOT(setDisabled(bool))); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); +} + +DlgSeparate::~DlgSeparate() +{ + delete m_page; +} + + + +enumSepAlphaOptions DlgSeparate::getAlphaOptions() +{ + return (enumSepAlphaOptions)m_page->grpAlpha->selectedId(); +} + +enumSepSource DlgSeparate::getSource() +{ + return (enumSepSource)m_page->grpSource->selectedId(); +} + +enumSepOutput DlgSeparate::getOutput() +{ + return (enumSepOutput)m_page->grpOutput->selectedId(); +} + + +bool DlgSeparate::getDownscale() +{ + return m_page->chkDownscale->isChecked(); +} + +bool DlgSeparate::getToColor() +{ + return m_page->chkColors->isChecked(); +} + +// SLOTS + +void DlgSeparate::okClicked() +{ + accept(); +} + +void DlgSeparate::slotSetColorSpaceLabel(int buttonid) +{ + if (buttonid == 0) { + m_page->lblColormodel->setText(m_layerCS); + } + else { + m_page->lblColormodel->setText(m_imageCS); + } +} +void DlgSeparate::enableDownscale(bool enable) { + m_page->chkDownscale->setEnabled(enable); +} + +#include "dlg_separate.moc" diff --git a/chalk/plugins/viewplugins/separate_channels/dlg_separate.h b/chalk/plugins/viewplugins/separate_channels/dlg_separate.h new file mode 100644 index 00000000..d3536dda --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/dlg_separate.h @@ -0,0 +1,68 @@ +/* + * dlg_imagesize.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_SEPARATE +#define DLG_SEPARATE + +#include +#include + +class WdgSeparations; + +/** + * This dialog allows the user to configure the decomposition of an image + * into layers: one layer for each color channel. + */ +class DlgSeparate: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgSeparate(const TQString & imageCS, const TQString & layerCS, TQWidget * tqparent = 0, + const char* name = 0); + ~DlgSeparate(); + +public: + + enumSepAlphaOptions getAlphaOptions(); + enumSepSource getSource(); + enumSepOutput getOutput(); + + bool getDownscale(); + void enableDownscale(bool enable); + + bool getToColor(); + + +private slots: + + void slotSetColorSpaceLabel(int buttonid); + void okClicked(); + +private: + + WdgSeparations * m_page; + TQString m_imageCS; + TQString m_layerCS; + +}; + +#endif // DLG_SEPARATE diff --git a/chalk/plugins/viewplugins/separate_channels/imageseparate.rc b/chalk/plugins/viewplugins/separate_channels/imageseparate.rc new file mode 100644 index 00000000..b0518510 --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/imageseparate.rc @@ -0,0 +1,9 @@ + + + + Image + + + + + diff --git a/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.cc b/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.cc new file mode 100644 index 00000000..3315177c --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.cc @@ -0,0 +1,301 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Michael Thaler + * + * ported from Gimp, Copyright (C) 1997 Eiichi Takamori + * original pixelize.c for GIMP 0.54 by Tracy Scott + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include +#include +#include "kis_meta_registry.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_channel_separator.h" + +KisChannelSeparator::KisChannelSeparator(KisView * view) + : m_view(view) +{ +} + +void KisChannelSeparator::separate(KisProgressDisplayInterface * progress, enumSepAlphaOptions alphaOps, enumSepSource sourceOps, enumSepOutput outputOps, bool downscale, bool toColor) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisLayerSP layer = image->activeLayer(); + if (!layer) return; + + KisPaintDeviceSP src = image->activeDevice(); + if (!src) return; + + m_cancelRequested = false; + if ( progress ) + progress->setSubject(this, true, true); + emit notifyProgressStage(i18n("Separating image..."), 0); + + KisColorSpace * dstCs = 0; + + TQ_UINT32 numberOfChannels = src->nChannels(); + KisColorSpace * srcCs = src->colorSpace(); + TQValueVector channels = srcCs->channels(); + + // Use the flattened image, if required + switch(sourceOps) { + + case(ALL_LAYERS): + src = image->mergedImage(); + break; + default: + break; + } + + vKisPaintDeviceSP layers; + + TQValueVector::const_iterator begin = channels.begin(); + TQValueVector::const_iterator end = channels.end(); + + + TQRect rect = src->exactBounds(); + + int i = 0; + TQ_UINT32 channelIndex = 0; + for (TQValueVector::const_iterator it = begin; it != end; ++it, ++channelIndex) + { + + KisChannelInfo * ch = (*it); + + if (ch->channelType() == KisChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { + continue; + } + + TQ_INT32 channelSize = ch->size(); + TQ_INT32 channelPos = ch->pos(); + TQ_INT32 destSize = 1; + + KisPaintDeviceSP dev; + if (toColor) { + // We don't downscale if we separate to color channels + dev = new KisPaintDevice(srcCs, "color separations"); + } + else { + if (channelSize == 1 || downscale) { + dev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("GRAYA",""),"" ), "8 bit grayscale sep"); + } + else { + dev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("GRAYA16",""),"" ), "16 bit grayscale sep"); + destSize = 2; + } + } + + dstCs = dev->colorSpace(); + + layers.push_back(dev); + + for (TQ_INT32 row = 0; row < rect.height(); ++row) { + + KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), rect.y() + row, rect.width(), false); + KisHLineIteratorPixel dstIt = dev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), true); + + while( ! srcIt.isDone() ) + { + if (srcIt.isSelected()) + { + if (toColor) { + dstCs->getSingleChannelPixel(dstIt.rawData(), srcIt.rawData(), channelIndex); + + if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { + //dstCs->setAlpha(dstIt.rawData(), srcIt.rawData()[srcAlphaPos], 1); + dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); + } + else { + dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); + } + } + else { + + // To grayscale + + // Decide wether we need downscaling + if (channelSize == 1 && destSize == 1) { + + // Both 8-bit channels + dstIt.rawData()[0] = srcIt.rawData()[channelPos]; + + if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { + dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); + } + else { + dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); + } + } + else if (channelSize == 2 && destSize == 2) { + + // Both 16-bit + dstIt.rawData()[0] = srcIt.rawData()[channelPos]; + dstIt.rawData()[1] = srcIt.rawData()[channelPos + 1]; + + if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { + dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); + } + else { + dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); + } + } + else if (channelSize != 1 && destSize == 1) { + // Downscale + memset(dstIt.rawData(), srcCs->scaleToU8(srcIt.rawData(), channelPos), 1); + + // XXX: Do alpha + dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); + } + else if (channelSize != 2 && destSize == 2) { + // Upscale + dstIt.rawData()[0] = srcCs->scaleToU8(srcIt.rawData(), channelPos); + + // XXX: Do alpha + dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); + + } + } + } + ++dstIt; + ++srcIt; + } + } + ++i; + + emit notifyProgress((i * 100) / numberOfChannels); + if (m_cancelRequested) { + break; + } + } + + vKisPaintDeviceSP_it deviceIt = layers.begin(); + + emit notifyProgressDone(); + + if (!m_cancelRequested) { + + KisUndoAdapter * undo = 0; + if ((undo = image->undoAdapter()) && undo->undo()) { + undo->beginMacro(i18n("Separate Image")); + } + + // Flatten the image if required + switch(sourceOps) { + case(ALL_LAYERS): + image->flatten(); + break; + default: + break; + } + + for (TQValueVector::const_iterator it = begin; it != end; ++it) + { + + KisChannelInfo * ch = (*it); + + if (ch->channelType() == KisChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { + // Don't make an separate separation of the alpha channel if the user didn't ask for it. + continue; + } + + if (outputOps == TO_LAYERS) { + KisPaintLayerSP l = new KisPaintLayer( image, ch->name(), OPACITY_OPAQUE, *deviceIt); + image->addLayer( dynamic_cast(l.data()), image->rootLayer(), 0); + } + else { + TQStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-chalk", KoFilterManager::Export); + TQString mimelist = listMimeFilter.join(" "); + + KFileDialog fd (TQString(), mimelist, m_view, "Export Layer", true); + fd.setCaption(i18n("Export Layer") + "(" + ch->name() + ")"); + fd.setMimeFilter(listMimeFilter); + fd.setOperationMode(KFileDialog::Saving); + fd.setURL(KURL(ch->name())); + if (!fd.exec()) return; + + KURL url = fd.selectedURL(); + TQString mimefilter = fd.currentMimeFilter(); + + if (url.isEmpty()) + return; + + KisPaintLayerSP l = new KisPaintLayer( image, ch->name(), OPACITY_OPAQUE, *deviceIt); + TQRect r = l->exactBounds(); + + KisDoc d; + d.prepareForImport(); + + KisImageSP dst = new KisImage(d.undoAdapter(), r.width(), r.height(), (*deviceIt)->colorSpace(), l->name()); + d.setCurrentImage( dst ); + dst->addLayer(l->clone(), dst->rootLayer(), 0); + + d.setOutputMimeType(mimefilter.latin1()); + d.exp0rt(url); + + } + + ++deviceIt; + } + + if (undo && undo->undo()) { + undo->endMacro(); + } + + m_view->canvasSubject()->document()->setModified(true); + } +} + + + + +#include "kis_channel_separator.moc" diff --git a/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.h b/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.h new file mode 100644 index 00000000..d8bf777e --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/kis_channel_separator.h @@ -0,0 +1,70 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_CHANNEL_SEPARATOR_H_ +#define _KIS_CHANNEL_SEPARATOR_H_ + +#include + +class KisView; +class KisProgressDisplayInterface; + + +enum enumSepAlphaOptions { + COPY_ALPHA_TO_SEPARATIONS = 0, + DISCARD_ALPHA = 1, + CREATE_ALPHA_SEPARATION = 2 +}; + + +enum enumSepSource { + CURRENT_LAYER = 0, + ALL_LAYERS = 1, + VISIBLE_LAYERS = 2 +}; + +enum enumSepOutput { + TO_LAYERS = 0, + TO_IMAGES = 1 +}; + +class KisChannelSeparator : public KisProgressSubject { + + Q_OBJECT + TQ_OBJECT + +public: + + KisChannelSeparator(KisView * view); + virtual ~KisChannelSeparator() {}; + + void separate(KisProgressDisplayInterface * progress, enumSepAlphaOptions alphaOps, enumSepSource sourceOps, enumSepOutput outputOps, bool downscale, bool toColor); + +public: // Implement KisProgressSubject + virtual void cancel() { m_cancelRequested = true; } + + +private: + KisView * m_view; + bool m_cancelRequested; + +}; + +#endif diff --git a/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc b/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc new file mode 100644 index 00000000..64a83db5 --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.cc @@ -0,0 +1,96 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_separate_channels_plugin.h" +#include "kis_channel_separator.h" +#include "dlg_separate.h" + +K_EXPORT_COMPONENT_FACTORY( chalkseparatechannels, KGenericFactory( "chalk" ) ) + +KisSeparateChannelsPlugin::KisSeparateChannelsPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) { + setInstance(KGenericFactory::instance()); + setXMLFile(locate("data","chalkplugins/imageseparate.rc"), true); + m_view = (KisView*) tqparent; + (void) new KAction(i18n("Separate Image..."), 0, 0, this, TQT_SLOT(slotSeparate()), actionCollection(), "separate"); + } +} + +KisSeparateChannelsPlugin::~KisSeparateChannelsPlugin() +{ +} + +void KisSeparateChannelsPlugin::slotSeparate() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisLayerSP l = image->activeLayer(); + if (!l) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + DlgSeparate * dlgSeparate = new DlgSeparate(dev->colorSpace()->id().name(), + image->colorSpace()->id().name(), m_view, "Separate"); + Q_CHECK_PTR(dlgSeparate); + + dlgSeparate->setCaption(i18n("Separate Image")); + + // If we're 8-bits, disable the downscale option + if (dev->pixelSize() == dev->nChannels()) { + dlgSeparate->enableDownscale(false); + } + + if (dlgSeparate->exec() == TQDialog::Accepted) { + + KisChannelSeparator separator(m_view); + separator.separate(m_view->canvasSubject()->progressDisplay(), + dlgSeparate->getAlphaOptions(), + dlgSeparate->getSource(), + dlgSeparate->getOutput(), + dlgSeparate->getDownscale(), + dlgSeparate->getToColor()); + + } + + delete dlgSeparate; + +} + +#include "kis_separate_channels_plugin.moc" diff --git a/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h b/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h new file mode 100644 index 00000000..ce3aa731 --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/kis_separate_channels_plugin.h @@ -0,0 +1,46 @@ +/* + * This file is part of Chalk + * + * Copyright (c) Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_SEPARATE_CHANNELS_PLUGIN_H_ +#define _KIS_SEPARATE_CHANNELS_PLUGIN_H_ + +#include + +class KisView; + + + +class KisSeparateChannelsPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + KisSeparateChannelsPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~KisSeparateChannelsPlugin(); + +private slots: + + void slotSeparate(); + +private: + + KisView * m_view; +}; + +#endif diff --git a/chalk/plugins/viewplugins/separate_channels/wdg_separations.ui b/chalk/plugins/viewplugins/separate_channels/wdg_separations.ui new file mode 100644 index 00000000..0593258b --- /dev/null +++ b/chalk/plugins/viewplugins/separate_channels/wdg_separations.ui @@ -0,0 +1,182 @@ + +WdgSeparations + + + WdgSeparations + + + + 0 + 0 + 570 + 350 + + + + + unnamed + + + + chkColors + + + Output to color, not grayscale + + + + + chkDownscale + + + Downscale to 8-bit before separating + + + + + grpAlpha + + + Alpha Options + + + + unnamed + + + + radioCopyAlpha + + + Copy alpha channel to each separated channel as an alpha channel + + + + + radioDiscardAlpha + + + Discard alpha channel + + + true + + + + + radioSeparateAlpha + + + Create separate separation from alpha channel + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + grpSource + + + Source + + + + unnamed + + + + radioCurrentLayer + + + Current layer + + + true + + + + + radioAllLayers + + + Flatten all layers before separation + + + + + + + grpOutput + + + Output + + + + unnamed + + + + radioLayers + + + To layers + + + true + + + + + radioImages + + + To images + + + + + + + lblColormodel + + + + + + + + textLabel1 + + + Current color model: + + + + + + radioCurrentLayer + radioLayers + radioDiscardAlpha + chkDownscale + chkColors + + + diff --git a/chalk/plugins/viewplugins/shearimage/Makefile.am b/chalk/plugins/viewplugins/shearimage/Makefile.am new file mode 100644 index 00000000..5f8efe55 --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/Makefile.am @@ -0,0 +1,25 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = shearimage.rc + +EXTRA_DIST = $(chalkrc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkshearimage.la + +kde_services_DATA = chalkshearimage.desktop + +chalkshearimage_la_SOURCES = wdg_shearimage.ui shearimage.cc dlg_shearimage.cc +noinst_HEADERS = wdg_shearimage.h dlg_shearimage.h shearimage.h + +chalkshearimage_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkshearimage_la_LIBADD = ../../../libchalkcommon.la + +chalkshearimage_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/shearimage/chalkshearimage.desktop b/chalk/plugins/viewplugins/shearimage/chalkshearimage.desktop new file mode 100644 index 00000000..6f3ac5ae --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/chalkshearimage.desktop @@ -0,0 +1,37 @@ +[Desktop Entry] +Name=Shear Image Plugin +Name[bg]=Приставка за отрязване на изображение +Name[ca]=Connector de tall d'imatge +Name[da]=Plugin for skævvrid billede +Name[de]="Bild scheren"-Modul +Name[el]=Πρόσθετο στρέβλωσης εικόνας +Name[es]=Complemento para cortar la imagen +Name[et]=Pildinihke plugin +Name[fa]=اشتراک وصلۀ تصویر +Name[fr]=Module de rognage d'images +Name[fy]=Ofbylding skeanlûke plugin +Name[gl]=Plugin de Inclinación da Imaxe +Name[hu]=Képnyíró modul +Name[is]=Klippa mynd íforrit +Name[it]=Plugin di distorsione delle immagini +Name[ja]=画像剪断変形プラグイン +Name[km]=កម្មវិធី​ជំនួយ​ដើម្បី​កាត់​រូបភាព +Name[nb]=Programtillegg for bildeskjæring +Name[nds]=Bildscheer-Moduul +Name[ne]=छवि प्लगइन अपूर्ण गर्नुहोस् +Name[nl]=Afbeelding schuintrekken +Name[pl]=Wtyczka obcinania obrazków +Name[pt]='Plugin' de Inclinação da Imagem +Name[pt_BR]=Plugin de Inclinação da Imagem +Name[ru]=Сдвиг +Name[sk]=Modul roztrhnutie obrázku +Name[sl]=Vstavek Ostriži sliko +Name[sr]=Прикључак за смицање слике +Name[sr@Latn]=Priključak za smicanje slike +Name[sv]=Insticksprogram för skjuva bild +Name[uk]=Втулок перекошення зображення +Name[zh_TW]=修剪圖片外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkshearimage +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/shearimage/dlg_shearimage.cc b/chalk/plugins/viewplugins/shearimage/dlg_shearimage.cc new file mode 100644 index 00000000..ff6dadde --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/dlg_shearimage.cc @@ -0,0 +1,96 @@ +/* + * dlg_shearimage.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include + +using namespace std; + +#include +#include +#include +#include + +#include +#include +#include + +#include "dlg_shearimage.h" +#include "wdg_shearimage.h" + + +DlgShearImage::DlgShearImage( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Shear Image"), Ok | Cancel, Ok) +{ + m_lock = false; + + m_page = new WdgShearImage(this, "shear_image"); + m_page->tqlayout()->setMargin(0); + Q_CHECK_PTR(m_page); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); + +} + +DlgShearImage::~DlgShearImage() +{ + delete m_page; +} + +void DlgShearImage::setAngleX(TQ_UINT32 angle) +{ + m_page->shearAngleX->setValue(angle); + m_oldAngle = angle; + +} + +void DlgShearImage::setAngleY(TQ_UINT32 angle) +{ + m_page->shearAngleY->setValue(angle); + m_oldAngle = angle; + +} + +TQ_INT32 DlgShearImage::angleX() +{ + return (TQ_INT32)tqRound(m_page->shearAngleX->value()); +} + +TQ_INT32 DlgShearImage::angleY() +{ + return (TQ_INT32)tqRound(m_page->shearAngleY->value()); +} + +// SLOTS + +void DlgShearImage::okClicked() +{ + accept(); +} + +#include "dlg_shearimage.moc" diff --git a/chalk/plugins/viewplugins/shearimage/dlg_shearimage.h b/chalk/plugins/viewplugins/shearimage/dlg_shearimage.h new file mode 100644 index 00000000..5c82abc7 --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/dlg_shearimage.h @@ -0,0 +1,55 @@ +/* + * dlg_shearimage.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_SHEARIMAGE +#define DLG_SHEARIMAGE + +#include + +class WdgShearImage; + +class DlgShearImage: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgShearImage(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgShearImage(); + + void setAngleX(TQ_UINT32 w); + void setAngleY(TQ_UINT32 w); + TQ_INT32 angleX(); + TQ_INT32 angleY(); + +private slots: + + void okClicked(); + +private: + + WdgShearImage * m_page; + double m_oldAngle; + bool m_lock; + +}; + +#endif // DLG_SHEARIMAGE diff --git a/chalk/plugins/viewplugins/shearimage/shearimage.cc b/chalk/plugins/viewplugins/shearimage/shearimage.cc new file mode 100644 index 00000000..4e7e61d6 --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/shearimage.cc @@ -0,0 +1,113 @@ +/* + * shearimage.cc -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "shearimage.h" +#include "dlg_shearimage.h" + +typedef KGenericFactory ShearImageFactory; +K_EXPORT_COMPONENT_FACTORY( chalkshearimage, ShearImageFactory( "chalk" ) ) + +// XXX: this plugin could also provide layer scaling/resizing +ShearImage::ShearImage(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + if ( tqparent->inherits("KisView") ) + { + setInstance(ShearImageFactory::instance()); + setXMLFile(locate("data","chalkplugins/shearimage.rc"), true); + + (void) new KAction(i18n("&Shear Image..."), 0, 0, this, TQT_SLOT(slotShearImage()), actionCollection(), "shearimage"); + (void) new KAction(i18n("&Shear Layer..."), 0, 0, this, TQT_SLOT(slotShearLayer()), actionCollection(), "shearlayer"); + + m_view = (KisView*) tqparent; + } +} + +ShearImage::~ShearImage() +{ + m_view = 0; +} + +void ShearImage::slotShearImage() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgShearImage * dlgShearImage = new DlgShearImage(m_view, "ShearImage"); + Q_CHECK_PTR(dlgShearImage); + + dlgShearImage->setCaption(i18n("Shear Image")); + + if (dlgShearImage->exec() == TQDialog::Accepted) { + TQ_INT32 angleX = dlgShearImage->angleX(); + TQ_INT32 angleY = dlgShearImage->angleY(); + m_view->shearCurrentImage(angleX, angleY); + } + delete dlgShearImage; +} + +void ShearImage::slotShearLayer() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (!image) return; + + DlgShearImage * dlgShearImage = new DlgShearImage(m_view, "ShearLayer"); + Q_CHECK_PTR(dlgShearImage); + + dlgShearImage->setCaption(i18n("Shear Layer")); + + if (dlgShearImage->exec() == TQDialog::Accepted) { + TQ_INT32 angleX = dlgShearImage->angleX(); + TQ_INT32 angleY = dlgShearImage->angleY(); + m_view->shearLayer(angleX, angleY); + + } + delete dlgShearImage; +} + +#include "shearimage.moc" diff --git a/chalk/plugins/viewplugins/shearimage/shearimage.h b/chalk/plugins/viewplugins/shearimage/shearimage.h new file mode 100644 index 00000000..c824fb51 --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/shearimage.h @@ -0,0 +1,47 @@ +/* + * shearimage.h -- Part of Chalk + * + * Copyright (c) 2004 Michael Thaler (michael.thaler@physik.tu-muenchen.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef SHEARIMAGE_H +#define SHEARIMAGE_H + +#include + +class KisView; + +class ShearImage : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + ShearImage(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~ShearImage(); + +private slots: + + void slotShearImage(); + void slotShearLayer(); + +private: + + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SHEARIMAGE_H diff --git a/chalk/plugins/viewplugins/shearimage/shearimage.rc b/chalk/plugins/viewplugins/shearimage/shearimage.rc new file mode 100644 index 00000000..8b6cbf1a --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/shearimage.rc @@ -0,0 +1,13 @@ + + + + &Image + + + + La&yer + + + + + diff --git a/chalk/plugins/viewplugins/shearimage/wdg_shearimage.ui b/chalk/plugins/viewplugins/shearimage/wdg_shearimage.ui new file mode 100644 index 00000000..d63b58f5 --- /dev/null +++ b/chalk/plugins/viewplugins/shearimage/wdg_shearimage.ui @@ -0,0 +1,102 @@ + +WdgShearImage + + + WdgShearImage + + + + 0 + 0 + 323 + 114 + + + + Shear Image + + + + unnamed + + + + grpPixelDimensions + + + &Shear Image + + + + unnamed + + + + shearAngleX + + + -45 + + + 45 + + + ° + + + + + lblShearAngelY + + + Shear angle Y: + + + + + shearAngleY + + + + 32767 + 100 + + + + -45 + + + 45 + + + ° + + + + + lblShearAngleX + + + Shear angle X: + + + intWidth + + + + + + + + + + shearAngleX + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/plugins/viewplugins/substrate/Makefile.am b/chalk/plugins/viewplugins/substrate/Makefile.am new file mode 100644 index 00000000..5331a04e --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/Makefile.am @@ -0,0 +1,26 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = substrate.rc + +EXTRA_DIST = $(chalkrc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalksubstrate.la + +chalksubstrate_la_SOURCES = substrate.cc dlg_substrate.cc wdgsubstrate.ui kis_repeating_substrate.cc +noinst_HEADERS = wdgsubstrate.h dlg_substrate.h kis_repeating_substrate.h substrate.h + +chalksubstrate_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalksubstrate_la_LIBADD = ../../../libchalkcommon.la + +kde_services_DATA = chalksubstrate.desktop + +METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/substrate/chalksubstrate.desktop b/chalk/plugins/viewplugins/substrate/chalksubstrate.desktop new file mode 100644 index 00000000..8d8a7f7b --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/chalksubstrate.desktop @@ -0,0 +1,35 @@ +[Desktop Entry] +Name=Substrate +Name[bg]=Основа +Name[ca]=Substrat +Name[da]=Substrat +Name[de]=Träger +Name[el]=Υπόστρωμα +Name[es]=Sustrato +Name[et]=Substraat +Name[fa]=زیربنا +Name[fy]=Substraat +Name[ga]=Foshraith +Name[gl]=Substrato +Name[hu]=Szubsztrát +Name[it]=Substrato +Name[ja]=下地 +Name[nb]=Substrat +Name[nds]=Wassboden +Name[ne]=जीवाधार +Name[nl]=Substraat +Name[pl]=Wycięcie +Name[pt]=Substrato +Name[pt_BR]=Substrato +Name[ru]=Подложка +Name[sk]=Substrát +Name[sl]=Substrat +Name[sr]=Супстрат +Name[sr@Latn]=Supstrat +Name[sv]=Substrat +Name[uk]=Підложка +Name[zh_TW]=基底 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalksubstrate +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/substrate/dlg_substrate.cc b/chalk/plugins/viewplugins/substrate/dlg_substrate.cc new file mode 100644 index 00000000..dcecce48 --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/dlg_substrate.cc @@ -0,0 +1,59 @@ +/* + * dlg_substrate.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "dlg_substrate.h" +#include "wdgsubstrate.h" + + +DlgSubstrate::DlgSubstrate( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_previewPix = TQPixmap(); + m_page = new WdgSubstrate(this, "substrate"); + Q_CHECK_PTR(m_page); + setCaption(i18n("Substrate")); + setMainWidget(m_page); + resize(m_page -> size()); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); +} + +DlgSubstrate::~DlgSubstrate() +{ + delete m_page; +} + +void DlgSubstrate::setPixmap(TQPixmap pix) +{ + m_previewPix = pix; + m_previewPix.detach(); +} + +void DlgSubstrate::okClicked() +{ + accept(); +} + +#include "dlg_substrate.moc" + diff --git a/chalk/plugins/viewplugins/substrate/dlg_substrate.h b/chalk/plugins/viewplugins/substrate/dlg_substrate.h new file mode 100644 index 00000000..82051ad3 --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/dlg_substrate.h @@ -0,0 +1,62 @@ +/* + * dlg_substrate.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_SUBSTRATE +#define DLG_SUBSTRATE + +#include + +#include + +#include "wdgsubstrate.h" + + +/** + * This dialog allows the user to modify a layer or a selection + * by adding more colour in a particular channel or lighten or + * darken an image. + */ +class DlgSubstrate: public KDialogBase { + + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgSubstrate(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgSubstrate(); + + /** + * Set the initial preview pixmap + */ + void setPixmap(TQPixmap pix); + +private slots: + + void okClicked(); + +private: + + WdgSubstrate * m_page; + TQPixmap m_previewPix; +}; + +#endif // DLG_SUBSTRATE diff --git a/chalk/plugins/viewplugins/substrate/kis_repeating_substrate.cc b/chalk/plugins/viewplugins/substrate/kis_repeating_substrate.cc new file mode 100644 index 00000000..e69de29b diff --git a/chalk/plugins/viewplugins/substrate/kis_repeating_substrate.h b/chalk/plugins/viewplugins/substrate/kis_repeating_substrate.h new file mode 100644 index 00000000..1a229dc1 --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/kis_repeating_substrate.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_SUBSTRATE_H +#define KIS_SUBSTRATE_H + +#include +#include + +class KisImage; + +/// All values are normalized to a range between 0 and 1. +/// XXX: Do we need more? +struct KisSubstratePixel { + float height; // absolute height of the current position + float smoothness; // determines how easily the painting tool "slips" over the surface + float absorbency; // determines how much wetness the substrate can absorb. XXX: How about speed of absorbing? + float r; //.Red component of reflectivity + float g; // Green component of reflectivity + float b; // Blue component of reflectivity + float transmittance; // Similar to alpha. XXX: Ask Leonardo about this. +}; + +/** + * This abstract class defines the properties of a substrate -- that is, the simulation + * of the paper or canvas for natural media. + * + * Subclass this interface to define a specific type of substrate: repeating, + * or full-size, with specific and cool ways of generating the surface, or + * maybe based on scans of real substrates. + */ +class KisSubstrate : public KShared { + +public: + + KisSubstrate(KisImage * /*img*/) : KShared() {}; + virtual ~KisSubstrate() {}; + + + /** + * Copy the pixel values in the specified rect into an array of Substrate. + * Make sure the array is big enough! + */ + virtual void getPixels(KisSubstratePixel * /*substrate*/, const TQRect & /*rc*/) = 0; + + /** + * Return a pointer to the substrate at the specified position. Note that + * you cannot do pointe arithmetic with this value: the position of the + * neighbouring pixels cannot be determined from this value + */ + virtual KisSubstratePixel * getPixel(uint x, uint y) = 0; + +}; + +#endif diff --git a/chalk/plugins/viewplugins/substrate/substrate.cc b/chalk/plugins/viewplugins/substrate/substrate.cc new file mode 100644 index 00000000..8aa4d32e --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/substrate.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "substrate.h" +#include "dlg_substrate.h" + +typedef KGenericFactory SubstrateFactory; +K_EXPORT_COMPONENT_FACTORY( chalksubstrate, SubstrateFactory( "chalk" ) ) + +SubstratePlugin::SubstratePlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) + { + setInstance(SubstrateFactory::instance()); + setXMLFile(locate("data","chalkplugins/substrate.rc"), true); + + (void) new KAction(i18n("&Substrate..."), 0, 0, this, TQT_SLOT(slotSubstrateActivated()), actionCollection(), "substrate"); + + m_view = (KisView*) tqparent; + } +} + +SubstratePlugin::~SubstratePlugin() +{ +} + +void SubstratePlugin::slotSubstrateActivated() +{ + DlgSubstrate * dlgSubstrate = new DlgSubstrate(m_view, "Substrate"); + Q_CHECK_PTR(dlgSubstrate); + if (dlgSubstrate -> exec() == TQDialog::Accepted) { + // Retrieve changes made by dialog + // Apply changes to layer (selection) + } + delete dlgSubstrate; +} + +#include "substrate.moc" + diff --git a/chalk/plugins/viewplugins/substrate/substrate.h b/chalk/plugins/viewplugins/substrate/substrate.h new file mode 100644 index 00000000..409a00f3 --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/substrate.h @@ -0,0 +1,45 @@ +/* + * substrate.h -- Part of Chalk + * + * Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef SUBSTATE_H +#define SUBSTATE_H + +#include + +class KisView; + +class SubstratePlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + SubstratePlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~SubstratePlugin(); + +private slots: + void slotSubstrateActivated(); + +private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // SUBSTATE_H diff --git a/chalk/plugins/viewplugins/substrate/substrate.rc b/chalk/plugins/viewplugins/substrate/substrate.rc new file mode 100644 index 00000000..cf8b8537 --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/substrate.rc @@ -0,0 +1,8 @@ + + + + Image + + + + diff --git a/chalk/plugins/viewplugins/substrate/wdgsubstrate.ui b/chalk/plugins/viewplugins/substrate/wdgsubstrate.ui new file mode 100644 index 00000000..be0713ed --- /dev/null +++ b/chalk/plugins/viewplugins/substrate/wdgsubstrate.ui @@ -0,0 +1,221 @@ + +WdgSubstrate + + + Form1 + + + + 0 + 0 + 478 + 358 + + + + + unnamed + + + + grpCustom + + + Custom Canvas Definition + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + + Custom + + + + cmbPredefinedCanvases + + + + + bnBackground + + + + + + + + textLabel1 + + + Save custom substrate as: + + + + + lblPredefined + + + &Pre-defined canvas types: + + + cmbPredefinedCanvases + + + + + lblColor + + + &Basic color: + + + bnBackground + + + + + lineEdit1 + + + + + + + tqlayout2 + + + + unnamed + + + + slAbsorbency + + + Horizontal + + + + + slFiber + + + Horizontal + + + + + textLabel9 + + + Grainy + + + + + lblSmoothness + + + &Smooth: + + + slSlippery + + + + + lblAbsorbency + + + &Water repellant: + + + slAbsorbency + + + + + slSlippery + + + Horizontal + + + + + lblHeight + + + &Flat: + + + slHeight + + + + + lblFiber + + + Fine &fiber: + + + slFiber + + + + + lblRough + + + Rough + + + + + slHeight + + + Horizontal + + + + + textLabel11 + + + Absorbent + + + + + textLabel10 + + + Coarse + + + + + + + + + + + + + kcolorbutton.h + + diff --git a/chalk/plugins/viewplugins/variations/Makefile.am b/chalk/plugins/viewplugins/variations/Makefile.am new file mode 100644 index 00000000..5a3fafc9 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/Makefile.am @@ -0,0 +1,26 @@ +chalkrcdir = $(kde_datadir)/chalkplugins +chalkrc_DATA = variations.rc + +EXTRA_DIST = $(chalkrc_DATA) + + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../chalkcolor/ \ + -I$(srcdir)/../../../ui \ + -I$/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkvariations.la + +chalkvariations_la_SOURCES = variations.cc dlg_variations.cc wdg_variations.ui +noinst_HEADERS = wdg_variations.h + +chalkvariations_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) chalkblurfilter_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) $(LIB_QT) -lkdecore -lkdeui -lkjs -lkdefx -lkio -lkparts -L../../../../chalk/chalkcolor/.libs -lchalkcolor -L../../../../chalk/core/.libs -lchalkimage \ + -L../../../../chalk/ui/.libs -lchalkui -L../../../../lib/kofficeui/.libs -lkofficeui +chalkvariations_la_LIBADD = ../../../libchalkcommon.la + +kde_services_DATA = chalkvariations.desktop + +chalkvariations_la_METASOURCES = AUTO diff --git a/chalk/plugins/viewplugins/variations/chalkvariations.desktop b/chalk/plugins/viewplugins/variations/chalkvariations.desktop new file mode 100644 index 00000000..32b873d1 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/chalkvariations.desktop @@ -0,0 +1,40 @@ +[Desktop Entry] +Name=Variations Plugin +Name[bg]=Приставка за вариации +Name[ca]=Connector de variacions +Name[da]=Plugin med variationer +Name[de]=Variationen-Modul +Name[el]=Πρόσθετο παραλλαγών +Name[eo]=Variaĵ-kromprogramo +Name[es]=Complemento para variaciones +Name[et]=Variatsioonide plugin +Name[fa]=وصلۀ تغییرات +Name[fr]=Module de variations +Name[fy]=Fariaasjeplugin +Name[gl]=Extensión de Variacións +Name[hu]=Variációk modul +Name[is]=Breytileika íforrit +Name[it]=Plugin delle variazioni +Name[ja]=バリエーションプラグイン +Name[km]=កម្មវិធី​ជំនួយ​ភាព​ប្រែប្រួល +Name[nb]=Programtillegg for variasjoner +Name[nds]=Varianten-Moduul +Name[ne]=भिन्नता प्लगइन +Name[nl]=Variatieplugin +Name[pl]=Wtyczka wariacji +Name[pt]='Plugin' de Variações +Name[pt_BR]=Plugin de Variações +Name[ru]=Вариации +Name[sk]=Modul variácie +Name[sl]=Vstavek Variacije +Name[sr]=Прикључак за варијације +Name[sr@Latn]=Priključak za varijacije +Name[sv]=Insticksprogram med variationer +Name[uk]=Варіації +Name[uz]=Variatsiya plagini +Name[uz@cyrillic]=Вариация плагини +Name[zh_TW]=變動外掛程式 +ServiceTypes=Chalk/ViewPlugin +Type=Service +X-KDE-Library=chalkvariations +X-Chalk-Version=2 diff --git a/chalk/plugins/viewplugins/variations/dlg_variations.cc b/chalk/plugins/viewplugins/variations/dlg_variations.cc new file mode 100644 index 00000000..13324623 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/dlg_variations.cc @@ -0,0 +1,58 @@ +/* + * dlg_variations.cc - part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "dlg_variations.h" +#include "wdg_variations.h" + + +DlgVariations::DlgVariations( TQWidget * tqparent, + const char * name) + : super (tqparent, name, true, i18n("Color Range"), Ok | Cancel, Ok) +{ + m_previewPix = TQPixmap(); + m_page = new WdgVariations(this, "variations"); + Q_CHECK_PTR(m_page); + setCaption(i18n("Variations")); + setMainWidget(m_page); + resize(m_page -> size()); + + connect(this, TQT_SIGNAL(okClicked()), + this, TQT_SLOT(okClicked())); +} + +DlgVariations::~DlgVariations() +{ + delete m_page; +} + +void DlgVariations::setPixmap(TQPixmap pix) +{ + m_previewPix = pix; + m_previewPix.detach(); +} + +void DlgVariations::okClicked() +{ + accept(); +} + +#include "dlg_variations.moc" diff --git a/chalk/plugins/viewplugins/variations/dlg_variations.h b/chalk/plugins/viewplugins/variations/dlg_variations.h new file mode 100644 index 00000000..e160e6aa --- /dev/null +++ b/chalk/plugins/viewplugins/variations/dlg_variations.h @@ -0,0 +1,62 @@ +/* + * dlg_variations.h -- part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_VARIATIONS +#define DLG_VARIATIONS + +#include + +#include + +#include "wdg_variations.h" + + +/** + * This dialog allows the user to modify a layer or a selection + * by adding more colour in a particular channel or lighten or + * darken an image. + */ +class DlgVariations: public KDialogBase { + + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + + DlgVariations(TQWidget * tqparent = 0, + const char* name = 0); + ~DlgVariations(); + + /** + * Set the initial preview pixmap + */ + void setPixmap(TQPixmap pix); + +private slots: + + void okClicked(); + +private: + + WdgVariations * m_page; + TQPixmap m_previewPix; +}; + +#endif // DLG_VARIATIONS diff --git a/chalk/plugins/viewplugins/variations/variations.cc b/chalk/plugins/viewplugins/variations/variations.cc new file mode 100644 index 00000000..40e8fcf8 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/variations.cc @@ -0,0 +1,88 @@ +/* + * variation.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "variations.h" +#include "dlg_variations.h" + +typedef KGenericFactory VariationsFactory; +K_EXPORT_COMPONENT_FACTORY( chalkvariations, VariationsFactory( "chalk" ) ) + +Variations::Variations(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + + if ( tqparent->inherits("KisView") ) + { + setInstance(VariationsFactory::instance()); + setXMLFile(locate("data","chalkplugins/variations.rc"), true); + + (void) new KAction(i18n("&Variations..."), 0, 0, this, TQT_SLOT(slotVariationsActivated()), actionCollection(), "variations"); + + m_view = (KisView*) tqparent; + } +} + +Variations::~Variations() +{ +} + +void Variations::slotVariationsActivated() +{ + DlgVariations * dlgVariations = new DlgVariations(m_view, "Variations"); + Q_CHECK_PTR(dlgVariations); + // Render layer to a TQIMage -- keep in mind possibility of selection + + // Scale TQImage + + // Set original TQImage in dialog + + if (dlgVariations -> exec() == TQDialog::Accepted) { + // Retrieve changes made by dialog + // Apply changes to layer (selection) + } + delete dlgVariations; +} + +#include "variations.moc" + diff --git a/chalk/plugins/viewplugins/variations/variations.h b/chalk/plugins/viewplugins/variations/variations.h new file mode 100644 index 00000000..d8680ba7 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/variations.h @@ -0,0 +1,45 @@ +/* + * variation.h -- Part of Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef VARIATIONS_H +#define VARIATIONS_H + +#include + +class KisView; + +class Variations : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + Variations(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~Variations(); + +private slots: + void slotVariationsActivated(); + +private: + KisView * m_view; + KisPainter * m_painter; + +}; + +#endif // VARIATIONS_H diff --git a/chalk/plugins/viewplugins/variations/variations.rc b/chalk/plugins/viewplugins/variations/variations.rc new file mode 100644 index 00000000..d5db6590 --- /dev/null +++ b/chalk/plugins/viewplugins/variations/variations.rc @@ -0,0 +1,8 @@ + + + + Image + + + + diff --git a/chalk/plugins/viewplugins/variations/wdg_variations.ui b/chalk/plugins/viewplugins/variations/wdg_variations.ui new file mode 100644 index 00000000..191b84bb --- /dev/null +++ b/chalk/plugins/viewplugins/variations/wdg_variations.ui @@ -0,0 +1,897 @@ + +WdgVariations + + + WdgVariations + + + + 0 + 0 + 763 + 852 + + + + + 5 + 5 + 0 + 0 + + + + Variations + + + + framePreview + + + + 11 + 11 + 328 + 255 + + + + + 166 + 188 + 153 + + + + NoFrame + + + Plain + + + + unnamed + + + + lblOriginal + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + lblCurrentPick + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel4 + + + Current Pick + + + AlignCenter + + + + + textLabel3 + + + Original + + + AlignCenter + + + + + + + grpOptions + + + + 345 + 11 + 210 + 250 + + + + Options + + + + unnamed + + + + radioShadows + + + &Shadows + + + + + radioMidtones + + + &Midtones + + + true + + + + + radioHighlights + + + &Highlights + + + + + radioSaturation + + + &Saturation + + + + + chkClipping + + + Show &clipping + + + + + slider1 + + + Horizontal + + + + + lblFine + + + Fine + + + + + lblCoars + + + Coarse + + + + + + + tqlayout5 + + + + 570 + 10 + 174 + 819 + + + + + unnamed + + + + bnLoad + + + &Load... + + + + + bnSave + + + &Save As... + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 187 + + + + + + frameLight + + + + 1 + 0 + 0 + 0 + + + + + 32767 + 556 + + + + + 166 + 188 + 153 + + + + NoFrame + + + Plain + + + + unnamed + + + + lblLighter + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel12 + + + Lighter + + + AlignCenter + + + + + lblCurrentPick3 + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel13 + + + Current Pick + + + AlignCenter + + + + + lblDarker + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel14 + + + Darker + + + AlignCenter + + + + + + + + + frameColor + + + + 10 + 270 + 540 + 556 + + + + + 0 + 0 + 0 + 0 + + + + + 540 + 556 + + + + + 540 + 556 + + + + + 166 + 188 + 153 + + + + NoFrame + + + Plain + + + + lblMoreCyan + + + + 30 + 190 + 150 + 150 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel9 + + + + 390 + 350 + 110 + 20 + + + + More Red + + + AlignCenter + + + + + textLabel7 + + + + 50 + 350 + 120 + 20 + + + + More Cyan + + + AlignCenter + + + + + lblMoreBlue + + + + 110 + 380 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel5 + + + + 140 + 170 + 91 + 20 + + + + More Green + + + AlignCenter + + + + + lblMoreRed + + + + 370 + 190 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + lblMoreYellow + + + + 280 + 10 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + lblMoreMagenta + + + + 280 + 380 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel8 + + + + 210 + 350 + 128 + 20 + + + + Current Pick + + + AlignCenter + + + + + textLabel6 + + + + 310 + 170 + 93 + 20 + + + + More Yellow + + + AlignCenter + + + + + lblCurrentPick2 + + + + 200 + 190 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + Box + + + image0 + + + true + + + + + lblMoreGreen + + + + 110 + 10 + 150 + 150 + + + + + 0 + 0 + 0 + 0 + + + + + 150 + 150 + + + + + 150 + 150 + + + + image0 + + + true + + + + + textLabel11 + + + + 290 + 540 + 128 + 20 + + + + More Magenta + + + AlignCenter + + + + + textLabel10 + + + + 140 + 540 + 77 + 20 + + + + More Blue + + + AlignCenter + + + + + + + 789cccbd47b7eb38b2ef397f9fa2d6e5ecae5e7cf266d0035266cb6da7ed77af1ed07b2f1aa9bf7c83883f704c56d5cd7c75bb5f95d6c9ca5f8a22114044202200f0fccffffcdbe7d3fddffef37ffe8fea625c02eb6f966f947ffb4fbb4e92ebfff57fff9fffcffff88fe160f0b7fecf68389bfe6df41fffc7fff80febf96fd6df9401ff5fcff64232ffde36244f7a762ac953fefd56f29cf35cf2a267f3072ff9f733c906e7836493f35eb2c59fd74ab6797b1f243bfcfb46b2cb7fef0a1e72799c5af2907f7f94cce5732cc963fefd483297cf3a8387d43f992999ffde0c25f3dfb79a64de5f662099dfcfe924cf386f24f3fe4a44ff0fd17e5b327f9e772799dfcfb8078fa87d662499cbebbb9249de6fc9bcbd9d2f99dab795ccc7b31a48e6e3b71a4ae6e315ed25f3f1b04f82a93f0dc1636a9ff32999daf32599f757a54ae6fde17e48e6fae23892b97e78a2bd63ea1f438cef849e97e892f9f7652b99b76f3d91cce53763f0947e6f08fd9c1137b664de5e43c83fc7f53bf0022cf475499c8be719c4f113d824de5cc01671fd0eb6895dbaff50d8ab174ae6f2ad3ac9a47f63c924df4832d73f732a99f777f324998fb73993ccfb5f7f96ccc7df3a49e6e3514592b9bd3aa664ae1fd6bd646eaf9a2b98f4ddf52573fdb58e60d89f6d49e6df9b13c97c3c1d45326fbf634826ffb2934cfee40086fdf88164de7ff65232d9eb9b646e1fa607867e9bbe641a8f816092cf14f2423f4d070c7d8b9f25f3e7bbaf60e89fb791ccfb3b15df43ffe22f30f42f13f240ffea1b18fab716bf877ee967b043dc92bf1f0ea16fdd9af3a8f740bc3dbe64f2f70bc9bcbfcd2fc9bcbfbd4432f90b4730f5cff55e3297bfc9c0187f732899f4772099c6e35b321f7f6b0fc6f8daa6649aff7692f9f3724d32d7f7cb4932ef6ffb4e32e9b302c6f86723c9dcdefc50326f9ff32e99f7975382a10fd75c32d7e795906742fdd3bd49e6df67a2bdd09ff20886beb89164fefcd54932ef9ffa2c98fca72bda0b7d6a9f25f3feb0c4f842bf9a07b0d02fd13fd0afe2090cffd6c660e85b24ae87be05a40f63e1df8277c9bc7debab643e5e575732efef6e2799cb1bfcf89ecbdbed2573fd5cfd781e1fcf952d98fa3b91cf277f74cd24f3fe0f3ec08807ba8d64ae9fc54232e98f27993faff9f13df787ae680ff4d57995cce57103c95c7fac3bc97c7c7c5f308d67b8028bf9f72299cbd3dc49e6f2981f92797fd69664de5f7e2499dbb33b92ccdb6f2dc1d067772099fca72e99b7ff6a49a6f946f437f4b9bd48267934b0d0ef77c9bc7dad68df9cee9fee25f3fe69447fcc31df88f1843eaf6e92f9f3da89649a0fee25f3f1cb85be41ff0331bed07f5f8ca7f0a7d43f13a1df9d2a99f777f32899dfffea80111faeae92b93cee41f090f7effa0c463ce77f48a6f9ee51321fafeb4930f547bb01433fecb164fe7cff5b321f2f2f92ccfb3f93d793bd745b30f421ae2593bfd94be6fd1b2692b93cde4e32b79fda164ced8ddec1d017e74332f9dbb564de5e772899e299140c7dcaa692b93db8df92797fe61d18fe3117e303fd59b792e979b164de3f8918ff05f5cf46f40ff4c715e301fdb9bd80e13f57f792797fad4a30fce906bf17f3f51ae331c4fc19a13d43f89780e693a9f0a7ed028cebfd4e321fafe6198c7cc00b2473f9bc77c95cdf4a4ff0908fc75a5c8f78bfb52553fcf02999ebbfdf08a6f10e5ec1c2bfdc49a6f97c2b99e6ff27c9642f3fbee7fab416f2407fc299643efe912f99ec692099cbd3b492b9bc9ab8ff94c63711fd0bfdb2a792c93e2ac9140f689229df5125f3feed5660e85ffd2a99fce34432efdfee00867e5e14c9941f8ec0d0bfcc904cf9572a99b7a76e25f3fe73c760a1afaa646ebf99e85fe86f2ec61bfaea0b79e11f0ba12f2eda8bfb4b7d267b98897c64dd81a1cfeb503297afbd934cf1d45e30fc93f81ef363b896ccefbf3a4a26793dc1149fae7d30f247ff2a99ea1d3fbee7fed68b05a31eb1924cf9c2083ca5f6076bc9542fd948e6fa900e2473fdbbbc09463d630246be1a6692f9f84481643edef95532b73f5df01cfd7993ccdb7be92453beb5924cf3c14432efbf5cfc7e01fffa2999e6bfb1646e5f9b022ce2cba364de3e37114cfec132c0d047f74d32f9e37b30f26b2f05431f5763c9bc7f42c1d04797e6cf99d0c71be41fc21fa52a18fe24207d9f0bfd5a1d04d3f8570fe009d573dca3642e7fbb054f697ca237c1246f3a944cf53a5b32c5a72f60f81bd796ccaf4f2bc994af2d2593be6f2453bea682e7345eed4e32d5ff14c9bcbf2f57c95cff7dd15ef8a35097ccdb93cd25537e2bfa6b3124fffd055ec2bfcc24537c548045fe518331decda7647ebd2eda6ba37fc478c01f6d44ffb8d43e1ded17e3af3960cc97f5022cf481e257a6dd149fd96bf08cc6ffe64aa6f92604c35eec4032b7efab2799e2375b30e94b2aae5f50ff58aa642e6fe148a67ce1065e927fb80d2553bd2494cc9fdf3e49a6fc45c863c07e1dc97cfcd3a3606a5f7d05633e887682497faf4bb08df8e2030cfb2bc9de17a2ff4bf49f886762f4cf10f666bd80618f3e8dff92f5177f5e914be6ed2f36e005c91b5f24533cf22598ecafeec04be467ae64f28757b041bfaf5f040f29fe68c0268d9726da63917e14a2bdd0c7f424998f5f44fdb314fd91bf83a18f8105467fdc4660e86783e789fee94a30e215e3118c78a3a0f9dc60fd45fa34072f491fc329d8a0f685a964aae7dfc0265d5f2f05537f568f60d86bb091ccfbe36248e6fad988dfbba85f8e24533e48f66f88fe892b30fa67634ba6f97508467f6d1cb0a827435ed11f35fa6388f9c9a7f8c814f157fd065e92fe5f6e6083e42f5cb0897ac417d8227dca3fc036f55fb305431fba77c1747f3b02bba4df3ad9ab29e42f669229df46fb647fe460d8d3aa0243fecd2758d4bbefc0a21eb403a33f2a8a772c263f6fff35055ba827d1f85aa2bf2f1a58f4f70a8cfb252a18febdf1c0f02701f58f2dda7f5d48a6fe9b8071fff21d2cfc83603caf51c1b87fb106433f4b1a1f87fd17eebf1b17ec903efbd43e46b0f71a0c79cb2d58c4e72d18cf2f1bb078be0dc6f3339abf5cd11f8906c6f5de1a8cf846e3f6c1cbe724df068cf6548964ae3f1b130c7f9096608c7f7603a3bde90e8ce7bb2f60b4d77e00c39f075c9f98f639e47fa34832d7e7f84c2c9eb7ba80216ffb08c6f3cc042cd64f1a30e42f9760d88fe382d19e1ced19c11e42aebf0cf17cd306435ecb04a33d610e16f20b16f1470a16ed3981457cf9443c82bdae2660e19f79bc341c8be7d70e18cfd71ec022df8ac178feaa05e379d72bf108e3df70ff369cc8fe1d8345bc9c81d1fe60452cfaeb7a03c3be74ba7e2adbd382f1fbcb3b18e3910dc1689f4df24e657fd4603cafb2c168bffb0cc6f32b1ebf0c67e2fe01e9d34cdcef1283e12faa6f30ee67f860e1ffe660a1efdc7f0ee7e2fed58c58b6e70cc6ef8d002cd6173db0a83f2dc0d0b78edbf77021e5bd078bf6aec1f87d41fabd14f2155bb0f8fd108cdfeb2330da93de83f1fc8ac6d310f2ac1a309ed772ff3734c5fdb48d64ee0fb72e58d4e75ec0f87d7202a33f0d713df4a5237bb7e4782a60b11ee681d15eed112cee1782a1cf158f4f86b6b8bf6581c5fa2af5a733823f762d30eed7d2efdd11f2efcd1d18d76bdc5e468311f2a3c007e379f5082cea75f760e8fbfa8d782cf49dfba3d150fcbebc030b7bdc83a17f099faf472371ffe64c2ceed73460e883cefb6b3416f7ab4fc463e10f2c30e46b8927e279b94b2cee6f6cc1d087ec092cec4930c6f342f24f85fc46442caef75660e8cf85fb93d18cfd9ec783f1162ceaa37cfe19cdc5fd3ceabfb990d79d80d13eeb152cd64fe9fa85f8de7c05a33df9188cf66cbec0d0c7f50d0c7df3b8ff1f2d85bcce002ce227078ceb1d0f2cfca54e3c41fb6f74bd21ef5780f17c5d058bf53beeaf46e618ebd77a2299c77f5bba9f25c6b7f4c1c2bfbd80d19eeb07f104fda1933cb678de2603e37eba01c6ef6f57b0a8ff71ff3d72c6a8b7e8d47faee88fb507c6effd188cdf3bdc1ec67d38c739e2e3c5a63393e21723269e60fde4f22c99d677b93e307577285eb7b8fd8f27ecfe9cf50e0c7d8a79ff8ca7ec7bfefb6b412cc627db81c57e823730ead9eb1158d43fb8bce399b8fe7a0716eb5d7330c663c3fb733c67eda1fa484d2cc6c39a83a11fed193ca57a651282b13e16f3f96ebc9860bdc8d880c5fe810c2cf21bae8fe3e544d4cb23c93c5ed30a30ea071b170cff92d0f81813d443d71730eaed9a07c6f53eb7b7b1c9bee7fa117c49a6f5024b30c5b3760cb6b19ec9e3adb13331e8face93ccfbaf3883f13c23013ba8a72e05d3fd0d1b8c7c734df23b53d8df86facf9da03e7e1b80f1fc82f7e76430813e6d63e229fa3be5e333194e4cd40b52b04ded31b8fe4e4653110ff2fa0a73a736f28d9a788afd67fa180cfd6a1db0588fe3fe7f32610accfb77c3f59721f2c77c493cc5fe0aaf00e37eb731788afa4e059ed1f8361f60d48f6dde1f93d914ebc7460a46bd2fe4fd37994fc7940f6cbec1e89f98cf5f93a578def5013c433d86da6f4c51bf09b9bd4dcce982f2b39cebcbc49a22fff6b83e4dec29ea15d95932adb704c433acffebf43c776ad1fd039d7886f5d315bf3f5356f09acf77d3d1d4a5fa65734f3cc3fe035d134cf7372c30ec355b824dc413dc3fb0e9906574dcdf79c4e2f74501c6fa5b74104cdfb73c3e9d4ea6d6887f7fdb10b3e791bef1f9940ddf1ceb078fe005f5b7c5e7e3e96c86f58f8d0246fd3a76c1f311f9b377b043e31bf07c693a9fa1de19df816dec07f804bb584fa3fe5accc47a86069e517b82002cd6f775b043f39bc6e3dde9923d8eeb7332035bd47f3705ec60ff824d3cc7fecf84ebefd498c19e2faf609bfa2be6f9f0d49c2d51cff5c016e5fb2b176c8f78fb8b15d8a5fa99c9e7d7a93543fdab1b831dfafde6287844f5d10e8cf1af49bfac39c63bff024f499e98ee6fb3fb937f7d023bd4fed407bb435aafb124d37e2d5d30b53f03cf87d43eeb0d8cf5dd7803c67cb7e1f63d75587f707df1e9fece7c30a2fd5d7b30f6b3469f9269fdc792cce5594dc1587fba52ffb84c1edebecd5e326f7f41faebceb19f2cda8271bfa6133ca2e727e0118d4fb2164cfa9c2892f978af4c30eca1f1c19321d7bf2bff7e3660e34ff5e53bb043cfaf5dc174bf6c0076a97fdb929805acfcfb6d0446bdbee4ed9f0d857eddd660f89b6e2298da5f05c4ac3f687e6bc0c311ad87e07a263f9f0fda77f094da537f8067245fc5f569369a1963d29f2b31eb5fdabfe20ba6e7a777e0d188ff3eb9815906c29fa78227d04f053ca3f6b65c3f6663260fd553a93d2cfca4fec91bc95cfeea041e517f5fb8fece2662fcdd023c86ff33c1d31167cd06cf21cf5c308d679d8017d41f0df72fb3e9cc1ef3ebab14ec8c69bfc05432ed47d38885fe5d4cc9b4fe37028fc8fecb37c9649f25784cf6ebbf82e7f47dbc042fe87e05f5cf4ce8936b82e7f4fb36113ca6f17a002fe8f986b8de80fe8bef4dd28fc292cce52fa68269fc4d1effb0db2f49decd0c0c7fdc92fe2ce6131a3f6d2d98fcb7bf02cf49bf370330d68fea5a30fdde38831dfabea3fe59b2fea178b0009bd41e4f03db23aeff37713decb5f00593fc2df5a7c1ee47eb6f2330eadd17156c8ea87ff7609bfc45590b267f78d5c02e714bfa6ab2f1207ff80136c87ef22918f34dfe06c67cd186c48b018dafcee3cd99c5ee47faa48217647f99609bf4c7a0f1b2160392afa3f6da6cfc68bcd69279ff949f6093daef4ec1f067f5817831a4e76de8f70ebb9ece177c806d6abfb3235ec0dfba2bc9b4df9bc6d7ed1376ae5f5c3fe703263f6f4f520a1e53fc99102f66d4be8cf7cf7cc8e4e3d7673e784c7cdd82a7d4de5a03c3fe751e9f3265c2fca09be009d94fc2e397394b87c99f186bf08cfa4fe3fd3b9fb0e7717dacc792e97c0b8f5f58f8bb20d6793d613e5f2cc7b49fc5005bd49e35b56fb1c4fcecf1fe9e2fd9f7743dfdde582ca83f8267b049ed59f3f9686eb2eb69fd782699d62fa83de67244f67de1fa3eb79643b237ef2698f4ab9e8347d4feb0008fc99e1c6a8fbd70d05f4762261e6f9f46e3e730a6f3160618fdbbe6f9c6dc5d0ea8bd0df5bf6b88f89aebdfa25f00a5f8ff4e32edd749c0636aff66019ee17939780e7de2f92a73f643e8bb031e537b7c133c237bf5dec073ba7f44f71f1a225ea3e78f447f79dfe011ddcfe3f22dc68c29feff06e379ba0e9ed2ef0b1effb1747d44f3b1fd0d5ed2f78d0236c65cdf367c7e5fb0009858bf07cfd15f7bf082f4a3492473f96f19d8257b6df8f82e66cb05f55fbe223630ff6f797cbc98b3f67079527afe82319d17e1f6b7581a03fafdc693ccc7d7a0fb194b97da7bbb111b63f2af1bae9f0bd31810eb7cbd61612d1dd2bf94da671943c8cfe7af856d8c69be6e0563be594f2573fdd7b8bd2c1c763ded0f53c01392c7bb4ae6fdd3717d5db8c684fa4bbb134cdfa767f094e28180fba3e5c080fff15fc0b309f5ef9764d24ff13dfc43cae7a3e5d0807d6cf8782d47acbdfcfeed0b783ea1fad50ebca0ef6f3ed82079a32f30f2c5644f6c627f5acce7df655fd0e1e3930460a662dc3f1cc14beaaf40133ca178a8069bf47cdf90ccc74ff3c10e8de78dfa676c8afd09b564daff5982b1ff36a6f64c58ffd2fed40b7836a1fac504bc9c50fd6101c6fc97abc426e2b3700fc67911f3018cf33ac99d643e1edd198cf3176e07463da4fa0063bf8826be47bd53e7fe773965e345fded806db217eb1d8c78f29612b3f6923ea9603cbffb0663bf4949d7b38083c663b3022f68fceb7bb043f6118682a9ff8c02ec92bfcbe9fe7dba49f5c30d18fb636c9e2f2ce7ecf7144f2a6097e4bbe5c4ecf7140fcdc0b0b734018bfde03a784af3c53504cfb15f47dc0ffb0bbb8160ecbffc002fa95e58edc1d8bf1a4dc1163d2f36c1a8575495609c5f1a4aa6f3a134febd83e2ed2f376093faafa3e72fcc01f1f50b3c217ddd5660ac37ad63f00cfe5407cf69beef5230ea35c6026c60bfe55532e55b39d8a4eb6f73b0d8df20ee6f637fe04a32cdff03b043fd757b904cf9d9168c7ae7ed2299ce7b3692697fc898d8c2f99ddb128cf3b317f49f85fa6348f75f1a06d9afb604c37ff817b04dfa1c0ec10ee9bb4ef22ecd015d7fdd8047345eb5079e907e598e60d2d7b40363ffe3762598e2d5750e16e703d692297ffc128cf35768af897afb36108cfaee5c32d56b0f9269fe2e24f3f61731d880ff5125d37ed80558ac974c25d37ec09d64de7fe64132f73fea27d8a2f15732c9b4bea008a6f655a23fb1dfb28c24d3fe470d8c7ae1ed5132e95b2099cf8fa6e82fd4e3c32fc9b4bee3125b38ef7723ff641816d99b7d03dbe48fc22bd8a1f9f95a825d9adf4af28706eb1ede5eaf060fe97aaf133ca1fc5605237e6d8ee009e5bbd5198cf58b4efc1efb6fb71730f67bae66e025c5df8a09c6fecae020998fafd248a6f3ba909fd93b6f4f71025bb0af52329ddf9849e6cf533fc036e993924ba6f96726993f2fcec00ef57ff12e99e2c34a32ed7f0cc1f017d5bb649aef7cc9bc3f22f13c97fa4fc3f859388f5a6d25f3f69443c1d86f3b06e37c4be54ae6edd354c9bc7dd791643aefdc4aa67acf2b18e7f134f13dced325a4ef26d3379affc95f9826e2cb952a99c6f7153ca57835fd0463ff691108267fb579028b78c2001b34dee14532bf7f62814df88b4832d52f2ab085f59d0118eba3752899ecff2699eae307c9b43fb405431f9454329d2fbb97ccdb938cc02ee95b2adaebd2f8b590dfc279e448974ce3f12998e67b4d30ce074713c934ff403e0be72d2dba9fc5e607defeca014fc85f5413f094e2313b954cfea0114cfe467901233fd41792a99e6a49a6f527c198afd71bc9549fb9822dea8fba944cf9502799dad782b17e6d7592c9be6782495fea42321fdff8c7f77cbcb477b043fa1deb9229ff4904e37cc697641a7f0decd27828aa647abfc45032ade7b982495f13b25fcbc2fb0c944032d9cb93606abf5949a6f314cf60bc4fc00a24f3f6b79960d29f5a914cf11dfa53d87bf82999d6df303e16ceb755a4cf369b3fc8ff7660ec3f57de04933ff0f760ac5f665bc114df2b67c1a44f57156c507f5f1cc9b49ff3198cfdc69bab60aac7ac4f601be7fd22c1781fc95132ddaf95ccdbabd492b93e794f60e883229e87fd9ef959326fbf3a964cf9e00318fe5d9d4be6fda192fed916ce83a92f92a93dbe64ca8fd11f229e4c6f92f9f3938164ca1f4f82b1fe994ae6df871f60acf79a6bc9bc7f62f49785f3b1b75230d95775914cf30bfacfc279b22df90f47c413a621995f9f7be011f99b6d2b98e2136d021e4f683d63059e4cb83e7ae2fa19dd4f3b83e734df943118f581f22099cba33c8397549f592dc026d69b8f9279fb6f9f60e453d6156c537f5a63c9644f8160aa47695330fc8dee0aa6e7c5b964f28791648a6fe692297e580aa6fa6628da8bf8c3bc974cf9642118fa38954cf58f89649acf1692e93c27e9936361ffbdd149e6df2b9e609c1f7d96ccf549ad24d37974e887d0676721998f8fba924cf1fa9364b247713df687754f92e9fc672399ea45a23d581f35af92f9f7b9f81eef13885ac1181f4b32d5dfa10f16f6a3044bc974dee9158cfd3f892399fcbb2d993fff26fa6786fd3ba23f711ef146d7bbcc7e283f7b944ce7995ec0639aafab25784af671db0a9e52feb200cfc9fe320f2cec650f5e52beae7d49a6f319e2fe4bd457766083f453bf80b11fa878154cf6b2adc1585f37c4fde0af235530f251717fc45b9e90d7c17ca848a67add5530ad1f74a160aa8f76e279c8e7c34630f97f3b174cf2379a645abf247fe35a781f90ff2818f3c1443297571d49a67cfd4930cd87da1b58e8ff5630ece74b32cd1fa564aaef7982697dc87900633f73694ae6faa0be4aa6fd789a648aa724637fd25a32ed3f79924ceb3d3330f6f325ad64de1fd98364927f2598facbd42553fd3594ccafcf311e16cecbdf22c95c5e652a99de7f267e8ff3c9e1bb641a6f4732bf3efb008bfd812f92297eb32473794b31bec87fa30a2ccea3ee0493ff30f79269bfe23718f53e6b2099ea0377609c7f34be2453fc7b914cf91c1f2f63c0e6478a0fb6e019d58be207c1538aff8fe039e503712b99e6eb5c3297a750c04b1afff22618fb1922c1347fc73bc9b47f4630f2f9eda360b2efab2e98fcd1ea158cfd83452598f47f6b48e6cf8feec1a8b7a40bc1f05f3bc9bcffb61918f596f85d32d5e3447fbaa48ff94030f6ffdc24737bf267c416f6a7ac3f2453fe580bc67e99122cceeb9c24533d6b2299f4ad108cfce30773fd500cc9341f7792a9fe6b0ba6f5da6b2399ce372ec1d85f1d9d25f3efd59b60f89f3bc9bc3fd4a364f22f6f60ec97543792797fa8a960d8c74d32f9932918f61ed49269ff832d99e44d24f3f61a23c1d43f96fc1ef1fe1c8cf763448e645a3f16cfc3fe3d632899e2955832cdafd01f0be7d5ad4a32ad9f3792b9fcc64030ced3d792b93e9723c9b41feb02c6fe67732b99f68b7c4aa6faa3180f9c17f6499ffa032dc46bf098ec5d8f24d3fe08133ca1f530ed049e527eb7f50593ffb83c48a6fd570a7846f7d36b30e6fff25b32d5ab73c1145f28ef82299ed1e660d473b64f92a9def92698fcdd5a3cdf46fd24914cfbcd74c9b43e21e445fda611f7437cb1fe124cf65edcc02edd3f7225d3fb001e05d3fc5ebd108b7879bb93ccfbc72f05937e66a9605abf538e92493f56e021d99f6249a6fa5b2b98fc9f72914cedc3785a789f52f12698e42943c964ef17c9e40fe792697e1849e6f2648e60ac470660bc9f243b4aa6fd3fa1647ebda20826f9d24c32ef0ff55e32d5d7447f60fe2f9f25933f5a4aa6f8e62c18f9502299f40ffa61e1fd4b4a2899f6279492495ed19e29e297028cf795048d64dedef05530e29137c9e47fe4efb19f740cc6fed152134ced0f55c9fcfb488c17dedf74b9934cf64dfa3c326754ffab0cc1643f510ac67a78ba04633e77466083ecb309c026cdffa921998f476582b19fa7ba0aa6f93e5e0ba6fca6188051bf4b447bb1bf4aff00237ff60f92e9fd41f792e9bc7d2599e6f717c1d8cf247e8f7a5d160ba6fecf23c1b4bf21a0f86264e13c72f82499f2fd57c1f06727c954bfcec098df755b30d9ef7a2e98ecdf78974cf54cb447d47b3d5330e2cb0fc9b4df47dc0ffbd12ea9647a9fec1e2cde07f92e99f60b1c05239e3e4ba6f9df974cf9d74932ed9ffff17b2e5f70014f90ef288261df8664b25f5332bd6f0ae36be1fc4ef92499f22d4b3297ff593c0fefb7525dc9e4df3c30de5fa53a9229feb12553bc2ec66f46f2565f92c97f37609ca7b4df25d37e825a32adff89fba39eaafb92293fea24f3ebb7627cb13ebbfd944cfbadbf2453fe37154cf287a664d257d15e715e80fa6fcce673f2af117846f94076075e503d2188c1d88f9a9b82c91f2457c954cf38832df2279ba9647adfe70a8cfaecf62098e2ef6e2699ce27ed04533cb2d5c0d8efaa3c09a6fa46f12199ec5d3c0feba51dcd9f63517f5dbd0886bd3f4be6d76f7f30d59b62c164afde5432d5271f2453bdf0118c7abd77124ced4f1ac914afae2553bd5edc0ff3b9f32498ec6d1308a6f66c55c9341fdd83313f9ba23da8ef46a564dabf664aa6fd21f27b8a37e291643abfe249a6f9ce174cfb13a2028cf78b25b9647a1fd4a364f20fdf92c97f0c25d37a512599d607a03f22bf375ac994ffa49229ff78944cf94a2618fe48fe1ef59e4632bd3f270163becf2ac994bf8beb71fe4b0d2453bd27964cf552d13fa807da2f9269ff612499e627d13ed40f424330b55f13d763bfc6ed4332c50f37c1f0f78a64daff3d964cfb43c578637daf7a138cfd39429f719e6745fa30314df21f590ec6fedd32134cfbb10c5d30f98bcb8b64da2f3c01dbd87fbc174cf5c92001e37c4d25eee760fff1b7605a0fc8b792e9fc81b8bf43f149740263ff68fe2a989eb722fb9c8878201849a6f75f9e25d3f37cc974fee15532bdaf752898ecdd0904d37a475080512faf7e30e9432e18e7f56e82914f5482c91e0bf13ce4ff7e2698c627fb924cebcfe2f7d8ff1b3e80719eaa934cfaee3992491e717ff80f6f2699f22ff13dcecfa753c9e4bf0e92293f394aa6fd139660b2cfc8904cf9df4230e68b4a32add78bf1c0feda740ec6fbebcab3648a8f2792c95fd492299e1848a67ccd164cf25b2d58f887ab64f2379d64de3fea4132bd6f4efc7e8e7827944cfb7f1e2553bd4f134cfa6c799269ffb6781eea8df14432b57f2718ebe591645a2f8b05231f15bfc77e0f652699e229f13cbc7faa9a4ba6f361427fb03f5013fa8cf5e2c495ccbfd73dc924af180fec0fd33e24737922f17c9c6f6cc91ea626f69b5e13f082fccfe64d32d547bfc0385f565ec0886fba1cecd07a663394ccfb237b05633d627b144cf6779949a6f75fd682c93f06349f4dc5fa433d154cfaace982697d721b4aa6f3c11918f585742299fce5bd64aa67958229be5ac560ac27ac12c178bfd79b64da0ff1e37b7adf95fc3dcef70592a95ebb174cfe3a10cf47fda01c08c67e1b5f32bdcfb0134cfde12a92493ed17f585fc81f25d378dc49a6f8e253308d57249e3f417c7a904cfbcd7e30c5d382b11e982592797f24df82b1de954ba67aa6907f4af69baec138af6c8d24533d692f99ea733bc1e4ff3c0b2cde37be944cfe712499f2b1b964b2675732c52bd0670bfb45d54832e58fba64da0fb301e3fd8d4a2499d67f857ee0fc72f82d99be5f81713e3e194aa6fd49e27e588fb89ec1884fae13c9d4ffa27fb0bff0229e67537fae481f66e612fb2d776083ec3debc026eaa53618f18a3b0323fe580f04d3f5c98b64da7f63825df217852e99ce77907c33113f6c4dc134df6f1f24d37c9982b17ee04f05537b9a77c9148f88dfa3deb07a92ccfb7f73168cf365778229be48bf25537d19f28bf501e55e309d4fc94f92c97fcec158cf2b12c1e41fbb4fc9b43e3d104cf3f7f6158cf87ebb170cffe448267942c1e47fba05187f1f455049a6f5614330f4ff0d8cf3b88ab83fde3770d94ba6fafc12bca0f6a557c1c80f6dc9644fb964aa7f1492a99eb1934cf3f718bc44fd632199f2ab67c914bfd782518f16e389f78346a23dd8bfa58c25d379ba4030c95b5f2453fc5c824deacfec2299f6eb6c25d37ae74630e2b94632ad170bf9b13fb87b964cf514713df61bd4aa643a9f0f7bb31cecbf10fa28f6e3f89269bd83e2adb9399f52bd33032fa6fcfef9086cd07e8d95f81eeb1b97a964b2bf0dd8a2f958ff02dbb41fbbbb825d9a3f2eb5608a3fe28560caafb6141fcd45fdb11a83b11e180f05d37e5c5f114cfe669d8051ef6f3dc1a40fab108cf3d9e55a30ce3b1a60d4d78bab649a5fe5f7645f978364dededbb360f247452899ea616730d6e7d6779269fdfb4330f9bbd4148cf8e7058cf5b8e44932bdffe25e30f6835c24d3f9d1b964b27f713decdd16ed9b937fd2f792a99ed2082679a247b0380f33964cf3ab18af05c52f57d1df381f5baf2453bcff0046fcacfe60daaf6a4aa6f9ed4b30ce7fce25d3fedd1918f65f8af1c37e6d4f954cf9cf5a32c927fa17fbede254326faf22aec77c1bd582a9fd971d58ecef3524d3fe5ea1bfd84f97d1f82ec47a83be124cf5c8ca07dba4efbab8de9df2dffba44f0b51afeb5cc1747d32154cf61eecc043ccf74f9269ffd3098cf7495c1e25d3f9c14a30ad9f281f92693de2001ee3bcf34430e94f71114cfe259883f17ef6b52599de2f36144cfaa23c4aa6fafd188cfa79d60a267de832c1345f1786649a3f7e30cd97a2bdc86ff55232c54fb9648a6fc4f367e44fbaa1649a5f669269ffb7f87e4ef6915f2453beaf4ba6f9443c1feb655a2c99e47b944cfb532493ff6bef25d3f86ec1e2bc532318ef1712fa82f3cdc55e32b5ff1b0c7b5acd25d3df9fa04ba67ac25e32bd0f44b4cfc0f95ad13f787f759c08c6fb8f34c9141f6e2453fee80b46fe22fac7c2fbafef24933f17fa8efdf9590dc6fb8d4a8a079626ceb3d513b04bfa5a527cb664f645eb65067848f359fd8369bfec063cc27ae45532d5e31f25f3f15c3d83315f5d12c9544f740553fe1e6592a93f3dc158bfb88127145ffb9560b2873a96cce5d75f25537ce90ba6fa62f283a95e2ae49bd2f82b0f82c93ef385645a6f17ed453d39984aa6fac04c32fdfd5607c1a42ff14a30cdb7b74232e5a76f60e483fe5132cdafb960c4fb5f60c4aba52218ebaf7b30d69fb6e27b9c1f0ceec1d82f962b92c95f1d24537da7148cf93d05239f534f92e9bc8bb81fcefb1547c9544fabc1383fe68af1c67e92f807d3fe43213ff6af7662fcb19fdaa37cc410f5ebfc5e30cd1f6b07ecd2f85a347e06332faa8f1cc0d0efdb17784cf6e91a82499ff44ff004eb318f92693fdebd649adf5f05937efa67c1347fe91618e7bb6e7782112faa60ac8736a1601a8fac00a31ee98c05e37d155bc1347ff8aa647a1fc009bca0f1f21682c99f9ae2fe0b6acf360763fd62bb168cfcb0148cf7790879f1be9ad4954cf53cd17fd8bfe49f24533db1164cfdbd7d07e33cd346fc1efb17b789643a4f300423bf303760bcdfec42f669b27885ee47f38169e1bc977e124cf18d3706e3fd11fa163c22fdda9482a7b43e7805c3ff058660ba9f2b9e87f364d14632d5fb4792e9ef37fe02e33cd926028bf364efe039c9b712f747fdd9ad24d3f58231fee58b601affdb9b648a6f7230dedfe12d25d3fa760a467d3817f218145fd99f9269bda1924cefdf93df23fe7e009b349f98623c2c1a5ffb2298ee97d8609c3f32e6609c3f8b2cc9646f0bc914cf3f4aa6786607c6fe958ee20f8bcdafb43f81e20b165e93fe5c3e25d37e30f13dea3ddd093cc27ede2d18f5983804e3fd1d9a25989ed7168269ff61fa089e223f9e8167d47f862699d6f39e25d3fe68152ce2b70318e7c9ec67c9f4fe12138cf70f252918f1932b9e67507caf08f9f1be9938069b648fc15e308dbf32108cf7df88e7637f627c150cff7a0163ff42f000c6f99c88ec9b4d37a867d1fc62b3f1a3fd3c743f5b8c5ff102463cb2da82117fb4df9269bde12498ec510f25d3fef01c8cfcb8b425d37eaa5232bd5f2506235ed85a9269bda4154ce31d89f6cef17ea8037841f76b447b17d84fb6012fa9fd6b211fea49978b608a4f0c156c423f3bc9b49f3602c31e6f7bc1d0bf4a32c50fe44f6c1bfb3be22918e7e93a6287d907adb70ec063eacfd51b784afdb3d1c0c85f8a5232cd97afe0398ddf652d99fcf75130e5879d09c67c961482c97eae7bb049f74b3ac9349e86649a4f2692b93cb978be8df749b88229be509660eca7f39f24d3f922713dd6afaedf8269bcd690c7c6f9d755001e52bc5b533ceb5a63d29fab2199ce63edc1139a9f82083c25f9f5068cf745dd2cf082c6238d25d3fb1d378229bf503ec178dfce6a0946fce9bd0aa6fe5ccf04e37d0af27aca77ac1bd8a2e747df9229fe2dc136f98ffc4530e9f34a934cf9f10fa6e78be739387f48fde9daa8f7273c3e310716f67b260f9269ffde1318efefb91e24537dcd06e3fd79f6156ca0deb1904cf6a080d1fe6a2199e67b5f303d4fbb801dd8fb0a8cf8f9a611db78ff5dac8211df745f60d413133e7e2c389be17ccc183c27ff97459279ffac4b30de27947e0826f94c4532bd7f5d032fa9fd6d2a784af58e21d8a0f9e1aa48a6f53f5b30d58ffd6730de5f94ad89ed01d9ef86eb2b0b2eb0feac6fc04b92af7525d3fbcd8f6093fccde64532d9cb4d30c57fe1128cfd33eb77c1a41feb028cf7355a1f82e9f9ee1cec62ffea9b60f227892918e785f0bd8dfdafe9b3601a4f270463fda81980f17ea59adbbf3966fd41ef472dc14bf2075b1b6c60fdec4132d50f0bc9944f1cc126c693dad7bf5e9ff2075c6f63bd6b45fd33b1e6549fb8adc0580fdc7682c97fdd5ab035a5f74309c67961e50bec523c1de2f736eaf7f11c3ca4feaba8bfa6d664467fffdc080c7f53b492a97e6f08a6f686776013fab4964cf69982717ed224ff30b5b15fe81608c6fbd3ce60c48b2d8dd78cdd8ff2eb5430c5839b5730f2dff60086be74a4af33d6ff148fdd8391ff6a74bf390b30693de808b6917f64c436ce8fdf1230f6bfb7345e0b6b3a27fbe9c0f319bdaf8bfcc782a5f7e43f0f60cc4705f99f256b3fedf71c826d92ef3625b627349f68dcdf9b2c9f9b927f237d3458ffd1fc5b8327f007241f530f1aaf6b00467cad51ffb2f8674efd41fed5b6711ed0e4fac192cf39b57733022fe97ecf977feda32abf7d8c9f3e26ffa7827fa74fcf0afb9da5daaac3fe58ff6a0be8f3df21cb2f72b9ecf3bb5c0afe9b90afff77f7df5116d62247f5d81ffad87ddba87590cbfd87bfb3f1f9779605f20899fa6be8cfffb79fff167b71e9f393743ffadc1663f4e33aa96fbdedf8eccf3f18b9ffff65e16dfbc90e6009240d1fa9bf2b3bc9439ee0df4d1661eb3f64f9313a3f24f3e4e717cbfa7791e5379fecfefa91d758f05a8e94457a8a7f2b590235542335561335553335570b364ea55aa917b5669f86e951ab76ec7365b2de544dd5d99f15ff9dc67eb1fe379365a3aed827652391a85bf6b963d2ecd43dfbec982c07464726dd91fdfb4e3da9f74cce7bf5817d0c76e53ff4daff5b6479e43dfdc446e699fddb597d515fb94ebda9efea87faa906ec9a9449f8c524f85607ea501da96375a24ed5993a67d2fc1bc9c25a7a5637ec9f91ba607f02d8fd92c9f2cafe6929aafaa4284cc7be15431d2ba662b18fad380af31a8aa7f8ff3d92fcf7cc954aa0844aa4c44aa2a44aa6e44ccf5ca63d2dfbf4b6622a059b45064aa954ca45a9954669954eb92a3745537465a5acffe8b5ff37cab251b6ca9db253cf8aa2ec95036bf1513929f7ca83f2a83c29cfca5979515e9537e55df9503e952ff6dfbf9581325446ca589928d37f23596c65a6cc9505d3b393b26413cd83f261288661b044c0b00dc7700dcff08dc0088dc8888dc4488dccc88dc2288dcab8a87746fddf23c99f9345b58ca6ff23a390df6677a3353ae36adc0ccdd08d95b13636c6d6b83376c69efd391847e364dcb3cf897d8e8c1fd8e7d178329e8db3f162bc1a6fc6bbf1c1b4b0cf02685e757f9b797f9aadfe999ff8af6561527c1a5feccfb7313086c6c818315fd4186363624c8d194b9916c6b2370ad3304dd3326de3683aa68b8fc73ebe19b04f684666c465eaa53a9a31936a6726666a66666e16666956e6c5accdc66ccdcebc9a375333757365aecdcd2f33b1f2eb1cfcd764311a736bde3169becd9db9e7b21ccc8379344fe6bdf9603e9a4fe6b379365fcc57f3cd7c373fcc4ff38b7dbecd8139c467648ed967c23e63736aceccb9b960992a3334e3de322cd3b22cdb722cd7f22cdf0aacd08aacd84aacd4caacdc2aac12b9dc2f91c5ffaa2c56655dac4b3f2e566d0cad5a3d5b8dd55a9d75b56e9666e9d6ca5a5b1bd6d3f7ccd96ead3bd6522689b5b3f61677bfd6019f2393666a9dac7beb817d1ead27ebd93ab351da592fd6abf566bd5b1fd6274b98bf5884b0601e3d61b3e9c0faeea3cf1fd1d1bfa2634cb31a8bfe82f001fff74a89aca135b2c6d6c49a5a336b6e2d7acdb196cc74fa4a9ed18f85b5b34d48f2439643bf4c614e6ddb766cd77ab03ddbb7033bb42326cfc178b4633bb1533bb37336abda766197ea935dd997de92fecce74fc932307756cdc6646055aa67d77663b776675fed9badd9ba71303fec95bdb6376c249ef9676fed9924625414662bcc5e602bf766681bf6d6beb377f6de3eb0cfde3eda27fb9e8debde7eb01fed27fbd93eb319d7b35fec57656fbfb1d1b07efffcafc9f27cb16a66274cb78cc6f8b4df992c1ff6a7fd657fdb037bc8faf3c47a7864bbe6dc1edb137b6a2db924bb7e64fab161ff9cb1f6ce85fd9b91bdb0972c485698ddcc1dc3311d662c8eed384cd2bde33a9ee33b8113b218f5dd89545df17fcdecfe155954d7183ab113333bb1edda499cd4c9ec2f27778a5e0ea7640ff0ed3d6b55653d3b17361acf4cc706cc6216dc6ed8ff3b356b6be3b44ca6b9d3998173756e8e66f7938feeac9cb5b3b1b7ecf78eb365d21c8d9d73e7ec9cbd73708ecec9b9771e7ec9107ecb7a7eb6a03f234b2f09f3c683fe7ecea3f3e43c3b67e7c58cadb33db1ced6b33d6656cc3ece2b6b5dc5dab5c0a7f765ec63cfe9e374f8bc39efbd24f6d20e9d0f66fd47e7d3f9ea7fe954ce379366dffff5f6cec8e9ff5acca933b3eb9fe4f8576599ab9db3b05f9c25fba1e21a6ce2b08c23f34accd3bab6ebb8aebd702a73e17ab66b1f5d9ff9a8931b981fccdacfaca5f76ec86c2ae673e6d18ddcd84d98bde0e3746e6a7acc73b02b594fbcd93336be67377373b7704bb7722f6e6d176e63356e6b358ae67656f3afe8987a70afaaeddeecd6d55cdd5db96b3626cfeec6dd9a43f7ceddb97b3622dbde86dd837bb4576e6031ed331df7e4debb0feea3fbe43e1b817b765fdc472195fbeabeb9efec5707f7c3f9703fdd2ff7db1db84377c474f1c0fe7dec4edca93b73e7eec25daabd2f6091b8a7aa81f70fbdda9f91c533d8f46d79b6e778ae937b9e71b2179eef055ec8e4601fdbf0222ff612e6030eb6d1eb8c977a99977b85577a9577f16aaff15aaff3aedecdd33cdd5b796b36e7c7c6c9db785befce7a70471ebb0b1b5d9dfd3ff36fde8e59cec1db7b07efe89dbc7bb5f01e58467af31ebcc71f5af5bb1ff853b23c79cfded97bf15ebd37a730637362dbde3bd32f2e099368cbe6f229b39ae7de76bd0fefd3fbf2bebd8137f446ded89b78536fe6cdbd85b76441d7a3aff8866ffa966ffb8e71f45ddfb31e7c9ff9e8ad6df8811ff663e547ee8069e4831ffb899ffa198bd6be51bffd523c9189fe75599e2f7eee177ee957fec5af0d6603e6d46f7a49fc967d3aff6acead27ffd6cf77bee6ebfeca5ffb1b7febdff93b7fef1ffca37f62f966a2bef8f78aea3ff88ffe93ffec9ffd17ffd57ff3df8da3bdf03ffc4fff8bf9f485bd30c74ee57ffb037fe88f8cbd3ff627fed49ff9737fa1382c27fd6679f70f597ea97dfc99d8d25f066aa004060b112da65f6aff97c0f7fae5b7811d38fe3570cd0fe31478811f04411844411c24411a64411e14411954c14509839a7d1afb3d68838ee59af3e06a3f07b7400bf460c5fc48ef0d9560ddeb99ad30d906f6c27a0e36ecaedbe02ed8057ba50e0e4a191c8353708f0af54f35ab3f2d8b1d3c048fc153f01c9ccdd829ad73f012bcf6da15bc05ef81137c049fccf38c83afe03b1804c360148c8309fb330d66c19c49b47016c1325443253442d3188416fbc39c71e8865ee88741188651c86cc73a8709f3cb4698f29881c50f61d6fbfc300f8bb00cabf012d661e32fd421d3b41fb2387f94e5e77af6cf63d25f1db661175ec39b19875aa8b3bbafac636f27e13a5c33795e8c7b2f0d37e136bc0b77e13e3c84c7f014de870fe163f8143e8767f52d7c095fc337ab08dfc38ff033fc62d2982c22f6d97ff90e07e1301c8563e3184ed82cb40dd6e1943d63e6ee99fd7c9b53f6dfe7e1225c466aa428456444e68fcacdaf5a46b288ff862c28f1d4c8525fd5d7c88e1c7f19b9e673e41987c8376751c02375a61351c8e2f7cf88e524511c25511a65c62dca8347ab65f369cafe3c4645f01895aa1255d125aaa3266a5910d345d7e8166966678ccc75d4467ab48ad6d126da4677c629da452c82f0039ef778d68ecdb40bf6bc7d74888ed129ba77d2e8217aecefcdabed866af4d1eeaff6f2932c068fb043b77516ca2e7a8a9ea373f4629ea357f6a437e6750d16a79ca37773c2e6e8aad7eae823fa8cbea2ef68a0ce153f1a2aea8f2a2c7f9e1b8da27134096d2b8ca6d1cc8aa379b48896b11a2b56111b319bac629b85166eccbc3d9f73962c7f93b29843e33ef6e3200ea3fb388ae3f081f554cadbcafc5a1f25fe2c0b7ff68f7131d4f8f9e22cd4f73889d3388bf3b888cbb86277bcb0f87111d7d6dedd5b4f7c2639b959dcc46ddcc557ff515dfdb4f662cb3bbaca5875e25bacc5ba3f8b57f13adec4dbf82edec57ba5890fea323ec6a7f83e7e881fe327e3143fb3d866c9bc7380b86e689de373fc120ce2d76011bfc5effd88736b3055a38fdeff992c0ad34726cb6b9cb8adba8a3f4c23fe649db7641ec6b09ee3da665ed3fc0c33f6dcaff83b1ec4c378a456eaca7e51ee94713c862c3c1eecff9dfdb7493c55f57816cfe345bc4c54e3c17e4894c448ccc44aecc449dcc44bfc24484263efde9b3e8bd8d887e7a42c3b65f3d6d17c4da2244e92244db2a84872b1baf07765b1c886f8155b36bbb2fe65914fa2b8499194e69b71f26fd69e8dc9d9b998dff6c13ad953e39054c925a99326d6d5f7beea9db4ccca52f40d55c1d97d95bb385332bb4abae49adc12cd38252ceb4956c93ad924dbe42eba26bb641f1c9243724cd82c657a8ec272014364d94c9b4b2f4dee9387e4d158264f09b34ab146d2e722ff4c96e499f5e198e50e2bf6efe7e4257935dfad3e3f3f276f56ff8afa7df26ece8dfb709c7c249fc957f29d0c143d192a8b64c4abe3bdc7b4fbac8dc9c264b2df93713231de9269324be6c63159d8c76469c6a99a2aa9919aa995daa9e3dfa76eeaa5bef1603a2cbfe1b2f45910cb54b769601cd3308dd2384dd294cbc2d76dfa7cc4180aaff6932c96b0fe3453466e6b97cc8e9d344f8bb4343fd22a4c98f75a5afdfe8687f4621becee75daa46ddaa5d7d451f4a04b6fa996ea91c9fd3f978549c3644957e93adda4dbf42eddb15fedd3837d4c8fe9c9d8a7f7e943fa18fae953642b7a344c9fd373fa92bed2c8902c2ca7db4681719fbea5efe947fa997ef5feb197a56f7f9f5bfd2acb8f91e17a78607dbb5412ff2139a7dfce9069eb673ae86da5f7c54ee5fa696f8f553a4ac7e9249da6b3a4b50b65c3f42c5177fe23ef31361a7d0edad724d379ba4897999a29c63163f971b4efb3e3ccecb3e2649559999d39ea57ea0475e6665ee66781e9fa81a3a06ab0eb675096e1c5599845599c25ce23b3172e8b6af5b9d52fb2889a9add3f99d14efd4a064ccf952c553eb2cc74cc2fe61b077dcecbf477613d982316e37efaeb2ccf8aaccc2a61e7e45b98b34db24b56678d5dc763f53b6bb32ebb662c62f343d6df6ff6c2fd66de9c652c99661ce3a74ccf56d93adb306bd3b36d76e74efa5999c53363a603cf76bfcd8445369691edb23d93e5901db313d31d85db7491ddff268bf28b2ca67a973d3032b24743c99eb82ccc37f67d642ebcc4661146f69c9db397ec357bcbde852c1855577d4bdaec23fb8c9e93419a655fd97736c8d8e866a36cec8eb24936355da7cc66d9bcf7ebacbf17d93257734509552b377233b7723b77d8377d3d6dc29edad74398b7cedddccbfdec900779a828ff4496be024a7dabf8bd36f63edacc23c330ee982cbd97efed70c024619219f7799c27fe364ff32c3c30597eac4172bf95e779919779a556f925aff3266f8d63dee5d75eb7dc613f1ef9cdfdeeb3e25cb316f153aee7ab7cad9eed32dfe4dbfcced67396c1b09879c8729a4bafd9feb7719f29f93e3fe4c73cc88e4c9b1392c52afe812cbd0f559209d332db2ed5263f1926f32baed05ca6678eed5877ecbfbce6f7fe5dfe104cf347a3fd690d92d97afe943f671725cecff94bfe9abfe5ef7dd4937ff49909af719cddaf6cca73628dcd8871fe997fe5dff9404d9cc833f3613ecac7f1579ff1997dbc4c51b4cfee30c9a7f92cc9988e1d59a699f47e377c0bdffe200bb75792259fab7b854d65ea77be302c63cfd2fb1dd5bc481673943bf9b2500b8545f5b3e8814547b6dcabc0575793b1fa919f0ba33059b7d9ac557d2cbfe8f312ebaeb7e4c2e96b1785cb62ad53e1157e111461112923d52ee22229d22233f67d5ec365611ac6aecdd98cb92f8aa22caa3c2459faf6b398f5f597f9e5375958c6b34f6fcc62be8b0b7be4ce74a97227646177ae8ba6688b2e288a6b714bf25f7684303d53fc645268855eac8ab5710835e7b597a5d8b06cabaf6a7ef4d5be60cd243916dbe2aed815fbe2a0d8c5317b284ec57df1503c16cc3efa1a279764614e0b268f7128cec54bf15abcfd248b1aaa7f57164fcab22bde59fe742a3ed894b5efa33c5420875c9645f1597c15dfc5a01806398ba2c90bffd8555114a3625c4c8a692f4931ebd72c989ea8c5bc8f467b5b6677e03163b12cd5ecbb544287c540d7d250c2d22cadd22e9dd2354ebc22c2ae36c7f6a1f498cdc6a55f06e1ae64290dd731f7efc822d654c40cf3adb665c472b053191b2ecbef852cfb5e16f3cb3a9749999659996749745f163f564a7824669465599597b22e9b5e92b2cd34661b565f3b6371dc985bb4e10ffaaca7ecca6b79b3be4acd0a4a9d8d67c4a45995eb72536e992cbabdeda326368e5bebbecf64cabb7257ee7b591425cd7a6d28b552fb45961fd13ef773ea8dcd103b75c56439183e1bebc81c5b7d3d2cb0674e63cfcb63792aefcb87f2b17c6271ce86e527a398c594ca9d5d97cfe5b97c295fcbb7f29d79d12eef32adafee9bb3bebec13f337b5f7eb079bc2c3fcbaff2bb1c985d392c47e5b89c94d3c42d67e5bc5c944be3c45c7d156a7c4c0f665f1939564a655466d06746a7e0d4ef2ab2aadf62fedefb3059d8b7663f36c8d834bbaa2c26cbbd19b2deec97483a264b6b06c6a1b22bc79bc5e3a00996e5c4dc562e538ba86236cfa29545e5574115329fca66bb3ea736471513d73a313946fd9a4515dbdb2aa9d22aabf2aaa84a2bacaaea52d55553b5556745c1b1ba062b362e5ba7a355b57ebda3aff254b74aabf42467b21c83a36ad9f51f641151a5cf6571d488e9e246bd315559556b264bc4662c268b193269f64c96a37bf65a6fae2e2387e9eb5bb5a9b6d55db5abf6cab53a54c7ea54f575e17be6c717d681c5d5233e26a3fe2ebd3d570f4c96c7eaa97af646d5b97ab1aaead5dc556fd57bf5517d565ff128afabef5e966ac07ac2e5f5cf678bddb11a56a36a9ce4ce23c6c5339adf627e4bca6270efba60d1ee539ac5a36a524db98e912c51af654c965335f33a8f656bca3c34ccae9a87af9eaac6ac3f17d5f2a26637f7f5a25cb81fb615f38349d17f26b406c3ee7570377d7e75312fd6c5be38e1cbc5bd78179f8d897f092e6134b8449798c9d2b91fccbadefb159cde673059946a7449823e47f6d9c7fea32ca859283c96225912f549bdbfa4ec9e593fc6fdfa9c6df523d4af3d18a774e75d2fb9925e8ad0c8eefbbcfd525eaacbe5525f9a4b6b9c2edde56a6fcdd1e5165f98bd93244764f10773e445d68e5da55df4cbeab2b6c2cbe6b2bddc5d7655a7b697fde57039ba2fbd2c173633b1d8cde27fd5d684fde2fef27079e4b2a0adfd5add3f95256071f24d29c2faf27479eeb585d61bfb95a07ecd81e9d8a377f35545b3df7975c88ca6feec72bebc5c5ecdc4383afae58daf136d8235f75dbd7e8db92c7c3d96f5f196c5dd5333bebc5f3e2e9f97afcb777cbcf06a13d388e16578195dc66c869ddb6c66cd466c967db5ee7adbbf4c2ed3cb8ccba2f0bcc2fe5d16392f4096545373b5cdcf97f9657159f6eb90bdcdb2d8b85fd50accc08d8c83a7298f8a1fb4c620fca8d55a49b6b5519bc98ac9f9565bb56def1cc38bfaf99ecd8d336ef74cc7b8341e9b3146e6dcdef82cdeac9ddaadbddaaf83484b46e9ad0eeba88eeb84e5ca9fcce3796c6e9db008f4c9dd32590e755a67756e325990875bfd0aeaeff9cbcfb2287eaa2b6e5dd4a5f25557c68149c0bc0fb3dfa8978569716cc69eee2b6aa9cc422bfc8caa9a4590ec7f0d6b5beb7eb84347cdaf2c63af9cd73063f67faa22f6ebdeaff7d27875c746f9cbfc626d5cd6d7fa566bb55eafea35d36ca77c8af27a536fcdd8b9b23cdceb6318d6239bdec2eabb7a57efcb3d932515759e3fe695d8112074cc55efd44370523ae5b13e184cb3597e7f6fdbbc12cfda581f599b4ff57dfde0b6a1556d13b77eac9fea67e3549feb17a65b8bfab59f159cd728b02d1691ceeb37bfb1b7fe376fd994b220ca89acbdfb5abfd71ff56738a8bfeaef7a500fcba01e992ed3c27db17077aec3f29881cb324b63578feb493de5b2507ef20f7264f6a797a59ffb13f6ff0d9bfda7f5ac9ed70b9657b2fc8bc52e5b7b592f9d779bcdc98dda288de13f5a35f3ca1f8dd958c64363db47f6d9374e3f438693be6ed3fbb2c665ff34a2d0def09a9af1cb1ae0d074eb5be3357e1334a1f3d4444ddc244dcafae291e54977eeaec9ac2dfb158b429bbc299ab2a9b8bdd09ca8f42b763fcb42732397c5e4b364aa8cd2cc99c77a7369eaa6316377c3eefb7039352d0b8359d6e186c6aee99a6b738badd0b48a466b74fbc18c9b557aecc7c57c6fd64cdfc76c2c3efa5cbdd9345bebdcdcb9dbbe8283d53fac9c9b5ebfb3a4d935fbe6604d9a63736aee9b0726c363f3d43c3799bbeb6be64c2fe3e6dcbc34afcd9b948559c51f65a1d95ecaa2f1959bb5faa138cd7bf3c1a22ac7ff609e89d973bfa6686f9b4fe3e0dbcd57f31dbae167ad3483669828d60b7bde283359ae356bc66c961b46611f41369366dacc9ab971b296eeb6e1e3815566167d9b9ed3354b63efad5bb5555aa3355bcbe8ebd581396efb15c45d9f2b87ba71689dd66dbdd6ef63181e7719aadfaf09ff365752a5cfa4bdc2fdfa937a8bc76de03dc65d1b1afd4afdb658703fbbed6dba8d8c531bb7499b865ef5de666d9e9fdaa22ddbcad8370fed85595585fce4beaddba66ddbaebd5e5876dfded8bcf3ddd70ee4eabfefed5aaddf1de36baddeaeda755bb35f6dda6df0dede056f5ec89eb7734a63d7eedb437b6c4f52163f38fd41161bd97abff39945bc2c951e313ddbe5b9a2b7f7ed43fbc8b4f7686ffa9d05b5d53ef55adf326fdf9edb97f6d518861f4e5c44ed5bb269df59ccb3cf3b7bc9645ef5f949fbd17eb65fed773b6887eda865b3068b697aed123b19f67e906bf6b69db0acf8d44edb593b6751cb397875ed76d12e3bb59fdbeace38754a67746667c571922779af472c8e39fe4116e75759d84c99a94967770e93e6dab99d67192cd770d89cb063be56ef7c7b5b9f7d3753baa00bbba8da767197746997b1b0b8e8ca7e6dc8db75157bfea5abbbc6df756dd775d7eed6699ddeadfaac8e723b5ec95b326b687b8fe2fb4e65dce75db7ee36eeaedb76776c02d875fbe6397aef0eddb13b75f7dd43f7f8ab2cbfc563b40fdae2fbb87b59fabdb76ef7d43de7cfddb97be95e6bc738b9ae7de8ff1a4166c38eb3eddeba77964f9cba8feeb3fbeabe9d85fad80dba6137eac6d19d195b0b33f6b56ed24dbb5937ef16ddf2aa5e95ab71358d9dfbca7763f9bd1ce6d00ffa99fd6ad97bc7bada4cbe73b7bb322bb18ee1cadd5d5deffdea3109dfaffe35b886d7280fa302b66ffe1d1d13eb0b72bf196a7fdcef5de36b52b2d65d53ebe19ab119ef6c9dddcf7eb5f79ab3ff5a5ccb6bc5e29897ebe55a5bfeb5b9b6d7ee7acd27d7db55bb321d5533b30bdf8da69c5c57d7f57573dde6937efe655aa8f4750ce623a2be06c6f7638dd87c74ecfd38d515ade7de5aaa8171bcde5d77d7bdda3847b5edab2c5993353c07367f9c07f8afd7f89ca7ebe17a8cd953afa7eb3d3dddbf998b6641d1eef5e1fa787dba3e5fcfd797eb6bad3069deaeefd78febe7f5ebfa5d75d74139bc0eafa3eb987d26d7e975769d7b6bd60b8bcccccceb92dba2f5f327f2dd7d73c7fc1c27ebcc52c3a79b7263f955348c4c36f3b9aa6dbf33591cbebef31764b99937eb66df1cd6379ecb66877edf8bad140b2fb9b139d0b8f7b51b0b346f8152ddc25b748bd5db2db9a5b7ec96df8a68d025e15755df4a7377ab6e97f0e3c626c65b5bac6e9db1ef772df0fd16d6af1f5eafb0d86cc4246aee7236b3dcaeb7db4d4bc6d133cb2d44fefb87ddf3ffb52ce6e34dbfad6eeb86c5860d1b0d663515f3f8ecff6d8fc5eecc9fe593dbe6b6bdddd5a5fa62d7cae2b65386b7fdeda0d4ea58dd869f55773bde4eb7fbcbddede1f6787bba3ddfce51623f180fb71733643e7af24759983454afa4fbbfdede54f7f67efb48068a226ac97f7d7d3f2a6e9fb7afdbf76dc02b565f2cb35c58776c86d89a73162f6d6e43e3741bddc6b7c96d9abab759eadce6f1241ef77bf56f8bc80a5fa2eab6d4d4a8d394a85202f5ac199aa9599aadb1b16e5acdedade4e78fbbef3396c82759cc58f3345f0bb4508bf242d1d20ce3f287d3597fc25e1eb5584bb454cbfad981dd7b617e7a119385f624cdedad96f733a75668a5566917ad564325615ed0b65fe289b25322add15aadd3aedacdf84c1dd573979aa6e9da4a5b6b1b7ba16da99af0ebc8b03f2a8bb1ad7667dada9db653bba0b9bddbef2c7f37642dcfa1f8f22fc8926a7beda01db59376af3db008efce9cfa1f2c3bda71eb6451633568f92e43ed517bd29eb5b3f6a2bd46b935d2de8c85f61e4fb40f36269f2c216e94246ccb2767e999da97f6ad0d3436a6edeeefd98bf5dcee2c35f2b59136d6260a8bd955d72eed525db37111f562ef2fcbf2a84db59936d716da52578d7da8318f79673d9993b86e6fecb363518056b6bac26c79a71bbad92a9dab5bc64db77527327457c97596ee844e7fe622ce597e32d4033dd4233dd6133dedc7e0d74f98f5b2447e2f95bbd7333dcfebb2d20bf6fbfe0c84266b797c86ff2b3a16157aa957fa45aff5466ff5aedf11c3f2de39af8f322fa45ffb798faffbfaa6ebbe66817ed3355dd757fa5adfe85bfdcef850bff59dbe77c6d5413fe847fda4dfeb0ffaa3fe14bd07aece722db28dde4ef86e0bf3e78fe9e8e764adbfe8af4aa36ead86cdca34abf4f6eff075c43fbd8724c9f537fdbdb8ea1ffaa7fea57febcc07588affed6ed3ca56a3f7beea637afd3a561f4733895c33d687fa888dd0589fe8537da6cff585be5ca92b6565accc95e5eddd3c7ded778d38d5ca5e39b6e1eec90f0b0ff68b2cae7170dc95bbf2567e3c535f56415f310a4e2cdeea57df6a5a7bfb73b2048fab701505b355bc4a56e92a5be5ed78555807166b6efa5ccb3afe248bc9b28265dee5ceed8565b4b755b9aa5697555dcd568d3e5ab5b1c7f7c23129dcddaaeb76abab395e752c5bbbe3f66e626ef955166f7533e3b261f9d270a5b1f178e335567efeafaf2afd9571311f57fa6ab55a6bb362b8daacb6abbbcbc76ad75767d2a05f79b0b67d0ecf64796372ec983c0adfc570cff7819ef85efea3d8cf6bdcbbdf76e87ff8cd6abf3aac8ead1d7cb84edffa7e9e679aa6b63b6627bfcae2af4eab7b9643ad570fcdfbea919fce727f3a052c4f69fca971795a3dafceab176db67ad5ebd5dbea7df5b1fa8cbff26ef595f615a31fbbddf98749f7c177bc0f9d57f6795b7daf06d17e35147b2cfbbdbccd9339ee7739b58bd5a8d72e173b9358e3acdf65b1ceab717d67ec5693d574355bcd51c3b7708ec1fdf3314c92af16abe55a5d2b6b439badcdb5b5b6d7ceda5d7bc69e45cffb1f7bdefb489eaffb32097a7b62b3105fc7e3fba9f9beea7e36627e6318266b7f1dacc3c0091cbecb91452c6431bd17f85d967e7473dbd8d7efeb681dab77e20c2d9745f9b16be9cff8b1f03198af933c5d5bc1789daeb375be2ed6e5ba5a5fd6b5b5b437741601fbf7fbd5b30fbe57a25f6bb15a16fc34ceba757416dfb3e83e9ce9d77ecd807df6ebceefd6cc62bc50c8d2eeb411f366bfd90bd7d26374b7beadb53573e4b2fee5fed5793f628aba5eaf37ebedfa6ebd5befd787f5717d5adfaf1fd68feba790c5fdd69eef5ac1b8b04fbf9ef76a7e704b3e584bbedb9f5950bffba8f7e2eb7e97fcb1df83b63eaf5f02d736cc28effa73246c8e1feb193f73d2e7373edfafe4b23c69bb7e5dbf35cafa7dfdc1e617c8f2f7f78ffdf38ff3283f69566595d196e7f5e7fa6bfdbd1eac87eb11d335bea38c568b980e4db0afbf8fa6c6acc7cffc04c6b2dfadd7cbe90f7a7bea77569a43967505d5e0a69a713e6171d79d36d1f3f5b8f776eb49bfa3b61f93cb389f38de7aba9eade7eabdd8d32b674be7afc8f2d3d9621ecf798f6a11dcaf179774bdcc5f36ea46d9181bb37faead164ebf368979c230a77db5439cb4602336661ab91436d3dc39174ba1fd0a2caa7f6511e4ae0f0b36569fdfacc6cce59f8ce3c6c9271b77e36dfc4d607da94f56f35b9bfed2b8fc7eb6381a2a9ee2da55972acd26dc449b78936cd24db6c9f9aa0bcb6eac27ffdbf68bbc782effdf76ae6549552488eee733a6f615fdba7dbb6356a899203e5a6db51f3b4444f0c14b1489987f9faa8202a4bd37b457331113b9d010943a661645669d93b6d9e37b5a6207f5ce54d90a7b630ee6244ed8f3c2d4532060d9afca32ad349d280e4d481246103617866ae8b10a11c3b2b36c86248e1fe983506f36cb7bd7f59cde1344592e9dd23decc91c0e90c0115250a0014d680104cf80a691efb672cf7c667bc1191af13a6a6c8d2ed758790ea8a041fba8a546ca6681e23a2c67047dffd9b4a1130fb9e20cbad0833e2ce34747a706bc2c0e85fef98baee722bfd4f4404187dc51957668dcd0c2d0b660004318c12b8c61025378f3347fb13bb0acbe5df0f8ab3a31cdd0e01d3ee0136ee036e9c2ddb1ed7437f7e95459c13d7169c0bcfd003fe0117eb2bb700a4ff08c94def1b9eef5e9337dca1557dfc052a8ea8aefae6ed98c216b9d45ef4ffa485524aebeeaa181333471eeaa5edbb7f71bff47100423b4421517519a70a1686ff7106f632dbe471b97ebe0a027b3a4874ec8a276354cdffc603e255ca59dee228325a4b8c2354b719e8d29bbca113774bcb961e319c8f15c1f6327bd3884873ca043ee1bdcda7dce35430f7d0c30740718e10e636fed2f7ddd7f0cc2861b3aa1161991827b3cecfa8d66ec6112bce2115354f693204dfadb96d559cd6ccab25f967cd21655d61b3627a2d61336b0892d72a03dc20e53978ef868d8fa229f5faee75a7fe935c07eb745b764495b08ec7d0311d5f514356ca3bffd70224ff774bfb3f1822818bb5ad8461d3bd8c5de6e837df6fe0507fb088787258ef015c7d68bd0fa1a7cc79ef3f0a8623d21573237714a0f6bb636061dba66de58d0211dac1b76bfe293ef6039b59ad281736c393795d713791dceebf80ee712f96e3009ddd07544a5d179e13613e6e4967d435ca3ec245389a0cad56bfd58aad7bf7aee9fc122ff178e852391e3f3ba9c7d9399eff23a234758aeb7d96b869def6fe7fb0f468e60216ac18678a2378b9890bd31a42ee18c42f1d27b720dcf09969c1fb0909d7904e76ec356026184f0baafc89d66956e3da5fecbf6f6f369d67545d6b5c5d924df135a7ec542cb5e26e49a7cbfc201afa191da8093df3604f79408ae9ab0ad576031ca9ca3caca1635c83935653d22cfb448ce3bcf6adc752c32e62a9eb9443352aa19aaaae7e288acea1ab4729f2cb50e052bf5d4871cf952b02732ae47d9db635ea9689b453c57bc2062244752ad5f5e84c592fcc3e1ee4c949995795bc152fdbea830d827ffc84c20e9088f91d2fb395e4b665b520152c3422492ebf27dce3a1163b10a2cc60916c11710bad85b6ed69a7320cdc09db863ceee0a1533e20c1ccef6c814cd995eb334f9fc9ecf4b7ebda988b5c23b67b1108e04dff03d63da7fc32f8b9a5f4caeec2fc7c9c7e6f5bc5e154b795ce2e596e3679fca7dd222b624e3bc58134fe3a1e0bbcd199677fcb81c4b3d6a7ea7d6aeb0fb7e71ceb9a3f5738b7cbeda2ba7de3ba79caf57e52fff15fb1fcbbfd3fefcfbaf3ffe0193cc32fd + + + + diff --git a/chalk/sdk/Makefile.am b/chalk/sdk/Makefile.am new file mode 100644 index 00000000..0c7f4c18 --- /dev/null +++ b/chalk/sdk/Makefile.am @@ -0,0 +1,23 @@ +KDE_OPTIONS = nofinal + +INCLUDES = $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) \ + $(all_includes) + +noinst_LTLIBRARIES = libchalksdk.la +libchalksdk_la_SOURCES = kis_progress_subject.cc +libchalksdk_la_METASOURCES = AUTO + +include_HEADERS = \ + kis_annotation.h \ + kis_canvas_controller.h \ + kis_canvas_observer.h \ + kis_canvas_subject.h \ + kis_global.h \ + kis_id.h \ + kis_integer_maths.h \ + kis_progress_display_interface.h \ + kis_progress_subject.h \ + kis_shared_ptr_vector.h \ + kis_undo_adapter.h \ + kis_generic_registry.h + diff --git a/chalk/sdk/kis_annotation.h b/chalk/sdk/kis_annotation.h new file mode 100644 index 00000000..0753af8f --- /dev/null +++ b/chalk/sdk/kis_annotation.h @@ -0,0 +1,89 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_ANNOTATION_H_ +#define _KIS_ANNOTATION_H_ + +#include +#include "kis_shared_ptr_vector.h" + +#include +#include +#include + +/** + * An data extension mechanism for Chalk. + * + * An annotation can be of something like a TQByteArray or a TQString op a more specific + * datatype that can be attached to an image (or maybe later, if needed, to a layer) + * and contains data that must be associated with an image for purposes of import/export. + * + * Annotations will be saved to chalk images and may be exported in filetypes that support + * them. + * + * Examples of annotations are EXIF data and ICC profiles. + */ +class KisAnnotation : public KShared { + + +public: + + /** + * Creates a new annotation object. The annotation object cannot be changed later + * + * @param type a non-localized string identifying the type of the annotation + * @param description a localized string describing the annotation + * @param data a binary blob containing the annotation data + */ + KisAnnotation(const TQString & type, const TQString & description, const TQByteArray & data) + : m_type(type), + m_description(description), + m_annotation(data) {}; + + /** + * @return a non-localized string identifiying the type of the annotation + */ + TQString & type() {return m_type;}; + + /** + * @return a localized string describing the type of the annotations + * for user interface purposes. + */ + TQString & description() {return m_description;}; + + /** + * @return a binary blob representation of this annotation + */ + TQByteArray & annotation() { return m_annotation;}; + +private: + + TQString m_type; + TQString m_description; + TQByteArray m_annotation; + +}; + +typedef KSharedPtr KisAnnotationSP; +typedef KisSharedPtrVector vKisAnnotationSP; +typedef vKisAnnotationSP::iterator vKisAnnotationSP_it; +typedef vKisAnnotationSP::const_iterator vKisAnnotationSP_cit; + +#endif // _KIS_ANNOTATION_H_ diff --git a/chalk/sdk/kis_canvas_controller.h b/chalk/sdk/kis_canvas_controller.h new file mode 100644 index 00000000..6ed8f1b9 --- /dev/null +++ b/chalk/sdk/kis_canvas_controller.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CANVAS_CONTROLLER_H_ +#define KIS_CANVAS_CONTROLLER_H_ + +#include +#include +#include +#include "kis_types.h" + +class TQWidget; +class KisTool; +class KisRect; +class KisPoint; +class KisCanvas; +class KisInputDevice; + +/** + * Interface for classes that implement a canvas; i.e., a widget where KisImages + * are painted onto. This is the "view" part of the model-view-controller paradigm; + * the naming is a confusing historical artefact. + */ +class KisCanvasController { +public: + KisCanvasController() {}; + virtual ~KisCanvasController() {}; + +public: + + /** + * @return the canvas object + */ + virtual KisCanvas *kiscanvas() const = 0; + + + /** + * @return the value of the horizontal scrollbar. + */ + virtual TQ_INT32 horzValue() const = 0; + + /** + * @return the value of the vertical scrollbar + */ + virtual TQ_INT32 vertValue() const = 0; + + /** + * Sets the horizontal and vertical scrollbars to the specified values + * + * @param x the value the horizontal scrollbar is set to + * @param y the value the vertical scrollbar is set to + */ + virtual void scrollTo(TQ_INT32 x, TQ_INT32 y) = 0; + + /** + * Tell all of the canvas to tqrepaint itself. + */ + virtual void updateCanvas() = 0; + + + /** + * Tell the canvas to tqrepaint the rectangle defined by x, y, w and h. + * The coordinates are image coordinates. + */ + virtual void updateCanvas(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) = 0; + + /** + * Tell the canvas tqrepaint the specified rectangle. The coordinates + * are image coordinates, not view coordinates. + */ + virtual void updateCanvas(const TQRect& rc) = 0; + + /** + * Increase the zoomlevel one step + */ + virtual void zoomIn() = 0; + + /** + * Increase the zoomlevel one step and make sure that x,y is the center point of the view. + * + * @param x The x coordinate of the visible point in image coordinates + * @param y the y coordinate of the visible point in image coordinates + */ + virtual void zoomIn(TQ_INT32 x, TQ_INT32 y) = 0; + + /** + * Decrease the zoomlevel one step + */ + virtual void zoomOut() = 0; + + + /** + * Decrease the zoomlevel one step and make sure that x,y is the center point of the view. + * + * @param x the x coordinate of the visible point in image coordinates + * @param y the y coordinate of the visible point in image coordinates + */ + virtual void zoomOut(TQ_INT32 x, TQ_INT32 y) = 0; + + /** + * To centre the view on the given point with the given zoom factor. + * + * @param x the x coordinate of the center point in image coordinates + * @param y the y coordinate of the center point in image coordinates + * @param zf the zoomfactor + */ + virtual void zoomAroundPoint(double x, double y, double zf) = 0; + + /** + * Make the rect defined by x, y, w and h visible, zooming in or + * out as necessary. The view will be centered around the center point + * of the specified rect. + */ + virtual void zoomTo(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) = 0; + + /** + * Make the rect defined by x, y, w and h visible, zooming in or + * out as necessary. The view will be centered around the center point + * of the specified rect. + */ + virtual void zoomTo(const TQRect& r) = 0; + + /** + * Make the rect defined by x, y, w and h visible, zooming in or + * out as necessary. The view will be centered around the center point + * of the specified rect. + */ + virtual void zoomTo(const KisRect& r) = 0; + + /** + * Conversion functions from view coordinates to image coordinates + * + * You can get the rectangle of the image that's visible using the + * viewToWindow() functions (KisCanvasController). E.g. + * viewToWindow(TQRect(0, 0, canvasWidth, canvasHeight)). + * + * Here, the view is the canvas widget in the view widget, and the window + * is the window on the image. + */ + virtual TQPoint viewToWindow(const TQPoint& pt) = 0; + virtual KisPoint viewToWindow(const KisPoint& pt) = 0; + virtual TQRect viewToWindow(const TQRect& rc) = 0; + virtual KisRect viewToWindow(const KisRect& rc) = 0; + virtual void viewToWindow(TQ_INT32 *x, TQ_INT32 *y) = 0; + + /** + * Conversion functions from image coordinates to view coordinates + */ + virtual TQPoint windowToView(const TQPoint& pt) = 0; + virtual KisPoint windowToView(const KisPoint& pt) = 0; + virtual TQRect windowToView(const TQRect& rc) = 0; + virtual KisRect windowToView(const KisRect& rc) = 0; + virtual void windowToView(TQ_INT32 *x, TQ_INT32 *y) = 0; + + /** + * Set the cursor shown when the pointer is over the canvas widget to + * the specified cursor. + * + * @param cursor the new cursor + * @return the old cursor + */ + virtual TQCursor setCanvasCursor(const TQCursor & cursor) = 0; + + /** + * Set the active input device to the specified input device, This + * could be a mouse, a stylus, an eraser or any other pointing input + * device. + * + * @param inputDevice the new input device + */ + virtual void setInputDevice(KisInputDevice inputDevice) = 0; + + /** + * @return the current input device, such as a mouse or a stylus + */ + virtual KisInputDevice currentInputDevice() const = 0; + + +private: + KisCanvasController(const KisCanvasController&); + KisCanvasController& operator=(const KisCanvasController&); +}; + +#endif // KIS_CANVAS_CONTROLLER_H_ + diff --git a/chalk/sdk/kis_canvas_observer.h b/chalk/sdk/kis_canvas_observer.h new file mode 100644 index 00000000..e62d23f3 --- /dev/null +++ b/chalk/sdk/kis_canvas_observer.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CANVAS_OBSERVER_H_ +#define KIS_CANVAS_OBSERVER_H_ + +class KisCanvasSubject; + +/** + * This is the base interface plugins use to implement the Observer + * design pattern. Observer can register themselves with an implementation + * of KisCanvasSubject. The KisCanvasSubject will then call update() + * on all registered observers whenever something interesting has happened. + * + * (This is something my predecessor should have done with signals and slots, + * I think...) + */ +class KisCanvasObserver { +public: + KisCanvasObserver() {}; + virtual ~KisCanvasObserver() {}; + +public: + /** + * Implement this function to query the KisCanvasSubject implementation + * about state that may be interesting, such as current paint color and + * so on. + * + * @param subject the KisCanvasSubject that may know something that's + * interesting for us. + */ + virtual void update(KisCanvasSubject *subject) = 0; + +private: + KisCanvasObserver(const KisCanvasObserver&); + KisCanvasObserver& operator=(const KisCanvasObserver&); +}; + +#endif // KIS_CANVAS_OBSERVER_H_ + diff --git a/chalk/sdk/kis_canvas_subject.h b/chalk/sdk/kis_canvas_subject.h new file mode 100644 index 00000000..07713576 --- /dev/null +++ b/chalk/sdk/kis_canvas_subject.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CANVAS_SUBJECT_H_ +#define KIS_CANVAS_SUBJECT_H_ + +#include "kis_types.h" +#include "kis_id.h" + +class KisDoc; +class KisBrush; +class KisCanvasController; +class KisCanvasObserver; +class KisGradient; +class KisPattern; +class KisPaintOpFactory; +class KisToolControllerInterface; +class KisUndoAdapter; +class KisProgressDisplayInterface; +class KisSelectionManager; +class TQWidget; +class TQCursor; +class KisColor; +class KoPaletteManager; +class KisProfile; +class KisPaintOpSettings; +class KisPerspectiveGridManager; + +/** + * KisCanvasSubject is part of the Observer pattern. Classes implementing KisCanvasObserver + * that have attached themselves to a class implementing this interface will be notified + * whenever any of the methods defined in this class will return something different. + * + * Historical notes: This class has grown a bit an now seems to be the abstract definition + * of the View part in the Model-View-Controller pattern. We need to fix this! + */ +class KisCanvasSubject { + +public: + KisCanvasSubject() {}; + virtual ~KisCanvasSubject() {}; + +public: + + /** + * From now on, the observer will be notified of changes in + * brush, foreground color, background color, pattern, gradient + * and paintop + */ + virtual void attach(KisCanvasObserver *observer) = 0; + + /** + * From now on, the specified observer will no longer be informed + * of changes. + */ + virtual void detach(KisCanvasObserver *observer) = 0; + + /** + * Calling this method will notify all observers. Do not call this + * method from the Update method of a KisCanvasObserver! + */ + virtual void notifyObservers() = 0; + + /** + * @return the image that is currently active. + */ + virtual KisImageSP currentImg() const = 0; + + /** + * @return the background color + */ + virtual KisColor bgColor() const = 0; + + /** + * Set the background color. This should cause all observers to be notified. Do not call from KisCanvasObserver::update()! + * + * @param c the new background color + */ + virtual void setBGColor(const KisColor& c) = 0; + + /** + * @return the currently set foreground or painting color + */ + virtual KisColor fgColor() const = 0; + + /** + * Set the foreground or painting color. This should cause all observers to be notified. Do not call from KisCanvasObserver::update()! + * + * @param c the new foreground color + */ + virtual void setFGColor(const KisColor& c) = 0; + + /** + * @return the exposure value. This determines which exposure of multiple exposure or HDR images will be displayed + */ + virtual float HDRExposure() const = 0; + + /** + * Set the exposure value. This determines which exposure of multiple exposure or HDR images will be displayed. All observers should be notified. + * + * @param exposure the new exposure value + */ + virtual void setHDRExposure(float exposure) = 0; + + /** + * @return the current brush object. + */ + virtual KisBrush *currentBrush() const = 0; + + /** + * @return the current pattern object. + */ + virtual KisPattern *currentPattern() const = 0; + + /** + * @return the current gradient object + */ + virtual KisGradient *currentGradient() const = 0; + + /** + * @return the identification of the current paintop object, not the paintop object itself. + */ + virtual KisID currentPaintop() const = 0; + + /** + * @return the settings for the current paintop object, or 0 if there are no options set. + */ + virtual const KisPaintOpSettings *currentPaintopSettings() const = 0; + + /** + * @return the currently applied zoom factor. XXX: Shouldn't this be in the canvas controller? + */ + virtual double zoomFactor() const = 0; + + /** + * retrieve the undo adapater -- there is one undo adapter + * per document, and it collects all transactions + */ + virtual KisUndoAdapter *undoAdapter() const = 0; + + /** + * @return the interface to the canvas widget + */ + virtual KisCanvasController *canvasController() const = 0; + + /// XXX: Remove this method + virtual KisToolControllerInterface *toolController() const = 0; + + /// XXX: Remove this method + virtual KisDoc * document() const = 0; + + /// XXX: Remove this method + virtual KisProgressDisplayInterface *progressDisplay() const = 0; + + /// XXX: Remove this method + virtual KisSelectionManager * selectionManager() = 0; + + /// XXX: Remove this method + virtual KoPaletteManager * paletteManager() = 0; + + /** + * Get the profile that this view uses to display itself on + * he monitor. + */ + virtual KisProfile * monitorProfile() = 0; + + /** + * Get the perspective grid manager. + */ + virtual KisPerspectiveGridManager* perspectiveGridManager() = 0; +private: + KisCanvasSubject(const KisCanvasSubject&); + KisCanvasSubject& operator=(const KisCanvasSubject&); +}; + +#endif // KIS_CANVAS_SUBJECT_H_ + diff --git a/chalk/sdk/kis_debug_areas.h b/chalk/sdk/kis_debug_areas.h new file mode 100644 index 00000000..67cb3566 --- /dev/null +++ b/chalk/sdk/kis_debug_areas.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DEBUG_AREAS_H_ +#define KIS_DEBUG_AREAS_H_ + +#define DBG_AREA_CORE 41001 +#define DBG_AREA_REGISTRY 40002 +#define DBG_AREA_TOOLS 41003 +#define DBG_AREA_CMS 41004 +#define DBG_AREA_FILTERS 41005 +#define DBG_AREA_PLUGINS 41006 +#define DBG_AREA_UI 41007 +#define DBG_AREA_FILE 41008 +#define DBG_AREA_MATH 41009 +#define DBG_AREA_RENDER 41010 +#define DBG_AREA_SCRIPT 41011 + + +#endif diff --git a/chalk/sdk/kis_generic_registry.h b/chalk/sdk/kis_generic_registry.h new file mode 100644 index 00000000..a806ea50 --- /dev/null +++ b/chalk/sdk/kis_generic_registry.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_GENERIC_REGISTRY_H_ +#define _KIS_GENERIC_REGISTRY_H_ + +#include + +#include +#include + +#include + +/** + * Base class for registry objects in Chalk. Chalk registries + * contain resources such as filters, tools or colorspaces. + * + * Items are mapped by KisID. A KisID is the combination of + * a non-localized string that can be used in files and a + * user-visible, translated string that can be used in the + * user interface. + */ +template +class KisGenericRegistry { +protected: + typedef std::map storageMap; +public: + KisGenericRegistry() { }; + virtual ~KisGenericRegistry() { }; +public: + + /** + * add an object to the registry + * @param item the item to add (NOTE: _T must have an KisID id() function) + */ + void add(_T item) + { + m_storage.insert( typename storageMap::value_type( item->id(), item) ); + } + /** + * add an object to the registry + * @param id the id of the object + * @param item the item + */ + void add(KisID id, _T item) + { + m_storage.insert(typename storageMap::value_type(id, item)); + } + /** + * This function remove an item from the registry + * @return the object which have been remove from the registry and which can be safely delete + */ + _T remove(const KisID& name) + { + _T p = 0; + typename storageMap::iterator it = m_storage.find(name); + if (it != m_storage.end()) { + m_storage.erase(it); + p = it->second; + } + return p; + } + /** + * This function remove an item from the registry + * @param id the identifiant of the object + * @return the object which have been remove from the registry and which can be safely delete + */ + _T remove(const TQString& id) + { + return remove(KisID(id,"")); + } + /** + * This function allow to get an object from its KisID + * @param name the KisID of the object + * @return _T the object + */ + _T get(const KisID& name) const + { + _T p = 0; + typename storageMap::const_iterator it = m_storage.find(name); + if (it != m_storage.end()) { + p = it->second; + } + return p; + } + + /** + * Get a single entry based on the identifying part of KisID, not the + * the descriptive part. + */ + _T get(const TQString& id) const + { + return get(KisID(id, "")); + } + + /** + * @param id + * @return true if there is an object corresponding to id + */ + bool exists(const KisID& id) const + { + typename storageMap::const_iterator it = m_storage.find(id); + return (it != m_storage.end()); + } + + bool exists(const TQString& id) const + { + return exists(KisID(id, "")); + } + /** + * This function allow to search a KisID from the name. + * @param t the name to search + * @param result The result is filled in this variable + * @return true if the search has been successfull, false otherwise + */ + bool search(const TQString& t, KisID& result) const + { + for(typename storageMap::const_iterator it = m_storage.begin(); + it != m_storage.end(); ++it) + { + if(it->first.name() == t) + { + result = it->first; + return true; + } + } + return false; + } + + /** This function return a list of all the keys + */ + KisIDList listKeys() const + { + KisIDList list; + typename storageMap::const_iterator it = m_storage.begin(); + typename storageMap::const_iterator endit = m_storage.end(); + while( it != endit ) + { + list.append(it->first); + ++it; + } + return list; + } + +protected: + KisGenericRegistry(const KisGenericRegistry&) { }; + KisGenericRegistry operator=(const KisGenericRegistry&) { }; + storageMap m_storage; +}; + +#endif diff --git a/chalk/sdk/kis_global.h b/chalk/sdk/kis_global.h new file mode 100644 index 00000000..249d312e --- /dev/null +++ b/chalk/sdk/kis_global.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 Matthias Elter + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KISGLOBAL_H_ +#define KISGLOBAL_H_ + +#include +#include LCMS_HEADER +#include +#include +#include + +#define KRITA_VERSION VERSION + +const TQ_UINT8 TQ_UINT8_MAX = UCHAR_MAX; +const TQ_UINT16 TQ_UINT16_MAX = 65535; + +const TQ_INT32 TQ_INT32_MAX = (2147483647); +const TQ_INT32 TQ_INT32_MIN = (-2147483647-1); + +const TQ_UINT8 OPACITY_TRANSPARENT = 0; +const TQ_UINT8 OPACITY_OPAQUE = UCHAR_MAX; + +const TQ_UINT8 MAX_SELECTED = UCHAR_MAX; +const TQ_UINT8 MIN_SELECTED = 0; +const TQ_UINT8 SELECTION_THRESHOLD = 1; + +enum enumCursorStyle { + CURSOR_STYLE_TOOLICON = 0, + CURSOR_STYLE_CROSSHAIR = 1, + CURSOR_STYLE_POINTER = 2, + CURSOR_STYLE_OUTLINE = 3 +}; + +enum enumResourceTypes { + RESOURCE_PAINTOP, + RESOURCE_FILTER, + RESOURCE_TOOL, + RESOURCE_COLORSPACE +}; + +/* + * Most wacom pads have 512 levels of pressure; TQt only supports 256, and even + * this is downscaled to 127 levels because the line would be too jittery, and + * the amount of tqmasks take too much memory otherwise. + */ +const TQ_INT32 PRESSURE_LEVELS= 127; +const double PRESSURE_MIN = 0.0; +const double PRESSURE_MAX = 1.0; +const double PRESSURE_DEFAULT = (PRESSURE_MAX - PRESSURE_MIN) / 2; +const double PRESSURE_THRESHOLD = 5.0 / 255.0; + +#define CLAMP(x,l,u) ((x)<(l)?(l):((x)>(u)?(u):(x))) + + +namespace chalk { + + // String constants for palettes and palette widgets + const TQString TOOL_OPTION_WIDGET ("tooloptions"); + + const TQString CONTROL_PALETTE ("controlpalette"); + const TQString PAINTBOX ("paintbox"); + const TQString COLORBOX ("colorbox"); + const TQString LAYERBOX ("layerbox"); +} + +#endif // KISGLOBAL_H_ + diff --git a/chalk/sdk/kis_id.h b/chalk/sdk/kis_id.h new file mode 100644 index 00000000..d15c5f27 --- /dev/null +++ b/chalk/sdk/kis_id.h @@ -0,0 +1,108 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_ID_H_ +#define _KIS_ID_H_ + +#include +#include + +/** + * Chalk has a large number of extensible resources. Think: + * + * - Brushes + * - Palettes + * - Patterns + * - Gradients + * - Color models + * - Filters + * - Composition operations + * - Paint operations + * - Tools + * - Docker tabs + * + * and more... + * + * Many of these resources are stored in KisGenericRegistry-based + * registries. If we store these resources with a descriptive string + * as a key use the same string in our UI, then our UI will not be + * localizable, because the identifications of particular resources + * will be stored in files, and those files need to be exchangeable. + * + * So, instead we use and ID class that couples an identification + * string that will be the same across all languages, an i18n-able + * string that will be used in comboboxes and that has a fast equality + * operator to make it well suited for use as key in a registry map. + * + * That last bit has not been solved yet. + * + */ +class KisID { + + +public: + + KisID() : m_id(TQString()), m_name(TQString()) {} + + KisID(const TQString & id, const TQString & name = TQString()) + : m_id(id), + m_name(name) {}; + + TQString id() const { return m_id; }; + TQString name() const { return m_name; }; + + friend inline bool operator==(const KisID &, const KisID &); + friend inline bool operator!=(const KisID &, const KisID &); + friend inline bool operator<(const KisID &, const KisID &); + friend inline bool operator>(const KisID &, const KisID &); + +private: + + TQString m_id; + TQString m_name; + +}; + +inline bool operator==(const KisID &v1, const KisID &v2) +{ + return v1.m_id == v2.m_id; +} + +inline bool operator!=(const KisID &v1, const KisID &v2) +{ + return v1.m_id != v2.m_id; +} + + +inline bool operator<(const KisID &v1, const KisID &v2) +{ + return v1.m_id < v2.m_id; +} + + +inline bool operator>(const KisID &v1, const KisID &v2) +{ + return v1.m_id < v2.m_id; +} + + +typedef TQValueList KisIDList; + +#endif // _KIS_ID_H_ diff --git a/chalk/sdk/kis_integer_maths.h b/chalk/sdk/kis_integer_maths.h new file mode 100644 index 00000000..c8db9aee --- /dev/null +++ b/chalk/sdk/kis_integer_maths.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_INTEGER_MATHS_H +#define KIS_INTEGER_MATHS_H + +#define UINT8_MAX 255u +#define UINT8_MIN 0u + +#define UINT16_MAX 65535u +#define UINT16_MIN 0u + +#define UINT32_MAX (4294967295u) +#define UINT32_MIN 0u + +#define INT16_MAX 32767 +#define INT16_MIN -32768 + +/// take a and scale it up by 256*b/255 +inline uint UINT8_SCALEBY(uint a, uint b) +{ + uint c = a * b + 0x80u; + return (c >> 8) + c; +} + +inline uint UINT8_MULT(uint a, uint b) +{ + uint c = a * b + 0x80u; + return ((c >> 8) + c) >> 8; +} + +inline uint UINT8_DIVIDE(uint a, uint b) +{ + uint c = (a * UINT8_MAX + (b / 2u)) / b; + return c; +} + +inline uint UINT8_BLEND(uint a, uint b, uint alpha) +{ + // Basically we do a*alpha + b*(1-alpha) + // However refactored to (a-b)*alpha + b since that saves a multiplication + // Signed arithmetic is needed since a-b might be negative + int c = ((int(a) - int(b)) * int(alpha)) >> 8; + + return uint(c + b); +} + +inline uint UINT16_MULT(uint a, uint b) +{ + uint c = a * b + 0x8000u; + return ((c >> 16) + c) >> 16; +} + +inline int INT16_MULT(int a, int b) +{ + return (a*b) / INT16_MAX; +} + +inline uint UINT16_DIVIDE(uint a, uint b) +{ + uint c = (a * UINT16_MAX + (b / 2u)) / b; + return c; +} + +inline uint UINT16_BLEND(uint a, uint b, uint alpha) +{ + // Basically we do a*alpha + b*(1-alpha) + // However refactored to (a-b)*alpha + b since that saves a multiplication + // Signed arithmetic is needed since a-b might be negative + int c = ((int(a) - int(b)) * int(alpha)) >> 16; + return uint(c + b); +} + +inline uint UINT8_TO_UINT16(uint c) +{ + return c | (c<<8); +} + +inline uint UINT16_TO_UINT8(uint c) +{ + //return round(c / 257.0); + //For all UINT16 this calculation is the same and a lot faster (off by c/65656 which for every c is 0) + c = c - (c >> 8) + 128; + return c >>8; +} + +inline int INT16_BLEND(int a, int b, uint alpha) +{ + // Basically we do a*alpha + b*(1-alpha) + // However refactored to (a-b)*alpha + b since that saves a multiplication + int c = ((int(a) - int(b)) * int(alpha)) >> 16; + return c + b; +} + +#endif + diff --git a/chalk/sdk/kis_progress_display_interface.h b/chalk/sdk/kis_progress_display_interface.h new file mode 100644 index 00000000..2674c6ab --- /dev/null +++ b/chalk/sdk/kis_progress_display_interface.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PROGRESS_DISPLAY_INTERFACE_H_ +#define KIS_PROGRESS_DISPLAY_INTERFACE_H_ + +class KisProgressSubject; + + +namespace KisProgress { + + const int ProgressEventBase = TQEvent::User + 42 + 42; + + class UpdateEvent : TQCustomEvent { + + public: + + UpdateEvent(int percent) : TQCustomEvent(ProgressEventBase + 1), m_percent(percent) {}; + int m_percent; + }; + + class UpdateStageEvent : TQCustomEvent { + + public: + + UpdateStageEvent(const TQString & stage, int percent) : TQCustomEvent(ProgressEventBase + 2 ), m_stage(stage), m_percent(percent) {}; + TQString m_stage; + int m_percent; + }; + + class DoneEvent : TQCustomEvent { + DoneEvent() : TQCustomEvent(ProgressEventBase + 3){}; + }; + + class ErrorEvent : TQCustomEvent { + ErrorEvent() : TQCustomEvent(ProgressEventBase + 4){}; + }; + + class DestroyedEvent: TQCustomEvent { + DestroyedEvent() : TQCustomEvent(ProgressEventBase + 5){}; + }; + + +} + + + +class KisProgressDisplayInterface { +public: + KisProgressDisplayInterface() {} + virtual ~KisProgressDisplayInterface() {} + + virtual void setSubject(KisProgressSubject *subject, bool modal, bool canCancel) = 0; + +private: + KisProgressDisplayInterface(const KisProgressDisplayInterface&); + KisProgressDisplayInterface& operator=(const KisProgressDisplayInterface&); +}; + +#endif // KIS_PROGRESS_DISPLAY_INTERFACE_H_ + diff --git a/chalk/sdk/kis_progress_subject.cc b/chalk/sdk/kis_progress_subject.cc new file mode 100644 index 00000000..fa53086b --- /dev/null +++ b/chalk/sdk/kis_progress_subject.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2002 Patrick Julien + * 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "kis_progress_subject.h" + +KisProgressSubject::~KisProgressSubject() +{ +} + +#include "kis_progress_subject.moc" + diff --git a/chalk/sdk/kis_progress_subject.h b/chalk/sdk/kis_progress_subject.h new file mode 100644 index 00000000..59a8acb1 --- /dev/null +++ b/chalk/sdk/kis_progress_subject.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002 Patrick Julien + * 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PROGRESS_SUBJECT_H_ +#define KIS_PROGRESS_SUBJECT_H_ + +#include +#include + +class KRITAUI_EXPORT KisProgressSubject : public TQObject { + Q_OBJECT + TQ_OBJECT + +protected: + KisProgressSubject() {}; + KisProgressSubject(TQObject * tqparent, const char * name) : TQObject(tqparent, name) {}; + virtual ~KisProgressSubject(); + +public: + virtual void cancel() = 0; + +signals: + void notifyProgress(int percent); + void notifyProgressStage(const TQString& stage, int percent); + void notifyProgressDone(); + void notifyProgressError(); +}; + +#endif // KIS_PROGRESS_SUBJECT_H_ + diff --git a/chalk/sdk/kis_shared_ptr_vector.h b/chalk/sdk/kis_shared_ptr_vector.h new file mode 100644 index 00000000..679bdd9f --- /dev/null +++ b/chalk/sdk/kis_shared_ptr_vector.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_SHARED_PTR_VECTOR_H +#define KIS_SHARED_PTR_VECTOR_H + +#include + +#include + +/** + * TQValueVector does not always destroy an element when it is erased. + * If the items it is holding are KSharedPtr, this can result in hidden + * references to objects that cannot be accounted for. This class + * sets the KSharedPtr to 0 on erase, which dereferences the object as + * expected. + */ +template +class KisSharedPtrVector : public TQValueVector< KSharedPtr > +{ + typedef TQValueVector< KSharedPtr > super; +public: + KisSharedPtrVector() {} + + void pop_back() + { + if (!super::empty()) { + super::back() = 0; + super::pop_back(); + } + } + + typename super::iterator erase(typename super::iterator it) + { + *it = 0; + return super::erase(it); + } + + typename super::iterator erase(typename super::iterator first, typename super::iterator last) + { + tqFill(first, last, 0); + return super::erase(first, last); + } + + bool tqcontains(KSharedPtr ptr) const + { + for (int i = 0, n = super::count(); i < n; ++i) + if (super::at(i) == ptr) + return true; + return false; + } +}; + +#endif // KIS_SHARED_PTR_VECTOR_H + diff --git a/chalk/sdk/kis_undo_adapter.h b/chalk/sdk/kis_undo_adapter.h new file mode 100644 index 00000000..cb9172ee --- /dev/null +++ b/chalk/sdk/kis_undo_adapter.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_UNDO_ADAPTER_H_ +#define KIS_UNDO_ADAPTER_H_ + +#include + +class TQString; +class KCommand; + +/** + * Undo listeners want to be notified of undo and redo actions. + * add notification is given _before_ the command is added to the + * stack. + * execute notification is given on undo and redo + */ +class KisCommandHistoryListener { + +public: + + KisCommandHistoryListener(){}; + + virtual void notifyCommandAdded(KCommand * cmd) = 0; + virtual void notifyCommandExecuted(KCommand * cmd) = 0; +}; + +class KisUndoAdapter { +public: + KisUndoAdapter() {}; + virtual ~KisUndoAdapter() {}; + +public: + + virtual void setCommandHistoryListener(const KisCommandHistoryListener *) = 0; + virtual void removeCommandHistoryListener(const KisCommandHistoryListener *) = 0; + + virtual KCommand * presentCommand() = 0; + virtual void addCommand(KCommand *cmd) = 0; + virtual void setUndo(bool undo) = 0; + virtual bool undo() const = 0; + virtual void beginMacro(const TQString& macroName) = 0; + virtual void endMacro() = 0; + +private: + KisUndoAdapter(const KisUndoAdapter&); + KisUndoAdapter& operator=(const KisUndoAdapter&); +}; + + +#endif // KIS_UNDO_ADAPTER_H_ + diff --git a/chalk/todo-1.6 b/chalk/todo-1.6 new file mode 100644 index 00000000..2d018fd0 --- /dev/null +++ b/chalk/todo-1.6 @@ -0,0 +1,74 @@ +Things To Do for 1.6 + +Please update & commit this list with every fix you make + +? = Alice Nonymus +A = Adrian Page +B = Casper Boemann +C = Cyrille Berger +R = Boudewijn Rempt +P = Bart Coppens +G = Gábor Level +S = Sander Koning +TZ = Thomas Zander (to refer to his ui hints) + +Colorspaces + +R * Fix drying the wet colorspace +R * Fix fill in wet + +Core + +? * Use the nextCol/nextRow of the line iterators wherever possible to get a speed boost. + +User interface + +? * after hiding and reshowing all palettes, the wrong ones are active + +Plugins + +C * finish, polish and document scripting support +P * Select By Color -> Sample Merged +P * Select plugins with sample merged -> default to sample merged when active layer is adj layer +P * See if it could be interesting to make the color select tool update while dragging + +Release + +R * develop thorough test plan and exercise it on several installations + before release + +Bugs + +? * Grow Selection doesn't seem to work on adj layers, investigate +? * Select Rect/Circle -> doesn't erase the XOR'ed outline on the KisCanvas +? * Selection Tools with Select All, Deselect and so don't play completely nicely with adj layers + +Also: see UIcomments! + +Michael's bugs: + +* Open an image, add image as new layer, resize layer, undo: undo removes the layer +* open an image, add an adjustment layer to the image (I used the pixelize + filter). Click on the original layer in the layer dialog box and paint + something. The undo the painting and undo add layer. Chalk's toolbox will + become greyed out and you can't paint. I think this is already a bug and + should be fixed. But next, try to add an adjustment layer again -> Chalk + crashes. +* The shrink etc selection are enabled when there is no selection +* select by colorrange does not actually set the selection (or something like that) + +Regressions + +? saving 16 bit grayscale to jpeg silently converts to 8 bit grayscale (actually it's not a regression, saving to both 8bits and 16bits jpeg with the same build is impossible with libjpeg) +? zooming in leaves display artefacts (see Bart's mail) +? rotate is broken for large images +? rotate visitor is used where transform visitor should be used +? undoing a rotation when a selection is active leads to weird results + +Painting with filters + +? sharpen: works badly, paints circles -- this used to be okay! +? small tiles: makes circles, otherwise effect is fun + +Note: make kivio flowchart of what happens when painting with and without filters, +with and without selection, direct or indirect, because I don't follow anymore diff --git a/chalk/ui/Makefile.am b/chalk/ui/Makefile.am new file mode 100644 index 00000000..34f67c91 --- /dev/null +++ b/chalk/ui/Makefile.am @@ -0,0 +1,75 @@ +INCLUDES = \ + -I$(srcdir) \ + -I$(srcdir)/../sdk \ + -I$(srcdir)/../core \ + -I$(srcdir)/../chalkcolor \ + $(KOFFICE_INCLUDES) \ + $(KOPAINTER_INCLUDES) \ + $(KDE_INCLUDES) \ + $(all_includes) + +lib_LTLIBRARIES = libchalkui.la +libchalkui_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries) +libchalkui_la_LIBADD = ../sdk/libchalksdk.la ../core/libchalkimage.la ../chalkcolor/libchalkcolor.la \ + $(LCMS_LIBS) $(LIB_KOFFICEUI) $(LIB_KOPAINTER) $(LIB_KOPALETTE) $(LIB_XINPUTEXT) $(GLLIB) + +libchalkui_la_SOURCES = kis_import_catcher.cc kis_histogram_view.cc imageviewer.cc kcurve.cc \ + kis_autobrush.cc kis_autogradient.cc kis_boundary_painter.cc kis_brush_chooser.cc \ + kis_canvas.cc kis_canvas_painter.cc kis_clipboard.cc kis_cmb_composite.cc \ + kis_cmb_idlist.cc kis_color_cup.cc kis_config.cc kis_controlframe.cc kis_cursor.cc \ + kis_dlg_apply_profile.cc kis_dlg_image_properties.cc kis_dlg_layer_properties.cc \ + kis_dlg_new_layer.cc kis_dlg_preferences.cc kis_doc.cc kis_doc_iface.cc kis_doc_iface.skel \ + kis_double_widget.cc kis_factory.cc kis_filter_manager.cc kis_gradient_chooser.cc \ + kis_gradient_slider_widget.cc kis_icon_item.cc kis_iconwidget.cc kis_int_spinbox.cc \ + kis_itemchooser.cc kis_label_cursor_pos.cc kis_label_progress.cc kis_label_zoom.cc \ + kis_layerbox.cc kis_layerlist.cc kis_multi_bool_filter_widget.cc \ + kis_multi_double_filter_widget.cc kis_multi_integer_filter_widget.cc kis_opengl_canvas.cc \ + kis_opengl_canvas_painter.cc kis_opengl_image_context.cc kis_paintop_box.cc kis_palette_view.cc \ + kis_palette_widget.cc kis_part_layer.cc kis_pattern_chooser.cc kis_previewdialog.cc \ + kis_previewwidget.cc kis_qpaintdevice_canvas.cc kis_qpaintdevice_canvas_painter.cc \ + kis_resource_mediator.cc kis_resourceserver.cc kis_ruler.cc kis_selection_manager.cc \ + kis_selection_options.cc kis_text_brush.cc kis_tool.cc kis_tool_dummy.cc kis_tool_freehand.cc \ + kis_tool_manager.cc kis_tool_non_paint.cc kis_tool_paint.cc kis_tool_registry.cc \ + kis_tool_shape.cc kis_birdeye_box.cc kis_view.cc kis_view_iface.cc kis_custom_brush.cc \ + kis_custom_palette.cc kis_custom_pattern.cc kis_custom_image_widget.cc kis_view_iface.skel \ + kobirdeyepanel.cpp kis_matrix_widget.ui kis_previewwidgetbase.ui layerlist.cpp \ + wdgapplyprofile.ui wdgautobrush.ui wdgautogradient.ui wdgbirdeye.ui wdgcolorsettings.ui \ + wdgdisplaysettings.ui wdggeneralsettings.ui wdglayerproperties.ui wdglayerbox.ui \ + wdgnewimage.ui wdgperformancesettings.ui wdgselectionoptions.ui wdgshapeoptions.ui \ + wdgpressuresettings.ui wdgcustombrush.ui wdgcustompalette.ui wdgcustompattern.ui \ + wdgtextbrush.ui kis_dlg_adjustment_layer.cc kis_filters_listview.cc \ + wdgpalettechooser.ui wdggridsettings.ui kis_grid_manager.cpp wdgtabletdevicesettings.ui \ + wdgtabletsettings.ui kis_input_device.cc kis_part_layer_handler.cc \ + kis_dlg_adj_layer_props.cc squeezedcombobox.cpp kis_perspective_grid_manager.cpp \ + kis_grid_drawer.cpp + +noinst_HEADERS = kis_aboutdata.h imageviewer.h layerlist.h kcurve.h \ + kis_autobrush.h kis_autogradient.h kis_birdeye_box.h kis_brush_chooser.h \ + kis_button_press_event.h kis_canvas.h kis_clipboard.h kis_controlframe.h \ + kis_dlg_apply_profile.h kis_dlg_image_properties.h kis_dlg_layer_properties.h \ + kis_dlg_new_layer.h kis_dlg_preferences.h kis_event.h kis_factory.h \ + kis_label_cursor_pos.h kis_label_progress.h kis_part_layer.h kis_pattern_chooser.h \ + kis_resource_mediator.h kis_resourceserver.h kis_ruler.h kis_selection_manager.h \ + kis_selection_options.h kis_view_iface.h kis_custom_brush.h kis_custom_pattern.h \ + kis_custom_image_widget.h kis_dlg_adjustment_layer.h kis_grid_manager.h \ + kis_dlg_adj_layer_props.h squeezedcombobox.h kis_perspective_grid_manager.h + +include_HEADERS = kis_button_event.h kis_button_release_event.h kis_canvas_painter.h kis_cmb_composite.h kis_cmb_idlist.h kis_color_cup.h kis_config.h \ + kis_cursor.h kis_doc.h kis_doc_iface.h \ + kis_double_click_event.h kis_double_widget.h kis_event.h kis_filter_manager.h \ + kis_gradient_chooser.h kis_gradient_slider_widget.h kis_histogram_view.h kis_icon_item.h \ + kis_iconwidget.h kis_itemchooser.h \ + kis_label_zoom.h kis_int_spinbox.h kis_layerbox.h kis_layerlist.h kis_matrix_widget.ui.h kis_move_event.h \ + kis_multi_bool_filter_widget.h kis_multi_double_filter_widget.h kis_multi_integer_filter_widget.h \ + kis_paintop_box.h kis_palette_widget.h \ + kis_previewdialog.h kis_previewwidget.h \ + kis_tool_controller.h kis_tool.h kis_tool_non_paint.h kis_tool_paint.h kis_tool_freehand.h \ + kis_tool_dummy.h kis_tool_manager.h kis_tool_types.h kis_tool_registry.h kis_view.h \ + kis_tool_factory.h \ + kobirdeyepanel.h \ + kis_filters_listview.h kis_input_device.h kis_opengl_image_context.h + +METASOURCES = AUTO + +KDE_OPTIONS = nofinal + diff --git a/chalk/ui/imageviewer.cc b/chalk/ui/imageviewer.cc new file mode 100644 index 00000000..b6d94ed9 --- /dev/null +++ b/chalk/ui/imageviewer.cc @@ -0,0 +1,78 @@ +/*************************************************************************** + * Copyright (C) 2005 Eyal Lotem * + * Copyright (C) 2005 Alexandre Oliveira * + * Copyright (C) 2006 Cyrille Berger * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#include "imageviewer.h" + +#include +#include +#include +#include + +#include +#include +#include + +ImageViewer::ImageViewer(TQWidget *widget, const char * name) + : TQScrollView(widget, name) + , m_isDragging(false) + , m_image(TQPixmap()) +{ + m_label = new TQLabel( viewport()); + tqsetSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding); + setCursor(KisCursor::handCursor()); + addChild(m_label); +} + +void ImageViewer::setImage(TQImage & image) +{ + m_image = TQPixmap(image); + m_label->setPixmap(m_image); + resizeContents( m_image.width(), m_image.height() ); + tqrepaintContents(false); +} + +void ImageViewer::contentsMousePressEvent(TQMouseEvent *event) +{ + if(Qt::LeftButton == event->button()) { + setCursor(KisCursor::closedHandCursor()); + m_currentPos = event->globalPos(); + m_isDragging = true; + } +} + +void ImageViewer::contentsMouseReleaseEvent(TQMouseEvent *event) +{ + if(Qt::LeftButton == event->button()) { + setCursor(KisCursor::handCursor()); + m_currentPos = event->globalPos(); + m_isDragging = false; + } +} + +void ImageViewer::contentsMouseMoveEvent(TQMouseEvent *event) +{ + if(m_isDragging) { + TQPoint delta = m_currentPos - event->globalPos(); + scrollBy(delta.x(), delta.y()); + m_currentPos = event->globalPos(); + } +} + +#include "imageviewer.moc" diff --git a/chalk/ui/imageviewer.h b/chalk/ui/imageviewer.h new file mode 100644 index 00000000..1865e5d0 --- /dev/null +++ b/chalk/ui/imageviewer.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2005 Eyal Lotem * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ +#ifndef PIXMAPVIEWER_H +#define PIXMAPVIEWER_H + +#include +#include + +class TQLabel; + +/** + * A scrollable image view. + * + * XXX: We should add a signal that emits newly eposed rects so the filters + * don't have to filter everything, but just the the new bits. + */ +class ImageViewer : public TQScrollView { + Q_OBJECT + TQ_OBJECT + +public: + ImageViewer(TQWidget *widget, const char * name = 0); + + void setImage(TQImage & image); + + void contentsMousePressEvent(TQMouseEvent *event); + void contentsMouseReleaseEvent(TQMouseEvent *event); + void contentsMouseMoveEvent(TQMouseEvent *event); + void wheelEvent(TQWheelEvent * event) { event->ignore(); }; +private: + TQLabel* m_label; + bool m_isDragging; + TQPoint m_currentPos; + TQPixmap m_image; +}; + +#endif diff --git a/chalk/ui/kcurve.cc b/chalk/ui/kcurve.cc new file mode 100644 index 00000000..47f9934a --- /dev/null +++ b/chalk/ui/kcurve.cc @@ -0,0 +1,450 @@ +/* ============================================================ + * Copyright 2004-2005 by Gilles Caulier + * Copyright 2005 by Casper Boemann (reworked to be generic) + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +// C++ includes. + +#include +#include + +// TQt includes. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE includes. + +#include +#include +#include + +// Local includes. + +#include "kcurve.h" + +KCurve::KCurve(TQWidget *tqparent, const char *name, WFlags f) + : TQWidget(tqparent, name, f) +{ + m_grab_point = NULL; + m_readOnlyMode = false; + m_guideVisible = false; + m_dragging = false; + m_pix = NULL; + + setMouseTracking(true); + setPaletteBackgroundColor(TQt::NoBackground); + setMinimumSize(150, 50); + TQPair *p = new TQPair; + p->first = 0.0; p->second=0.0; + m_points.append(p); + p = new TQPair; + p->first = 1.0; p->second=1.0; + m_points.append(p); + m_points.setAutoDelete(true); + setFocusPolicy(TQ_StrongFocus); +} + +KCurve::~KCurve() +{ + if (m_pix) delete m_pix; +} + +void KCurve::reset(void) +{ + m_grab_point = NULL; + m_guideVisible = false; + tqrepaint(false); +} + +void KCurve::setCurveGuide(TQColor color) +{ + m_guideVisible = true; + m_colorGuide = color; + tqrepaint(false); +} + +void KCurve::setPixmap(TQPixmap pix) +{ + if (m_pix) delete m_pix; + m_pix = new TQPixmap(pix); + tqrepaint(false); +} + +void KCurve::keyPressEvent(TQKeyEvent *e) +{ + if(e->key() == TQt::Key_Delete || e->key() == TQt::Key_Backspace) + { + TQPair *closest_point=NULL; + if(m_grab_point) + { + //first find closest point to get focus afterwards + TQPair *p = m_points.first(); + double distance = 1000; // just a big number + while(p) + { + if(p!=m_grab_point) + if (fabs (m_grab_point->first - p->first) < distance) + { + distance = fabs(m_grab_point->first - p->first); + closest_point = p; + } + p = m_points.next(); + } + m_points.remove(m_grab_point); + } + m_grab_point = closest_point; + tqrepaint(false); + } + else + TQWidget::keyPressEvent(e); +} + +void KCurve::paintEvent(TQPaintEvent *) +{ + int x, y; + int wWidth = width(); + int wHeight = height(); + + x = 0; + y = 0; + + // Drawing selection or all histogram values. + // A TQPixmap is used for enable the double buffering. + + TQPixmap pm(size()); + TQPainter p1; + p1.tqbegin(TQT_TQPAINTDEVICE(&pm), this); + + // draw background + if(m_pix) + { + p1.scale(1.0*wWidth/m_pix->width(), 1.0*wHeight/m_pix->height()); + p1.drawPixmap(0, 0, *m_pix); + p1.resetXForm(); + } + else + pm.fill(); + + // Draw grid separators. + p1.setPen(TQPen::TQPen(TQt::gray, 1, TQt::SolidLine)); + p1.drawLine(wWidth/3, 0, wWidth/3, wHeight); + p1.drawLine(2*wWidth/3, 0, 2*wWidth/3, wHeight); + p1.drawLine(0, wHeight/3, wWidth, wHeight/3); + p1.drawLine(0, 2*wHeight/3, wWidth, 2*wHeight/3); + + // Draw curve. + double curvePrevVal = getCurveValue(0.0); + p1.setPen(TQPen::TQPen(TQt::black, 1, TQt::SolidLine)); + for (x = 0 ; x < wWidth ; x++) + { + double curveX; + double curveVal; + + curveX = (x + 0.5) / wWidth; + + curveVal = getCurveValue(curveX); + + p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), + x, wHeight - int(curveVal * wHeight)); + + curvePrevVal = curveVal; + } + p1.drawLine(x - 1, wHeight - int(curvePrevVal * wHeight), + x, wHeight - int(getCurveValue(1.0) * wHeight)); + + // Drawing curve handles. + if ( !m_readOnlyMode ) + { + TQPair *p = m_points.first(); + + while(p) + { + double curveX = p->first; + double curveY = p->second; + + if(p == m_grab_point) + { + p1.setPen(TQPen::TQPen(TQt::red, 3, TQt::SolidLine)); + p1.drawEllipse( int(curveX * wWidth) - 2, + wHeight - 2 - int(curveY * wHeight), 4, 4 ); + } + else + { + p1.setPen(TQPen::TQPen(TQt::red, 1, TQt::SolidLine)); + + p1.drawEllipse( int(curveX * wWidth) - 3, + wHeight - 3 - int(curveY * wHeight), 6, 6 ); + } + + p = m_points.next(); + } + } + + p1.end(); + bitBlt(this, 0, 0, &pm); +} + +void KCurve::mousePressEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + TQPair *closest_point=NULL; + double distance; + + if (e->button() != Qt::LeftButton) + return; + + double x = e->pos().x() / (float)width(); + double y = 1.0 - e->pos().y() / (float)height(); + + distance = 1000; // just a big number + + TQPair *p = m_points.first(); + int insert_pos,pos=0; + while(p) + { + if (fabs (x - p->first) < distance) + { + distance = fabs(x - p->first); + closest_point = p; + if(x < p->first) + insert_pos = pos; + else + insert_pos = pos + 1; + } + p = m_points.next(); + pos++; + } + + + if(closest_point == NULL) + { + closest_point = new TQPair; + closest_point->first = x; + closest_point->second = y; + m_points.append(closest_point); + } + else if(distance * width() > 5) + { + closest_point = new TQPair; + closest_point->first = x; + closest_point->second = y; + m_points.insert(insert_pos, closest_point); + } + else + if(fabs(y - closest_point->second) * width() > 5) + return; + + + m_grab_point = closest_point; + m_grabOffsetX = m_grab_point->first - x; + m_grabOffsetY = m_grab_point->second - y; + m_grab_point->first = x + m_grabOffsetX; + m_grab_point->second = y + m_grabOffsetY; + m_dragging = true; + + setCursor( KCursor::crossCursor() ); + + // Determine the leftmost and rightmost points. + m_leftmost = 0; + m_rightmost = 1; + + p = m_points.first(); + while(p) + { + if (p != m_grab_point) + { + if(p->first> m_leftmost && p->first < x) + m_leftmost = p->first; + if(p->first < m_rightmost && p->first > x) + m_rightmost = p->first; + } + p = m_points.next(); + } + tqrepaint(false); +} + +void KCurve::mouseReleaseEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + if (e->button() != Qt::LeftButton) + return; + + setCursor( KCursor::arrowCursor() ); + m_dragging = false; + tqrepaint(false); + emit modified(); +} + +void KCurve::mouseMoveEvent ( TQMouseEvent * e ) +{ + if (m_readOnlyMode) return; + + double x = e->pos().x() / (float)width(); + double y = 1.0 - e->pos().y() / (float)height(); + + if (m_dragging == false) // If no point is selected set the the cursor tqshape if on top + { + double distance = 1000; + double ydistance = 1000; + TQPair *p = m_points.first(); + while(p) + { + if (fabs (x - p->first) < distance) + { + distance = fabs(x - p->first); + ydistance = fabs(y - p->second); + } + p = m_points.next(); + } + + if (distance * width() > 5 || ydistance * height() > 5) + setCursor( KCursor::arrowCursor() ); + else + setCursor( KCursor::crossCursor() ); + } + else // Else, drag the selected point + { + setCursor( KCursor::crossCursor() ); + + x += m_grabOffsetX; + y += m_grabOffsetY; + + if (x <= m_leftmost) + x = m_leftmost + 1E-4; // the addition so we can grab the dot later. + + if(x >= m_rightmost) + x = m_rightmost - 1E-4; + + if(y > 1.0) + y = 1.0; + + if(y < 0.0) + y = 0.0; + + m_grab_point->first = x; + m_grab_point->second = y; + + emit modified(); + } + + tqrepaint(false); +} + +double KCurve::getCurveValue(double x) +{ + return getCurveValue(m_points, x); +} + +double KCurve::getCurveValue(TQPtrList > &curve, double x) +{ + double t; + TQPair *p; + TQPair *p0,*p1,*p2,*p3; + double c0,c1,c2,c3; + double val; + + if(curve.count() == 0) + return 0.5; + + // First find curve segment + p = curve.first(); + if(x < p->first) + return p->second; + + p = curve.last(); + if(x >= p->first) + return p->second; + + // Find the four control points (two on each side of x) + p = curve.first(); + while(x >= p->first) + { + p = curve.next(); + } + curve.prev(); + + if((p0 = curve.prev()) == NULL) + p1 = p0 = curve.first(); + else + p1 = curve.next(); + + p2 = curve.next(); + if( (p = curve.next()) ) + p3 = p; + else + p3 = p2; + + // Calculate the value + t = (x - p1->first) / (p2->first - p1->first); + c2 = (p2->second - p0->second) * (p2->first-p1->first) / (p2->first-p0->first); + c3 = p1->second; + c0 = -2*p2->second + 2*c3 + c2 + (p3->second - p1->second) * (p2->first - p1->first) / (p3->first - p1->first); + c1 = p2->second - c3 - c2 - c0; + val = ((c0*t + c1)*t + c2)*t + c3; + + if(val < 0.0) + val = 0.0; + if(val > 1.0) + val = 1.0; + return val; +} + +TQPtrList > KCurve::getCurve() +{ + TQPtrList > outlist; + TQPair *p; + TQPair *outpoint; + + p = m_points.first(); + while(p) + { + outpoint = new TQPair(p->first, p->second); + outlist.append(outpoint); + p = m_points.next(); + } + return outlist; +} + +void KCurve::setCurve(TQPtrList >inlist) +{ + TQPair *p; + TQPair *inpoint; + + m_points.clear(); + + inpoint = inlist.first(); + while(inpoint) + { + p = new TQPair(inpoint->first, inpoint->second); + m_points.append(p); + inpoint = inlist.next(); + } +} + +void KCurve::leaveEvent( TQEvent * ) +{ +} + +#include "kcurve.moc" diff --git a/chalk/ui/kcurve.h b/chalk/ui/kcurve.h new file mode 100644 index 00000000..820b5f5a --- /dev/null +++ b/chalk/ui/kcurve.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * Copyright 2004-2005 by Gilles Caulier (original work as digikam curveswidget) + * Copyright 2005 by Casper Boemann (reworked to be generic) + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +#ifndef KCURVE_H +#define KCURVE_H + +// TQt includes. + +#include +#include +#include +#include +#include +class KRITAUI_EXPORT KCurve : public TQWidget +{ +Q_OBJECT + TQ_OBJECT + +public: + KCurve(TQWidget *tqparent = 0, const char *name = 0, WFlags f = 0); + + virtual ~KCurve(); + + void reset(void); + void setCurveGuide(TQColor color); + void setPixmap(TQPixmap pix); + + +signals: + + void modified(void); + +protected: + + void keyPressEvent(TQKeyEvent *); + void paintEvent(TQPaintEvent *); + void mousePressEvent (TQMouseEvent * e); + void mouseReleaseEvent ( TQMouseEvent * e ); + void mouseMoveEvent ( TQMouseEvent * e ); + void leaveEvent ( TQEvent * ); + +public: + static double getCurveValue(TQPtrList > &curve, double x); + double getCurveValue(double x); + + TQPtrList > getCurve(); + void setCurve(TQPtrList >inlist); + +private: + double m_leftmost; + double m_rightmost; + TQPair *m_grab_point; + bool m_dragging; + double m_grabOffsetX; + double m_grabOffsetY; + + bool m_readOnlyMode; + bool m_guideVisible; + TQColor m_colorGuide; + TQPtrList > m_points; + TQPixmap *m_pix; +}; + + +#endif /* KCURVE_H */ diff --git a/chalk/ui/kis_aboutdata.h b/chalk/ui/kis_aboutdata.h new file mode 100644 index 00000000..d06fd134 --- /dev/null +++ b/chalk/ui/kis_aboutdata.h @@ -0,0 +1,68 @@ +/* + * kis_aboutdata.h - part of Krayon + * + * Copyright (c) 1999-2000 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_ABOUT_DATA_H_ +#define KIS_ABOUT_DATA_H_ + +#include +#include +#include +#include + +KAboutData * newChalkAboutData() +{ + KAboutData * aboutData = new KAboutData( "chalk", + I18N_NOOP("Chalk"), + KOFFICE_VERSION_STRING, + I18N_NOOP("KOffice image manipulation application"), + KAboutData::License_GPL, + I18N_NOOP("(c) 1999-2006 The Chalk team.\n"), + "", + "http://www.koffice.org/chalk", + "submit@bugs.kde.org"); + aboutData->addAuthor("Adrian Page", 0, "Adrian.Page@tesco.net"); + aboutData->addAuthor("Alan Horkan", 0, "", "http://www.openclipart.org"); + aboutData->addAuthor("Bart Coppens", 0, "kde@bartcoppens.be"); + aboutData->addAuthor("Boudewijn Rempt", 0, "boud@valdyas.org", "http://www.valdyas.org/fading/index.cgi"); + aboutData->addAuthor("Carsten Pfeiffer", 0, "carpdjih@cetus.zrz.tu-berlin.de"); + aboutData->addAuthor("Casper Boemann", 0, "cbr@boemann.dk"); + aboutData->addAuthor("Clarence Dang", 0, "dang@kde.org"); + aboutData->addAuthor("Cyrille Berger", 0, "cyb@lepi.org"); + aboutData->addAuthor("Dirk Schoenberger", 0, "dirk.schoenberger@sz-online.de"); + aboutData->addAuthor("Danny Allen", 0 , "danny@dannyallen.co.uk"); + aboutData->addAuthor("Emanuele Tamponi", 0, "emanuele@valinor.it"); + aboutData->addAuthor("Gábor Lehel", 0, ""); + aboutData->addAuthor("John Califf",0, "jcaliff@compuzone.net"); + aboutData->addAuthor("Laurent Montel",0, "lmontel@mandrakesoft.com"); + aboutData->addAuthor("Matthias Elter", 0, "me@kde.org"); + aboutData->addAuthor("Melchior Franz", 0, "mfranz@kde.org"); + aboutData->addAuthor("Michael Koch", 0, "koch@kde.org"); + aboutData->addAuthor("Michael Thaler", 0, "michael.thaler@physik.tu-muenchen.de"); + aboutData->addAuthor("Patrick Julien", 0, "freak@codepimps.org"); + aboutData->addAuthor("Roger Larsson", 0, "roger.larsson@norran.net"); + aboutData->addAuthor("Sven Langkamp", 0, "longamp@reallygood.de"); + aboutData->addAuthor("Toshitaka Fujioka", 0, "fujioka@kde.org"); + aboutData->addAuthor("Thomas Zander", 0, "zander@kde.org"); + aboutData->addAuthor("Sander Koning", 0, "sanderkoning@kde.nl"); + aboutData->addAuthor("Ronan Zeegers",/*"icons"*/ 0,0); + aboutData->addAuthor("Frédéric Coiffier", 0, "frederic.coiffier@free.fr"); + return aboutData; +} + +#endif // KIS_ABOUT_DATA_H_ diff --git a/chalk/ui/kis_autobrush.cc b/chalk/ui/kis_autobrush.cc new file mode 100644 index 00000000..3d081188 --- /dev/null +++ b/chalk/ui/kis_autobrush.cc @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_autobrush.h" +#include +#include +#include +#include +#include +#include +#include + + +KisAutobrush::KisAutobrush(TQWidget *tqparent, const char* name, const TQString& caption) : KisWdgAutobrush(tqparent, name) +{ + setCaption(caption); + + m_linkSize = true; + m_linkFade = true; + + linkFadeToggled(m_linkSize); + linkSizeToggled(m_linkFade); + + connect(bnLinkSize, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(linkSizeToggled( bool ))); + connect(bnLinkFade, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(linkFadeToggled( bool ))); + + connect((TQObject*)comboBoxShape, TQT_SIGNAL(activated(int)), this, TQT_SLOT(paramChanged())); + spinBoxWidth->setMinValue(1); + connect(spinBoxWidth,TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxWidthChanged(int))); + spinBoxHeigth->setMinValue(1); + connect(spinBoxHeigth,TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxHeigthChanged(int))); + spinBoxHorizontal->setMinValue(0); + connect(spinBoxHorizontal,TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxHorizontalChanged(int))); + spinBoxVertical->setMinValue(0); + connect(spinBoxVertical,TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxVerticalChanged(int))); + + m_brsh = new TQImage(1,1,32); + Q_CHECK_PTR(m_brsh); + + paramChanged(); + + + connect(brushPreview, TQT_SIGNAL(clicked()), TQT_SLOT(paramChanged())); + +} + +void KisAutobrush::resizeEvent ( TQResizeEvent * ) +{ + brushPreview->setMinimumHeight(brushPreview->width()); // dirty hack ! + brushPreview->setMaximumHeight(brushPreview->width()); // dirty hack ! +} + +void KisAutobrush::activate() +{ + paramChanged(); +} + +void KisAutobrush::paramChanged() +{ + TQ_INT32 fh = TQMIN( spinBoxWidth->value()/2, spinBoxHorizontal->value() ) ; + TQ_INT32 fv = TQMIN( spinBoxHeigth->value()/2, spinBoxVertical->value() ); + KisAutobrushShape* kas; + + if(comboBoxShape->currentItem() == 0) // use index compare instead of comparing a translatable string + { + kas = new KisAutobrushCircleShape(spinBoxWidth->value(), spinBoxHeigth->value(), fh, fv); + Q_CHECK_PTR(kas); + + } else { + kas = new KisAutobrushRectShape(spinBoxWidth->value(), spinBoxHeigth->value(), fh, fv); + Q_CHECK_PTR(kas); + + } + kas->createBrush(m_brsh); + + TQPixmap p; + TQImage pi(*m_brsh); + double coeff = 1.0; + int bPw = brushPreview->width()-3; + if(pi.width() > bPw) + { + coeff = bPw /(double)pi.width(); + } + int bPh = brushPreview->height()-3; + if(pi.height() > coeff * bPh) + { + coeff = bPh /(double)pi.height(); + } + if( coeff < 1.0) + { + pi = pi.smoothScale( (int)(coeff * pi.width()) , (int)(coeff * pi.height())); + } + + p.convertFromImage(pi); + brushPreview->setPixmap(p); + KisAutobrushResource * resource = new KisAutobrushResource(*m_brsh); + Q_CHECK_PTR(resource); + + emit(activatedResource(resource)); + delete kas; +} +void KisAutobrush::spinBoxWidthChanged(int a) +{ + spinBoxHorizontal->setMaxValue(a/2); + if(m_linkSize) + { + spinBoxHeigth->setValue(a); + spinBoxVertical->setMaxValue(a/2); + } + this->paramChanged(); +} +void KisAutobrush::spinBoxHeigthChanged(int a) +{ + spinBoxVertical->setMaxValue(a/2); + if(m_linkSize) + { + spinBoxWidth->setValue(a); + spinBoxHorizontal->setMaxValue(a/2); + } + this->paramChanged(); +} +void KisAutobrush::spinBoxHorizontalChanged(int a) +{ + if(m_linkFade) + spinBoxVertical->setValue(a); + this->paramChanged(); +} +void KisAutobrush::spinBoxVerticalChanged(int a) +{ + if(m_linkFade) + spinBoxHorizontal->setValue(a); + this->paramChanged(); +} + +void KisAutobrush::linkSizeToggled(bool b) +{ + m_linkSize = b; + + KoImageResource kir; + if (b) { + bnLinkSize->setPixmap(kir.chain()); + } + else { + bnLinkSize->setPixmap(kir.chainBroken()); + } +} + +void KisAutobrush::linkFadeToggled(bool b) +{ + m_linkFade = b; + + KoImageResource kir; + if (b) { + bnLinkFade->setPixmap(kir.chain()); + } + else { + bnLinkFade->setPixmap(kir.chainBroken()); + } +} + + +#include "kis_autobrush.moc" diff --git a/chalk/ui/kis_autobrush.h b/chalk/ui/kis_autobrush.h new file mode 100644 index 00000000..92b8509d --- /dev/null +++ b/chalk/ui/kis_autobrush.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_AUTOBRUSH_H_ +#define _KIS_AUTOBRUSH_H_ + +#include +#include "wdgautobrush.h" +#include + +class KisAutobrush : public KisWdgAutobrush +{ + Q_OBJECT + TQ_OBJECT +public: + KisAutobrush(TQWidget *tqparent, const char* name, const TQString& caption); + void activate(); + +signals: + void activatedResource(KisResource *r); + +private slots: + void paramChanged(); + void spinBoxWidthChanged(int ); + void spinBoxHeigthChanged(int ); + void spinBoxHorizontalChanged(int); + void spinBoxVerticalChanged(int); + void linkSizeToggled(bool); + void linkFadeToggled(bool); + +protected: + virtual void resizeEvent ( TQResizeEvent * ); + +private: + TQImage* m_brsh; + bool m_linkSize; + bool m_linkFade; +}; + + +#endif diff --git a/chalk/ui/kis_autogradient.cc b/chalk/ui/kis_autogradient.cc new file mode 100644 index 00000000..86b755f9 --- /dev/null +++ b/chalk/ui/kis_autogradient.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_autogradient.h" + +#include +#include + +#include +#include +#include "kis_int_spinbox.h" +#include "kis_gradient.h" +#include "kis_autogradient_resource.h" + +#include "kis_gradient_slider_widget.h" + +/****************************** KisAutogradient ******************************/ + +KisAutogradient::KisAutogradient(TQWidget *tqparent, const char* name, const TQString& caption) : KisWdgAutogradient(tqparent, name) +{ + setCaption(caption); + m_autogradientResource = new KisAutogradientResource(); + m_autogradientResource->createSegment( INTERP_LINEAR, COLOR_INTERP_RGB, 0.0, 1.0, 0.5, TQt::black, TQt::white ); + connect(gradientSlider, TQT_SIGNAL( sigSelectedSegment( KisGradientSegment* ) ), TQT_SLOT( slotSelectedSegment(KisGradientSegment*) )); + connect(gradientSlider, TQT_SIGNAL( sigChangedSegment(KisGradientSegment*) ), TQT_SLOT( slotChangedSegment(KisGradientSegment*) )); + gradientSlider->setGradientResource( m_autogradientResource ); + connect(comboBoxColorInterpolationType, TQT_SIGNAL( activated(int) ), TQT_SLOT( slotChangedColorInterpolation(int) )); + connect(comboBoxInterpolationType, TQT_SIGNAL( activated(int) ), TQT_SLOT( slotChangedInterpolation(int) )); + connect(leftColorButton, TQT_SIGNAL( changed(const TQColor&) ), TQT_SLOT( slotChangedLeftColor(const TQColor&) )); + connect(rightColorButton, TQT_SIGNAL( changed(const TQColor&) ), TQT_SLOT( slotChangedRightColor(const TQColor&) )); + +// intNumInputLeftOpacity->setRange( 0, 100, false); + connect(intNumInputLeftOpacity, TQT_SIGNAL( valueChanged(int) ), TQT_SLOT( slotChangedLeftOpacity(int) )); +// intNumInputRightOpacity->setRange( 0, 100, false); + connect(intNumInputRightOpacity, TQT_SIGNAL( valueChanged(int) ), TQT_SLOT( slotChangedRightOpacity(int) )); + +} + +void KisAutogradient::activate() +{ + paramChanged(); +} + +void KisAutogradient::slotSelectedSegment(KisGradientSegment* segment) +{ + leftColorButton->setColor( segment->startColor().color() ); + rightColorButton->setColor( segment->endColor().color() ); + comboBoxColorInterpolationType->setCurrentItem( segment->colorInterpolation() ); + comboBoxInterpolationType->setCurrentItem( segment->interpolation() ); + + int leftOpacity = tqRound(segment->startColor().alpha() * 100); + intNumInputLeftOpacity->setValue( leftOpacity ); + + int rightOpacity = tqRound(segment->endColor().alpha() * 100); + intNumInputRightOpacity->setValue( rightOpacity ); + + paramChanged(); +} + +void KisAutogradient::slotChangedSegment(KisGradientSegment*) +{ + paramChanged(); +} + +void KisAutogradient::slotChangedInterpolation(int type) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setInterpolation( type ); + gradientSlider->update(); + + paramChanged(); +} + +void KisAutogradient::slotChangedColorInterpolation(int type) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setColorInterpolation( type ); + gradientSlider->update(); + + paramChanged(); +} + +void KisAutogradient::slotChangedLeftColor( const TQColor& color) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setStartColor( Color( color, segment->startColor().alpha() ) ); + gradientSlider->update(); + + paramChanged(); +} + +void KisAutogradient::slotChangedRightColor( const TQColor& color) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setEndColor( Color( color, segment->endColor().alpha() ) ); + gradientSlider->tqrepaint(); + + paramChanged(); +} + +void KisAutogradient::slotChangedLeftOpacity( int value ) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setStartColor( Color( segment->startColor().color(), (double)value / 100 ) ); + gradientSlider->tqrepaint(false); + + paramChanged(); +} + +void KisAutogradient::slotChangedRightOpacity( int value ) +{ + KisGradientSegment* segment = gradientSlider->selectedSegment(); + if(segment) + segment->setEndColor( Color( segment->endColor().color(), (double)value / 100 ) ); + gradientSlider->tqrepaint(false); + + paramChanged(); +} + +void KisAutogradient::paramChanged() +{ + m_autogradientResource->updatePreview (); + emit activatedResource( m_autogradientResource ); +} + +#include "kis_autogradient.moc" diff --git a/chalk/ui/kis_autogradient.h b/chalk/ui/kis_autogradient.h new file mode 100644 index 00000000..7399aa67 --- /dev/null +++ b/chalk/ui/kis_autogradient.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_AUTOGRADIENT_H_ +#define _KIS_AUTOGRADIENT_H_ + +#include "wdgautogradient.h" + +class KisResource; +class KisGradientSegment; +class KisAutogradientResource; + +class KisAutogradient : public KisWdgAutogradient +{ + Q_OBJECT + TQ_OBJECT + + public: + KisAutogradient(TQWidget *tqparent, const char* name, const TQString& caption); + void activate(); + signals: + void activatedResource(KisResource *r); + private: + KisAutogradientResource* m_autogradientResource; + private slots: + void slotSelectedSegment(KisGradientSegment* segment); + void slotChangedSegment(KisGradientSegment* segment); + void slotChangedInterpolation(int type); + void slotChangedColorInterpolation(int type); + void slotChangedLeftColor( const TQColor& color); + void slotChangedRightColor( const TQColor& color); + void slotChangedLeftOpacity( int value ); + void slotChangedRightOpacity( int value ); + void paramChanged(); +}; + +#endif diff --git a/chalk/ui/kis_birdeye_box.cc b/chalk/ui/kis_birdeye_box.cc new file mode 100644 index 00000000..1484563f --- /dev/null +++ b/chalk/ui/kis_birdeye_box.cc @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2004 Kivio Team + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tqlayout.h" +#include "tqlabel.h" +#include "tqpixmap.h" +#include "tqpainter.h" +#include "tqimage.h" +#include "config.h" +#include LCMS_HEADER +#include "klocale.h" +#include "tqtooltip.h" + +#include "kis_view.h" +#include "kis_doc.h" +#include "kis_canvas_controller.h" +#include "kis_birdeye_box.h" +#include "kis_double_widget.h" +#include "kis_canvas.h" +#include "kis_image.h" +#include "kis_rect.h" +#include "kis_iterators_pixel.h" + +#include "kobirdeyepanel.h" + +namespace { + + class CanvasAdapter : public KoCanvasAdapter { + + public: + CanvasAdapter(KisCanvasSubject * canvasSubject) : KoCanvasAdapter(), m_canvasSubject(canvasSubject) {} + virtual ~CanvasAdapter() {} + + public: + + virtual KoRect visibleArea() + { + if (!m_canvasSubject->currentImg()) return KoRect(0,0,0,0); + + KisCanvasController * c = m_canvasSubject->canvasController(); + + if (c && c->kiscanvas()) + return c->viewToWindow(KisRect(0, 0, c->kiscanvas()->width(), c->kiscanvas()->height())); + else + return KoRect(0,0,0,0); + } + + virtual double zoomFactor() + { + return m_canvasSubject->zoomFactor(); + } + + virtual TQRect size() + { + if (!m_canvasSubject->currentImg()) return TQRect(0,0,0,0); + + return TQRect(0, 0, m_canvasSubject->currentImg()->width(), m_canvasSubject->currentImg()->height()); + } + + virtual void setViewCenterPoint(double x, double y) + { + m_canvasSubject->canvasController()->zoomAroundPoint(x, y, m_canvasSubject->zoomFactor()); + } + + private: + + KisCanvasSubject * m_canvasSubject; + + }; + + class ZoomListener : public KoZoomAdapter { + + public: + + ZoomListener(KisCanvasController * canvasController) + : KoZoomAdapter() + , m_canvasController(canvasController) {} + virtual ~ZoomListener() {} + + public: + + void zoomTo( double x, double y, double factor ) { m_canvasController->zoomAroundPoint(x, y, factor); } + void zoomIn() { m_canvasController->zoomIn(); } + void zoomOut() { m_canvasController->zoomOut(); } + double getMinZoom() { return (1.0 / 500); } + double getMaxZoom() { return 16.0; } + + private: + + KisCanvasController * m_canvasController; + + }; + + class ThumbnailProvider : public KoThumbnailAdapter { + + public: + ThumbnailProvider(KisImageSP image, KisCanvasSubject* canvasSubject) + : KoThumbnailAdapter() + , m_image(image) + , m_canvasSubject(canvasSubject) {} + + virtual ~ThumbnailProvider() {} + + public: + + virtual TQSize pixelSize() + { + if (!m_image) return TQSize(0, 0); + return TQSize(m_image->width(), m_image->height()); + } + + virtual TQImage image(TQRect r, TQSize thumbnailSize) + { + if (!m_image || r.isEmpty() || thumbnailSize.width() == 0 || thumbnailSize.height() == 0) { + return TQImage(); + } + + KisPaintDevice thumbnailRect(m_image->colorSpace(), "thumbnailRect"); + KisPaintDeviceSP mergedImage = m_image->projection(); + + TQ_INT32 imageWidth = m_image->width(); + TQ_INT32 imageHeight = m_image->height(); + TQ_UINT32 pixelSize = m_image->colorSpace()->pixelSize(); + + for (TQ_INT32 y = 0; y < r.height(); ++y) { + + KisHLineIteratorPixel it = thumbnailRect.createHLineIterator(0, y, r.width(), true); + TQ_INT32 thumbnailY = r.y() + y; + TQ_INT32 thumbnailX = r.x(); + TQ_INT32 imageY = (thumbnailY * imageHeight) / thumbnailSize.height(); + KisHLineIteratorPixel srcIt = mergedImage -> createHLineIterator(0, imageY, imageWidth, false); + + while (!it.isDone()) { + + TQ_INT32 imageX = (thumbnailX * imageWidth) / thumbnailSize.width(); + TQ_INT32 dx = imageX - srcIt.x(); + srcIt += dx; + + //KisColor pixelColor = mergedImage->colorAt(imageX, imageY); + memcpy(it.rawData(), srcIt.rawData(), pixelSize); + + ++it; + ++thumbnailX; + } + } + + return thumbnailRect.convertToTQImage(m_canvasSubject->monitorProfile(), 0, 0, r.width(), r.height(), + m_canvasSubject->HDRExposure()); + } + + void setImage(KisImageSP image) + { + m_image = image; + } + private: + + KisImageSP m_image; + KisCanvasSubject * m_canvasSubject; + + }; + +} + +KisBirdEyeBox::KisBirdEyeBox(KisView * view, TQWidget* tqparent, const char* name) + : TQWidget(tqparent, name) + , m_view(view) + , m_subject(view->canvasSubject()) +{ + TQVBoxLayout * l = new TQVBoxLayout(this); + + m_image = m_subject->currentImg(); + + m_zoomAdapter = new ZoomListener(m_subject->canvasController()); // The birdeye panel deletes + KoThumbnailAdapter * ktp = new ThumbnailProvider(m_image, m_subject); // The birdeye panel deletes + KoCanvasAdapter * kpc = new CanvasAdapter(m_subject); // The birdeye panel deletes + + m_birdEyePanel = new KoBirdEyePanel(m_zoomAdapter, ktp, kpc, this); + + connect(view, TQT_SIGNAL(cursorPosition( TQ_INT32, TQ_INT32 )), m_birdEyePanel, TQT_SLOT(cursorPosChanged( TQ_INT32, TQ_INT32 ))); + connect(view, TQT_SIGNAL(viewTransformationsChanged()), m_birdEyePanel, TQT_SLOT(slotViewTransformationChanged())); + + l->addWidget(m_birdEyePanel); + + TQHBoxLayout * hl = new TQHBoxLayout(l); + + m_exposureLabel = new TQLabel(i18n("Exposure:"), this); + hl->addWidget(m_exposureLabel); + + m_exposureDoubleWidget = new KisDoubleWidget(-10, 10, this); + m_exposureDoubleWidget->tqsetSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Fixed); + hl->addWidget(m_exposureDoubleWidget); + TQToolTip::add(m_exposureDoubleWidget, i18n("Select the exposure (stops) for HDR images")); + l->addItem(new TQSpacerItem(0, 1, TQSizePolicy::Minimum, TQSizePolicy::MinimumExpanding)); + + m_exposureDoubleWidget->setPrecision(1); + m_exposureDoubleWidget->setValue(0); + m_exposureDoubleWidget->setLineStep(0.1); + m_exposureDoubleWidget->setPageStep(1); + + connect(m_exposureDoubleWidget, TQT_SIGNAL(valueChanged(double)), TQT_SLOT(exposureValueChanged(double))); + connect(m_exposureDoubleWidget, TQT_SIGNAL(sliderPressed()), TQT_SLOT(exposureSliderPressed())); + connect(m_exposureDoubleWidget, TQT_SIGNAL(sliderReleased()), TQT_SLOT(exposureSliderReleased())); + + m_draggingExposureSlider = false; + + Q_ASSERT(m_subject->document() != 0); + connect(m_subject->document(), TQT_SIGNAL(sigCommandExecuted()), TQT_SLOT(slotDocCommandExecuted())); + + if (m_image) { + connect(m_image, TQT_SIGNAL(sigImageUpdated(TQRect)), TQT_SLOT(slotImageUpdated(TQRect))); + } +} + +KisBirdEyeBox::~KisBirdEyeBox() +{ + // Huh? Why does this cause a crash? + // delete m_zoomAdapter; +} + +void KisBirdEyeBox::setImage(KisImageSP image) +{ + if (m_image) { + m_image->disconnect(this); + } + + m_image = image; + + KoThumbnailAdapter * ktp = new ThumbnailProvider(m_image, m_subject); + m_birdEyePanel->setThumbnailProvider(ktp); + + if (m_image) { + connect(m_image, TQT_SIGNAL(sigImageUpdated(TQRect)), TQT_SLOT(slotImageUpdated(TQRect))); + connect(m_image, TQT_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)), TQT_SLOT(slotImageSizeChanged(TQ_INT32, TQ_INT32))); + connect(m_image, TQT_SIGNAL(sigColorSpaceChanged(KisColorSpace *)), TQT_SLOT(slotImageColorSpaceChanged(KisColorSpace *))); + m_birdEyePanel->slotUpdate(m_image->bounds()); + slotImageColorSpaceChanged(m_image->colorSpace()); + } +} + +void KisBirdEyeBox::slotDocCommandExecuted() +{ + if (m_image) { + if (!m_dirtyRect.isEmpty()) { + m_birdEyePanel->slotUpdate(m_dirtyRect); + } + m_dirtyRect = TQRect(); + } +} + +void KisBirdEyeBox::slotImageUpdated(TQRect r) +{ + m_dirtyRect |= r; +} + +void KisBirdEyeBox::slotImageSizeChanged(TQ_INT32 /*w*/, TQ_INT32 /*h*/) +{ + if (m_image) { + m_birdEyePanel->slotUpdate(m_image->bounds()); + } +} + +void KisBirdEyeBox::slotImageColorSpaceChanged(KisColorSpace *cs) +{ + if (cs->hasHighDynamicRange()) { + m_exposureDoubleWidget->show(); + m_exposureLabel->show(); + } else { + m_exposureDoubleWidget->hide(); + m_exposureLabel->hide(); + } +} + +void KisBirdEyeBox::exposureValueChanged(double exposure) +{ + if (!m_draggingExposureSlider) { + m_subject->setHDRExposure(exposure); + + if (m_image && m_image->colorSpace()->hasHighDynamicRange()) { + m_birdEyePanel->slotUpdate(m_image->bounds()); + } + } +} + +void KisBirdEyeBox::exposureSliderPressed() +{ + m_draggingExposureSlider = true; +} + +void KisBirdEyeBox::exposureSliderReleased() +{ + m_draggingExposureSlider = false; + exposureValueChanged(m_exposureDoubleWidget->value()); +} + +#include "kis_birdeye_box.moc" diff --git a/chalk/ui/kis_birdeye_box.h b/chalk/ui/kis_birdeye_box.h new file mode 100644 index 00000000..b9550474 --- /dev/null +++ b/chalk/ui/kis_birdeye_box.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004 Kivio Team + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_BIRDEYE_BOX_H +#define KIS_BIRDEYE_BOX_H + +#include "tqwidget.h" + +#include "kis_types.h" + +class KoBirdEyePanel; +class KisDoubleWidget; +class KisView; +class KisCanvasSubject; +class KoZoomAdapter; +class KisColorSpace; + +class KisBirdEyeBox : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + +public: + + KisBirdEyeBox(KisView * view, TQWidget * tqparent = 0, const char* name=0); + ~KisBirdEyeBox(); + + void setImage(KisImageSP image); + +public slots: + void slotDocCommandExecuted(); + void slotImageUpdated(TQRect r); + void slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h); + void slotImageColorSpaceChanged(KisColorSpace *cs); + +protected slots: + void exposureValueChanged(double exposure); + void exposureSliderPressed(); + void exposureSliderReleased(); + +private: + KoBirdEyePanel * m_birdEyePanel; + KisDoubleWidget * m_exposureDoubleWidget; + TQLabel *m_exposureLabel; + KisView * m_view; + KisCanvasSubject * m_subject; + bool m_draggingExposureSlider; + KoZoomAdapter * m_zoomAdapter; + KisImageSP m_image; + TQRect m_dirtyRect; +}; + +#endif // KIS_BIRDEYE_BOX_H diff --git a/chalk/ui/kis_boundary_painter.cc b/chalk/ui/kis_boundary_painter.cc new file mode 100644 index 00000000..b07bcb51 --- /dev/null +++ b/chalk/ui/kis_boundary_painter.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "kis_boundary.h" +#include "kis_boundary_painter.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" + +TQPixmap KisBoundaryPainter::createPixmap(const KisBoundary& boundary, int w, int h) +{ + TQPixmap target(w, h); + KisCanvasPainter painter(TQT_TQPAINTDEVICE(&target)); + + painter.eraseRect(0, 0, w, h); + + paint(boundary, painter); + + painter.end(); + return target; +} + +void KisBoundaryPainter::paint(const KisBoundary& boundary, KisCanvasPainter& painter) +{ + KisBoundary::PointPairListList::const_iterator it = boundary.m_horSegments.constBegin(); + KisBoundary::PointPairListList::const_iterator end = boundary.m_horSegments.constEnd(); + + //Qt::Horizontal + while (it != end) { + KisBoundary::PointPairList::const_iterator lineIt = (*it).constBegin(); + KisBoundary::PointPairList::const_iterator lineEnd = (*it).constEnd(); + while (lineIt != lineEnd) { + int x1 = (*lineIt).first.floorX(); + int y = (*lineIt).first.floorY(); + int x2 = x1 + (*lineIt).second; + + painter.drawLine(x1, y, x2, y); + painter.drawPoint(x2, y); + + ++lineIt; + } + ++it; + } + + //Qt::Vertical + it = boundary.m_vertSegments.constBegin(); + end = boundary.m_vertSegments.constEnd(); + + while (it != end) { + KisBoundary::PointPairList::const_iterator lineIt = (*it).constBegin(); + KisBoundary::PointPairList::const_iterator lineEnd = (*it).constEnd(); + while (lineIt != lineEnd) { + int x = (*lineIt).first.floorX(); + int y1 = (*lineIt).first.floorY(); + int y2 = y1 + (*lineIt).second; + + painter.drawLine(x, y1, x, y2); + painter.drawPoint(x, y2); + + ++lineIt; + } + ++it; + } +} + diff --git a/chalk/ui/kis_boundary_painter.h b/chalk/ui/kis_boundary_painter.h new file mode 100644 index 00000000..c8f18cd4 --- /dev/null +++ b/chalk/ui/kis_boundary_painter.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_BOUNDARY_PAINTER_H_ +#define _KIS_BOUNDARY_PAINTER_H_ + +#include + +class KisBoundary; +class KisCanvasPainter; + +class KRITACORE_EXPORT KisBoundaryPainter { +public: + static void paint(const KisBoundary& boundary, KisCanvasPainter& painter); + static TQPixmap createPixmap(const KisBoundary& boundary, int w, int h); +}; + +#endif // _KIS_BOUNDARY_PAINTER_H_ + diff --git a/chalk/ui/kis_brush_chooser.cc b/chalk/ui/kis_brush_chooser.cc new file mode 100644 index 00000000..69aeafdf --- /dev/null +++ b/chalk/ui/kis_brush_chooser.cc @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include "kis_double_widget.h" +#include "kis_brush_chooser.h" +#include "kis_global.h" +#include "kis_icon_item.h" +#include "kis_brush.h" + +KisBrushChooser::KisBrushChooser(TQWidget *tqparent, const char *name) + : super(tqparent, name) +{ + m_lbSpacing = new TQLabel(i18n("Spacing:"), this); + m_slSpacing = new KisDoubleWidget(0.0, 10, this, "double_widget"); + m_slSpacing->setTickmarks(TQSlider::Below); + m_slSpacing->setTickInterval(1); + TQObject::connect(m_slSpacing, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(slotSetItemSpacing(double))); + + m_chkColorMask = new TQCheckBox(i18n("Use color as tqmask"), this); + TQObject::connect(m_chkColorMask, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetItemUseColorAsMask(bool))); + + m_lbName = new TQLabel(this); + + TQVBoxLayout *mainLayout = new TQVBoxLayout(this, 2, -1, "main tqlayout"); + + mainLayout->addWidget(m_lbName); + mainLayout->addWidget(chooserWidget(), 10); + + TQGridLayout *spacingLayout = new TQGridLayout( 2, 2); + + mainLayout->addLayout(spacingLayout, 1); + + spacingLayout->addWidget(m_lbSpacing, 0, 0); + spacingLayout->addWidget(m_slSpacing, 0, 1); + + spacingLayout->addMultiCellWidget(m_chkColorMask, 1, 1, 0, 1); +} + +KisBrushChooser::~KisBrushChooser() +{ +} + +void KisBrushChooser::slotSetItemSpacing(double spacingValue) +{ + KisIconItem *item = static_cast(currentItem()); + + if (item) { + KisBrush *brush = static_cast(item->resource()); + brush->setSpacing(spacingValue); + } +} + +void KisBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask) +{ + KisIconItem *item = static_cast(currentItem()); + + if (item) { + KisBrush *brush = static_cast(item->resource()); + brush->setUseColorAsMask(useColorAsMask); + item->updatePixmaps(); + emit selected(currentItem()); + } +} + +void KisBrushChooser::update(KoIconItem *item) +{ + KisIconItem *kisItem = static_cast(item); + + if (kisItem) { + KisBrush *brush = static_cast(kisItem->resource()); + + TQString text = TQString("%1 (%2 x %3)").tqarg(brush->name()).tqarg(brush->width()).tqarg(brush->height()); + + m_lbName->setText(text); + m_slSpacing->setValue(brush->spacing()); + m_chkColorMask->setChecked(brush->useColorAsMask()); + m_chkColorMask->setEnabled(brush->hasColor()); + } +} + +#include "kis_brush_chooser.moc" + diff --git a/chalk/ui/kis_brush_chooser.h b/chalk/ui/kis_brush_chooser.h new file mode 100644 index 00000000..99438e70 --- /dev/null +++ b/chalk/ui/kis_brush_chooser.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_BRUSH_CHOOSER_H_ +#define KIS_BRUSH_CHOOSER_H_ + +#include "kis_itemchooser.h" + +class TQLabel; +class TQCheckBox; + +class KisDoubleWidget; + +class KisBrushChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + TQ_OBJECT + +public: + KisBrushChooser(TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisBrushChooser(); + +protected: + virtual void update(KoIconItem *item); + +private slots: + void slotSetItemSpacing(double spacing); + void slotSetItemUseColorAsMask(bool); + +private: + TQLabel *m_lbName; + TQLabel *m_lbSpacing; + KisDoubleWidget *m_slSpacing; + TQCheckBox *m_chkColorMask; +}; + +#endif // KIS_BRUSH_CHOOSER_H_ + diff --git a/chalk/ui/kis_button_event.h b/chalk/ui/kis_button_event.h new file mode 100644 index 00000000..f9b6a385 --- /dev/null +++ b/chalk/ui/kis_button_event.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_BUTTON_EVENT_H_ +#define KIS_BUTTON_EVENT_H_ + +#include "kis_event.h" + +class KisButtonEvent : public KisEvent { + typedef KisEvent super; +public: + TQt::ButtonState button() const { return m_button; } + +protected: + KisButtonEvent() {} + KisButtonEvent(enumEventType type, + KisInputDevice device, + const KisPoint& pos, + const KisPoint& globalPos, + double pressure, + double xTilt, double yTilt, + TQt::ButtonState button, + TQt::ButtonState state) + : super(type, device, pos, globalPos, pressure, xTilt, yTilt, state) + , m_button(button) {} + + TQt::ButtonState m_button; +}; + +#endif // KIS_BUTTON_EVENT_H_ + diff --git a/chalk/ui/kis_button_press_event.h b/chalk/ui/kis_button_press_event.h new file mode 100644 index 00000000..20dfafc6 --- /dev/null +++ b/chalk/ui/kis_button_press_event.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_BUTTON_PRESS_EVENT_H_ +#define KIS_BUTTON_PRESS_EVENT_H_ + +#include "kis_button_event.h" + +class KisButtonPressEvent : public KisButtonEvent { + typedef KisButtonEvent super; +public: + KisButtonPressEvent() {} + KisButtonPressEvent(KisInputDevice device, const KisPoint& pos, const KisPoint& globalPos, double pressure, double xTilt, double yTilt, TQt::ButtonState button, TQt::ButtonState state) : super(ButtonPressEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_BUTTON_PRESS_EVENT_H_ + diff --git a/chalk/ui/kis_button_release_event.h b/chalk/ui/kis_button_release_event.h new file mode 100644 index 00000000..f6da4dfd --- /dev/null +++ b/chalk/ui/kis_button_release_event.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_BUTTON_RELEASE_EVENT_H_ +#define KIS_BUTTON_RELEASE_EVENT_H_ + +#include "kis_button_event.h" + +class KisButtonReleaseEvent : public KisButtonEvent { + typedef KisButtonEvent super; +public: + KisButtonReleaseEvent() {} + KisButtonReleaseEvent(KisInputDevice device, const KisPoint& pos, const KisPoint& globalPos, double pressure, double xTilt, double yTilt, TQt::ButtonState button, TQt::ButtonState state) : super(ButtonReleaseEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_BUTTON_RELEASE_EVENT_H_ + diff --git a/chalk/ui/kis_canvas.cc b/chalk/ui/kis_canvas.cc new file mode 100644 index 00000000..01ca372e --- /dev/null +++ b/chalk/ui/kis_canvas.cc @@ -0,0 +1,1355 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004-2006 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + + Some of the X11-specific event handling code is based upon code from + src/kernel/qapplication_x11.cpp from the TQt GUI Toolkit and is subject + to the following license and copyright: + + **************************************************************************** +** +** +** Implementation of X11 startup routines and event handling +** +** Created : 931029 +** +** Copyright (C) 1992-2003 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses for Unix/X11 may use this file in accordance with the TQt Commercial +** License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include + +#include "kis_canvas.h" +#include "kis_cursor.h" +#include "kis_move_event.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_double_click_event.h" +#include "kis_config.h" +#include "kis_qpaintdevice_canvas.h" +#include "kis_opengl_canvas.h" +#include "kis_config.h" +#include "kis_input_device.h" +#include "fixx11h.h" + +#ifdef Q_WS_X11 + +#include +#include + +#include + +bool KisCanvasWidget::X11SupportInitialised = false; +long KisCanvasWidget::X11AltMask = 0; +long KisCanvasWidget::X11MetaMask = 0; + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + +int KisCanvasWidget::X11DeviceMotionNotifyEvent = -1; +int KisCanvasWidget::X11DeviceButtonPressEvent = -1; +int KisCanvasWidget::X11DeviceButtonReleaseEvent = -1; +int KisCanvasWidget::X11ProximityInEvent = -1; +int KisCanvasWidget::X11ProximityOutEvent = -1; + +//X11XIDTabletDeviceMap KisCanvasWidget::X11TabletDeviceMap; +std::map KisCanvasWidget::X11TabletDeviceMap; + +#endif // EXTENDED_X11_TABLET_SUPPORT + +#endif // Q_WS_X11 + +KisCanvasWidget::KisCanvasWidget() +{ + m_enableMoveEventCompressionHint = false; + m_lastPressure = 0; + +#ifdef Q_WS_X11 + if (!X11SupportInitialised) { + initX11Support(); + } + + m_lastRootX = -1; + m_lastRootY = -1; +#endif +} + +KisCanvasWidget::~KisCanvasWidget() +{ +} + +void KisCanvasWidget::widgetGotPaintEvent(TQPaintEvent *e) +{ + emit sigGotPaintEvent(e); +} + +void KisCanvasWidget::widgetGotMousePressEvent(TQMouseEvent *e) +{ + KisButtonPressEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + buttonPressEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseReleaseEvent(TQMouseEvent *e) +{ + KisButtonReleaseEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + buttonReleaseEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseDoubleClickEvent(TQMouseEvent *e) +{ + KisDoubleClickEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->button(), e->state()); + doubleClickEvent(&ke); +} + +void KisCanvasWidget::widgetGotMouseMoveEvent(TQMouseEvent *e) +{ + KisMoveEvent ke(KisInputDevice::mouse(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->state()); + moveEvent(&ke); +} + +void KisCanvasWidget::widgetGotTabletEvent(TQTabletEvent *e) +{ + KisInputDevice device; + + switch (e->device()) { + default: + case TQTabletEvent::NoDevice: + case TQTabletEvent::Stylus: + device = KisInputDevice::stylus(); + break; + case TQTabletEvent::Puck: + device = KisInputDevice::puck(); + break; + case TQTabletEvent::Eraser: + device = KisInputDevice::eraser(); + break; + } + + double pressure = e->pressure() / 255.0; + + if (e->type() == TQEvent::TabletPress) { + KisButtonPressEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton); + translateTabletEvent(&ke); + } + else + if (e->type() == TQEvent::TabletRelease) { + KisButtonReleaseEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), Qt::LeftButton, Qt::NoButton); + translateTabletEvent(&ke); + } + else { + KisMoveEvent ke(device, KisPoint(e->pos()), KisPoint(e->globalPos()), pressure, e->xTilt(), e->yTilt(), Qt::NoButton); + translateTabletEvent(&ke); +#ifdef Q_WS_X11 + // Fix the problem that when you change from using a tablet device to the mouse, + // the first mouse button event is not recognised. This is because we handle + // X11 core mouse move events directly so TQt does not get to see them. This breaks + // the tablet event accept/ignore mechanism, causing TQt to consume the first + // mouse button event it sees, instead of a mouse move. 'Ignoring' tablet move events + // stops TQt from stealing the next mouse button event. This does not affect the + // tablet aware tools as they do not care about mouse moves while the tablet device is + // drawing. + e->ignore(); +#endif + } +} + +void KisCanvasWidget::widgetGotEnterEvent(TQEvent *e) +{ + emit sigGotEnterEvent(e); +} + +void KisCanvasWidget::widgetGotLeaveEvent(TQEvent *e) +{ + emit sigGotLeaveEvent(e); +} + +void KisCanvasWidget::widgetGotWheelEvent(TQWheelEvent *e) +{ + emit sigGotMouseWheelEvent(e); +} + +void KisCanvasWidget::widgetGotKeyPressEvent(TQKeyEvent *e) +{ + emit sigGotKeyPressEvent(e); +} + +void KisCanvasWidget::widgetGotKeyReleaseEvent(TQKeyEvent *e) +{ + emit sigGotKeyReleaseEvent(e); +} + +void KisCanvasWidget::widgetGotDragEnterEvent(TQDragEnterEvent *e) +{ + emit sigGotDragEnterEvent(e); +} + +void KisCanvasWidget::widgetGotDropEvent(TQDropEvent *e) +{ + emit sigGotDropEvent(e); +} + +void KisCanvasWidget::moveEvent(KisMoveEvent *e) +{ + emit sigGotMoveEvent(e); +} + +void KisCanvasWidget::buttonPressEvent(KisButtonPressEvent *e) +{ + TQWidget *widget = dynamic_cast(this); + Q_ASSERT(widget != 0); + + if (widget) { + widget->setFocus(); + } + + emit sigGotButtonPressEvent(e); +} + +void KisCanvasWidget::buttonReleaseEvent(KisButtonReleaseEvent *e) +{ + emit sigGotButtonReleaseEvent(e); +} + +void KisCanvasWidget::doubleClickEvent(KisDoubleClickEvent *e) +{ + emit sigGotDoubleClickEvent(e); +} + +void KisCanvasWidget::translateTabletEvent(KisEvent *e) +{ + bool checkThresholdOnly = false; + + if (e->type() == KisEvent::ButtonPressEvent || e->type() == KisEvent::ButtonReleaseEvent) { + KisButtonEvent *b = static_cast(e); + + if (b->button() == Qt::MidButton || b->button() == Qt::RightButton) { + + if (e->type() == KisEvent::ButtonPressEvent) { + buttonPressEvent(static_cast(e)); + } else { + buttonReleaseEvent(static_cast(e)); + } + + checkThresholdOnly = true; + } + } + + // Use pressure threshold to detect 'left button' press/release + if (e->pressure() >= PRESSURE_THRESHOLD && m_lastPressure < PRESSURE_THRESHOLD) { + KisButtonPressEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), Qt::LeftButton, e->state()); + buttonPressEvent(&ke); + } else if (e->pressure() < PRESSURE_THRESHOLD && m_lastPressure >= PRESSURE_THRESHOLD) { + KisButtonReleaseEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), Qt::LeftButton, e->state()); + buttonReleaseEvent(&ke); + } else { + if (!checkThresholdOnly) { + KisMoveEvent ke(e->device(), e->pos(), e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->state()); + moveEvent(&ke); + } + } + + m_lastPressure = e->pressure(); +} + +#ifdef Q_WS_X11 + +void KisCanvasWidget::initX11Support() +{ + if (X11SupportInitialised) + { + return; + } + + X11SupportInitialised = true; + + Display *x11Display = TQApplication::desktop()->x11Display(); + + // Look at the modifier mapping and get the correct tqmasks for alt/meta + XModifierKeymap *map = XGetModifierMapping(x11Display); + + if (map) { + int mapIndex = 0; + + for (int tqmaskIndex = 0; tqmaskIndex < 8; tqmaskIndex++) { + for (int i = 0; i < map->max_keypermod; i++) { + if (map->modifiermap[mapIndex]) { + + KeySym sym = XKeycodeToKeysym(x11Display, map->modifiermap[mapIndex], 0); + + if (X11AltMask == 0 && (sym == XK_Alt_L || sym == XK_Alt_R)) { + X11AltMask = 1 << tqmaskIndex; + } + if (X11MetaMask == 0 && (sym == XK_Meta_L || sym == XK_Meta_R)) { + X11MetaMask = 1 << tqmaskIndex; + } + } + + mapIndex++; + } + } + + XFreeModifiermap(map); + } + else { + // Assume defaults + X11AltMask = Mod1Mask; + X11MetaMask = Mod4Mask; + } + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + + int numDevices = 0; + const XDeviceInfo *devices = XListInputDevices(x11Display, &numDevices); + + if (devices != NULL) { + XID lastStylusSeen = 0; + XID lastEraserSeen = 0; + bool foundStylus = false; + bool foundEraser = false; + + for (int i = 0; i < numDevices; i++) { + + const XDeviceInfo *device = devices + i; + X11TabletDevice tabletDevice(device); + + if (tabletDevice.mightBeTabletDevice()) { + + tabletDevice.readSettingsFromConfig(); + + TQString lowerCaseName = tabletDevice.name().lower(); + + // Find the devices that TQt will use as its stylus and eraser devices. + if (!foundStylus || !foundEraser) { + if (lowerCaseName.startsWith("stylus") || lowerCaseName.startsWith("pen")) { + lastStylusSeen = device->id; + foundStylus = true; + } + else if (lowerCaseName.startsWith("eraser")) { + lastEraserSeen = device->id; + foundEraser = true; + } + } + + X11TabletDeviceMap[device->id] = tabletDevice; + + // Event types are device-independent. Store any + // the device supports. + if (tabletDevice.buttonPressEvent() >= 0) { + X11DeviceButtonPressEvent = tabletDevice.buttonPressEvent(); + } + if (tabletDevice.buttonReleaseEvent() >= 0) { + X11DeviceButtonReleaseEvent = tabletDevice.buttonReleaseEvent(); + } + if (tabletDevice.motionNotifyEvent() >= 0) { + X11DeviceMotionNotifyEvent = tabletDevice.motionNotifyEvent(); + } + if (tabletDevice.proximityInEvent() >= 0) { + X11ProximityInEvent = tabletDevice.proximityInEvent(); + } + if (tabletDevice.proximityOutEvent() >= 0) { + X11ProximityOutEvent = tabletDevice.proximityOutEvent(); + } + } + } + + // Allocate input devices. + for (X11XIDTabletDeviceMap::iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) { + + X11TabletDevice& tabletDevice = (*it).second; + + if (foundStylus && tabletDevice.id() == lastStylusSeen) { + tabletDevice.setInputDevice(KisInputDevice::stylus()); + } else if (foundEraser && tabletDevice.id() == lastEraserSeen) { + tabletDevice.setInputDevice(KisInputDevice::eraser()); + } else { + tabletDevice.setInputDevice(KisInputDevice::allocateInputDevice()); + } + } + + XFreeDeviceList(const_cast(devices)); + } +#endif // EXTENDED_X11_TABLET_SUPPORT +} + +TQt::ButtonState KisCanvasWidget::translateX11ButtonState(int state) +{ + int buttonState = 0; + + if (state & Button1Mask) + buttonState |= Qt::LeftButton; + if (state & Button2Mask) + buttonState |= Qt::MidButton; + if (state & Button3Mask) + buttonState |= Qt::RightButton; + if (state & ShiftMask) + buttonState |= TQt::ShiftButton; + if (state & ControlMask) + buttonState |= TQt::ControlButton; + if (state & X11AltMask) + buttonState |= TQt::AltButton; + if (state & X11MetaMask) + buttonState |= TQt::MetaButton; + + return static_cast(buttonState); +} + +TQt::ButtonState KisCanvasWidget::translateX11Button(unsigned int X11Button) +{ + TQt::ButtonState qtButton; + + switch (X11Button) { + case Button1: + qtButton = Qt::LeftButton; + break; + case Button2: + qtButton = Qt::MidButton; + break; + case Button3: + qtButton = Qt::RightButton; + break; + default: + qtButton = Qt::NoButton; + } + + return qtButton; +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + +KisCanvasWidget::X11TabletDevice::X11TabletDevice() +{ + m_mightBeTabletDevice = false; + m_inputDevice = KisInputDevice::unknown(); + m_enabled = false; + m_xAxis = NoAxis; + m_yAxis = NoAxis; + m_pressureAxis = NoAxis; + m_xTiltAxis = NoAxis; + m_yTiltAxis = NoAxis; + m_wheelAxis = NoAxis; + m_toolIDAxis = NoAxis; + m_serialNumberAxis = NoAxis; + m_buttonPressEvent = -1; + m_buttonReleaseEvent = -1; + m_motionNotifyEvent = -1; + m_proximityInEvent = -1; + m_proximityOutEvent = -1; +} + +KisCanvasWidget::X11TabletDevice::X11TabletDevice(const XDeviceInfo *deviceInfo) +{ + m_mightBeTabletDevice = false; + m_inputDevice = KisInputDevice::unknown(); + m_enabled = false; + m_xAxis = NoAxis; + m_yAxis = NoAxis; + m_pressureAxis = NoAxis; + m_xTiltAxis = NoAxis; + m_yTiltAxis = NoAxis; + m_wheelAxis = NoAxis; + m_toolIDAxis = NoAxis; + m_serialNumberAxis = NoAxis; + + m_deviceId = deviceInfo->id; + m_name = deviceInfo->name; + + // Get the ranges of the valuators + XAnyClassPtr classInfo = const_cast(deviceInfo->inputclassinfo); + + for (int i = 0; i < deviceInfo->num_classes; i++) { + + if (classInfo->c_class == ValuatorClass) { + + const XValuatorInfo *valuatorInfo = reinterpret_cast(classInfo); + + // Need at least x, y, and pressure. + + if (valuatorInfo->num_axes >= 3) { + + for (unsigned int axis = 0; axis < valuatorInfo->num_axes; axis++) { + m_axisInfo.append(valuatorInfo->axes[axis]); + } + + m_mightBeTabletDevice = true; + } + } + + classInfo = reinterpret_cast(reinterpret_cast(classInfo) + classInfo->length); + } + + // Determine the event types it supports. We're only interested in + // buttons and motion at the moment. + m_buttonPressEvent = -1; + m_buttonReleaseEvent = -1; + m_motionNotifyEvent = -1; + m_proximityInEvent = -1; + m_proximityOutEvent = -1; + + m_XDevice = XOpenDevice(TQApplication::desktop()->x11Display(), m_deviceId); + + if (m_XDevice != NULL) { + for (int i = 0; i < m_XDevice->num_classes; i++) { + + XEventClass eventClass; + + if (m_XDevice->classes[i].input_class == ButtonClass) { + DeviceButtonPress(m_XDevice, m_buttonPressEvent, eventClass); + m_eventClassList.append(eventClass); + + DeviceButtonRelease(m_XDevice, m_buttonReleaseEvent, eventClass); + m_eventClassList.append(eventClass); + } + else + if (m_XDevice->classes[i].input_class == ValuatorClass) { + DeviceMotionNotify(m_XDevice, m_motionNotifyEvent, eventClass); + m_eventClassList.append(eventClass); + } + else + if (m_XDevice->classes[i].input_class == ProximityClass) { + ProximityIn(m_XDevice, m_proximityInEvent, eventClass); + m_eventClassList.append(eventClass); + + ProximityOut(m_XDevice, m_proximityOutEvent, eventClass); + m_eventClassList.append(eventClass); + } + } + + // Note: We don't XCloseXDevice() since TQt will have already opened + // it, and only one XCloseDevice() call closes it for all opens. + } + + if (m_buttonPressEvent == -1 || m_buttonReleaseEvent == -1 || m_motionNotifyEvent == -1) { + m_mightBeTabletDevice = false; + } +} + +void KisCanvasWidget::X11TabletDevice::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +bool KisCanvasWidget::X11TabletDevice::enabled() const +{ + return m_enabled; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::numAxes() const +{ + return m_axisInfo.count(); +} + +void KisCanvasWidget::X11TabletDevice::setXAxis(TQ_INT32 axis) +{ + m_xAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setYAxis(TQ_INT32 axis) +{ + m_yAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setPressureAxis(TQ_INT32 axis) +{ + m_pressureAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setXTiltAxis(TQ_INT32 axis) +{ + m_xTiltAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setYTiltAxis(TQ_INT32 axis) +{ + m_yTiltAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setWheelAxis(TQ_INT32 axis) +{ + m_wheelAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setToolIDAxis(TQ_INT32 axis) +{ + m_toolIDAxis = axis; +} + +void KisCanvasWidget::X11TabletDevice::setSerialNumberAxis(TQ_INT32 axis) +{ + m_serialNumberAxis = axis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::xAxis() const +{ + return m_xAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::yAxis() const +{ + return m_yAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::pressureAxis() const +{ + return m_pressureAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::xTiltAxis() const +{ + return m_xTiltAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::yTiltAxis() const +{ + return m_yTiltAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::wheelAxis() const +{ + return m_wheelAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::toolIDAxis() const +{ + return m_toolIDAxis; +} + +TQ_INT32 KisCanvasWidget::X11TabletDevice::serialNumberAxis() const +{ + return m_serialNumberAxis; +} + +void KisCanvasWidget::X11TabletDevice::readSettingsFromConfig() +{ + KisConfig cfg; + + m_enabled = cfg.tabletDeviceEnabled(m_name); + + m_xAxis = cfg.tabletDeviceAxis(m_name, "XAxis", DefaultAxis); + m_yAxis = cfg.tabletDeviceAxis(m_name, "YAxis", DefaultAxis); + m_pressureAxis = cfg.tabletDeviceAxis(m_name, "PressureAxis", DefaultAxis); + m_xTiltAxis = cfg.tabletDeviceAxis(m_name, "XTiltAxis", DefaultAxis); + m_yTiltAxis = cfg.tabletDeviceAxis(m_name, "YTiltAxis", DefaultAxis); + m_wheelAxis = cfg.tabletDeviceAxis(m_name, "WheelAxis", DefaultAxis); + m_toolIDAxis = cfg.tabletDeviceAxis(m_name, "ToolIDAxis", DefaultAxis); + m_serialNumberAxis = cfg.tabletDeviceAxis(m_name, "SerialNumberAxis", DefaultAxis); + + if (!m_enabled && m_xAxis == DefaultAxis && m_yAxis == DefaultAxis && m_pressureAxis == DefaultAxis && + m_xTiltAxis == DefaultAxis && m_yTiltAxis == DefaultAxis && m_wheelAxis == DefaultAxis && + m_toolIDAxis == DefaultAxis && m_serialNumberAxis == DefaultAxis) { + // This is the first time this device has been seen. Set up default values, assuming + // it's a Wacom pad. + m_xAxis = 0; + m_yAxis = 1; + m_pressureAxis = 2; + + if (m_axisInfo.count() >= 4) { + m_xTiltAxis = 3; + } else { + m_xTiltAxis = NoAxis; + } + + if (m_axisInfo.count() >= 5) { + m_yTiltAxis = 4; + } else { + m_yTiltAxis = NoAxis; + } + + if (m_axisInfo.count() >= 6) { + m_wheelAxis = 5; + } else { + m_wheelAxis = NoAxis; + } + + // Available since driver version 0.7.2. + if (m_axisInfo.count() >= 7) { + m_toolIDAxis = 6; + } else { + m_toolIDAxis = NoAxis; + } + + if (m_axisInfo.count() >= 8) { + m_serialNumberAxis = 7; + } else { + m_serialNumberAxis = NoAxis; + } + } +} + +void KisCanvasWidget::X11TabletDevice::writeSettingsToConfig() +{ + KisConfig cfg; + + cfg.setTabletDeviceEnabled(m_name, m_enabled); + + cfg.setTabletDeviceAxis(m_name, "XAxis", m_xAxis); + cfg.setTabletDeviceAxis(m_name, "YAxis", m_yAxis); + cfg.setTabletDeviceAxis(m_name, "PressureAxis", m_pressureAxis); + cfg.setTabletDeviceAxis(m_name, "XTiltAxis", m_xTiltAxis); + cfg.setTabletDeviceAxis(m_name, "YTiltAxis", m_yTiltAxis); + cfg.setTabletDeviceAxis(m_name, "WheelAxis", m_wheelAxis); + cfg.setTabletDeviceAxis(m_name, "ToolIDAxis", m_toolIDAxis); + cfg.setTabletDeviceAxis(m_name, "SerialNumberAxis", m_serialNumberAxis); +} + +void KisCanvasWidget::X11TabletDevice::enableEvents(TQWidget *widget) const +{ + if (!m_eventClassList.isEmpty()) { + int result = XSelectExtensionEvent(TQT_TQPAINTDEVICE(widget)->x11AppDisplay(), widget->handle(), + const_cast(&m_eventClassList[0]), + m_eventClassList.count()); + + if (result != Success) { + kdDebug(41001) << "Failed to select extension events for " << m_name << endl; + } + } +} + +double KisCanvasWidget::X11TabletDevice::translateAxisValue(int value, const XAxisInfo& axisInfo) const +{ + int axisRange = axisInfo.max_value - axisInfo.min_value; + double translatedValue = 0; + + if (axisRange != 0) { + translatedValue = (static_cast(value) - axisInfo.min_value) / axisRange; + if (axisInfo.min_value < 0) { + translatedValue -= 0.5; + } + } + + return translatedValue; +} + +KisCanvasWidget::X11TabletDevice::State::State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel, + TQ_UINT32 toolID, TQ_UINT32 serialNumber) + : m_pos(pos), + m_pressure(pressure), + m_tilt(tilt), + m_wheel(wheel), + m_toolID(toolID), + m_serialNumber(serialNumber) +{ +} + +KisCanvasWidget::X11TabletDevice::State KisCanvasWidget::X11TabletDevice::translateAxisData(const int *axisData) const +{ + KisPoint pos(0, 0); + + if (m_xAxis != NoAxis && m_yAxis != NoAxis) { + pos = KisPoint(translateAxisValue(axisData[m_xAxis], m_axisInfo[m_xAxis]), + translateAxisValue(axisData[m_yAxis], m_axisInfo[m_yAxis])); + } + + double pressure = PRESSURE_DEFAULT; + + if (m_pressureAxis != NoAxis) { + pressure = translateAxisValue(axisData[m_pressureAxis], m_axisInfo[m_pressureAxis]); + } + + KisVector2D tilt = KisVector2D(0, 0); + TQ_UINT32 toolID = 0; + TQ_UINT32 serialNumber = 0; + + if (m_xTiltAxis != NoAxis) { + // Latest wacom driver returns the tool id and serial number in + // the upper 16 bits of the x and y tilts and wheel. + int xTiltAxisValue = (TQ_INT16)(axisData[m_xTiltAxis] & 0xffff); + toolID = ((TQ_UINT32)axisData[m_xTiltAxis] >> 16) & 0xffff; + + tilt.setX(translateAxisValue(xTiltAxisValue, m_axisInfo[m_xTiltAxis])); + } + + if (m_yTiltAxis != NoAxis) { + int yTiltAxisValue = (TQ_INT16)(axisData[m_yTiltAxis] & 0xffff); + serialNumber = (TQ_UINT32)axisData[m_yTiltAxis] & 0xffff0000; + + tilt.setY(translateAxisValue(yTiltAxisValue, m_axisInfo[m_yTiltAxis])); + } + + double wheel = 0; + + if (m_wheelAxis != NoAxis) { + int wheelAxisValue = (TQ_INT16)(axisData[m_wheelAxis] & 0xffff); + serialNumber |= ((TQ_UINT32)axisData[m_wheelAxis] >> 16) & 0xffff; + + wheel = translateAxisValue(wheelAxisValue, m_axisInfo[m_wheelAxis]); + } + + //TQString ids; + //ids.sprintf("Tool ID: %8x Serial Number: %8x", toolID, serialNumber); + + return State(pos, pressure, tilt, wheel, toolID, serialNumber); +} + +KisCanvasWidget::X11XIDTabletDeviceMap& KisCanvasWidget::tabletDeviceMap() +{ + return X11TabletDeviceMap; +} + +void KisCanvasWidget::selectTabletDeviceEvents(TQWidget *widget) +{ + for (X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) { + + const X11TabletDevice& device = (*it).second; + + if (device.enabled()) { + device.enableEvents(widget); + } + } +} + +#endif // EXTENDED_X11_TABLET_SUPPORT + +bool KisCanvasWidget::x11Event(XEvent *event, Display *x11Display, WId winId, TQPoint widgetOriginPos) +{ + if (event->type == MotionNotify) { + // Mouse move + if (!m_enableMoveEventCompressionHint) { + + XMotionEvent motion = event->xmotion; + TQPoint globalPos(motion.x_root, motion.y_root); + + if (globalPos.x() != m_lastRootX || globalPos.y() != m_lastRootY) { + + int state = translateX11ButtonState(motion.state); + TQPoint pos(motion.x, motion.y); + TQMouseEvent e(TQEvent::MouseMove, pos, globalPos, Qt::NoButton, state); + + widgetGotMouseMoveEvent(&e); + } + + m_lastRootX = globalPos.x(); + m_lastRootY = globalPos.y(); + + return true; + } + else { + return false; + } + } + else +#if defined(EXTENDED_X11_TABLET_SUPPORT) + if (event->type == X11DeviceMotionNotifyEvent || event->type == X11DeviceButtonPressEvent || event->type == X11DeviceButtonReleaseEvent) { + // Tablet event. + int deviceId; + const int *axisData; + TQt::ButtonState button; + TQt::ButtonState buttonState; + + if (event->type == X11DeviceMotionNotifyEvent) { + // Tablet move + const XDeviceMotionEvent *motion = reinterpret_cast(event); + XEvent mouseEvent; + + // Look for an accompanying core event. + if (XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &mouseEvent)) { + if (motion->time == mouseEvent.xmotion.time) { + // Do nothing + } else { + XPutBackEvent(x11Display, &mouseEvent); + } + } + + if (m_enableMoveEventCompressionHint) { + while (true) { + // Look for another motion notify in the queue and skip + // to that if found. + if (!XCheckTypedWindowEvent(x11Display, winId, X11DeviceMotionNotifyEvent, &mouseEvent)) { + break; + } + + motion = reinterpret_cast(&mouseEvent); + + XEvent coreMotionEvent; + + // Look for an accompanying core event. + if (!XCheckTypedWindowEvent(x11Display, winId, MotionNotify, &coreMotionEvent)) { + // Do nothing + } + } + } + + deviceId = motion->deviceid; + axisData = motion->axis_data; + button = Qt::NoButton; + buttonState = translateX11ButtonState(motion->state); + } + else + if (event->type == X11DeviceButtonPressEvent) { + // Tablet button press + const XDeviceButtonPressedEvent *buttonPressed = reinterpret_cast(event); + deviceId = buttonPressed->deviceid; + axisData = buttonPressed->axis_data; + button = translateX11Button(buttonPressed->button); + buttonState = translateX11ButtonState(buttonPressed->state); + + if (TQApplication::activePopupWidget() == 0) { + XEvent mouseEvent; + + // Look for and swallow an accompanying core event, but only if there's + // no active popup, as that needs to see it. + if (XCheckTypedWindowEvent(x11Display, winId, ButtonPress, &mouseEvent)) { + if (buttonPressed->time == mouseEvent.xbutton.time) { + // Do nothing + } + else { + XPutBackEvent(x11Display, &mouseEvent); + } + } + } + } + else { + // Tablet button release + const XDeviceButtonReleasedEvent *buttonReleased = reinterpret_cast(event); + deviceId = buttonReleased->deviceid; + axisData = buttonReleased->axis_data; + button = translateX11Button(buttonReleased->button); + buttonState = translateX11ButtonState(buttonReleased->state); + + if (TQApplication::activePopupWidget() == 0) { + XEvent mouseEvent; + + // Look for and swallow an accompanying core event, but only if there's + // no active popup, as that needs to see it. + if (XCheckTypedWindowEvent(x11Display, winId, ButtonRelease, &mouseEvent)) { + if (buttonReleased->time == mouseEvent.xbutton.time) { + // Do nothing + } + else { + XPutBackEvent(x11Display, &mouseEvent); + } + } + } + } + + X11XIDTabletDeviceMap::const_iterator it = X11TabletDeviceMap.find(deviceId); + + if (it != X11TabletDeviceMap.end()) { + + const X11TabletDevice& tabletDevice = (*it).second; + + if (tabletDevice.enabled()) { + X11TabletDevice::State deviceState = tabletDevice.translateAxisData(axisData); + + // Map normalised position coordinates to screen coordinates + TQDesktopWidget *desktop = TQApplication::desktop(); + KisPoint globalPos(deviceState.pos().x() * desktop->width(), deviceState.pos().y() * desktop->height()); + // Convert screen coordinates to widget coordinates + KisPoint pos = globalPos - KoPoint( widgetOriginPos ); + + // Map tilt to -60 - +60 degrees + KisVector2D tilt(deviceState.tilt().x() * 60, deviceState.tilt().y() * 60); + + if (event->type == X11DeviceMotionNotifyEvent) { + KisMoveEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), buttonState); + translateTabletEvent(&e); + } + else + if (event->type == X11DeviceButtonPressEvent) { + KisButtonPressEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState); + translateTabletEvent(&e); + } + else { + KisButtonReleaseEvent e(tabletDevice.inputDevice(), pos, globalPos, deviceState.pressure(), tilt.x(), tilt.y(), button, buttonState); + translateTabletEvent(&e); + } + } + + // Consume the event even if the device is disabled otherwise TQt will + // process it and send a TQTabletEvent. + return true; + } + else { + return false; + } + } + else +#endif // EXTENDED_X11_TABLET_SUPPORT + { + return false; + } +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + +KisInputDevice KisCanvasWidget::findActiveInputDevice() +{ + X11XIDTabletDeviceMap::const_iterator it; + + for (it = X11TabletDeviceMap.begin(); it != X11TabletDeviceMap.end(); ++it) { + const X11TabletDevice& tabletDevice = (*it).second; + + XDeviceState *deviceState = XQueryDeviceState(TQApplication::desktop()->x11Display(), + tabletDevice.xDevice()); + + // If your the laptop sleeps, and you remove the mouse from the usb + // port, then on wake-up Chalk can crash because the above call will + // return 0. + if (!deviceState) continue; + + const XInputClass *inputClass = deviceState->data; + bool deviceIsInProximity = false; + + for (int i = 0; i < deviceState->num_classes; i++) { + + if (inputClass->c_class == ValuatorClass) { + + const XValuatorState *valuatorState = reinterpret_cast(inputClass); + + if ((valuatorState->mode & ProximityState) == InProximity) { + deviceIsInProximity = true; + break; + } + } + + inputClass = reinterpret_cast(reinterpret_cast(inputClass) + inputClass->length); + } + + XFreeDeviceState(deviceState); + + if (deviceIsInProximity && tabletDevice.enabled()) { + return tabletDevice.inputDevice(); + } + } + + return KisInputDevice::mouse(); +} + +#endif // EXTENDED_X11_TABLET_SUPPORT + + +#endif // Q_WS_X11 + +/*************************************************************************/ + +#define TQPAINTDEVICE_CANVAS_WIDGET false +#define OPENGL_CANVAS_WIDGET true + +KisCanvas::KisCanvas(TQWidget *tqparent, const char *name) +{ + m_parent = tqparent; + m_name = name; + m_enableMoveEventCompressionHint = false; + m_canvasWidget = 0; + m_useOpenGL = false; + createCanvasWidget(TQPAINTDEVICE_CANVAS_WIDGET); +} + +KisCanvas::~KisCanvas() +{ + delete m_canvasWidget; +} + +#ifdef HAVE_GL +void KisCanvas::createCanvasWidget(bool useOpenGL, TQGLWidget *sharedContextWidget) +#else +void KisCanvas::createCanvasWidget(bool useOpenGL) +#endif +{ + delete m_canvasWidget; + +#ifndef HAVE_GL + useOpenGL = false; +#else + if (useOpenGL && !TQGLFormat::hasOpenGL()) { + kdDebug(41001) << "Tried to create OpenGL widget when system doesn't have OpenGL\n"; + useOpenGL = false; + } + + if (useOpenGL) { + m_canvasWidget = new KisOpenGLCanvasWidget(m_parent, m_name.latin1(), sharedContextWidget); + } else +#endif + { + m_canvasWidget = new KisTQPaintDeviceCanvasWidget(m_parent, m_name.latin1()); + } + + m_useOpenGL = useOpenGL; + + Q_CHECK_PTR(m_canvasWidget); + TQWidget *widget = dynamic_cast(m_canvasWidget); + + widget->setBackgroundMode(TQWidget::NoBackground); + widget->setMouseTracking(true); + widget->setAcceptDrops(true); + m_canvasWidget->enableMoveEventCompressionHint(m_enableMoveEventCompressionHint); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + selectTabletDeviceEvents(); +#endif + + connect(m_canvasWidget, TQT_SIGNAL(sigGotPaintEvent(TQPaintEvent *)), TQT_SIGNAL(sigGotPaintEvent(TQPaintEvent *))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotEnterEvent(TQEvent*)), TQT_SIGNAL(sigGotEnterEvent(TQEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotLeaveEvent(TQEvent*)), TQT_SIGNAL(sigGotLeaveEvent(TQEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotMouseWheelEvent(TQWheelEvent*)), TQT_SIGNAL(sigGotMouseWheelEvent(TQWheelEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotKeyReleaseEvent(TQKeyEvent*)), TQT_SIGNAL(sigGotKeyReleaseEvent(TQKeyEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotDragEnterEvent(TQDragEnterEvent*)), TQT_SIGNAL(sigGotDragEnterEvent(TQDragEnterEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotDropEvent(TQDropEvent*)), TQT_SIGNAL(sigGotDropEvent(TQDropEvent*))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent *)), TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent *))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *)), TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent *))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *)), TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent *))); + connect(m_canvasWidget, TQT_SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *)), TQT_SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent *))); +} + +void KisCanvas::createTQPaintDeviceCanvas() +{ + createCanvasWidget(TQPAINTDEVICE_CANVAS_WIDGET); +} + +#ifdef HAVE_GL +void KisCanvas::createOpenGLCanvas(TQGLWidget *sharedContextWidget) +{ + createCanvasWidget(OPENGL_CANVAS_WIDGET, sharedContextWidget); +} +#endif + +bool KisCanvas::isOpenGLCanvas() const +{ + return m_useOpenGL; +} + +void KisCanvas::enableMoveEventCompressionHint(bool enableMoveCompression) +{ + m_enableMoveEventCompressionHint = enableMoveCompression; + if (m_canvasWidget != 0) { + m_canvasWidget->enableMoveEventCompressionHint(enableMoveCompression); + } +} + +TQWidget *KisCanvas::TQPaintDeviceWidget() const +{ + if (m_useOpenGL) { + return 0; + } else { + return dynamic_cast(m_canvasWidget); + } +} + +#ifdef HAVE_GL +TQGLWidget *KisCanvas::OpenGLWidget() const +{ + if (m_useOpenGL) { + return dynamic_cast(m_canvasWidget); + } else { + return 0; + } +} +#endif + +KisCanvasWidgetPainter *KisCanvas::createPainter() +{ + Q_ASSERT(m_canvasWidget != 0); + return m_canvasWidget->createPainter(); +} + +KisCanvasWidget *KisCanvas::canvasWidget() const +{ + return m_canvasWidget; +} + +void KisCanvas::setGeometry(int x, int y, int width, int height) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->setGeometry(x, y, width, height); +} + +void KisCanvas::show() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->show(); +} + +void KisCanvas::hide() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->hide(); +} + +int KisCanvas::width() const +{ + Q_ASSERT(m_canvasWidget); + return dynamic_cast(m_canvasWidget)->width(); +} + +int KisCanvas::height() const +{ + Q_ASSERT(m_canvasWidget); + return dynamic_cast(m_canvasWidget)->height(); +} + +void KisCanvas::update() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->update(); +} + +void KisCanvas::update(const TQRect& r) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->update(r); +} + +void KisCanvas::update(int x, int y, int width, int height) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->update(x, y, width, height); +} + +void KisCanvas::tqrepaint() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->tqrepaint(); +} + +void KisCanvas::tqrepaint(bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->tqrepaint(erase); +} + +void KisCanvas::tqrepaint(int x, int y, int width, int height, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->tqrepaint(x, y, width, height, erase); +} + +void KisCanvas::tqrepaint(const TQRect& r, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->tqrepaint(r, erase); +} + +void KisCanvas::tqrepaint(const TQRegion& r, bool erase) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->tqrepaint(r, erase); +} + +bool KisCanvas::isUpdatesEnabled() const +{ + Q_ASSERT(m_canvasWidget); + return dynamic_cast(m_canvasWidget)->isUpdatesEnabled(); +} + +void KisCanvas::setUpdatesEnabled(bool updatesEnabled) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->setUpdatesEnabled(updatesEnabled); +} + +void KisCanvas::updateGeometry() +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->updateGeometry(); +} + +void KisCanvas::setFocusPolicy(TQ_FocusPolicy focusPolicy) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->setFocusPolicy(focusPolicy); +} + +const TQCursor& KisCanvas::cursor() const +{ + Q_ASSERT(m_canvasWidget); + return dynamic_cast(m_canvasWidget)->cursor(); +} + +void KisCanvas::setCursor(const TQCursor& cursor) +{ + Q_ASSERT(m_canvasWidget); + dynamic_cast(m_canvasWidget)->setCursor(cursor); +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) +void KisCanvas::selectTabletDeviceEvents() +{ + Q_ASSERT(m_canvasWidget); + m_canvasWidget->selectTabletDeviceEvents(); +} +#endif + +bool KisCanvas::cursorIsOverCanvas() const +{ + if (TQApplication::activePopupWidget() != 0) { + return false; + } + if (TQApplication::activeModalWidget() != 0) { + return false; + } + + TQWidget *canvasWidget = dynamic_cast(m_canvasWidget); + Q_ASSERT(canvasWidget != 0); + + if (canvasWidget) { + if (TQApplication::widgetAt(TQCursor::pos(), true) == canvasWidget) { + return true; + } + } + return false; +} + +void KisCanvas::handleKeyEvent(TQEvent *e) +{ + TQKeyEvent *ke = dynamic_cast(e); + + Q_ASSERT(ke != 0); + + if (ke) { + TQWidget *canvasWidget = dynamic_cast(m_canvasWidget); + Q_ASSERT(canvasWidget != 0); + + if (canvasWidget) { + canvasWidget->setFocus(); + + if (e->type() == TQEvent::KeyPress) { + emit sigGotKeyPressEvent(ke); + } else { + emit sigGotKeyReleaseEvent(ke); + } + } + } +} + +#include "kis_canvas.moc" + diff --git a/chalk/ui/kis_canvas.h b/chalk/ui/kis_canvas.h new file mode 100644 index 00000000..ea36f8a9 --- /dev/null +++ b/chalk/ui/kis_canvas.h @@ -0,0 +1,387 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004-2006 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CANVAS_H_ +#define KIS_CANVAS_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_GL +#include +#endif +#include + +#include "kis_global.h" +#include "kis_point.h" +#include "kis_vec.h" +#include "kis_input_device.h" + +#ifdef Q_MOC_RUN +#define Q_WS_X11 +#endif // Q_MOC_RUN + +#ifdef Q_WS_X11 + +// Irix has a different (and better) XInput tablet driver to +// the XFree/xorg driver. TQt needs a separate code path for that +// and so would we. +#if defined(HAVE_XINPUTEXT) && !defined(Q_OS_IRIX) +#define EXTENDED_X11_TABLET_SUPPORT +#endif + +#include +#include + +#if defined(EXTENDED_X11_TABLET_SUPPORT) +#include +#endif + +#endif // Q_WS_X11 + +class KisEvent; +class KisMoveEvent; +class KisButtonPressEvent; +class KisButtonReleaseEvent; +class KisDoubleClickEvent; +class KisCanvasWidgetPainter; + +class KisCanvasWidget : public TQObject { + Q_OBJECT + TQ_OBJECT + +public: + KisCanvasWidget(); + virtual ~KisCanvasWidget(); + + // When enabled, the canvas may throw away move events if the application + // is unable to keep up with them, i.e. intermediate move events in the event + // queue are skipped. + void enableMoveEventCompressionHint(bool enableMoveCompression) { m_enableMoveEventCompressionHint = enableMoveCompression; } + + virtual KisCanvasWidgetPainter *createPainter() = 0; + +#ifdef EXTENDED_X11_TABLET_SUPPORT + static KisInputDevice findActiveInputDevice(); + virtual void selectTabletDeviceEvents() = 0; + + static void selectTabletDeviceEvents(TQWidget *widget); +#endif + +#ifdef Q_WS_X11 + static void initX11Support(); +#endif + +signals: + void sigGotPaintEvent(TQPaintEvent*); + void sigGotEnterEvent(TQEvent*); + void sigGotLeaveEvent(TQEvent*); + void sigGotMouseWheelEvent(TQWheelEvent*); + void sigGotKeyPressEvent(TQKeyEvent*); + void sigGotKeyReleaseEvent(TQKeyEvent*); + void sigGotDragEnterEvent(TQDragEnterEvent*); + void sigGotDropEvent(TQDropEvent*); + void sigGotMoveEvent(KisMoveEvent *); + void sigGotButtonPressEvent(KisButtonPressEvent *); + void sigGotButtonReleaseEvent(KisButtonReleaseEvent *); + void sigGotDoubleClickEvent(KisDoubleClickEvent *); + +protected: + void widgetGotPaintEvent(TQPaintEvent *event); + void widgetGotMousePressEvent(TQMouseEvent *event); + void widgetGotMouseReleaseEvent(TQMouseEvent *event); + void widgetGotMouseDoubleClickEvent(TQMouseEvent *event); + void widgetGotMouseMoveEvent(TQMouseEvent *event); + void widgetGotTabletEvent(TQTabletEvent *event); + void widgetGotEnterEvent(TQEvent *event ); + void widgetGotLeaveEvent(TQEvent *event); + void widgetGotWheelEvent(TQWheelEvent *event); + void widgetGotKeyPressEvent(TQKeyEvent *event); + void widgetGotKeyReleaseEvent(TQKeyEvent *event); + void widgetGotDragEnterEvent(TQDragEnterEvent *event); + void widgetGotDropEvent(TQDropEvent *event); + void moveEvent(KisMoveEvent *event); + void buttonPressEvent(KisButtonPressEvent *event); + void buttonReleaseEvent(KisButtonReleaseEvent *event); + void doubleClickEvent(KisDoubleClickEvent *event); + void translateTabletEvent(KisEvent *event); + +protected: + + bool m_enableMoveEventCompressionHint; + double m_lastPressure; + +#ifdef Q_WS_X11 + // On X11 systems, TQt throws away mouse move events if the application + // is unable to keep up with them. We override this behaviour so that + // we receive all move events, so that painting follows the mouse's motion + // accurately. + bool x11Event(XEvent *event, Display *x11Display, WId winId, TQPoint widgetOriginPos); + static TQt::ButtonState translateX11ButtonState(int state); + static TQt::ButtonState translateX11Button(unsigned int button); + + static bool X11SupportInitialised; + + // Modifier tqmasks for alt/meta - detected at run-time + static long X11AltMask; + static long X11MetaMask; + + int m_lastRootX; + int m_lastRootY; + +#ifdef EXTENDED_X11_TABLET_SUPPORT + +public: + class X11TabletDevice + { + public: + X11TabletDevice(); + X11TabletDevice(const XDeviceInfo *deviceInfo); + + bool mightBeTabletDevice() const { return m_mightBeTabletDevice; } + + XID id() const { return m_deviceId; } + XDevice *xDevice() const { return m_XDevice; } + TQString name() const { return m_name; } + + KisInputDevice inputDevice() const { return m_inputDevice; } + void setInputDevice(KisInputDevice inputDevice) { m_inputDevice = inputDevice; } + + void setEnabled(bool enabled); + bool enabled() const; + + TQ_INT32 numAxes() const; + + void setXAxis(TQ_INT32 axis); + void setYAxis(TQ_INT32 axis); + void setPressureAxis(TQ_INT32 axis); + void setXTiltAxis(TQ_INT32 axis); + void setYTiltAxis(TQ_INT32 axis); + void setWheelAxis(TQ_INT32 axis); + void setToolIDAxis(TQ_INT32 axis); + void setSerialNumberAxis(TQ_INT32 axis); + + static const TQ_INT32 NoAxis = -1; + static const TQ_INT32 DefaultAxis = -2; + + TQ_INT32 xAxis() const; + TQ_INT32 yAxis() const; + TQ_INT32 pressureAxis() const; + TQ_INT32 xTiltAxis() const; + TQ_INT32 yTiltAxis() const; + TQ_INT32 wheelAxis() const; + TQ_INT32 toolIDAxis() const; + TQ_INT32 serialNumberAxis() const; + + void readSettingsFromConfig(); + void writeSettingsToConfig(); + + // These return -1 if the device does not support the event + int buttonPressEvent() const { return m_buttonPressEvent; } + int buttonReleaseEvent() const { return m_buttonReleaseEvent; } + int motionNotifyEvent() const { return m_motionNotifyEvent; } + int proximityInEvent() const { return m_proximityInEvent; } + int proximityOutEvent() const { return m_proximityOutEvent; } + + void enableEvents(TQWidget *widget) const; + + class State + { + public: + State() {} + State(const KisPoint& pos, double pressure, const KisVector2D& tilt, double wheel, + TQ_UINT32 toolID, TQ_UINT32 serialNumber); + + // Position, pressure and wheel are normalised to 0 - 1 + KisPoint pos() const { return m_pos; } + double pressure() const { return m_pressure; } + // Tilt is normalised to -1->+1 + KisVector2D tilt() const { return m_tilt; } + double wheel() const { return m_wheel; } + // Wacom tool id and serial number of device. + TQ_UINT32 toolID() const { return m_toolID; } + TQ_UINT32 serialNumber() const { return m_serialNumber; } + + private: + KisPoint m_pos; + double m_pressure; + KisVector2D m_tilt; + double m_wheel; + TQ_UINT32 m_toolID; + TQ_UINT32 m_serialNumber; + }; + + State translateAxisData(const int *axisData) const; + + private: + double translateAxisValue(int value, const XAxisInfo& axisInfo) const; + + XID m_deviceId; + XDevice *m_XDevice; + + TQString m_name; + + bool m_mightBeTabletDevice; + KisInputDevice m_inputDevice; + + bool m_enabled; + + TQ_INT32 m_xAxis; + TQ_INT32 m_yAxis; + TQ_INT32 m_pressureAxis; + TQ_INT32 m_xTiltAxis; + TQ_INT32 m_yTiltAxis; + TQ_INT32 m_wheelAxis; + TQ_INT32 m_toolIDAxis; + TQ_INT32 m_serialNumberAxis; + + TQValueVector m_axisInfo; + + int m_motionNotifyEvent; + int m_buttonPressEvent; + int m_buttonReleaseEvent; + int m_proximityInEvent; + int m_proximityOutEvent; + + TQValueVector m_eventClassList; + }; + + typedef std::map X11XIDTabletDeviceMap; + static X11XIDTabletDeviceMap& tabletDeviceMap(); + +protected: + static int X11DeviceMotionNotifyEvent; + static int X11DeviceButtonPressEvent; + static int X11DeviceButtonReleaseEvent; + static int X11ProximityInEvent; + static int X11ProximityOutEvent; + + static X11XIDTabletDeviceMap X11TabletDeviceMap; + +#endif // EXTENDED_X11_TABLET_SUPPORT + +#endif // Q_WS_X11 +}; + +class KisCanvas : public TQObject { + Q_OBJECT + TQ_OBJECT + +public: + KisCanvas(TQWidget *tqparent, const char *name); + virtual ~KisCanvas(); + + // When enabled, the canvas may throw away move events if the application + // is unable to keep up with them, i.e. intermediate move events in the event + // queue are skipped. + void enableMoveEventCompressionHint(bool enableMoveCompression); + + bool isOpenGLCanvas() const; + + /** + * Returns true if the cursor is over the canvas. + */ + bool cursorIsOverCanvas() const; + + /** + * Handle the given event (which must be a key event) as if the canvas + * had received it directly. + */ + void handleKeyEvent(TQEvent *e); + + int width() const; + int height() const; + + void update(); + void update(const TQRect& r); + void update(int x, int y, int width, int height); + void tqrepaint(); + void tqrepaint(bool erase); + void tqrepaint(int x, int y, int width, int height, bool erase = true); + void tqrepaint(const TQRect& r, bool erase = true); + void tqrepaint(const TQRegion& r, bool erase = true); + + void updateGeometry(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + void selectTabletDeviceEvents(); +#endif + +signals: + void sigGotPaintEvent(TQPaintEvent*); + void sigGotEnterEvent(TQEvent*); + void sigGotLeaveEvent(TQEvent*); + void sigGotMouseWheelEvent(TQWheelEvent*); + void sigGotKeyPressEvent(TQKeyEvent*); + void sigGotKeyReleaseEvent(TQKeyEvent*); + void sigGotDragEnterEvent(TQDragEnterEvent*); + void sigGotDropEvent(TQDropEvent*); + void sigGotMoveEvent(KisMoveEvent *); + void sigGotButtonPressEvent(KisButtonPressEvent *); + void sigGotButtonReleaseEvent(KisButtonReleaseEvent *); + void sigGotDoubleClickEvent(KisDoubleClickEvent *); + +protected: + // Allow KisView to render on the widget directly, but everything else + // has restricted access. + friend class KisView; + friend class KisCanvasPainter; + + // One of these will be valid, the other null. In TQt3, using a TQPainter on + // a TQGLWidget is not reliable. + TQWidget *TQPaintDeviceWidget() const; +#ifdef HAVE_GL + TQGLWidget *OpenGLWidget() const; +#endif + void createTQPaintDeviceCanvas(); +#ifdef HAVE_GL + void createOpenGLCanvas(TQGLWidget *sharedContextWidget); +#endif + void show(); + void hide(); + void setGeometry(int x, int y, int width, int height); + + void setUpdatesEnabled(bool updatesEnabled); + bool isUpdatesEnabled() const; + + void setFocusPolicy(TQ_FocusPolicy focusPolicy); + + const TQCursor& cursor() const; + void setCursor(const TQCursor& cursor); + + KisCanvasWidgetPainter *createPainter(); + KisCanvasWidget *canvasWidget() const; + +protected: +#ifdef HAVE_GL + void createCanvasWidget(bool useOpenGL, TQGLWidget *sharedContextWidget = 0); +#else + void createCanvasWidget(bool useOpenGL); +#endif + TQWidget *m_parent; + TQString m_name; + KisCanvasWidget *m_canvasWidget; + bool m_enableMoveEventCompressionHint; + bool m_useOpenGL; +}; + +#endif // KIS_CANVAS_H_ + diff --git a/chalk/ui/kis_canvas_painter.cc b/chalk/ui/kis_canvas_painter.cc new file mode 100644 index 00000000..ed5be01d --- /dev/null +++ b/chalk/ui/kis_canvas_painter.cc @@ -0,0 +1,1440 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_qpaintdevice_canvas_painter.h" + +KisCanvasWidgetPainter::KisCanvasWidgetPainter() +{ +} + +KisCanvasWidgetPainter::~KisCanvasWidgetPainter() +{ +} + +bool KisCanvasWidgetPainter::end() +{ + return true; +} + +void KisCanvasWidgetPainter::save() +{ +} + +void KisCanvasWidgetPainter::restore() +{ +} + +TQFontMetrics KisCanvasWidgetPainter::fontMetrics() const +{ + return TQFontMetrics(TQFont()); +} + +TQFontInfo KisCanvasWidgetPainter::fontInfo() const +{ + return TQFontInfo(TQFont()); +} + +const TQFont& KisCanvasWidgetPainter::font() const +{ + return m_defaultFont; +} + +void KisCanvasWidgetPainter::setFont(const TQFont& /*font*/) +{ +} + +const TQPen& KisCanvasWidgetPainter::pen() const +{ + return m_defaultPen; +} + +void KisCanvasWidgetPainter::setPen(const TQPen& /*pen*/) +{ +} + +void KisCanvasWidgetPainter::setPen(Qt::PenStyle /*penStyle*/) +{ +} + +void KisCanvasWidgetPainter::setPen(const TQColor& /*color*/) +{ +} + +const TQBrush& KisCanvasWidgetPainter::brush() const +{ + return m_defaultBrush; +} + +void KisCanvasWidgetPainter::setBrush(const TQBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::setBrush(TQt::BrushStyle /*brushStyle*/) +{ +} + +void KisCanvasWidgetPainter::setBrush(const TQColor& /*color*/) +{ +} + +TQPoint KisCanvasWidgetPainter::pos() const +{ + return TQPoint(); +} + +const TQColor& KisCanvasWidgetPainter::backgroundColor() const +{ + return m_defaultColor; +} + +void KisCanvasWidgetPainter::setBackgroundColor(const TQColor& /*color*/) +{ +} + +Qt::BGMode KisCanvasWidgetPainter::backgroundMode() const +{ + return Qt::TransparentMode; +} + +void KisCanvasWidgetPainter::setBackgroundMode(Qt::BGMode /*bgMode*/) +{ +} + +TQt::RasterOp KisCanvasWidgetPainter::rasterOp() const +{ + return TQt::CopyROP; +} + +void KisCanvasWidgetPainter::setRasterOp(TQt::RasterOp /*rasterOp*/) +{ +} + +const TQPoint& KisCanvasWidgetPainter::brushOrigin() const +{ + return m_defaultBrushOrigin; +} + +void KisCanvasWidgetPainter::setBrushOrigin(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::setBrushOrigin(const TQPoint& /*origin*/) +{ +} + +bool KisCanvasWidgetPainter::hasViewXForm() const +{ + return false; +} + +bool KisCanvasWidgetPainter::hasWorldXForm() const +{ + return false; +} + +void KisCanvasWidgetPainter::setViewXForm(bool /*enable*/) +{ +} + +TQRect KisCanvasWidgetPainter::window() const +{ + return TQRect(); +} + +void KisCanvasWidgetPainter::setWindow(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::setWindow(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +TQRect KisCanvasWidgetPainter::viewport() const +{ + return TQRect(); +} + +void KisCanvasWidgetPainter::setViewport(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::setViewport(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + + +void KisCanvasWidgetPainter::setWorldXForm(bool /*enable*/) +{ +} + +const TQWMatrix& KisCanvasWidgetPainter::tqworldMatrix() const +{ + return m_defaultWorldMatrix; +} + +void KisCanvasWidgetPainter::setWorldMatrix(const TQWMatrix& /*matrix*/, bool /*combine*/) +{ +} + +void KisCanvasWidgetPainter::saveWorldMatrix() +{ +} + +void KisCanvasWidgetPainter::restoreWorldMatrix() +{ +} + +void KisCanvasWidgetPainter::scale(double /*sx*/, double /*sy*/) +{ +} + +void KisCanvasWidgetPainter::shear(double /*sh*/, double /*sv*/) +{ +} + +void KisCanvasWidgetPainter::rotate(double /*a*/) +{ +} + +void KisCanvasWidgetPainter::translate(double /*dx*/, double /*dy*/) +{ +} + +void KisCanvasWidgetPainter::resetXForm() +{ +} + +double KisCanvasWidgetPainter::translationX() const +{ + return 0; +} + +double KisCanvasWidgetPainter::translationY() const +{ + return 0; +} + +TQPoint KisCanvasWidgetPainter::xForm(const TQPoint& point) const +{ + return point; +} + +TQRect KisCanvasWidgetPainter::xForm(const TQRect& r) const +{ + return r; +} + +TQPointArray KisCanvasWidgetPainter::xForm(const TQPointArray& pointArray) const +{ + return pointArray; +} + +TQPointArray KisCanvasWidgetPainter::xForm(const TQPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +TQPoint KisCanvasWidgetPainter::xFormDev(const TQPoint& point) const +{ + return point; +} + +TQRect KisCanvasWidgetPainter::xFormDev(const TQRect& r) const +{ + return r; +} + +TQPointArray KisCanvasWidgetPainter::xFormDev(const TQPointArray& pointArray) const +{ + return pointArray; +} + +TQPointArray KisCanvasWidgetPainter::xFormDev(const TQPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +void KisCanvasWidgetPainter::setClipping(bool /*enable*/) +{ +} + +bool KisCanvasWidgetPainter::hasClipping() const +{ + return true; +} + +TQRegion KisCanvasWidgetPainter::clipRegion(TQPainter::CoordinateMode /*mode*/) const +{ + return TQRegion(); +} + +void KisCanvasWidgetPainter::setClipRect(const TQRect& /*r*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::setClipRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::setClipRegion(const TQRegion& /*rgn*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisCanvasWidgetPainter::drawPoint(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::drawPoint(const TQPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawPoints(const TQPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::moveTo(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::moveTo(const TQPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::lineTo(int /*x*/, int /*y*/) +{ +} + +void KisCanvasWidgetPainter::lineTo(const TQPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawLine(int /*x1*/, int /*y1*/, int /*x2*/, int /*y2*/) +{ +} + +void KisCanvasWidgetPainter::drawLine(const TQPoint& /*start*/, const TQPoint& /*end*/) +{ +} + +void KisCanvasWidgetPainter::drawRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawRect(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const TQColor& /*bgColor*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawWinFocusRect(const TQRect& /*r*/, const TQColor& /*bgColor*/) +{ +} + +void KisCanvasWidgetPainter::drawRoundRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*xRnd*/, int /*yRnd*/) +{ +} + +void KisCanvasWidgetPainter::drawRoundRect(const TQRect& /*r*/, int /*xRnd*/, int /*yRnd*/) +{ +} + +void KisCanvasWidgetPainter::drawEllipse(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::drawEllipse(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawArc(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawArc(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawPie(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawPie(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawChord(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawChord(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisCanvasWidgetPainter::drawLineSegments(const TQPointArray& /*pointArray*/, int /*index*/, int /*nlines*/) +{ +} + +void KisCanvasWidgetPainter::drawPolyline(const TQPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawPolygon(const TQPointArray& /*pointArray*/, bool /*winding*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawConvexPolygon(const TQPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +void KisCanvasWidgetPainter::drawCubicBezier(const TQPointArray& /*pointArray*/, int /*index*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(int /*x*/, int /*y*/, const TQPixmap& /*pixmap*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const TQPoint& /*point*/, const TQPixmap& /*pixmap*/, const TQRect& /*sr*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const TQPoint& /*point*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::drawPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(int /*x*/, int /*y*/, const TQImage& /*image*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/, int /*conversionFlags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const TQPoint& /*point*/, const TQImage& /*image*/, const TQRect& /*sr*/, int /*conversionFlags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const TQPoint& /*point*/, const TQImage& /*image*/, int /*conversion_flags*/) +{ +} + +void KisCanvasWidgetPainter::drawImage(const TQRect& /*r*/, const TQImage& /*image*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const TQPixmap& /*pixmap*/, int /*sx*/, int /*sy*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/, const TQPoint& /*point*/) +{ +} + +void KisCanvasWidgetPainter::drawTiledPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisCanvasWidgetPainter::fillRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const TQBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::fillRect(const TQRect& /*r*/, const TQBrush& /*brush*/) +{ +} + +void KisCanvasWidgetPainter::eraseRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisCanvasWidgetPainter::eraseRect(const TQRect& /*r*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, const TQString& /*text*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const TQPoint& /*point*/, const TQString& /*text*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, const TQString& /*text*/, int /*pos*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const TQPoint& /*point*/, const TQString& /*text*/, int /*pos*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisCanvasWidgetPainter::drawText(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQRect */*br*/, TQTextParag **/*intern*/) +{ +} + +void KisCanvasWidgetPainter::drawText(const TQRect& /*r*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQRect */*br*/, TQTextParag **/*intern*/) +{ +} + +void KisCanvasWidgetPainter::tqdrawTextItem(int /*x*/, int /*y*/, const TQTextItem& /*ti*/, int /*textflags*/) +{ +} + +void KisCanvasWidgetPainter::tqdrawTextItem(const TQPoint& /*p*/, const TQTextItem& /*ti*/, int /*textflags*/) +{ +} + +TQRect KisCanvasWidgetPainter::boundingRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQTextParag **/*intern*/) +{ + return TQRect(); +} + +TQRect KisCanvasWidgetPainter::boundingRect(const TQRect& /*r*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQTextParag **/*intern*/) +{ + return TQRect(); +} + +int KisCanvasWidgetPainter::tabStops() const +{ + return 0; +} + +void KisCanvasWidgetPainter::setTabStops(int /*ts*/) +{ +} + +int *KisCanvasWidgetPainter::tabArray() const +{ + return 0; +} + +void KisCanvasWidgetPainter::setTabArray(int */*ts*/) +{ +} + +/*************************************************************************/ + +KisCanvasPainter::KisCanvasPainter() +{ + m_canvasWidgetPainter = 0; +} + +KisCanvasPainter::KisCanvasPainter(KisCanvas *canvas) +{ + m_canvasWidgetPainter = canvas->createPainter(); +} + +KisCanvasPainter::KisCanvasPainter(const TQPaintDevice *paintDevice) +{ + m_canvasWidgetPainter = new KisTQPaintDeviceCanvasPainter(paintDevice); +} + +KisCanvasPainter::~KisCanvasPainter() +{ + delete m_canvasWidgetPainter; +} + +bool KisCanvasPainter::begin(KisCanvas *canvas, bool unclipped) +{ + delete m_canvasWidgetPainter; + m_canvasWidgetPainter = canvas->createPainter(); + return m_canvasWidgetPainter->begin(canvas->canvasWidget(), unclipped); +} + +bool KisCanvasPainter::begin(const TQPaintDevice *paintDevice, bool unclipped) +{ + delete m_canvasWidgetPainter; + m_canvasWidgetPainter = new KisTQPaintDeviceCanvasPainter(); + return static_cast(m_canvasWidgetPainter)->begin(paintDevice, unclipped); +} + +bool KisCanvasPainter::end() +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->end(); + } + return false; +} + +void KisCanvasPainter::save() +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->save(); + } +} + +void KisCanvasPainter::restore() +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->restore(); + } +} + +TQFontMetrics KisCanvasPainter::fontMetrics() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->fontMetrics(); + } + return TQFontMetrics(TQFont()); +} + +TQFontInfo KisCanvasPainter::fontInfo() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->fontInfo(); + } + return TQFontInfo(TQFont()); +} + +const TQFont& KisCanvasPainter::font() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->font(); + } + return m_defaultFont; +} + +void KisCanvasPainter::setFont(const TQFont& font) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setFont(font); + } +} + +const TQPen& KisCanvasPainter::pen() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->pen(); + } + return m_defaultPen; +} + +void KisCanvasPainter::setPen(const TQPen& pen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setPen(pen); + } +} + +void KisCanvasPainter::setPen(Qt::PenStyle penStyle) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setPen(penStyle); + } +} + +void KisCanvasPainter::setPen(const TQColor& color) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setPen(color);; + } +} + +const TQBrush& KisCanvasPainter::brush() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->brush(); + } + return m_defaultBrush; +} + +void KisCanvasPainter::setBrush(const TQBrush& brush) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(brush); + } +} + +void KisCanvasPainter::setBrush(TQt::BrushStyle brushStyle) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(brushStyle); + } +} + +void KisCanvasPainter::setBrush(const TQColor& color) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrush(color); + } +} + +TQPoint KisCanvasPainter::pos() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->pos(); + } + return TQPoint(); +} + +const TQColor& KisCanvasPainter::backgroundColor() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->backgroundColor(); + } + return m_defaultColor; +} + +void KisCanvasPainter::setBackgroundColor(const TQColor& color) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBackgroundColor(color); + } +} + +Qt::BGMode KisCanvasPainter::backgroundMode() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->backgroundMode(); + } + return Qt::TransparentMode; +} + +void KisCanvasPainter::setBackgroundMode(Qt::BGMode bgMode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBackgroundMode(bgMode); + } +} + +TQt::RasterOp KisCanvasPainter::rasterOp() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->rasterOp(); + } + return TQt::CopyROP; +} + +void KisCanvasPainter::setRasterOp(TQt::RasterOp rasterOp) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setRasterOp(rasterOp); + } +} + +const TQPoint& KisCanvasPainter::brushOrigin() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->brushOrigin(); + } + return m_defaultBrushOrigin; +} + +void KisCanvasPainter::setBrushOrigin(int x, int y) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrushOrigin(x, y); + } +} + +void KisCanvasPainter::setBrushOrigin(const TQPoint& origin) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setBrushOrigin(origin); + } +} + +bool KisCanvasPainter::hasViewXForm() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->hasViewXForm(); + } + return false; +} + +bool KisCanvasPainter::hasWorldXForm() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->hasWorldXForm(); + } + return false; +} + +void KisCanvasPainter::setViewXForm(bool enable) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setViewXForm(enable); + } +} + +TQRect KisCanvasPainter::window() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->window(); + } + return TQRect(); +} + +void KisCanvasPainter::setWindow(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setWindow(r); + } +} + +void KisCanvasPainter::setWindow(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setWindow(x, y, w, h); + } +} + +TQRect KisCanvasPainter::viewport() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->viewport(); + } + return TQRect(); +} + +void KisCanvasPainter::setViewport(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setViewport(r); + } +} + +void KisCanvasPainter::setViewport(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setViewport(x, y, w, h); + } +} + +void KisCanvasPainter::setWorldXForm(bool enable) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setWorldXForm(enable); + } +} + +const TQWMatrix& KisCanvasPainter::tqworldMatrix() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->tqworldMatrix(); + } + return m_defaultWorldMatrix; +} + +void KisCanvasPainter::setWorldMatrix(const TQWMatrix& matrix, bool combine) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setWorldMatrix(matrix, combine); + } +} + +void KisCanvasPainter::saveWorldMatrix() +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->saveWorldMatrix(); + } +} + +void KisCanvasPainter::restoreWorldMatrix() +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->restoreWorldMatrix(); + } +} + +void KisCanvasPainter::scale(double sx, double sy) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->scale(sx, sy); + } +} + +void KisCanvasPainter::shear(double sh, double sv) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->shear(sh, sv); + } +} + +void KisCanvasPainter::rotate(double a) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->rotate(a); + } +} + +void KisCanvasPainter::translate(double dx, double dy) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->translate(dx, dy); + } +} + +void KisCanvasPainter::resetXForm() +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->resetXForm(); + } +} + +double KisCanvasPainter::translationX() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->translationX(); + } + return 0; +} + +double KisCanvasPainter::translationY() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->translationY(); + } + return 0; +} + +TQPoint KisCanvasPainter::xForm(const TQPoint& point) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(point); + } + return point; +} + +TQRect KisCanvasPainter::xForm(const TQRect& r) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(r); + } + return r; +} + +TQPointArray KisCanvasPainter::xForm(const TQPointArray& pointArray) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(pointArray); + } + return pointArray; +} + +TQPointArray KisCanvasPainter::xForm(const TQPointArray& pointArray, int index, int npoints) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xForm(pointArray, index, npoints); + } + return pointArray; +} + +TQPoint KisCanvasPainter::xFormDev(const TQPoint& point) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(point); + } + return point; +} + +TQRect KisCanvasPainter::xFormDev(const TQRect& r) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(r); + } + return r; +} + +TQPointArray KisCanvasPainter::xFormDev(const TQPointArray& pointArray) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(pointArray); + } + return pointArray; +} + +TQPointArray KisCanvasPainter::xFormDev(const TQPointArray& pointArray, int index, int npoints) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->xFormDev(pointArray, index, npoints); + } + return pointArray; +} + +void KisCanvasPainter::setClipping(bool enable) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipping(enable); + } +} + +bool KisCanvasPainter::hasClipping() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->hasClipping(); + } + return true; +} + +TQRegion KisCanvasPainter::clipRegion(TQPainter::CoordinateMode mode) const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->clipRegion(mode); + } + return TQRegion(); +} + +void KisCanvasPainter::setClipRect(const TQRect& r, TQPainter::CoordinateMode mode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipRect(r, mode); + } +} + +void KisCanvasPainter::setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode mode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipRect(x, y, w, h, mode); + } +} + +void KisCanvasPainter::setClipRegion(const TQRegion& rgn, TQPainter::CoordinateMode mode) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setClipRegion(rgn, mode); + } +} + +void KisCanvasPainter::drawPoint(int x, int y) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPoint(x, y); + } +} + +void KisCanvasPainter::drawPoint(const TQPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPoint(point); + } +} + +void KisCanvasPainter::drawPoints(const TQPointArray& pointArray, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPoints(pointArray, index, npoints); + } +} + +void KisCanvasPainter::moveTo(int x, int y) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->moveTo(x, y); + } +} + +void KisCanvasPainter::moveTo(const TQPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->moveTo(point); + } +} + +void KisCanvasPainter::lineTo(int x, int y) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->lineTo(x, y); + } +} + +void KisCanvasPainter::lineTo(const TQPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->lineTo(point); + } +} + +void KisCanvasPainter::drawLine(int x1, int y1, int x2, int y2) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawLine(x1, y1, x2, y2); + } +} + +void KisCanvasPainter::drawLine(const TQPoint& start, const TQPoint& end) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawLine(start, end); + } +} + +void KisCanvasPainter::drawRect(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawRect(x, y, w, h); + } +} + +void KisCanvasPainter::drawRect(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawRect(r); + } +} + +void KisCanvasPainter::drawWinFocusRect(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(x, y, w, h); + } +} + +void KisCanvasPainter::drawWinFocusRect(int x, int y, int w, int h, const TQColor& bgColor) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(x, y, w, h, bgColor); + } +} + +void KisCanvasPainter::drawWinFocusRect(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(r); + } +} + +void KisCanvasPainter::drawWinFocusRect(const TQRect& r, const TQColor& bgColor) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawWinFocusRect(r, bgColor); + } +} + +void KisCanvasPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawRoundRect(x, y, w, h, xRnd, yRnd); + } +} + +void KisCanvasPainter::drawRoundRect(const TQRect& r, int xRnd, int yRnd) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawRoundRect(r, xRnd, yRnd); + } +} + +void KisCanvasPainter::drawEllipse(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawEllipse(x, y, w, h); + } +} + +void KisCanvasPainter::drawEllipse(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawEllipse(r); + } +} + +void KisCanvasPainter::drawArc(int x, int y, int w, int h, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawArc(x, y, w, h, a, alen); + } +} + +void KisCanvasPainter::drawArc(const TQRect& r, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawArc(r, a, alen); + } +} + +void KisCanvasPainter::drawPie(int x, int y, int w, int h, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPie(x, y, w, h, a, alen); + } +} + +void KisCanvasPainter::drawPie(const TQRect& r, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPie(r, a, alen); + } +} + +void KisCanvasPainter::drawChord(int x, int y, int w, int h, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawChord(x, y, w, h, a, alen); + } +} + +void KisCanvasPainter::drawChord(const TQRect& r, int a, int alen) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawChord(r, a, alen); + } +} + +void KisCanvasPainter::drawLineSegments(const TQPointArray& pointArray, int index, int nlines) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawLineSegments(pointArray, index, nlines); + } +} + +void KisCanvasPainter::drawPolyline(const TQPointArray& pointArray, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPolyline(pointArray, index, npoints); + } +} + +void KisCanvasPainter::drawPolygon(const TQPointArray& pointArray, bool winding, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPolygon(pointArray, winding, index, npoints); + } +} + +void KisCanvasPainter::drawConvexPolygon(const TQPointArray& pointArray, int index, int npoints) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawConvexPolygon(pointArray, index, npoints); + } +} + +void KisCanvasPainter::drawCubicBezier(const TQPointArray& pointArray, int index) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawCubicBezier(pointArray, index); + } +} + +void KisCanvasPainter::drawPixmap(int x, int y, const TQPixmap& pixmap, int sx, int sy, int sw, int sh) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(x, y, pixmap, sx, sy, sw, sh); + } +} + +void KisCanvasPainter::drawPixmap(const TQPoint& point, const TQPixmap& pixmap, const TQRect& sr) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(point, pixmap, sr); + } +} + +void KisCanvasPainter::drawPixmap(const TQPoint& point, const TQPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(point, pixmap); + } +} + +void KisCanvasPainter::drawPixmap(const TQRect& r, const TQPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawPixmap(r, pixmap); + } +} + +void KisCanvasPainter::drawImage(int x, int y, const TQImage& image, int sx, int sy, int sw, int sh, int conversionFlags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(x, y, image, sx, sy, sw, sh, conversionFlags); + } +} + +void KisCanvasPainter::drawImage(const TQPoint& point, const TQImage& image, const TQRect& sr, int conversionFlags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(point, image, sr, conversionFlags); + } +} + +void KisCanvasPainter::drawImage(const TQPoint& point, const TQImage& image, int conversion_flags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(point, image, conversion_flags); + } +} + +void KisCanvasPainter::drawImage(const TQRect& r, const TQImage& image) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawImage(r, image); + } +} + +void KisCanvasPainter::drawTiledPixmap(int x, int y, int w, int h, const TQPixmap& pixmap, int sx, int sy) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(x, y, w, h, pixmap, sx, sy); + } +} + +void KisCanvasPainter::drawTiledPixmap(const TQRect& r, const TQPixmap& pixmap, const TQPoint& point) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(r, pixmap, point); + } +} + +void KisCanvasPainter::drawTiledPixmap(const TQRect& r, const TQPixmap& pixmap) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawTiledPixmap(r, pixmap); + } +} + +void KisCanvasPainter::fillRect(int x, int y, int w, int h, const TQBrush& brush) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->fillRect(x, y, w, h, brush); + } +} + +void KisCanvasPainter::fillRect(const TQRect& r, const TQBrush& brush) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->fillRect(r, brush); + } +} + +void KisCanvasPainter::eraseRect(int x, int y, int w, int h) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->eraseRect(x, y, w, h); + } +} + +void KisCanvasPainter::eraseRect(const TQRect& r) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->eraseRect(r); + } +} + +void KisCanvasPainter::drawText(int x, int y, const TQString& text, int len, TQPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, text, len, dir); + } +} + +void KisCanvasPainter::drawText(const TQPoint& point, const TQString& text, int len, TQPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(point, text, len, dir); + } +} + +void KisCanvasPainter::drawText(int x, int y, const TQString& text, int pos, int len, TQPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, text, pos, len, dir); + } +} + +void KisCanvasPainter::drawText(const TQPoint& point, const TQString& text, int pos, int len, TQPainter::TextDirection dir) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(point, text, pos, len, dir); + } +} + +void KisCanvasPainter::drawText(int x, int y, int w, int h, int flags, const TQString& text, int len, TQRect *br, TQTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(x, y, w, h, flags, text, len, br, intern); + } +} + +void KisCanvasPainter::drawText(const TQRect& r, int flags, const TQString& text, int len, TQRect *br, TQTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->drawText(r, flags, text, len, br, intern); + } +} + +void KisCanvasPainter::tqdrawTextItem(int x, int y, const TQTextItem& ti, int textflags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->tqdrawTextItem(x, y, ti, textflags); + } +} + +void KisCanvasPainter::tqdrawTextItem(const TQPoint& p, const TQTextItem& ti, int textflags) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->tqdrawTextItem(p, ti, textflags); + } +} + +TQRect KisCanvasPainter::boundingRect(int x, int y, int w, int h, int flags, const TQString& text, int len, TQTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->boundingRect(x, y, w, h, flags, text, len, intern); + } + return TQRect(); +} + +TQRect KisCanvasPainter::boundingRect(const TQRect& r, int flags, const TQString& text, int len, TQTextParag **intern) +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->boundingRect(r, flags, text, len, intern); + } + return TQRect(); +} + +int KisCanvasPainter::tabStops() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->tabStops(); + } + return 0; +} + +void KisCanvasPainter::setTabStops(int ts) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setTabStops(ts); + } +} + +int *KisCanvasPainter::tabArray() const +{ + if (m_canvasWidgetPainter != 0) { + return m_canvasWidgetPainter->tabArray(); + } + return 0; +} + +void KisCanvasPainter::setTabArray(int *ts) +{ + if (m_canvasWidgetPainter != 0) { + m_canvasWidgetPainter->setTabArray(ts); + } +} + diff --git a/chalk/ui/kis_canvas_painter.h b/chalk/ui/kis_canvas_painter.h new file mode 100644 index 00000000..9a719eea --- /dev/null +++ b/chalk/ui/kis_canvas_painter.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CANVAS_PAINTER_H_ +#define KIS_CANVAS_PAINTER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "kis_global.h" + +class KisCanvas; +class KisCanvasWidget; + +class KisCanvasWidgetPainter { +public: + KisCanvasWidgetPainter(); + virtual ~KisCanvasWidgetPainter(); + + virtual bool begin(KisCanvasWidget *canvasWidget, bool unclipped = false) = 0; + virtual bool end(); + + virtual void save(); + virtual void restore(); + + virtual TQFontMetrics fontMetrics() const; + virtual TQFontInfo fontInfo() const; + + virtual const TQFont& font() const; + virtual void setFont(const TQFont&); + virtual const TQPen& pen() const; + virtual void setPen(const TQPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const TQColor&); + virtual const TQBrush&brush() const; + virtual void setBrush(const TQBrush&); + virtual void setBrush(TQt::BrushStyle); + virtual void setBrush(const TQColor&); + virtual TQPoint pos() const; + + virtual const TQColor&backgroundColor() const; + virtual void setBackgroundColor(const TQColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual TQt::RasterOp rasterOp() const; + virtual void setRasterOp(TQt::RasterOp); + virtual const TQPoint&brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const TQPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual TQRect window() const; + virtual void setWindow(const TQRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual TQRect viewport() const; + virtual void setViewport(const TQRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const TQWMatrix&tqworldMatrix() const; + virtual void setWorldMatrix(const TQWMatrix&, bool combine=FALSE); + + virtual void saveWorldMatrix(); + virtual void restoreWorldMatrix(); + + virtual void scale(double sx, double sy); + virtual void shear(double sh, double sv); + virtual void rotate(double a); + + virtual void translate(double dx, double dy); + virtual void resetXForm(); + virtual double translationX() const; + virtual double translationY() const; + + virtual TQPoint xForm(const TQPoint&) const; + virtual TQRect xForm(const TQRect&) const; + virtual TQPointArray xForm(const TQPointArray&) const; + virtual TQPointArray xForm(const TQPointArray&, int index, int npoints) const; + virtual TQPoint xFormDev(const TQPoint&) const; + virtual TQRect xFormDev(const TQRect&) const; + virtual TQPointArray xFormDev(const TQPointArray&) const; + virtual TQPointArray xFormDev(const TQPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual TQRegion clipRegion(TQPainter::CoordinateMode = TQPainter::CoordDevice) const; + virtual void setClipRect(const TQRect&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRegion(const TQRegion&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const TQPoint&); + virtual void drawPoints(const TQPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const TQPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const TQPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const TQPoint&, const TQPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const TQRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const TQColor&bgColor); + virtual void drawWinFocusRect(const TQRect&); + virtual void drawWinFocusRect(const TQRect&, const TQColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const TQRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const TQRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const TQRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const TQRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const TQRect&, int a, int alen); + virtual void drawLineSegments(const TQPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const TQPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const TQPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const TQPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const TQPoint&, const TQPixmap&, const TQRect&sr); + virtual void drawPixmap(const TQPoint&, const TQPixmap&); + virtual void drawPixmap(const TQRect&, const TQPixmap&); + virtual void drawImage(int x, int y, const TQImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, const TQRect&sr, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, int conversion_flags = 0); + virtual void drawImage(const TQRect&, const TQImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const TQPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&, const TQPoint&); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&); + //virtual void drawPicture(const TQPicture&); + //virtual void drawPicture(int x, int y, const TQPicture&); + //virtual void drawPicture(const TQPoint&, const TQPicture&); + + virtual void fillRect(int x, int y, int w, int h, const TQBrush&); + virtual void fillRect(const TQRect&, const TQBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const TQRect&); + + virtual void drawText(int x, int y, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&p, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + virtual void drawText(const TQRect&, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + + virtual void tqdrawTextItem(int x, int y, const TQTextItem&ti, int textflags = 0); + virtual void tqdrawTextItem(const TQPoint& p, const TQTextItem&ti, int textflags = 0); + + virtual TQRect boundingRect(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + virtual TQRect boundingRect(const TQRect&, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + + virtual int tabStops() const; + virtual void setTabStops(int); + virtual int *tabArray() const; + virtual void setTabArray(int *); + +protected: + TQFont m_defaultFont; + TQPen m_defaultPen; + TQBrush m_defaultBrush; + TQColor m_defaultColor; + TQPoint m_defaultBrushOrigin; + TQWMatrix m_defaultWorldMatrix; +}; + +class KisCanvasPainter { +public: + KisCanvasPainter(); + KisCanvasPainter(KisCanvas *canvas); + KisCanvasPainter(const TQPaintDevice *paintDevice); + + ~KisCanvasPainter(); + + bool begin(KisCanvas *canvas, bool unclipped = false); + bool begin(const TQPaintDevice *paintDevice, bool unclipped = false); + + bool end(); + + void save(); + void restore(); + + TQFontMetrics fontMetrics() const; + TQFontInfo fontInfo() const; + + const TQFont& font() const; + void setFont(const TQFont&); + const TQPen& pen() const; + void setPen(const TQPen&); + void setPen(Qt::PenStyle); + void setPen(const TQColor&); + const TQBrush&brush() const; + void setBrush(const TQBrush&); + void setBrush(TQt::BrushStyle); + void setBrush(const TQColor&); + TQPoint pos() const; + + const TQColor&backgroundColor() const; + void setBackgroundColor(const TQColor&); + Qt::BGMode backgroundMode() const; + void setBackgroundMode(Qt::BGMode); + TQt::RasterOp rasterOp() const; + void setRasterOp(TQt::RasterOp); + const TQPoint&brushOrigin() const; + void setBrushOrigin(int x, int y); + void setBrushOrigin(const TQPoint&); + + bool hasViewXForm() const; + bool hasWorldXForm() const; + + void setViewXForm(bool); + TQRect window() const; + void setWindow(const TQRect&); + void setWindow(int x, int y, int w, int h); + TQRect viewport() const; + void setViewport(const TQRect&); + void setViewport(int x, int y, int w, int h); + + void setWorldXForm(bool); + const TQWMatrix&tqworldMatrix() const; + void setWorldMatrix(const TQWMatrix&, bool combine=FALSE); + + void saveWorldMatrix(); + void restoreWorldMatrix(); + + void scale(double sx, double sy); + void shear(double sh, double sv); + void rotate(double a); + + void translate(double dx, double dy); + void resetXForm(); + double translationX() const; + double translationY() const; + + TQPoint xForm(const TQPoint&) const; + TQRect xForm(const TQRect&) const; + TQPointArray xForm(const TQPointArray&) const; + TQPointArray xForm(const TQPointArray&, int index, int npoints) const; + TQPoint xFormDev(const TQPoint&) const; + TQRect xFormDev(const TQRect&) const; + TQPointArray xFormDev(const TQPointArray&) const; + TQPointArray xFormDev(const TQPointArray&, int index, int npoints) const; + + void setClipping(bool); + bool hasClipping() const; + TQRegion clipRegion(TQPainter::CoordinateMode = TQPainter::CoordDevice) const; + void setClipRect(const TQRect&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + void setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode = TQPainter::CoordDevice); + void setClipRegion(const TQRegion&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + + void drawPoint(int x, int y); + void drawPoint(const TQPoint&); + void drawPoints(const TQPointArray& a, int index=0, int npoints=-1); + void moveTo(int x, int y); + void moveTo(const TQPoint&); + void lineTo(int x, int y); + void lineTo(const TQPoint&); + void drawLine(int x1, int y1, int x2, int y2); + void drawLine(const TQPoint&, const TQPoint&); + void drawRect(int x, int y, int w, int h); + void drawRect(const TQRect&); + void drawWinFocusRect(int x, int y, int w, int h); + void drawWinFocusRect(int x, int y, int w, int h, const TQColor&bgColor); + void drawWinFocusRect(const TQRect&); + void drawWinFocusRect(const TQRect&, const TQColor&bgColor); + void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + void drawRoundRect(const TQRect&, int = 25, int = 25); + void drawEllipse(int x, int y, int w, int h); + void drawEllipse(const TQRect&); + void drawArc(int x, int y, int w, int h, int a, int alen); + void drawArc(const TQRect&, int a, int alen); + void drawPie(int x, int y, int w, int h, int a, int alen); + void drawPie(const TQRect&, int a, int alen); + void drawChord(int x, int y, int w, int h, int a, int alen); + void drawChord(const TQRect&, int a, int alen); + void drawLineSegments(const TQPointArray&, int index=0, int nlines=-1); + void drawPolyline(const TQPointArray&, int index=0, int npoints=-1); + void drawPolygon(const TQPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + void drawConvexPolygon(const TQPointArray&, int index=0, int npoints=-1); + void drawCubicBezier(const TQPointArray&, int index=0); + void drawPixmap(int x, int y, const TQPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + void drawPixmap(const TQPoint&, const TQPixmap&, const TQRect&sr); + void drawPixmap(const TQPoint&, const TQPixmap&); + void drawPixmap(const TQRect&, const TQPixmap&); + void drawImage(int x, int y, const TQImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + void drawImage(const TQPoint&, const TQImage&, const TQRect&sr, int conversionFlags = 0); + void drawImage(const TQPoint&, const TQImage&, int conversion_flags = 0); + void drawImage(const TQRect&, const TQImage&); + void drawTiledPixmap(int x, int y, int w, int h, const TQPixmap&, int sx=0, int sy=0); + void drawTiledPixmap(const TQRect&, const TQPixmap&, const TQPoint&); + void drawTiledPixmap(const TQRect&, const TQPixmap&); + //void drawPicture(const TQPicture&); + //void drawPicture(int x, int y, const TQPicture&); + //void drawPicture(const TQPoint&, const TQPicture&); + + void fillRect(int x, int y, int w, int h, const TQBrush&); + void fillRect(const TQRect&, const TQBrush&); + void eraseRect(int x, int y, int w, int h); + void eraseRect(const TQRect&); + + void drawText(int x, int y, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + void drawText(const TQPoint&, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + + void drawText(int x, int y, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + void drawText(const TQPoint&p, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + + void drawText(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + void drawText(const TQRect&, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + + void tqdrawTextItem(int x, int y, const TQTextItem&ti, int textflags = 0); + void tqdrawTextItem(const TQPoint& p, const TQTextItem&ti, int textflags = 0); + + TQRect boundingRect(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + TQRect boundingRect(const TQRect&, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + + int tabStops() const; + void setTabStops(int); + int *tabArray() const; + void setTabArray(int *); + +protected: + KisCanvasWidgetPainter *m_canvasWidgetPainter; + TQFont m_defaultFont; + TQPen m_defaultPen; + TQBrush m_defaultBrush; + TQColor m_defaultColor; + TQPoint m_defaultBrushOrigin; + TQWMatrix m_defaultWorldMatrix; +}; + +#endif // KIS_CANVAS_PAINTER_H_ + diff --git a/chalk/ui/kis_clipboard.cc b/chalk/ui/kis_clipboard.cc new file mode 100644 index 00000000..d52f5ec9 --- /dev/null +++ b/chalk/ui/kis_clipboard.cc @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kdebug.h" + +#include "KoStore.h" +#include "KoStoreDrag.h" + +#include "kis_types.h" +#include "kis_paint_device.h" +#include "kis_config.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_factory.h" +#include +#include "kis_clipboard.h" + +KisClipboard *KisClipboard::m_singleton = 0; + +KisClipboard::KisClipboard() +{ + Q_ASSERT(KisClipboard::m_singleton == 0); + KisClipboard::m_singleton = this; + + m_pushedClipboard = false; + m_hasClip = false; + m_clip = 0; + + // Check that we don't already have a clip ready + clipboardDataChanged(); + + // Make sure we are notified when clipboard changes + connect( TQApplication::tqclipboard(), TQT_SIGNAL( dataChanged() ), + this, TQT_SLOT( clipboardDataChanged() ) ); +} + +KisClipboard::~KisClipboard() +{ +} + +KisClipboard* KisClipboard::instance() +{ + if(KisClipboard::m_singleton == 0) + { + KisClipboard::m_singleton = new KisClipboard(); + Q_CHECK_PTR(KisClipboard::m_singleton); + } + return KisClipboard::m_singleton; +} + +void KisClipboard::setClip(KisPaintDeviceSP selection) +{ + m_clip = selection; + + if (!selection) + return; + + m_hasClip = true; + + // We'll create a store (ZIP format) in memory + TQBuffer buffer; + TQCString mimeType("application/x-chalk-selection"); + KoStore* store = KoStore::createStore( TQT_TQIODEVICE(&buffer), KoStore::Write, mimeType ); + Q_ASSERT( store ); + Q_ASSERT( !store->bad() ); + + // Layer data + if (store->open("layerdata")) { + if (!selection->write(store)) { + selection->disconnect(); + store->close(); + return; + } + store->close(); + } + + // ColorSpace id of layer data + if (store->open("colorspace")) { + TQString csName = selection->colorSpace()->id().id(); + store->write(csName.ascii(), strlen(csName.ascii())); + store->close(); + } + + if (selection->colorSpace()->getProfile()) { + KisAnnotationSP annotation = selection->colorSpace()->getProfile()->annotation(); + if (annotation) { + // save layer profile + if (store->open("profile.icc")) { + store->write(annotation->annotation()); + store->close(); + } + } + } + + delete store; + + // We also create a TQImage so we can interchange with other applications + TQImage qimg; + KisConfig cfg; + TQString monitorProfileName = cfg.monitorProfile(); + KisProfile * monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + qimg = selection->convertToTQImage(monitorProfile); + + TQImageDrag *qimgDrag = new TQImageDrag(qimg); + KMultipleDrag *multiDrag = new KMultipleDrag(); + if ( !qimg.isNull() ) + multiDrag->addDragObject( qimgDrag ); + KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 ); + storeDrag->setEncodedData( buffer.buffer() ); + multiDrag->addDragObject( storeDrag ); + + + TQClipboard *cb = TQApplication::tqclipboard(); + cb->setData(multiDrag); + m_pushedClipboard = true; +} + +KisPaintDeviceSP KisClipboard::clip() +{ + TQClipboard *cb = TQApplication::tqclipboard(); + TQCString mimeType("application/x-chalk-selection"); + TQMimeSource *cbData = cb->data(); + + if(cbData && cbData->provides(mimeType)) + { + TQBuffer buffer(cbData->tqencodedData(mimeType)); + KoStore* store = KoStore::createStore( TQT_TQIODEVICE(&buffer), KoStore::Read, mimeType ); + KisProfile *profile=0; + + if (store->hasFile("profile.icc")) { + TQByteArray data; + store->open("profile.icc"); + data = store->read(store->size()); + store->close(); + profile = new KisProfile(data); + } + + TQString csName; + // ColorSpace id of layer data + if (store->hasFile("colorspace")) { + store->open("colorspace"); + csName = TQString(store->read(store->size())); + store->close(); + } + + KisColorSpace *cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName, ""), profile); + + m_clip = new KisPaintDevice(cs, "clip"); + + if (store->hasFile("layerdata")) { + store->open("layerdata"); + m_clip->read(store); + store->close(); + } + delete store; + } + else + { + TQImage qimg = cb->image(); + + if (qimg.isNull()) + return 0; + + KisConfig cfg; + + TQ_UINT32 behaviour = cfg.pasteBehaviour(); + + if(behaviour==2) + { + // Ask user each time + behaviour = TQMessageBox::question(0,i18n("Pasting data from simple source"),i18n("The image data you are trying to paste has no colour profile information.\n\nOn the web and in simple applications the data are supposed to be in sRGB color format.\nImporting as web will show it as it is supposed to look.\nMost monitors are not perfect though so if you made the image yourself\nyou might want to import it as it looked on you monitor.\n\nHow do you want to interpret these data?"),i18n("As &Web"),i18n("As on &Monitor")); + } + + KisColorSpace * cs; + TQString profileName(""); + if(behaviour==1) + profileName = cfg.monitorProfile(); + + cs = KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""), profileName); + m_clip = new KisPaintDevice(cs, "from paste"); + Q_CHECK_PTR(m_clip); + m_clip->convertFromTQImage(qimg, profileName); + } + + return m_clip; +} + +void KisClipboard::clipboardDataChanged() +{ + if (!m_pushedClipboard) { + m_hasClip = false; + TQClipboard *cb = TQApplication::tqclipboard(); + TQImage qimg = cb->image(); + TQMimeSource *cbData = cb->data(); + TQCString mimeType("application/x-chalk-selection"); + + if(cbData && cbData->provides(mimeType)) + m_hasClip = true; + + if (!qimg.isNull()) + m_hasClip = true; + } + + m_pushedClipboard = false; +} + + +bool KisClipboard::hasClip() +{ + return m_hasClip; +} + +TQSize KisClipboard::clipSize() +{ + + TQClipboard *cb = TQApplication::tqclipboard(); + TQCString mimeType("application/x-chalk-selection"); + TQMimeSource *cbData = cb->data(); + + KisPaintDeviceSP clip; + + if(cbData && cbData->provides(mimeType)) { + + TQBuffer buffer(cbData->tqencodedData(mimeType)); + KoStore* store = KoStore::createStore( TQT_TQIODEVICE(&buffer), KoStore::Read, mimeType ); + KisProfile *profile=0; + + if (store->hasFile("profile.icc")) { + TQByteArray data; + store->open("profile.icc"); + data = store->read(store->size()); + store->close(); + profile = new KisProfile(data); + } + + TQString csName; + // ColorSpace id of layer data + if (store->hasFile("colorspace")) { + store->open("colorspace"); + csName = TQString(store->read(store->size())); + store->close(); + } + + KisColorSpace *cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName, ""), profile); + + clip = new KisPaintDevice(cs, "clip"); + + if (store->hasFile("layerdata")) { + store->open("layerdata"); + clip->read(store); + store->close(); + } + delete store; + + return clip->exactBounds().size(); + } + else { + TQImage qimg = cb->image(); + return qimg.size(); + } +; + +} + +#include "kis_clipboard.moc" diff --git a/chalk/ui/kis_clipboard.h b/chalk/ui/kis_clipboard.h new file mode 100644 index 00000000..020240e6 --- /dev/null +++ b/chalk/ui/kis_clipboard.h @@ -0,0 +1,80 @@ +/* + * kis_clipboard.h - part of Krayon + * + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_CLIPBOARD_H_ +#define __KIS_CLIPBOARD_H_ + + +#include +#include "kis_types.h" + +class TQImage; + +/** + * The Chalk clipboard is a clipboard that can store paint devices + * instead of just qimage's. + */ +class KisClipboard : public TQObject { + + Q_OBJECT + TQ_OBJECT + +public: + + virtual ~KisClipboard(); + + static KisClipboard* instance(); + + /** + * Sets the clipboard to the contents of the specified paint device; also + * set the system clipboard to a TQImage representation of the specified + * paint device. + */ + void setClip(KisPaintDeviceSP layer); + + /** + * Get the contents of the clipboard in the form of a paint device. + */ + KisPaintDeviceSP clip(); + + bool hasClip(); + + TQSize clipSize(); + +private slots: + + void clipboardDataChanged(); +private: + + KisClipboard(); + KisClipboard(const KisClipboard &); + KisClipboard operator=(const KisClipboard &); + + static KisClipboard * m_singleton; + + KisPaintDeviceSP m_clip; + bool m_hasClip; + + bool m_pushedClipboard; + + +}; + +#endif // __KIS_CLIPBOARD_H_ diff --git a/chalk/ui/kis_cmb_composite.cc b/chalk/ui/kis_cmb_composite.cc new file mode 100644 index 00000000..54c4b643 --- /dev/null +++ b/chalk/ui/kis_cmb_composite.cc @@ -0,0 +1,88 @@ +/* + * kis_cmb_composite.cc - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include "kis_cmb_composite.h" + +KisCmbComposite::KisCmbComposite(TQWidget * tqparent, const char * name) + : super( false, tqparent, name ) +{ + connect(this, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotOpActivated(int))); + connect(this, TQT_SIGNAL(highlighted(int)), this, TQT_SLOT(slotOpHighlighted(int))); +} + +KisCmbComposite::~KisCmbComposite() +{ +} + +void KisCmbComposite::setCompositeOpList(const KisCompositeOpList & list) +{ + super::clear(); + m_list = list; + KisCompositeOpList::iterator it; + for( it = m_list.begin(); it != m_list.end(); ++it ) + insertItem((*it).id().name()); +} + +KisCompositeOp KisCmbComposite::currentItem() const +{ + TQ_UINT32 i = super::currentItem(); + if (i > m_list.count()) return KisCompositeOp(); + + return m_list[i]; +} + +void KisCmbComposite::setCurrentItem(const KisCompositeOp& op) +{ + if (m_list.tqfind(op) != m_list.end()) { + super::setCurrentText(op.id().name()); + } +} + +void KisCmbComposite::setCurrentText(const TQString & s) +{ + KisCompositeOpList::iterator it; + for( it = m_list.begin(); it != m_list.end(); ++it ) + if ((*it).id().id() == s) { + super::setCurrentText((*it).id().name()); + } +} + +void KisCmbComposite::slotOpActivated(int i) +{ + if ((TQ_UINT32)i > m_list.count()) return; + + emit activated(m_list[i]); +} + +void KisCmbComposite::slotOpHighlighted(int i) +{ + if ((TQ_UINT32)i > m_list.count()) return; + + emit highlighted(m_list[i]); +} + + +#include "kis_cmb_composite.moc" + diff --git a/chalk/ui/kis_cmb_composite.h b/chalk/ui/kis_cmb_composite.h new file mode 100644 index 00000000..ef5df0e6 --- /dev/null +++ b/chalk/ui/kis_cmb_composite.h @@ -0,0 +1,71 @@ +/* + * kis_cmb_composite.h - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CMB_COMPOSITE_H_ +#define KIS_CMB_COMPOSITE_H_ + +#include +#include "tqcombobox.h" +#include "kis_composite_op.h" + +/** + * A combobox filled with the various composition strategies defined in kis_global. + * + * XXX: devise some kind of capabilities database for the various colour strategies + * + * enum constant Description CMYK RGBA GRAYA + * 1 COMPOSITE_OVER Over X - X + * + * But that's for later... + */ + +class KRITAUI_EXPORT KisCmbComposite : public TQComboBox +{ + typedef TQComboBox super; + + Q_OBJECT + TQ_OBJECT + + public: + + KisCmbComposite(TQWidget * tqparent = 0, const char * name = 0 ); + virtual ~KisCmbComposite(); + + KisCompositeOp currentItem() const; + + void setCompositeOpList(const KisCompositeOpList& list); + void setCurrentItem(const KisCompositeOp& op); + void setCurrentText(const TQString & s); + +signals: + + void activated(const KisCompositeOp &); + void highlighted(const KisCompositeOp &); + +private slots: + + void slotOpActivated(int i); + void slotOpHighlighted(int i); + +private: + KisCompositeOpList m_list; +}; + +#endif diff --git a/chalk/ui/kis_cmb_idlist.cc b/chalk/ui/kis_cmb_idlist.cc new file mode 100644 index 00000000..bdd6f09b --- /dev/null +++ b/chalk/ui/kis_cmb_idlist.cc @@ -0,0 +1,97 @@ +/* + * kis_cmb_idlist.cc - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include + +#include "kis_id.h" +#include "kis_cmb_idlist.h" + +KisCmbIDList::KisCmbIDList(TQWidget * tqparent, const char * name) + : super( false, tqparent, name ) +{ + connect(this, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotIDActivated(int))); + connect(this, TQT_SIGNAL(highlighted(int)), this, TQT_SLOT(slotIDHighlighted(int))); +} + +KisCmbIDList::~KisCmbIDList() +{ +} + + +void KisCmbIDList::setIDList(const KisIDList & list) +{ + m_list = list; + KisIDList::iterator it; + for( it = m_list.begin(); it != m_list.end(); ++it ) + insertItem((*it).name()); +} + + +KisID KisCmbIDList::currentItem() const +{ + TQ_UINT32 i = super::currentItem(); + if (i > m_list.count()) return KisID(); + + return m_list[i]; +} + +void KisCmbIDList::setCurrent(const KisID id) +{ + if (m_list.tqfind(id) != m_list.end()) + super::setCurrentText(id.name()); + else { + m_list.push_back(id); + insertItem(id.name()); + super::setCurrentText(id.name()); + } +} + +void KisCmbIDList::setCurrentText(const TQString & s) +{ + KisIDList::iterator it; + for( it = m_list.begin(); it != m_list.end(); ++it ) + if ((*it).id() == s) { + super::setCurrentText((*it).name()); + } +} + +void KisCmbIDList::slotIDActivated(int i) +{ + if ((uint)i > m_list.count()) return; + + emit activated(m_list[i]); + +} + +void KisCmbIDList::slotIDHighlighted(int i) +{ + if ((uint)i > m_list.count()) return; + + emit highlighted(m_list[i]); + +} + + + +#include "kis_cmb_idlist.moc" + diff --git a/chalk/ui/kis_cmb_idlist.h b/chalk/ui/kis_cmb_idlist.h new file mode 100644 index 00000000..2665c8f8 --- /dev/null +++ b/chalk/ui/kis_cmb_idlist.h @@ -0,0 +1,68 @@ +/* + * kis_cmb_imagetype.h - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CMB_IDLIST_H_ +#define KIS_CMB_IDLIST_H_ + +#include "tqcombobox.h" + +#include "kis_id.h" + +/** + * A combobox that is associated with a list of KisID's. The + * descriptive (i18n'ed) text is displayed, but the various + * signals return a KisID. + */ +class KisCmbIDList : public TQComboBox +{ + typedef TQComboBox super; + + Q_OBJECT + TQ_OBJECT + +public: + + KisCmbIDList(TQWidget * tqparent = 0, const char * name = 0 ); + virtual ~KisCmbIDList(); + + +public: + void setIDList(const KisIDList & list); + void setCurrent(const KisID id); + void setCurrentText(const TQString & s); + + KisID currentItem() const; + +signals: + + void activated(const KisID &); + void highlighted(const KisID &); + +private slots: + + void slotIDActivated(int i); + void slotIDHighlighted(int i); + +private: + + KisIDList m_list; + +}; +#endif diff --git a/chalk/ui/kis_color_cup.cc b/chalk/ui/kis_color_cup.cc new file mode 100644 index 00000000..44a9699b --- /dev/null +++ b/chalk/ui/kis_color_cup.cc @@ -0,0 +1,118 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 1999 Matthias Elter (me@kde.org) + * Copyright (c) 2001-2002 Igor Jansen (rm@kde.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +KisColorPopup::KisColorPopup(TQColor c, TQWidget * tqparent, const char * name) + : TQFrame(tqparent, name, WType_Popup | WStyle_Customize | WStyle_NoBorder) +{ + m_color = c; + setMargin(4); + setFocusPolicy(TQ_StrongFocus); + TQHBoxLayout * l = new TQHBoxLayout(this); + l->add(m_khsSelector = new KHSSelector(this)); + m_khsSelector->setMinimumSize(140, 7); + l->add(m_valueSelector = new KValueSelector(this)); + m_valueSelector->setMinimumSize(26, 70); + m_khsSelector->show(); + m_valueSelector->show(); + +} + +KisColorCup::KisColorCup(TQWidget * tqparent, const char * name) + : TQPushButton(tqparent, name) +{ + m_color = TQt::black; + m_popup = new KisColorPopup(m_color, this, "colorpopup"); + connect(this, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotClicked())); + connect(m_popup, TQT_SIGNAL(changed( const TQColor &)), this, TQT_SLOT(setColor(const TQColor &))); +} + +void KisColorCup::setColor(const TQColor & c) +{ + m_color = c; + emit changed(c); +} + +void KisColorCup::slotClicked() +{ +// m_popup->move(this->mapToGlobal( this->rect().topRight() ) ); +// m_popup->show(); + emit changed(m_color); +} + +TQSize KisColorCup::tqsizeHint() const +{ + return tqstyle().tqsizeFromContents(TQStyle::CT_PushButton, this, TQSize(24, 24)). + expandedTo(TQApplication::globalStrut()); +} + +void KisColorCup::drawButtonLabel( TQPainter *painter ) +{ + int x, y, w, h; + TQRect r = tqstyle().subRect( TQStyle::SR_PushButtonContents, this ); + r.rect(&x, &y, &w, &h); + + int margin = 2; //tqstyle().tqpixelMetric( TQStyle::PM_ButtonMargin, this ); + x += margin; + y += margin; + w -= 2*margin; + h -= 2*margin; + + if (isOn() || isDown()) { + x += tqstyle().tqpixelMetric( TQStyle::PM_ButtonShiftHorizontal, this ); + y += tqstyle().tqpixelMetric( TQStyle::PM_ButtonShiftVertical, this ); + } + + qDrawShadePanel( painter, x, y, w, h, tqcolorGroup(), true, 1, NULL); + if ( m_color.isValid() ) + painter->fillRect( x+1, y+1, w-2, h-2, m_color ); + + if ( hasFocus() ) { + TQRect focusRect = tqstyle().subRect( TQStyle::SR_PushButtonFocusRect, this ); + tqstyle().tqdrawPrimitive( TQStyle::PE_FocusRect, painter, focusRect, tqcolorGroup() ); + } + +} + +#include "kis_color_cup.moc" diff --git a/chalk/ui/kis_color_cup.h b/chalk/ui/kis_color_cup.h new file mode 100644 index 00000000..7a59837a --- /dev/null +++ b/chalk/ui/kis_color_cup.h @@ -0,0 +1,96 @@ +/* This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLOR_CUP_H +#define KIS_COLOR_CUP_H + +#include +#include +#include + +#include + +class TQSize; +class TQPainter; +class TQWidget; +class KHSSelector; +class KValueSelector; + +class KisColorPopup : public TQFrame { + + Q_OBJECT + TQ_OBJECT + +public: + + KisColorPopup(TQColor color, TQWidget * w, const char * name); + virtual ~KisColorPopup() {}; + +signals: + + void changed(const TQColor &); + +private: + + KHSSelector * m_khsSelector; + KValueSelector * m_valueSelector; + + TQColor m_color; +}; + +class KRITAUI_EXPORT KisColorCup : public TQPushButton { + + Q_OBJECT + TQ_OBJECT + +public: + + KisColorCup(TQWidget * tqparent, const char * name = 0); + + virtual ~KisColorCup() {}; + + TQColor color() { return m_color; }; + +signals: + + void changed(const TQColor &); + +public: + + TQSize tqsizeHint() const; + +public slots: + + void setColor(const TQColor & c); + + +private slots: + + void slotClicked(); + +protected: + + virtual void drawButtonLabel( TQPainter *p ); + +private: + + KisColorPopup * m_popup; + TQColor m_color; +}; + +#endif diff --git a/chalk/ui/kis_config.cc b/chalk/ui/kis_config.cc new file mode 100644 index 00000000..6d07790b --- /dev/null +++ b/chalk/ui/kis_config.cc @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include +#include + +#include LCMS_HEADER + +#include "kis_global.h" +#include "kis_config.h" + +namespace { + const double IMG_DEFAULT_RESOLUTION = 100.0; + const TQ_INT32 IMG_DEFAULT_WIDTH = 512; + const TQ_INT32 IMG_DEFAULT_HEIGHT = 512; + const enumCursorStyle DEFAULT_CURSOR_STYLE = CURSOR_STYLE_OUTLINE; + const TQ_INT32 DEFAULT_MAX_THREADS = 4; + const TQ_INT32 DEFAULT_MAX_TILES_MEM = 500; // 8192 kilobytes given 64x64 tiles with 32bpp + const TQ_INT32 DEFAULT_SWAPPINESS = 100; + const TQ_INT32 DEFAULT_PRESSURE_CORRECTION = 50; + const TQ_INT32 DEFAULT_DOCKABILITY = 0; + const TQ_INT32 DEFAULT_UNDO_LIMIT = 50; +} + +KisConfig::KisConfig() +{ + + m_cfg = KGlobal::config(); + if (!m_cfg) { + // Allow unit tests to test parts of the code without having to run the + // full application. + m_cfg = new KConfig(); + } + m_cfg->setGroup(""); +} + +KisConfig::~KisConfig() +{ + m_cfg->sync(); +} + + +bool KisConfig::fixDockerWidth() const +{ + return m_cfg->readBoolEntry("fixDockerWidth", true); +} + +void KisConfig::setFixedDockerWidth(bool fix) +{ + m_cfg->writeEntry("fixDockerWidth", fix); +} + +bool KisConfig::undoEnabled() const +{ + return m_cfg->readBoolEntry("undoEnabled", true); +} + +void KisConfig::setUndoEnabled(bool undo) +{ + m_cfg->writeEntry("undoEnabled", undo); +} + + +TQ_INT32 KisConfig::defUndoLimit() const +{ + return m_cfg->readNumEntry("undolimit", DEFAULT_UNDO_LIMIT); +} + +void KisConfig::defUndoLimit(TQ_INT32 limit) +{ + m_cfg->writeEntry("undolimit", limit); +} + +TQ_INT32 KisConfig::defImgWidth() const +{ + return m_cfg->readNumEntry("imgWidthDef", IMG_DEFAULT_WIDTH); +} + +TQ_INT32 KisConfig::defImgHeight() const +{ + return m_cfg->readNumEntry("imgHeightDef", IMG_DEFAULT_HEIGHT); +} + +double KisConfig::defImgResolution() const +{ + return m_cfg->readDoubleNumEntry("imgResolutionDef", IMG_DEFAULT_RESOLUTION); +} + +void KisConfig::defImgWidth(TQ_INT32 width) +{ + m_cfg->writeEntry("imgWidthDef", width); +} + +void KisConfig::defImgHeight(TQ_INT32 height) +{ + m_cfg->writeEntry("imgHeightDef", height); +} + +void KisConfig::defImgResolution(double res) +{ + m_cfg->writeEntry("imgResolutionDef", res); +} + +enumCursorStyle KisConfig::cursorStyle() const +{ + return (enumCursorStyle) m_cfg->readNumEntry("cursorStyleDef", DEFAULT_CURSOR_STYLE); +} + +enumCursorStyle KisConfig::getDefaultCursorStyle() const +{ + return DEFAULT_CURSOR_STYLE; +} + +void KisConfig::setCursorStyle(enumCursorStyle style) +{ + m_cfg->writeEntry("cursorStyleDef", style); +} + + +TQString KisConfig::monitorProfile() const +{ + return m_cfg->readEntry("monitorProfile", ""); +} + +void KisConfig::setMonitorProfile(TQString monitorProfile) +{ + m_cfg->writeEntry("monitorProfile", monitorProfile); +} + + +TQString KisConfig::workingColorSpace() const +{ + return m_cfg->readEntry("workingColorSpace", "RGBA"); +} + +void KisConfig::setWorkingColorSpace(TQString workingColorSpace) +{ + m_cfg->writeEntry(workingColorSpace, workingColorSpace); +} + + +TQString KisConfig::printerColorSpace() const +{ + return m_cfg->readEntry("printerColorSpace", "CMYK"); +} + +void KisConfig::setPrinterColorSpace(TQString printerColorSpace) +{ + m_cfg->writeEntry("printerColorSpace", printerColorSpace); +} + + +TQString KisConfig::printerProfile() const +{ + return m_cfg->readEntry("printerProfile", ""); +} + +void KisConfig::setPrinterProfile(TQString printerProfile) +{ + m_cfg->writeEntry("printerProfile", printerProfile); +} + + +bool KisConfig::useBlackPointCompensation() const +{ + return m_cfg->readBoolEntry("useBlackPointCompensation", false); +} + +void KisConfig::setUseBlackPointCompensation(bool useBlackPointCompensation) +{ + m_cfg->writeEntry("useBlackPointCompensation", useBlackPointCompensation); +} + + +bool KisConfig::showRulers() const +{ + return m_cfg->readBoolEntry("showrulers", false); +} + +void KisConfig::setShowRulers(bool rulers) +{ + m_cfg->writeEntry("showrulers", rulers); +} + + +TQ_INT32 KisConfig::pasteBehaviour() const +{ + return m_cfg->readNumEntry("pasteBehaviour", 2); +} + +void KisConfig::setPasteBehaviour(TQ_INT32 renderIntent) +{ + m_cfg->writeEntry("pasteBehaviour", renderIntent); +} + + +TQ_INT32 KisConfig::renderIntent() const +{ + return m_cfg->readNumEntry("renderIntent", INTENT_PERCEPTUAL); +} + +void KisConfig::setRenderIntent(TQ_INT32 renderIntent) +{ + m_cfg->writeEntry("renderIntent", renderIntent); +} + +bool KisConfig::useOpenGL() const +{ + return m_cfg->readBoolEntry("useOpenGL", false); +} + +void KisConfig::setUseOpenGL(bool useOpenGL) +{ + m_cfg->writeEntry("useOpenGL", useOpenGL); +} + +bool KisConfig::useOpenGLShaders() const +{ + return m_cfg->readBoolEntry("useOpenGLShaders", false); +} + +void KisConfig::setUseOpenGLShaders(bool useOpenGLShaders) +{ + m_cfg->writeEntry("useOpenGLShaders", useOpenGLShaders); +} + +TQ_INT32 KisConfig::maxNumberOfThreads() +{ + return m_cfg->readNumEntry("maxthreads", DEFAULT_MAX_THREADS); +} + +void KisConfig::setMaxNumberOfThreads(TQ_INT32 maxThreads) +{ + m_cfg->writeEntry("maxthreads", maxThreads); +} + +TQ_INT32 KisConfig::maxTilesInMem() const +{ + return m_cfg->readNumEntry("maxtilesinmem", DEFAULT_MAX_TILES_MEM); +} + +void KisConfig::setMaxTilesInMem(TQ_INT32 tiles) +{ + m_cfg->writeEntry("maxtilesinmem", tiles); +} + +TQ_INT32 KisConfig::swappiness() const +{ + return m_cfg->readNumEntry("swappiness", DEFAULT_SWAPPINESS); +} + +void KisConfig::setSwappiness(TQ_INT32 swappiness) +{ + m_cfg->writeEntry("swappiness", swappiness); +} + +TQ_INT32 KisConfig::getPressureCorrection() +{ + return m_cfg->readNumEntry( "pressurecorrection", DEFAULT_PRESSURE_CORRECTION ); +} + +void KisConfig::setPressureCorrection( TQ_INT32 correction ) +{ + m_cfg->writeEntry( "pressurecorrection", correction ); +} + +TQ_INT32 KisConfig::getDefaultPressureCorrection() +{ + return DEFAULT_PRESSURE_CORRECTION; +} + +bool KisConfig::tabletDeviceEnabled(const TQString& tabletDeviceName) const +{ + return m_cfg->readBoolEntry("TabletDevice" + tabletDeviceName + "Enabled", false); +} + +void KisConfig::setTabletDeviceEnabled(const TQString& tabletDeviceName, bool enabled) +{ + m_cfg->writeEntry("TabletDevice" + tabletDeviceName + "Enabled", enabled); +} + +TQ_INT32 KisConfig::tabletDeviceAxis(const TQString& tabletDeviceName, const TQString& axisName, TQ_INT32 defaultAxis) const +{ + return m_cfg->readNumEntry("TabletDevice" + tabletDeviceName + axisName, defaultAxis); +} + +void KisConfig::setTabletDeviceAxis(const TQString& tabletDeviceName, const TQString& axisName, TQ_INT32 axis) const +{ + m_cfg->writeEntry("TabletDevice" + tabletDeviceName + axisName, axis); +} + +void KisConfig::setDockability( TQ_INT32 dockability ) +{ + m_cfg->writeEntry( "palettesdockability", dockability ); +} + +TQ_INT32 KisConfig::dockability() +{ + return m_cfg->readNumEntry("palettesdockability", DEFAULT_DOCKABILITY); +} + +TQ_INT32 KisConfig::getDefaultDockability() +{ + return DEFAULT_DOCKABILITY; +} + +float KisConfig::dockerFontSize() +{ + return (float) m_cfg->readNumEntry("palettefontsize", (int)getDefaultDockerFontSize()); +} + +float KisConfig::getDefaultDockerFontSize() +{ + float ps = TQMIN(9, KGlobalSettings::generalFont().pointSize() * 0.8); + if (ps < 6) ps = 6; + return ps; +} + +void KisConfig::setDockerFontSize(float size) +{ + m_cfg->writeEntry("palettefontsize", size); +} + +TQ_UINT32 KisConfig::getGridMainStyle() +{ + TQ_UINT32 v = m_cfg->readNumEntry("gridmainstyle", 0); + if (v > 2) + v = 2; + return v; +} + +void KisConfig::setGridMainStyle(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridmainstyle", v); +} + +TQ_UINT32 KisConfig::getGridSubdivisionStyle() +{ + TQ_UINT32 v = m_cfg->readNumEntry("gridsubdivisionstyle", 1); + if (v > 2) v = 2; + return v; +} + +void KisConfig::setGridSubdivisionStyle(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridsubdivisionstyle", v); +} + +TQColor KisConfig::getGridMainColor() +{ + return m_cfg->readColorEntry("gridmaincolor", new TQColor(99,99,99)); +} + +void KisConfig::setGridMainColor(TQColor v) +{ + m_cfg->writeEntry("gridmaincolor", v); +} + +TQColor KisConfig::getGridSubdivisionColor() +{ + return m_cfg->readColorEntry("gridsubdivisioncolor", new TQColor(150,150,150)); +} + +void KisConfig::setGridSubdivisionColor(TQColor v) +{ + m_cfg->writeEntry("gridsubdivisioncolor", v); +} + +TQ_UINT32 KisConfig::getGridHSpacing() +{ + TQ_INT32 v = m_cfg->readNumEntry("gridhspacing", 10); + return (TQ_UINT32)TQMAX(1, v ); +} + +void KisConfig::setGridHSpacing(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridhspacing", v); +} + +TQ_UINT32 KisConfig::getGridVSpacing() +{ + TQ_INT32 v = m_cfg->readNumEntry("gridvspacing", 10); + return (TQ_UINT32)TQMAX(1, v ); +} + +void KisConfig::setGridVSpacing(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridvspacing", v); +} + +TQ_UINT32 KisConfig::getGridSubdivisions() +{ + TQ_INT32 v = m_cfg->readNumEntry("gridsubsivisons", 2); + return (TQ_UINT32)TQMAX(1, v ); +} + +void KisConfig::setGridSubdivisions(TQ_UINT32 v) +{ + return m_cfg->writeEntry("gridsubsivisons", v); +} + +TQ_UINT32 KisConfig::getGridOffsetX() +{ + TQ_INT32 v = m_cfg->readNumEntry("gridoffsetx", 0); + return (TQ_UINT32)TQMAX(0, v ); +} + +void KisConfig::setGridOffsetX(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridoffsetx", v); +} + +TQ_UINT32 KisConfig::getGridOffsetY() +{ + TQ_INT32 v = m_cfg->readNumEntry("gridoffsety", 0); + return (TQ_UINT32)TQMAX(0, v ); +} + +void KisConfig::setGridOffsetY(TQ_UINT32 v) +{ + m_cfg->writeEntry("gridoffsety", v); +} + diff --git a/chalk/ui/kis_config.h b/chalk/ui/kis_config.h new file mode 100644 index 00000000..4fe971df --- /dev/null +++ b/chalk/ui/kis_config.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_CONFIG_H_ +#define KIS_CONFIG_H_ + +#include "kis_global.h" +#include "koffice_export.h" + +class KRITACORE_EXPORT KisConfig { +public: + KisConfig(); + ~KisConfig(); + + bool fixDockerWidth() const; + void setFixedDockerWidth(bool fix); + + bool undoEnabled() const; + void setUndoEnabled(bool undo); + + TQ_INT32 defUndoLimit() const; + void defUndoLimit(TQ_INT32 limit); + + TQ_INT32 defImgWidth() const; + void defImgWidth(TQ_INT32 width); + + TQ_INT32 defImgHeight() const; + void defImgHeight(TQ_INT32 height); + + double defImgResolution() const; + void defImgResolution(double res); + + enumCursorStyle cursorStyle() const; + enumCursorStyle getDefaultCursorStyle() const; + void setCursorStyle(enumCursorStyle style); + + TQString monitorProfile() const; + void setMonitorProfile(TQString monitorProfile); + + TQString workingColorSpace() const; + void setWorkingColorSpace(TQString workingColorSpace); + + TQString importProfile() const; + void setImportProfile(TQString importProfile); + + TQString printerColorSpace() const; + void setPrinterColorSpace(TQString printerColorSpace); + + TQString printerProfile() const; + void setPrinterProfile(TQString printerProfile); + + bool useBlackPointCompensation() const; + void setUseBlackPointCompensation(bool useBlackPointCompensation); + + bool showRulers() const; + void setShowRulers(bool rulers); + + TQ_INT32 pasteBehaviour() const; + void setPasteBehaviour(TQ_INT32 behaviour); + + TQ_INT32 renderIntent() const; + void setRenderIntent(TQ_INT32 renderIntent); + + bool useOpenGL() const; + void setUseOpenGL(bool useOpenGL); + + bool useOpenGLShaders() const; + void setUseOpenGLShaders(bool useOpenGLShaders); + + TQ_INT32 maxNumberOfThreads(); + void setMaxNumberOfThreads(TQ_INT32 numberOfThreads); + + /// Maximum tiles in memory (this is a guideline, not absolute) + TQ_INT32 maxTilesInMem() const; + void setMaxTilesInMem(TQ_INT32 tiles); + + /// Number of tiles that will be swapped at once. The higher, the more swapped, but more + /// chance that it will become slow + TQ_INT32 swappiness() const; + void setSwappiness(TQ_INT32 swappiness); + + TQ_INT32 getPressureCorrection(); + void setPressureCorrection( TQ_INT32 correction); + TQ_INT32 getDefaultPressureCorrection(); + + bool tabletDeviceEnabled(const TQString& tabletDeviceName) const; + void setTabletDeviceEnabled(const TQString& tabletDeviceName, bool enabled); + + TQ_INT32 tabletDeviceAxis(const TQString& tabletDeviceName, const TQString& axisName, TQ_INT32 defaultAxis) const; + void setTabletDeviceAxis(const TQString& tabletDeviceName, const TQString& axisName, TQ_INT32 axis) const; + + TQ_INT32 dockability(); + TQ_INT32 getDefaultDockability(); + void setDockability( TQ_INT32 dockability); + + float dockerFontSize(); + float getDefaultDockerFontSize(); + void setDockerFontSize(float); + + + TQ_UINT32 getGridMainStyle(); + void setGridMainStyle(TQ_UINT32 v); + TQ_UINT32 getGridSubdivisionStyle(); + void setGridSubdivisionStyle(TQ_UINT32 v); + TQColor getGridMainColor(); + void setGridMainColor(TQColor v); + TQColor getGridSubdivisionColor(); + void setGridSubdivisionColor(TQColor v); + TQ_UINT32 getGridHSpacing(); + void setGridHSpacing(TQ_UINT32 v); + TQ_UINT32 getGridVSpacing(); + void setGridVSpacing(TQ_UINT32 v); + TQ_UINT32 getGridSubdivisions(); + void setGridSubdivisions(TQ_UINT32 v); + TQ_UINT32 getGridOffsetX(); + void setGridOffsetX(TQ_UINT32 v); + TQ_UINT32 getGridOffsetY(); + void setGridOffsetY(TQ_UINT32 v); + + +private: + KisConfig(const KisConfig&); + KisConfig& operator=(const KisConfig&); + +private: + mutable KConfig *m_cfg; +}; + +#endif // KIS_CONFIG_H_ diff --git a/chalk/ui/kis_controlframe.cc b/chalk/ui/kis_controlframe.cc new file mode 100644 index 00000000..29b9aa8b --- /dev/null +++ b/chalk/ui/kis_controlframe.cc @@ -0,0 +1,343 @@ +/* + * kis_controlframe.cc - part of Chalk + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_resourceserver.h" +#include "kis_controlframe.h" +#include "kis_resource_mediator.h" +#include "kis_itemchooser.h" +#include "kis_pattern_chooser.h" +#include "kis_gradient_chooser.h" +#include "kis_icon_item.h" +#include "kis_iconwidget.h" +#include "kis_brush.h" +#include "kis_pattern.h" +#include "kis_gradient.h" +#include "kis_brush_chooser.h" +#include "kis_view.h" +#include "kis_autobrush.h" +#include "kis_autogradient.h" +#include "kis_config.h" +#include "kis_paintop_box.h" +#include "kis_custom_brush.h" +#include "kis_custom_pattern.h" +#ifdef HAVE_TEXT_BRUSH +#include "kis_text_brush.h" +#endif +KisPopupFrame::KisPopupFrame(TQWidget * tqparent, const char* name) + : TQPopupMenu(tqparent, name) +{ + setFocusPolicy(TQ_StrongFocus); +} + +void KisPopupFrame::keyPressEvent(TQKeyEvent * e) +{ + if (e->key()== TQt::Key_Escape) + { + hide(); + e->accept(); + } + else { + e->ignore(); + } +} + + +KisControlFrame::KisControlFrame( KMainWindow * /*window*/, KisView * view, const char* name ) + : TQObject(view, name) + //: KToolBar ( window, TQt::DockTop, false, name, true, true ) + , m_view(view) + , m_brushWidget(0) + , m_patternWidget(0) + , m_gradientWidget(0) + , m_brushChooserPopup(0) + , m_patternChooserPopup(0) + , m_gradientChooserPopup(0) + , m_brushMediator(0) + , m_patternMediator(0) + , m_gradientMediator(0) + , m_paintopBox(0) +{ + + KisConfig cfg; + m_font = KGlobalSettings::generalFont(); + m_font.setPointSize((int)cfg.dockerFontSize()); + + m_brushWidget = new KisIconWidget(view, "brushes"); + m_brushWidget->setTextLabel( i18n("Brush Shapes") ); + // XXX: An action without a slot -- that's silly, what kind of action could we use here? + KAction * action = new KWidgetAction(m_brushWidget, + i18n("&Brush"), + 0, + TQT_TQOBJECT(view), + 0, + view->actionCollection(), + "brushes"); + + + m_patternWidget = new KisIconWidget(view, "patterns"); + m_patternWidget->setTextLabel( i18n("Fill Patterns") ); + action = new KWidgetAction(m_patternWidget, + i18n("&Patterns"), + 0, + TQT_TQOBJECT(view), + 0, + view->actionCollection(), + "patterns"); + + m_gradientWidget = new KisIconWidget(view, "gradients"); + m_gradientWidget->setTextLabel( i18n("Gradients") ); + action = new KWidgetAction(m_gradientWidget, + i18n("&Gradients"), + 0, + TQT_TQOBJECT(view), + 0, + view->actionCollection(), + "gradients"); + + m_paintopBox = new KisPaintopBox( view, view, "paintopbox" ); + action = new KWidgetAction(m_paintopBox, + i18n("&Painter's Tools"), + 0, + TQT_TQOBJECT(view), + 0, + view->actionCollection(), + "paintops"); + + m_brushWidget->setFixedSize( 26, 26 ); + m_patternWidget->setFixedSize( 26, 26 ); + m_gradientWidget->setFixedSize( 26, 26 ); + + createBrushesChooser(m_view); + createPatternsChooser(m_view); + createGradientsChooser(m_view); + + m_brushWidget->setPopup(m_brushChooserPopup); + m_brushWidget->setPopupDelay(1); + m_patternWidget->setPopup(m_patternChooserPopup); + m_patternWidget->setPopupDelay(1); + m_gradientWidget->setPopup(m_gradientChooserPopup); + m_gradientWidget->setPopupDelay(1); +} + + +void KisControlFrame::slotSetBrush(KoIconItem *item) +{ + if (item) + m_brushWidget->slotSetItem(*item); +} + +void KisControlFrame::slotSetPattern(KoIconItem *item) +{ + if (item) + m_patternWidget->slotSetItem(*item); +} + +void KisControlFrame::slotSetGradient(KoIconItem *item) +{ + if (item) + m_gradientWidget->slotSetItem(*item); +} + +void KisControlFrame::slotBrushChanged(KisBrush * brush) +{ + KisIconItem *item; + + if((item = m_brushMediator->itemFor(brush))) + { + slotSetBrush(item); + } else { + slotSetBrush( new KisIconItem(brush) ); + } + +} + +void KisControlFrame::slotPatternChanged(KisPattern * pattern) +{ + KisIconItem *item; + if (!pattern) + return; + + if ( (item = m_patternMediator->itemFor(pattern)) ) + slotSetPattern(item); + else + slotSetPattern( new KisIconItem(pattern) ); +} + + +void KisControlFrame::slotGradientChanged(KisGradient * gradient) +{ + KisIconItem *item; + if (!gradient) + return; + + if ( (item = m_gradientMediator->itemFor(gradient)) ) + slotSetGradient(item); + else + slotSetGradient( new KisIconItem(gradient) ); +} + +void KisControlFrame::createBrushesChooser(KisView * view) +{ + + m_brushChooserPopup = new KisPopupFrame(m_brushWidget, "brush_chooser_popup"); + + TQHBoxLayout * l = new TQHBoxLayout(m_brushChooserPopup, 2, 2, "brushpopuptqlayout"); + + TQTabWidget * m_brushesTab = new TQTabWidget(m_brushChooserPopup, "brushestab"); + m_brushesTab->setTabShape(TQTabWidget::Triangular); + m_brushesTab->setFocusPolicy(TQ_NoFocus); + m_brushesTab->setFont(m_font); + m_brushesTab->setMargin(1); + + l->add(m_brushesTab); + + KisAutobrush * m_autobrush = new KisAutobrush(m_brushesTab, "autobrush", i18n("Autobrush")); + m_brushesTab->addTab( m_autobrush, i18n("Autobrush")); + connect(m_autobrush, TQT_SIGNAL(activatedResource(KisResource*)), m_view, TQT_SLOT(brushActivated( KisResource* ))); + + KisBrushChooser * m_brushChooser = new KisBrushChooser(m_brushesTab, "brush_chooser"); + m_brushesTab->addTab( m_brushChooser, i18n("Predefined Brushes")); + + KisCustomBrush* customBrushes = new KisCustomBrush(m_brushesTab, "custombrush", + i18n("Custom Brush"), m_view); + m_brushesTab->addTab( customBrushes, i18n("Custom Brush")); + connect(customBrushes, TQT_SIGNAL(activatedResource(KisResource*)), + m_view, TQT_SLOT(brushActivated(KisResource*))); +#ifdef HAVE_TEXT_BRUSH + KisTextBrush* textBrushes = new KisTextBrush(m_brushesTab, "textbrush", + i18n("Text Brush")/*, m_view*/); + m_brushesTab->addTab( textBrushes, i18n("Text Brush")); + connect(textBrushes, TQT_SIGNAL(activatedResource(KisResource*)), + m_view, TQT_SLOT(brushActivated(KisResource*))); +#endif + + m_brushChooser->setFont(m_font); + m_brushMediator = new KisResourceMediator( m_brushChooser, this); + connect(m_brushMediator, TQT_SIGNAL(activatedResource(KisResource*)), m_view, TQT_SLOT(brushActivated(KisResource*))); + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("ImagePipeBrushServer"); + m_brushMediator->connectServer(rServer); + rServer = KisResourceServerRegistry::instance()->get("BrushServer"); + m_brushMediator->connectServer(rServer); + + KisControlFrame::connect(view, TQT_SIGNAL(brushChanged(KisBrush *)), this, TQT_SLOT(slotBrushChanged( KisBrush *))); + m_brushChooser->setCurrent( 0 ); + m_brushMediator->setActiveItem( m_brushChooser->currentItem() ); + customBrushes->setResourceServer(rServer); + + m_autobrush->activate(); +} + +void KisControlFrame::createPatternsChooser(KisView * view) +{ + m_patternChooserPopup = new KisPopupFrame(m_patternWidget, "pattern_chooser_popup"); + + TQHBoxLayout * l2 = new TQHBoxLayout(m_patternChooserPopup, 2, 2, "patternpopuptqlayout"); + + TQTabWidget * m_patternsTab = new TQTabWidget(m_patternChooserPopup, "patternstab"); + m_patternsTab->setTabShape(TQTabWidget::Triangular); + m_patternsTab->setFocusPolicy(TQ_NoFocus); + m_patternsTab->setFont(m_font); + m_patternsTab->setMargin(1); + l2->add( m_patternsTab ); + + KisPatternChooser * chooser = new KisPatternChooser(m_patternChooserPopup, "pattern_chooser"); + chooser->setFont(m_font); + chooser->setMinimumSize(200, 150); + m_patternsTab->addTab(chooser, i18n("Patterns")); + + KisCustomPattern* customPatterns = new KisCustomPattern(m_patternsTab, "custompatterns", + i18n("Custom Pattern"), m_view); + customPatterns->setFont(m_font); + m_patternsTab->addTab( customPatterns, i18n("Custom Pattern")); + + + m_patternMediator = new KisResourceMediator( chooser, TQT_TQOBJECT(view)); + connect( m_patternMediator, TQT_SIGNAL(activatedResource(KisResource*)), view, TQT_SLOT(patternActivated(KisResource*))); + connect(customPatterns, TQT_SIGNAL(activatedResource(KisResource*)), + TQT_TQOBJECT(view), TQT_SLOT(patternActivated(KisResource*))); + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("PatternServer"); + m_patternMediator->connectServer(rServer); + + KisControlFrame::connect(view, TQT_SIGNAL(patternChanged(KisPattern *)), this, TQT_SLOT(slotPatternChanged( KisPattern *))); + chooser->setCurrent( 0 ); + m_patternMediator->setActiveItem( chooser->currentItem() ); + + customPatterns->setResourceServer(rServer); +} + + +void KisControlFrame::createGradientsChooser(KisView * view) +{ + m_gradientChooserPopup = new KisPopupFrame(m_gradientWidget, "gradient_chooser_popup"); + + TQHBoxLayout * l2 = new TQHBoxLayout(m_gradientChooserPopup, 2, 2, "gradientpopuptqlayout"); + + TQTabWidget * m_gradientTab = new TQTabWidget(m_gradientChooserPopup, "gradientstab"); + m_gradientTab->setTabShape(TQTabWidget::Triangular); + m_gradientTab->setFocusPolicy(TQ_NoFocus); + m_gradientTab->setFont(m_font); + m_gradientTab->setMargin(1); + + l2->add( m_gradientTab); + + KisGradientChooser * m_gradientChooser = new KisGradientChooser(m_view, m_gradientChooserPopup, "gradient_chooser"); + m_gradientChooser->setFont(m_font); + m_gradientChooser->setMinimumSize(200, 150); + m_gradientTab->addTab( m_gradientChooser, i18n("Gradients")); + + m_gradientMediator = new KisResourceMediator( m_gradientChooser, TQT_TQOBJECT(view)); + connect(m_gradientMediator, TQT_SIGNAL(activatedResource(KisResource*)), view, TQT_SLOT(gradientActivated(KisResource*))); + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("GradientServer"); + m_gradientMediator->connectServer(rServer); + + connect(view, TQT_SIGNAL(gradientChanged(KisGradient *)), this, TQT_SLOT(slotGradientChanged( KisGradient *))); + m_gradientChooser->setCurrent( 0 ); + m_gradientMediator->setActiveItem( m_gradientChooser->currentItem() ); +} + + +#include "kis_controlframe.moc" + diff --git a/chalk/ui/kis_controlframe.h b/chalk/ui/kis_controlframe.h new file mode 100644 index 00000000..0c16c77f --- /dev/null +++ b/chalk/ui/kis_controlframe.h @@ -0,0 +1,130 @@ +/* + * kis_controlframe.h - part of Chalk + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef __kis_controlframe_h__ +#define __kis_controlframe_h__ + +#include + +#include + +#include + +class TQWidget; +class TQTabWidget; + +class KToolBar; + +class KoIconItem; +class KisIconWidget; +class KisGradientWidget; + +class KisAutobrush; +class KisAutogradient; +class KisBrush; +class KisBrushChooser; +class KisGradient; +class KisGradientChooser; +class KisItemChooser; +class KisPattern; +class KisResourceMediator; +class KisPaintopBox; +class KisView; + +class KisPopupFrame : public TQPopupMenu { + + Q_OBJECT + TQ_OBJECT + +public: + + KisPopupFrame(TQWidget * tqparent, const char * name = 0); + virtual void keyPressEvent(TQKeyEvent *); + +public: + + void setChooser(KisItemChooser * chooser) { m_chooser = chooser; }; + KisItemChooser * chooser() { return m_chooser; }; + +private: + KisItemChooser * m_chooser; +}; + + +/** + * Control Frame - status display with access to + * color selector, brushes, patterns, and preview + */ +class KisControlFrame : public TQObject //: public KToolBar +{ + Q_OBJECT + TQ_OBJECT + +public: + KisControlFrame(KMainWindow * window, KisView * view, const char *name = 0 ); + virtual ~KisControlFrame() {}; + +public slots: + + void slotSetBrush(KoIconItem *item); + void slotSetPattern(KoIconItem *item); + void slotSetGradient(KoIconItem *item); + + void slotBrushChanged(KisBrush * brush); + void slotPatternChanged(KisPattern * pattern); + void slotGradientChanged(KisGradient * gradient); + +private: + + void createBrushesChooser(KisView * view); + void createPatternsChooser(KisView * view); + void createGradientsChooser(KisView * view); + + +private: + TQFont m_font; + KisView * m_view; + + TQTabWidget * m_brushesTab; + TQTabWidget * m_gradientTab; + + KisIconWidget *m_brushWidget; + KisIconWidget *m_patternWidget; + KisIconWidget *m_gradientWidget; + + KisPopupFrame * m_brushChooserPopup; + KisPopupFrame * m_patternChooserPopup; + KisPopupFrame * m_gradientChooserPopup; + + KisResourceMediator *m_brushMediator; + KisResourceMediator *m_patternMediator; + KisResourceMediator *m_gradientMediator; + + + KisAutobrush * m_autobrush; + KisBrushChooser * m_brushChooser; + KisGradientChooser * m_gradientChooser; + + KisPaintopBox * m_paintopBox; +}; + +#endif + diff --git a/chalk/ui/kis_cursor.cc b/chalk/ui/kis_cursor.cc new file mode 100644 index 00000000..33c6ae04 --- /dev/null +++ b/chalk/ui/kis_cursor.cc @@ -0,0 +1,374 @@ +/* + * kis_cursor.cc - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_cursor.h" +#include "kis_factory.h" + +KisCursor::KisCursor() {} + +/* + * Predefined TQt cursors + */ +TQCursor KisCursor::arrowCursor() +{ + return TQt::arrowCursor; +} + +TQCursor KisCursor::upArrowCursor() +{ + return TQt::upArrowCursor; +} + +TQCursor KisCursor::crossCursor() +{ + return TQt::crossCursor; +} + +TQCursor KisCursor::waitCursor() +{ + return TQt::waitCursor; +} + +TQCursor KisCursor::ibeamCursor() +{ + return TQt::ibeamCursor; +} + +TQCursor KisCursor::sizeVerCursor() +{ + return TQt::sizeVerCursor; +} + +TQCursor KisCursor::sizeHorCursor() +{ + return TQt::sizeHorCursor; +} + +TQCursor KisCursor::sizeBDiagCursor() +{ + return TQt::sizeBDiagCursor; +} + +TQCursor KisCursor::sizeFDiagCursor() +{ + return TQt::sizeFDiagCursor; +} + +TQCursor KisCursor::sizeAllCursor() +{ + return TQt::sizeAllCursor; +} + +TQCursor KisCursor::blankCursor() +{ + return TQt::blankCursor; +} + +TQCursor KisCursor::splitVCursor() +{ + return TQt::splitVCursor; +} + +TQCursor KisCursor::splitHCursor() +{ + return TQt::splitHCursor; +} + +TQCursor KisCursor::pointingHandCursor() +{ + return TQt::pointingHandCursor; +} + + +/* + * Existing custom KimageShop cursors. Use the 'load' function for all new cursors. + */ + +TQCursor KisCursor::pickerCursor() +{ + static unsigned char picker_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x34, 0x00, 0x00, 0x7a, + 0x00, 0x00, 0x7d, 0x00, 0x80, 0x7e, 0x00, 0x60, 0x3f, 0x00, 0xd0, 0x1f, + 0x00, 0xa0, 0x0f, 0x00, 0x50, 0x07, 0x00, 0xc8, 0x06, 0x00, 0xe4, 0x02, + 0x00, 0x72, 0x01, 0x00, 0x39, 0x00, 0x80, 0x1c, 0x00, 0x40, 0x0e, 0x00, + 0x20, 0x07, 0x00, 0x90, 0x03, 0x00, 0xc8, 0x01, 0x00, 0xe4, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap picker_bitmap(24, 24, picker_bits, true); + TQBitmap picker_tqmask = picker_bitmap.createHeuristicMask( false ); + + return TQCursor( picker_bitmap, picker_tqmask, 1, 22 ); +} + + +TQCursor KisCursor::pickerPlusCursor() +{ + static unsigned char pickerplus_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x34, 0x00, 0x00, 0x7a, + 0x00, 0x00, 0x7d, 0x00, 0x80, 0x7e, 0x00, 0x60, 0x3f, 0x00, 0xd0, 0x1f, + 0x00, 0xa0, 0x0f, 0x00, 0x50, 0x07, 0x00, 0xc8, 0x06, 0x00, 0xe4, 0x02, + 0x00, 0x72, 0x01, 0x00, 0x39, 0x0c, 0x80, 0x1c, 0x0c, 0x40, 0x0e, 0x0c, + 0x20, 0x07, 0x0c, 0x90, 0x83, 0x7f, 0xc8, 0x81, 0x7f, 0xe4, 0x00, 0x0c, + 0x74, 0x00, 0x0c, 0x32, 0x00, 0x0c, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00}; + + TQBitmap picker_bitmap(24, 24, pickerplus_bits, true); + TQBitmap picker_tqmask = picker_bitmap.createHeuristicMask( false ); + + return TQCursor( picker_bitmap, picker_tqmask, 1, 22 ); +} + + +TQCursor KisCursor::pickerMinusCursor() +{ + static unsigned char pickerminus_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x34, 0x00, 0x00, 0x7a, + 0x00, 0x00, 0x7d, 0x00, 0x80, 0x7e, 0x00, 0x60, 0x3f, 0x00, 0xd0, 0x1f, + 0x00, 0xa0, 0x0f, 0x00, 0x50, 0x07, 0x00, 0xc8, 0x06, 0x00, 0xe4, 0x02, + 0x00, 0x72, 0x01, 0x00, 0x39, 0x00, 0x80, 0x1c, 0x00, 0x40, 0x0e, 0x00, + 0x20, 0x07, 0x00, 0x90, 0xc3, 0x7f, 0xc8, 0xc1, 0x7f, 0xe4, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x32, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap picker_bitmap(24, 24, pickerminus_bits, true); + TQBitmap picker_tqmask = picker_bitmap.createHeuristicMask( false ); + + return TQCursor( picker_bitmap, picker_tqmask, 1, 22 ); +} + + + +TQCursor KisCursor::penCursor() +{ + static unsigned char pen_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x7d, + 0x00, 0x80, 0x7e, 0x00, 0x40, 0x7f, 0x00, 0xa0, 0x3f, 0x00, 0xd0, 0x1f, + 0x00, 0xe8, 0x0f, 0x00, 0xf4, 0x07, 0x00, 0xfa, 0x03, 0x00, 0xfd, 0x01, + 0x80, 0xfe, 0x00, 0x40, 0x7f, 0x00, 0xa0, 0x3f, 0x00, 0xf0, 0x1f, 0x00, + 0xd0, 0x0f, 0x00, 0x88, 0x07, 0x00, 0x88, 0x03, 0x00, 0xe4, 0x01, 0x00, + 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap pen_bitmap( 24, 24, pen_bits, true ); + TQBitmap pen_tqmask = pen_bitmap.createHeuristicMask( false ); + + return TQCursor( pen_bitmap, pen_tqmask, 1, 22 ); +} + +TQCursor KisCursor::brushCursor() +{ + static unsigned char brush_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfd, 0x00, + 0x00, 0x80, 0x7e, 0x00, 0x00, 0x40, 0x3f, 0x00, 0x00, 0xa0, 0x1f, 0x00, + 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4, 0x03, 0x00, + 0x00, 0xe4, 0x01, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x80, 0x41, 0x00, 0x00, + 0x40, 0x32, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0xd0, 0x0f, 0x00, 0x00, + 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap brush_bitmap( 25, 23, brush_bits, true ); + TQBitmap brush_tqmask = brush_bitmap.createHeuristicMask( false ); + + return TQCursor( brush_bitmap, brush_tqmask, 1, 21 ); +} + +TQCursor KisCursor::airbrushCursor() +{ + static unsigned char airbrush_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x68, 0x00, 0x00, 0x74, + 0x00, 0x00, 0x7a, 0xf0, 0x00, 0x3d, 0x08, 0x81, 0x1e, 0xe8, 0x41, 0x0f, + 0xe8, 0xa1, 0x07, 0xe8, 0xd1, 0x03, 0xe8, 0xe9, 0x01, 0xe8, 0xf5, 0x00, + 0xe8, 0x7b, 0x00, 0xf0, 0x33, 0x00, 0xf0, 0x23, 0x1f, 0xa0, 0x9f, 0x3f, + 0xd0, 0xff, 0x31, 0xe8, 0xf7, 0x30, 0xf4, 0x03, 0x18, 0xfc, 0x01, 0x0c, + 0xf8, 0x00, 0x06, 0x76, 0x00, 0x03, 0x36, 0x00, 0x03, 0x00, 0x00, 0x00}; + + TQBitmap airbrush_bitmap( 24, 24, airbrush_bits, true ); + TQBitmap airbrush_tqmask = airbrush_bitmap.createHeuristicMask( false ); + + return TQCursor( airbrush_bitmap, airbrush_tqmask, 1, 22 ); +} + +TQCursor KisCursor::eraserCursor() +{ + static unsigned char eraser_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1d, 0x00, + 0x00, 0x80, 0x3e, 0x00, 0x00, 0x40, 0x7f, 0x00, 0x00, 0xa0, 0xff, 0x00, + 0x00, 0xd0, 0xff, 0x00, 0x00, 0xe8, 0x7f, 0x00, 0x00, 0xf4, 0x3f, 0x00, + 0x00, 0xfe, 0x1f, 0x00, 0x00, 0xf9, 0x0f, 0x00, 0x80, 0xf2, 0x07, 0x00, + 0x40, 0xe7, 0x03, 0x00, 0xa0, 0xcf, 0x01, 0x00, 0xd0, 0x9f, 0x00, 0x00, + 0xe8, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf2, 0x1f, 0x00, 0x00, + 0xe2, 0x0f, 0x00, 0x00, 0xc4, 0x07, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, + 0x10, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap eraser_bitmap( 25, 24, eraser_bits, true ); + TQBitmap eraser_tqmask = eraser_bitmap.createHeuristicMask( false ); + + return TQCursor( eraser_bitmap, eraser_tqmask, 7, 22 ); +} + +TQCursor KisCursor::fillerCursor() +{ + static unsigned char filler_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x54, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x85, 0x00, 0x80, 0x0a, 0x01, + 0x40, 0x11, 0x01, 0xe0, 0x00, 0x02, 0x58, 0x01, 0x04, 0x2c, 0x02, 0x04, + 0x44, 0x04, 0x08, 0x0c, 0x08, 0x18, 0x3c, 0x00, 0x14, 0x5c, 0x00, 0x0a, + 0x9c, 0x01, 0x05, 0x1c, 0x82, 0x02, 0x18, 0x4c, 0x01, 0x18, 0xb0, 0x00, + 0x08, 0x60, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap filler_bitmap( 22, 22, filler_bits, true ); + TQBitmap filler_tqmask = filler_bitmap.createHeuristicMask( false ); + + return TQCursor( filler_bitmap, filler_tqmask, 3, 20 ); +} + +TQCursor KisCursor::colorChangerCursor() +{ + static unsigned char colorChanger_bits[] = { + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x10, 0x01, 0x0e, 0x08, 0x02, 0x11, + 0x04, 0x82, 0x20, 0x64, 0x84, 0x20, 0x92, 0x44, 0x46, 0x12, 0x49, 0x5f, + 0x12, 0x31, 0x5f, 0x22, 0x01, 0x5f, 0xc2, 0x00, 0x4e, 0x02, 0x00, 0x40, + 0xc2, 0x00, 0x46, 0xe2, 0x01, 0x4f, 0xe4, 0x19, 0x2f, 0xe4, 0x3d, 0x2f, + 0xe8, 0x3d, 0x17, 0xd0, 0x3c, 0x10, 0x20, 0x38, 0x08, 0x40, 0x00, 0x06, + 0x80, 0x81, 0x01, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap colorChanger_bitmap( 24, 23, colorChanger_bits, true ); + TQBitmap colorChanger_tqmask = colorChanger_bitmap.createHeuristicMask( false ); + + return TQCursor( colorChanger_bitmap, colorChanger_tqmask, 12, 10 ); +} + +TQCursor KisCursor::zoomCursor() +{ + static unsigned char zoom_bits[] = { + 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0xf0, 0x3f, 0x00, 0x38, 0x70, 0x00, + 0x8c, 0xcf, 0x00, 0x0c, 0xdf, 0x00, 0x36, 0xbf, 0x01, 0xb6, 0xbf, 0x01, + 0xf6, 0xbf, 0x01, 0xf6, 0xbf, 0x01, 0xe6, 0x9f, 0x00, 0xcc, 0xcf, 0x00, + 0x9c, 0xe7, 0x01, 0x38, 0x70, 0x03, 0xf0, 0xbf, 0x05, 0xc0, 0xef, 0x0b, + 0x00, 0xc0, 0x17, 0x00, 0x80, 0x2f, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00}; + + TQBitmap zoom_bitmap( 24, 23, zoom_bits, true ); + TQBitmap zoom_tqmask = zoom_bitmap.createHeuristicMask( false ); + + return TQCursor( zoom_bitmap, zoom_tqmask, 9, 8 ); +} + +TQCursor KisCursor::moveCursor() +{ + static unsigned char move_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x7e, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x10, 0x18, 0x08, 0x18, 0x18, 0x18, 0x1c, 0x18, 0x38, 0xfe, 0xff, 0x7f, + 0xfe, 0xff, 0x7f, 0x1c, 0x18, 0x38, 0x18, 0x18, 0x18, 0x10, 0x18, 0x08, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}; + + TQBitmap move_bitmap( 24, 24, move_bits, true ); + TQBitmap move_tqmask = move_bitmap.createHeuristicMask( false ); + + return TQCursor( move_bitmap, move_tqmask, 12, 11 ); +} + +TQCursor KisCursor::handCursor() +{ + return KCursor::handCursor(); +} + +TQCursor KisCursor::selectCursor() +{ + static unsigned char select_bits[] = { + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0x7f, + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00}; + + TQBitmap select_bitmap(23, 23, select_bits, true); + TQBitmap select_tqmask = select_bitmap.createHeuristicMask( false ); + + return TQCursor( select_bitmap, select_tqmask, 11, 11 ); +} + +TQCursor KisCursor::openHandCursor() +{ + return load("openhand_cursor.xpm"); +} + +TQCursor KisCursor::closedHandCursor() +{ + return load("closedhand_cursor.xpm"); +} + +TQCursor KisCursor::rotateCursor() +{ + return load("rotate_cursor.xpm"); +} + +TQCursor KisCursor::load(const TQString & iconName, int hotspotX, int hotspotY) +{ + TQString filename = KisFactory::instance()->dirs()->findResource("kis_pics", iconName); + TQImage cursorImage; + + cursorImage.load(filename); + Q_ASSERT(!cursorImage.isNull()); + Q_ASSERT(cursorImage.hasAlphaBuffer()); + + TQBitmap bitmap(cursorImage.width(), cursorImage.height()); + TQBitmap tqmask(cursorImage.width(), cursorImage.height()); + + TQPainter bitmapPainter(&bitmap); + TQPainter tqmaskPainter(&tqmask); + + for (TQ_INT32 x = 0; x < cursorImage.width(); ++x) { + for (TQ_INT32 y = 0; y < cursorImage.height(); ++y) { + + TQRgb pixel = cursorImage.pixel(x, y); + + if (tqAlpha(pixel) < 128) { + bitmapPainter.setPen(TQt::color0); + tqmaskPainter.setPen(TQt::color0); + } else { + tqmaskPainter.setPen(TQt::color1); + + if (tqGray(pixel) < 128) { + bitmapPainter.setPen(TQt::color1); + } else { + bitmapPainter.setPen(TQt::color0); + } + } + + bitmapPainter.drawPoint(x, y); + tqmaskPainter.drawPoint(x, y); + } + } + + return TQCursor(bitmap, tqmask, hotspotX, hotspotY); +} + diff --git a/chalk/ui/kis_cursor.h b/chalk/ui/kis_cursor.h new file mode 100644 index 00000000..69c5cbd5 --- /dev/null +++ b/chalk/ui/kis_cursor.h @@ -0,0 +1,73 @@ +/* + * kis_cursor.h - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __kis_cursor_h__ +#define __kis_cursor_h__ +#include +class TQCursor; + +class KRITACORE_EXPORT KisCursor +{ + +public: + + KisCursor(); + + // Predefined TQt cursors. + static TQCursor arrowCursor(); // standard arrow cursor + static TQCursor upArrowCursor(); // upwards arrow + static TQCursor crossCursor(); // crosshair + static TQCursor waitCursor(); // hourglass/watch + static TQCursor ibeamCursor(); // ibeam/text entry + static TQCursor sizeVerCursor(); // vertical resize + static TQCursor sizeHorCursor(); // horizontal resize + static TQCursor sizeBDiagCursor(); // diagonal resize (/) + static TQCursor sizeFDiagCursor(); // diagonal resize (\) + static TQCursor sizeAllCursor(); // all directions resize + static TQCursor blankCursor(); // blank/invisible cursor + static TQCursor splitVCursor(); // vertical splitting + static TQCursor splitHCursor(); // horziontal splitting + static TQCursor pointingHandCursor(); // a pointing hand + + // Existing custom KimageShop cursors. Use the 'load' function for all new cursors. + static TQCursor moveCursor(); // move tool cursor + static TQCursor penCursor(); // pen tool cursor + static TQCursor brushCursor(); // brush tool cursor + static TQCursor airbrushCursor(); // airbrush tool cursor + static TQCursor eraserCursor(); // eraser tool cursor + static TQCursor fillerCursor(); // filler tool cursor + static TQCursor pickerCursor(); // color picker cursor + static TQCursor pickerPlusCursor(); // color picker cursor + static TQCursor pickerMinusCursor(); // color picker cursor + static TQCursor colorChangerCursor(); // color changer tool cursor + static TQCursor selectCursor(); // select cursor + static TQCursor zoomCursor(); // zoom tool cursor + static TQCursor handCursor(); // hand tool cursor + static TQCursor openHandCursor(); // Pan tool cursor + static TQCursor closedHandCursor(); // Pan tool cursor + static TQCursor rotateCursor(); // Transform tool cursor + + // Load a cursor from an image file. The image should have an alpha channel + // and will be converted to black and white on loading. Any format loadable by + // TQImage can be used. + static TQCursor load(const TQString & imageFilename, int hotspotX = -1, int hotspotY = -1); +}; +#endif // __kis_cursor_h__ diff --git a/chalk/ui/kis_custom_brush.cc b/chalk/ui/kis_custom_brush.cc new file mode 100644 index 00000000..49a44cc8 --- /dev/null +++ b/chalk/ui/kis_custom_brush.cc @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_view.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_brush.h" +#include "kis_imagepipe_brush.h" +#include "kis_custom_brush.h" +#include "kis_resource_mediator.h" +#include "kis_resourceserver.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" + +KisCustomBrush::KisCustomBrush(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view) + : KisWdgCustomBrush(tqparent, name), m_view(view) +{ + Q_ASSERT(m_view); + m_mediator = 0; + setCaption(caption); + + m_brush = 0; + + preview->setScaledContents(true); + + connect(addButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotAddPredefined())); + connect(brushButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotUseBrush())); +// connect(exportButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotExport())); + connect(style, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateCurrentBrush(int))); + connect(colorAsMask, TQT_SIGNAL(stateChanged(int)), this, TQT_SLOT(slotUpdateCurrentBrush(int))); +} + +KisCustomBrush::~KisCustomBrush() { + delete m_brush; +} + +void KisCustomBrush::showEvent(TQShowEvent *) { + slotUpdateCurrentBrush(0); +} + +void KisCustomBrush::slotUpdateCurrentBrush(int) { + delete m_brush; + if (m_view->canvasSubject() && m_view->canvasSubject()->currentImg()) { + createBrush(); + preview->setPixmap(TQPixmap(m_brush->img())); + } else { + m_brush = 0; + } +} + +void KisCustomBrush::slotExport() { + ; +} + +void KisCustomBrush::slotAddPredefined() { + // Save in the directory that is likely to be: ~/.kde/share/apps/chalk/brushes + // a unique file with this brushname + TQString dir = KGlobal::dirs()->saveLocation("data", "chalk/brushes"); + TQString extension; + + if (style->currentItem() == 0) { + extension = ".gbr"; + } else { + extension = ".gih"; + } + KTempFile file(dir, extension); + file.close(); // If we don't, and brush->save first, it might get truncated! + + // Save it to that file + m_brush->setFilename(file.name()); + + // Add it to the brush server, so that it automatically gets to the mediators, and + // so to the other brush choosers can pick it up, if they want to + if (m_server) + m_server->addResource(m_brush->clone()); +} + +void KisCustomBrush::slotUseBrush() { + KisBrush* copy = m_brush->clone(); + + Q_CHECK_PTR(copy); + + emit(activatedResource(copy)); +} + +void KisCustomBrush::createBrush() { + KisImageSP img = m_view->canvasSubject()->currentImg(); + + if (!img) + return; + + if (style->currentItem() == 0) { + m_brush = new KisBrush(img->mergedImage(), 0, 0, img->width(), img->height()); + if (colorAsMask->isChecked()) + m_brush->makeMaskImage(); + return; + } + + // For each layer in the current image, create a new image, and add it to the list + TQValueVector< TQValueVector > devices; + devices.push_back(TQValueVector()); + int w = img->width(); + int h = img->height(); + + // We only loop over the rootLayer. Since we actually should have a layer selection + // list, no need to elaborate on that here and now + KisLayer* layer = img->rootLayer()->firstChild(); + while (layer) { + KisPaintLayer* paint = 0; + if (layer->visible() && (paint = dynamic_cast(layer))) + devices.at(0).push_back(paint->paintDevice()); + layer = layer->nextSibling(); + } + TQValueVector modes; + + switch(comboBox2->currentItem()) { + case 0: modes.push_back(KisPipeBrushParasite::Constant); break; + case 1: modes.push_back(KisPipeBrushParasite::Random); break; + case 2: modes.push_back(KisPipeBrushParasite::Incremental); break; + case 3: modes.push_back(KisPipeBrushParasite::Pressure); break; + case 4: modes.push_back(KisPipeBrushParasite::Angular); break; + default: modes.push_back(KisPipeBrushParasite::Incremental); + } + + m_brush = new KisImagePipeBrush(img->name(), w, h, devices, modes); + if (colorAsMask->isChecked()) + m_brush->makeMaskImage(); +} + + +#include "kis_custom_brush.moc" diff --git a/chalk/ui/kis_custom_brush.h b/chalk/ui/kis_custom_brush.h new file mode 100644 index 00000000..56e90553 --- /dev/null +++ b/chalk/ui/kis_custom_brush.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CUSTOM_BRUSH_H_ +#define KIS_CUSTOM_BRUSH_H_ + +#include + +#include "wdgcustombrush.h" + + +class KisResource; +class KisView; +class KisResourceServerBase; + +class KisCustomBrush : public KisWdgCustomBrush +{ + Q_OBJECT + TQ_OBJECT +public: + KisCustomBrush(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view); + virtual ~KisCustomBrush(); + void setResourceServer(KisResourceServerBase* server) { m_server = server; } + +public slots: + void slotUseBrush(); + +signals: + void activatedResource(KisResource *); + +protected: + virtual void showEvent(TQShowEvent *); + +private slots: + void slotExport(); + void slotAddPredefined(); + void slotUpdateCurrentBrush(int); // To connect with activated(int) + +private: + void createBrush(); + KisView* m_view; + KisBrush* m_brush; + KisResourceMediator* m_mediator; + KisResourceServerBase* m_server; +}; + + +#endif // KIS_CUSTOM_BRUSH_H_ diff --git a/chalk/ui/kis_custom_image_widget.cc b/chalk/ui/kis_custom_image_widget.cc new file mode 100644 index 00000000..0b77da9f --- /dev/null +++ b/chalk/ui/kis_custom_image_widget.cc @@ -0,0 +1,110 @@ +/* This file is part of the KOffice project + * Copyright (C) 2005 Thomas Zander + * Copyright (C) 2005 Casper Boemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; version 2. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include "kis_colorspace_factory_registry.h" +#include "kis_profile.h" +#include "kis_colorspace.h" +#include "kis_id.h" +#include "kis_cmb_idlist.h" +#include "squeezedcombobox.h" +#include "kis_color.h" +#include "kis_image.h" +#include "kis_layer.h" + +#include + +#include +#include +#include +#include +#include +#include + +KisCustomImageWidget::KisCustomImageWidget(TQWidget *tqparent, KisDoc *doc, TQ_INT32 defWidth, TQ_INT32 defHeight, double resolution, TQString defColorSpaceName, TQString imageName) + : WdgNewImage(tqparent) { + m_doc = doc; + + txtName->setText(imageName); + + intWidth->setValue(defWidth); + intHeight->setValue(defHeight); + doubleResolution->setValue(resolution); + + cmbColorSpaces->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + cmbColorSpaces->setCurrentText(defColorSpaceName); + + connect(cmbColorSpaces, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(fillCmbProfiles(const KisID &))); + connect (m_createButton, TQT_SIGNAL( clicked() ), this, TQT_SLOT (buttonClicked()) ); + m_createButton -> setDefault(true); + + fillCmbProfiles(cmbColorSpaces->currentItem()); + lblResolution->hide(); + doubleResolution->hide(); +} + +void KisCustomImageWidget::buttonClicked() { + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(cmbColorSpaces->currentItem(), cmbProfile->currentText()); + + TQColor qc(cmbColor->color()); + + m_doc->newImage(txtName->text(), (TQ_INT32)intWidth->value(), (TQ_INT32)intHeight->value(), cs, KisColor(qc, cs), txtDescription->text(), doubleResolution->value()); + KisImageSP img = m_doc->currentImage(); + if (img) { + KisLayerSP layer = img->activeLayer(); + if (layer) { + layer->setOpacity(backgroundOpacity()); + } + } + emit documentSelected(); +} + +TQ_UINT8 KisCustomImageWidget::backgroundOpacity() const +{ + TQ_INT32 opacity = sliderOpacity->value(); + + if (!opacity) + return 0; + + return (opacity * 255) / 100; +} + +void KisCustomImageWidget::fillCmbProfiles(const KisID & s) +{ + cmbProfile->clear(); + + if (!KisMetaRegistry::instance()->csRegistry()->exists(s)) { + return; + } + + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + if (csf == 0) return; + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + cmbProfile->insertItem((*it)->productName()); + } + cmbProfile->setCurrentText(csf->defaultProfile()); +} + +#include "kis_custom_image_widget.moc" diff --git a/chalk/ui/kis_custom_image_widget.h b/chalk/ui/kis_custom_image_widget.h new file mode 100644 index 00000000..eef443dc --- /dev/null +++ b/chalk/ui/kis_custom_image_widget.h @@ -0,0 +1,58 @@ +/* This file is part of the KOffice project + * Copyright (C) 2005 Thomas Zander + * Copyright (C) 2005 Casper Boemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; version 2. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_CUSTOM_IMAGE_WIDGET_H +#define KIS_CUSTOM_IMAGE_WIDGET_H + +#include +#include "kis_global.h" + +class KisDoc; +class KisID; + +/** + * The 'Custom Document' widget in the Chalk startup widget. + * This class embeds the image size and colorspace to allow the user to select the image properties + * for a new empty image document. + */ +class KisCustomImageWidget : public WdgNewImage { + Q_OBJECT + TQ_OBJECT +public: + /** + * Constructor. Please note that this class is being used/created by KisDoc. + * @param tqparent the tqparent widget + * @param doc the document that wants to be altered + */ + KisCustomImageWidget(TQWidget *tqparent, KisDoc *doc, TQ_INT32 defWidth, TQ_INT32 defHeight, double resolution, TQString defColorSpaceName, TQString imageName); + +private slots: + void buttonClicked(); + void fillCmbProfiles(const KisID & s); + +signals: + /// this signal is emitted (as defined by KoDocument) the moment the document is 'ready' + void documentSelected(); + +private: + TQ_UINT8 backgroundOpacity() const; + + KisDoc *m_doc; +}; + +#endif diff --git a/chalk/ui/kis_custom_palette.cc b/chalk/ui/kis_custom_palette.cc new file mode 100644 index 00000000..47bd63b4 --- /dev/null +++ b/chalk/ui/kis_custom_palette.cc @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_view.h" +#include "kis_palette.h" +#include "kis_palette_view.h" +#include "kis_custom_palette.h" +#include "kis_resource_mediator.h" +#include "kis_resourceserver.h" + +KisCustomPalette::KisCustomPalette(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view) + : KisWdgCustomPalette(tqparent, name), m_view(view) +{ + Q_ASSERT(m_view); + m_mediator = 0; + m_server = 0; + m_editMode = false; + setCaption(caption); + + m_palette = new KisPalette(); + m_ownPalette = true; + this->view->setPalette(m_palette); + + connect(addColor, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotAddNew())); + connect(removeColor, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotRemoveCurrent())); + connect(addPalette, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotAddPredefined())); +} + +KisCustomPalette::~KisCustomPalette() { + if (m_ownPalette) + delete m_palette; +} + +void KisCustomPalette::setPalette(KisPalette* p) { + if (m_ownPalette) + delete m_palette; + m_ownPalette = false; + m_palette = p; + view->setPalette(m_palette); +} + +void KisCustomPalette::setEditMode(bool b) { + m_editMode = b; + + if (m_editMode) { + addPalette->setText(i18n("Save changes")); + } else { + addPalette->setText(i18n("Add to Predefined Palettes")); + } +} + +void KisCustomPalette::slotAddNew() { + // Let the user select a new color + // FIXME also let him add the current paint color to the palette + // or even better, let the color picker have an option 'Add to palette'! + + TQColor color; + int result = KColorDialog::getColor(color); + if (result != KColorDialog::Accepted) + return; + + bool ok; + TQRegExpValidator validator(TQRegExp(".*"), TQT_TQOBJECT(this)); + TQString name = KInputDialog::getText(i18n("Add Color to Palette"), + i18n("Color name (optional):"), + TQString(), &ok, + 0, 0, &validator); + if (!ok) + return; + + KisPaletteEntry entry; + entry.color = color; + entry.name = name; + + m_palette->add(entry); + + // Just reload the palette completely for the view updating + view->setPalette(m_palette); +} + +void KisCustomPalette::slotRemoveCurrent() { + m_palette->remove(view->currentEntry()); + // Just reload the palette completely for the view updating + view->setPalette(m_palette); +} + +void KisCustomPalette::slotAddPredefined() { + m_palette->setName(palettename->text()); + + if (!m_editMode) { + // Save in the directory that is likely to be: ~/.kde/share/apps/chalk/palettes + // a unique file with this palettename + TQString dir = KGlobal::dirs()->saveLocation("data", "chalk/palettes"); + TQString extension; + + extension = ".gpl"; + KTempFile file(dir, extension); + file.close(); // If we don't, and palette->save first, it might get truncated! + + // Save it to that file + m_palette->setFilename(file.name()); + } else { + // The filename is already set + } + + if (!m_palette->save()) { + KMessageBox::error(0, i18n("Cannot write to palette file %1. Maybe it is read-only.") + .tqarg(m_palette->filename()), i18n("Palette")); + return; + } + + // Add it to the palette server, so that it automatically gets to the mediators, and + // so to the other choosers can pick it up, if they want to + // This probably leaks! + if (m_server) + m_server->addResource(new KisPalette(*m_palette)); +} + + +#include "kis_custom_palette.moc" diff --git a/chalk/ui/kis_custom_palette.h b/chalk/ui/kis_custom_palette.h new file mode 100644 index 00000000..7ff9c9d8 --- /dev/null +++ b/chalk/ui/kis_custom_palette.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CUSTOM_PALETTE_H_ +#define KIS_CUSTOM_PALETTE_H_ + +#include + +#include "wdgcustompalette.h" + + +class KisResource; +class KisView; +class KisPalette; +class KisResourceServerBase; + +class KisCustomPalette : public KisWdgCustomPalette +{ + Q_OBJECT + TQ_OBJECT +public: + KisCustomPalette(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view); + virtual ~KisCustomPalette(); + void setResourceServer(KisResourceServerBase* server) { m_server = server; } + void setEditMode(bool b); + bool editMode() const { return m_editMode; } + void setPalette(KisPalette* p); + +signals: + void activatedResource(KisResource *); + +private slots: + void slotAddPredefined(); + void slotAddNew(); + void slotRemoveCurrent(); + +private: + bool m_ownPalette; + bool m_editMode; + KisView* m_view; + KisPalette* m_palette; + KisResourceMediator* m_mediator; + KisResourceServerBase* m_server; +}; + + +#endif // KIS_CUSTOM_PALETTE_H_ diff --git a/chalk/ui/kis_custom_pattern.cc b/chalk/ui/kis_custom_pattern.cc new file mode 100644 index 00000000..64430f1c --- /dev/null +++ b/chalk/ui/kis_custom_pattern.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_view.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_pattern.h" +#include "kis_custom_pattern.h" +#include "kis_resource_mediator.h" +#include "kis_resourceserver.h" +#include "kis_paint_layer.h" + +KisCustomPattern::KisCustomPattern(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view) + : KisWdgCustomPattern(tqparent, name), m_view(view) +{ + Q_ASSERT(m_view); + m_mediator = 0; + setCaption(caption); + + m_pattern = 0; + + preview->setScaledContents(true); + + connect(addButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotAddPredefined())); + connect(patternButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotUsePattern())); + connect(exportButton, TQT_SIGNAL(pressed()), this, TQT_SLOT(slotExport())); +} + +KisCustomPattern::~KisCustomPattern() { + delete m_pattern; +} + +void KisCustomPattern::showEvent(TQShowEvent *) { + slotUpdateCurrentPattern(0); +} + +void KisCustomPattern::slotUpdateCurrentPattern(int) { + delete m_pattern; + if (m_view->canvasSubject() && m_view->canvasSubject()->currentImg()) { + createPattern(); + preview->setPixmap(TQPixmap(m_pattern->img())); + } else { + m_pattern = 0; + } +} + +void KisCustomPattern::slotExport() { + ; +} + +void KisCustomPattern::slotAddPredefined() { + if (!m_pattern) + return; + + // Save in the directory that is likely to be: ~/.kde/share/apps/chalk/patterns + // a unique file with this pattern name + TQString dir = KGlobal::dirs()->saveLocation("data", "chalk/patterns"); + TQString extension; + + KTempFile file(dir, ".pat"); + file.close(); // If we don't, and pattern->save first, it might get truncated! + + // Save it to that file + m_pattern->setFilename(file.name()); + + // Add it to the pattern server, so that it automatically gets to the mediators, and + // so to the other pattern choosers can pick it up, if they want to + if (m_server) + m_server->addResource(m_pattern->clone()); +} + +void KisCustomPattern::slotUsePattern() { + if (!m_pattern) + return; + KisPattern* copy = m_pattern->clone(); + + Q_CHECK_PTR(copy); + + emit(activatedResource(copy)); +} + +void KisCustomPattern::createPattern() { + KisImageSP img = m_view->canvasSubject()->currentImg(); + + if (!img) + return; + + m_pattern = new KisPattern(img->mergedImage(), 0, 0, img->width(), img->height()); +} + + +#include "kis_custom_pattern.moc" diff --git a/chalk/ui/kis_custom_pattern.h b/chalk/ui/kis_custom_pattern.h new file mode 100644 index 00000000..993c9d10 --- /dev/null +++ b/chalk/ui/kis_custom_pattern.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_CUSTOM_PATTERN_H_ +#define KIS_CUSTOM_PATTERN_H_ + +#include + +#include "wdgcustompattern.h" + + +class KisResource; +class KisView; +class KisResourceServerBase; + +class KisCustomPattern : public KisWdgCustomPattern +{ + Q_OBJECT + TQ_OBJECT +public: + KisCustomPattern(TQWidget *tqparent, const char* name, const TQString& caption, KisView* view); + virtual ~KisCustomPattern(); + void setResourceServer(KisResourceServerBase* server) { m_server = server; } + +signals: + void activatedResource(KisResource *); + +protected: + virtual void showEvent(TQShowEvent *); + +private slots: + void slotExport(); + void slotAddPredefined(); + void slotUsePattern(); + void slotUpdateCurrentPattern(int); + +private: + void createPattern(); + KisView* m_view; + KisPattern* m_pattern; + KisResourceMediator* m_mediator; + KisResourceServerBase* m_server; +}; + + +#endif // KIS_CUSTOM_PATTERN_H_ diff --git a/chalk/ui/kis_dlg_adj_layer_props.cc b/chalk/ui/kis_dlg_adj_layer_props.cc new file mode 100644 index 00000000..c955eba3 --- /dev/null +++ b/chalk/ui/kis_dlg_adj_layer_props.cc @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include + +#include +#include + +#include "kis_filter_config_widget.h" +#include "kis_transaction.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_filters_listview.h" +#include "kis_image.h" +#include "kis_previewwidget.h" +#include "kis_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_paint_device.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_dlg_adj_layer_props.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" + +KisDlgAdjLayerProps::KisDlgAdjLayerProps(KisAdjustmentLayerSP layer, + const TQString & layerName, + const TQString & caption, + TQWidget *tqparent, + const char *name) + : KDialogBase(tqparent, name, true, "", Ok | Cancel) +{ + Q_ASSERT( layer ); + m_layer = layer; + + KisLayerSP next = layer->nextSibling(); + Q_ASSERT( next ); + + m_currentConfiguration = layer->filter(); + m_currentFilter = KisFilterRegistry::instance()->get(m_currentConfiguration->name()); + if (!m_currentFilter) { + kdWarning() << "No filter specified!\n"; + } + + KisPaintDeviceSP dev = 0; + + if( next ) + { + KisPaintLayer * pl = dynamic_cast(next.data()); + if (pl) { + dev = pl->paintDevice(); + } + else { + KisGroupLayer * gl = dynamic_cast(next.data()); + if (gl) { + dev = gl->projection(gl->extent()); + } + else { + KisAdjustmentLayer * al = dynamic_cast(next.data()); + if (al) { + dev = al->cachedPaintDevice(); + } + } + } + } else { + dev = new KisPaintDevice(m_layer->image()->colorSpace()); + } + setCaption(caption); + TQWidget * page = new TQWidget(this, "page widget"); + TQHBoxLayout * tqlayout = new TQHBoxLayout(page, 0, 6); + setMainWidget(page); + + m_preview = new KisPreviewWidget(page, "dlgadjustment.preview"); + m_preview->slotSetDevice( dev ); + + connect( m_preview, TQT_SIGNAL(updated()), this, TQT_SLOT(refreshPreview())); + tqlayout->addWidget(m_preview, 1, 1); + + TQVBoxLayout *v1 = new TQVBoxLayout( tqlayout ); + TQHBoxLayout *hl = new TQHBoxLayout( v1 ); + + TQLabel * lblName = new TQLabel(i18n("Layer name:"), page, "lblName"); + hl->addWidget(lblName, 0, 0); + + m_layerName = new KLineEdit(page, "m_layerName"); + m_layerName->setText(layerName); + m_layerName->tqsetSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed); + hl->addWidget(m_layerName, 0, 1); + connect( m_layerName, TQT_SIGNAL( textChanged ( const TQString & ) ), this, TQT_SLOT( slotNameChanged( const TQString & ) ) ); + + if ( m_currentFilter ) { + m_currentConfigWidget = m_currentFilter->createConfigurationWidget(page, dev); + if (m_currentConfigWidget) { + m_currentConfigWidget->setConfiguration( m_currentConfiguration ); + } + } + if ( m_currentFilter == 0 || m_currentConfigWidget == 0 ) { + TQLabel * labelNoConfigWidget = new TQLabel( i18n("No configuration options are available for this filter"), page ); + v1->addWidget( labelNoConfigWidget ); + } + else { + v1->addWidget( m_currentConfigWidget ); + connect(m_currentConfigWidget, TQT_SIGNAL(sigPleaseUpdatePreview()), this, TQT_SLOT(slotConfigChanged())); + } + + refreshPreview(); + enableButtonOK( !m_layerName->text().isEmpty() ); +} + +void KisDlgAdjLayerProps::slotNameChanged( const TQString & text ) +{ + enableButtonOK( !text.isEmpty() ); +} + +KisFilterConfiguration * KisDlgAdjLayerProps::filterConfiguration() const +{ + return m_currentFilter->configuration(m_currentConfigWidget); +} + +TQString KisDlgAdjLayerProps::layerName() const +{ + return m_layerName->text(); +} + +void KisDlgAdjLayerProps::slotConfigChanged() +{ + if(m_preview->getAutoUpdate()) + { + refreshPreview(); + } else { + m_preview->needUpdate(); + } +} + +void KisDlgAdjLayerProps::refreshPreview() +{ + if (!m_preview) { + kdDebug() << "no preview!\n"; + return; + } + + if (!m_currentFilter) { + return; + } + KisFilterConfiguration* config = m_currentFilter->configuration(m_currentConfigWidget); + + m_preview->runFilter(m_currentFilter, config); +} + +#include "kis_dlg_adj_layer_props.moc" diff --git a/chalk/ui/kis_dlg_adj_layer_props.h b/chalk/ui/kis_dlg_adj_layer_props.h new file mode 100644 index 00000000..de848002 --- /dev/null +++ b/chalk/ui/kis_dlg_adj_layer_props.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DLG_ADJ_LAYER_PROPS_H +#define KIS_DLG_ADJ_LAYER_PROPS_H + +#include + +class KisFilter; +class TQIconViewItem; +class TQLabel; +class TQHBoxLayout; +class KisPreviewWidget; +class KisFiltersListView; +class KisFilterConfiguration; +class KisImage; +class TQGroupBox; + +/** + * Create a new adjustment layer. + */ +class KisDlgAdjLayerProps : public KDialogBase +{ + + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Create a new adjustmentlayer dialog + * + * @param img the current image + * @param layername the name of the adjustment layer + * @param caption the caption for the dialog -- create or properties + * @param create if true, set the dialog up for creating a new adj. layer, if false, edit the + * propeties of the current adj. layer + * @param tqparent the widget tqparent of this dialog + * @param name the TQObject name, if any + */ + KisDlgAdjLayerProps(KisAdjustmentLayerSP layer, + const TQString & layerName, + const TQString & caption, + TQWidget *tqparent = 0, + const char *name = 0); + + KisFilterConfiguration * filterConfiguration() const; + TQString layerName() const; + +protected slots: + + void slotNameChanged( const TQString & ); + void slotConfigChanged(); + void refreshPreview(); + +private: + KisImage * m_image; + KisPreviewWidget * m_preview; + KisFilterConfigWidget * m_currentConfigWidget; + KisFilter* m_currentFilter; + KisFilterConfiguration * m_currentConfiguration; + KisAdjustmentLayer * m_layer; + KLineEdit * m_layerName; +}; + +#endif // KIS_DLG_ADJ_LAYER_PROPS_H diff --git a/chalk/ui/kis_dlg_adjustment_layer.cc b/chalk/ui/kis_dlg_adjustment_layer.cc new file mode 100644 index 00000000..22cb9c0d --- /dev/null +++ b/chalk/ui/kis_dlg_adjustment_layer.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include + +#include +#include + +#include "kis_filter_config_widget.h" +#include "kis_transaction.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_dlg_adjustment_layer.h" +#include "kis_filters_listview.h" +#include "kis_image.h" +#include "kis_previewwidget.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" + +KisDlgAdjustmentLayer::KisDlgAdjustmentLayer(KisImage * img, + const TQString & /*layerName*/, + const TQString & caption, + TQWidget *tqparent, + const char *name) + : KDialogBase(tqparent, name, true, "", Ok | Cancel) + , m_image(img) + , m_currentFilter(0) + , m_customName(false) + , m_freezeName(false) +{ + Q_ASSERT(img); + + KisLayerSP activeLayer = img->activeLayer(); + m_dev = 0; + + KisPaintLayer * pl = dynamic_cast(activeLayer.data()); + if (pl) { + m_dev = pl->paintDevice(); + } + else { + KisGroupLayer * gl = dynamic_cast(activeLayer.data()); + if (gl) { + m_dev = gl->projection(img->bounds()); + } + else { + KisAdjustmentLayer * al = dynamic_cast(activeLayer.data()); + if (al) { + m_dev = al->cachedPaintDevice(); + } + } + } + + setCaption(caption); + TQWidget * page = new TQWidget(this, "page widget"); + TQGridLayout * grid = new TQGridLayout(page, 3, 2, 0, 6); + setMainWidget(page); + + TQLabel * lblName = new TQLabel(i18n("Layer name:"), page, "lblName"); + grid->addWidget(lblName, 0, 0); + + m_layerName = new KLineEdit(page, "m_layerName"); + grid->addWidget(m_layerName, 0, 1); + connect( m_layerName, TQT_SIGNAL( textChanged ( const TQString & ) ), this, TQT_SLOT( slotNameChanged( const TQString & ) ) ); + + m_filtersList = new KisFiltersListView(m_dev, page, true, "dlgadjustment.filtersList"); + connect(m_filtersList , TQT_SIGNAL(selectionChanged(TQIconViewItem*)), this, TQT_SLOT(selectionHasChanged(TQIconViewItem* ))); + grid->addMultiCellWidget(m_filtersList, 1, 2, 0, 0); + + m_preview = new KisPreviewWidget(page, "dlgadjustment.preview"); + m_preview->slotSetDevice( m_dev ); + + connect( m_preview, TQT_SIGNAL(updated()), this, TQT_SLOT(refreshPreview())); + grid->addWidget(m_preview, 1, 1); + + m_configWidgetHolder = new TQGroupBox(i18n("Configuration"), page, "currentConfigWidget"); + m_configWidgetHolder->setColumnLayout(0, Qt::Horizontal); + grid->addWidget(m_configWidgetHolder, 2, 1); + + m_labelNoConfigWidget = new TQLabel(i18n("No configuration options are available for this filter"), + m_configWidgetHolder); + m_configWidgetHolder->tqlayout()->add(m_labelNoConfigWidget); + m_labelNoConfigWidget->hide(); + + resize( TQSize(600, 480).expandedTo(tqminimumSizeHint()) ); + + m_currentConfigWidget = 0; + + enableButtonOK(0); +} + +void KisDlgAdjustmentLayer::slotNameChanged( const TQString & text ) +{ + if (m_freezeName) + return; + + m_customName = !text.isEmpty(); + enableButtonOK( m_currentFilter && m_customName ); +} + +KisFilterConfiguration * KisDlgAdjustmentLayer::filterConfiguration() const +{ + return m_currentFilter->configuration(m_currentConfigWidget); +} + +TQString KisDlgAdjustmentLayer::layerName() const +{ + return m_layerName->text(); +} + +void KisDlgAdjustmentLayer::slotConfigChanged() +{ + if(m_preview->getAutoUpdate()) + { + refreshPreview(); + } else { + m_preview->needUpdate(); + } +} + +void KisDlgAdjustmentLayer::refreshPreview() +{ + KisFilterConfiguration* config = m_currentFilter->configuration(m_currentConfigWidget); + + m_preview->runFilter(m_currentFilter, config); +} + +void KisDlgAdjustmentLayer::selectionHasChanged ( TQIconViewItem * item ) +{ + KisFiltersIconViewItem* kisitem = (KisFiltersIconViewItem*) item; + + m_currentFilter = kisitem->filter(); + + if ( m_currentConfigWidget != 0 ) + { + m_configWidgetHolder->tqlayout()->remove(m_currentConfigWidget); + + delete m_currentConfigWidget; + m_currentConfigWidget = 0; + + } else { + + m_labelNoConfigWidget->hide(); + } + + if (m_dev) { + m_currentConfigWidget = m_currentFilter->createConfigurationWidget(m_configWidgetHolder, + m_dev); + } + + if (m_currentConfigWidget != 0) + { + m_configWidgetHolder->tqlayout()->add(m_currentConfigWidget); + m_currentConfigWidget->show(); + connect(m_currentConfigWidget, TQT_SIGNAL(sigPleaseUpdatePreview()), this, TQT_SLOT(slotConfigChanged())); + } else { + m_labelNoConfigWidget->show(); + } + + if (!m_customName) { + m_freezeName = true; + m_layerName->setText(m_currentFilter->id().name()); + m_freezeName = false; + } + + enableButtonOK( !m_layerName->text().isEmpty() ); + refreshPreview(); +} + +#include "kis_dlg_adjustment_layer.moc" diff --git a/chalk/ui/kis_dlg_adjustment_layer.h b/chalk/ui/kis_dlg_adjustment_layer.h new file mode 100644 index 00000000..4e20b8fd --- /dev/null +++ b/chalk/ui/kis_dlg_adjustment_layer.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KISDLGAdjustMENTLAYER_H +#define KISDLGAdjustMENTLAYER_H + +#include + +class KisFilter; +class TQIconViewItem; +class TQLabel; +class TQHBoxLayout; +class KisPreviewWidget; +class KisFiltersListView; +class KisFilterConfiguration; +class KisImage; +class TQGroupBox; + +/** + * Create a new adjustment layer. + */ +class KisDlgAdjustmentLayer : public KDialogBase +{ + + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Create a new adjustmentlayer dialog + * + * @param img the current image + * @param layername the name of the adjustment layer + * @param caption the caption for the dialog -- create or properties + * @param create if true, set the dialog up for creating a new adj. layer, if false, edit the + * propeties of the current adj. layer + * @param tqparent the widget tqparent of this dialog + * @param name the TQObject name, if any + */ + KisDlgAdjustmentLayer(KisImage * img, + const TQString & layerName, + const TQString & caption, + TQWidget *tqparent = 0, + const char *name = 0); + + KisFilterConfiguration * filterConfiguration() const; + TQString layerName() const; + +protected slots: + + void slotNameChanged( const TQString & ); + void slotConfigChanged(); + void refreshPreview(); + void selectionHasChanged ( TQIconViewItem * item ); + +private: + KisImage * m_image; + KisPaintDeviceSP m_dev; + KisFiltersListView * m_filtersList; + KisPreviewWidget * m_preview; + TQGroupBox * m_configWidgetHolder; + TQWidget * m_currentConfigWidget; + KisFilter* m_currentFilter; + KLineEdit * m_layerName; + TQLabel* m_labelNoConfigWidget; + bool m_customName; + bool m_freezeName; +}; + +#endif diff --git a/chalk/ui/kis_dlg_apply_profile.cc b/chalk/ui/kis_dlg_apply_profile.cc new file mode 100644 index 00000000..12134aa0 --- /dev/null +++ b/chalk/ui/kis_dlg_apply_profile.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "kis_factory.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_types.h" +#include "kis_profile.h" +#include "kis_colorspace.h" +#include "kis_dlg_apply_profile.h" +#include "kis_config.h" +#include "kis_id.h" +#include +#include "kis_cmb_idlist.h" +#include "squeezedcombobox.h" +#include "wdgapplyprofile.h" + +// XXX: Hardcode RGBA name. This should be a constant, somewhere. +KisDlgApplyProfile::KisDlgApplyProfile(TQWidget *tqparent, const char *name) + : super(tqparent, name, true, "", Ok | Cancel) +{ + + setCaption(i18n("Apply Image Profile to Clipboard Data")); + m_page = new WdgApplyProfile(this); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + // XXX: This is BAD! (bsar) + fillCmbProfiles(KisID("RGBA", "")); + KisConfig cfg; + m_page->grpRenderIntent->setButton(cfg.renderIntent()); + +} + +KisDlgApplyProfile::~KisDlgApplyProfile() +{ + delete m_page; +} + + +KisProfile * KisDlgApplyProfile::profile() const +{ + TQString profileName; + + profileName = m_page->cmbProfile->currentText(); + + return KisMetaRegistry::instance()->csRegistry()->getProfileByName(profileName); +} + +int KisDlgApplyProfile::renderIntent() const +{ + return m_page->grpRenderIntent->selectedId(); +} + + +// XXX: Copy & paste from kis_custom_image_widget -- refactor to separate class +void KisDlgApplyProfile::fillCmbProfiles(const KisID & s) +{ + m_page->cmbProfile->clear(); + + if (!KisMetaRegistry::instance()->csRegistry()->exists(s)) { + return; + } + + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + if (csf == 0) return; + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page->cmbProfile->insertItem((*it)->productName()); + } + m_page->cmbProfile->setCurrentText(csf->defaultProfile()); +} + +#include "kis_dlg_apply_profile.moc" + diff --git a/chalk/ui/kis_dlg_apply_profile.h b/chalk/ui/kis_dlg_apply_profile.h new file mode 100644 index 00000000..18f56d0a --- /dev/null +++ b/chalk/ui/kis_dlg_apply_profile.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DLG_APPLY_PROFILE_H_ +#define KIS_DLG_APPLY_PROFILE_H_ + +#include + +class KisID; +class WdgApplyProfile; + +class KisDlgApplyProfile : public KDialogBase { + typedef KDialogBase super; + + Q_OBJECT + TQ_OBJECT + +public: + KisDlgApplyProfile(TQWidget *tqparent = 0, + const char *name = 0); + virtual ~KisDlgApplyProfile(); + + + KisProfile * profile() const; + int renderIntent() const; + + void fillCmbProfiles(const KisID & s); + +private: + + WdgApplyProfile * m_page; +}; + +#endif // KIS_DLG_APPLY_PROFILE_H_ + diff --git a/chalk/ui/kis_dlg_image_properties.cc b/chalk/ui/kis_dlg_image_properties.cc new file mode 100644 index 00000000..72c26ec5 --- /dev/null +++ b/chalk/ui/kis_dlg_image_properties.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "kis_factory.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_dlg_image_properties.h" +#include "kis_profile.h" +#include "kis_types.h" +#include "kis_image.h" +#include "kis_config.h" +#include "kis_id.h" +#include "kis_cmb_idlist.h" +#include "squeezedcombobox.h" +#include "wdgnewimage.h" + +KisDlgImageProperties::KisDlgImageProperties(KisImageSP image, TQWidget *tqparent, const char *name) + : super(tqparent, name, true, "", Ok | Cancel) +{ + + setCaption(i18n("Image Properties")); + m_page = new WdgNewImage(this); + + m_page->lblResolution->hide(); + m_page->doubleResolution->hide(); + + + m_image = image; + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + m_page->txtName->setText(image->name()); + m_page->m_createButton->hide(); + KisConfig cfg; + + m_page->intWidth->setValue(image->width()); + m_page->intHeight->setValue(image->height()); + m_page->txtDescription->setText(image->description()); + m_page->doubleResolution->setValue(image->xRes()); // XXX: separate values for x & y? + + //m_page->cmbColorSpaces->hide(); + //m_page->lblColorSpaces->setText(image->colorSpace()->id().name()); + KisIDList colorSpaces = KisMetaRegistry::instance()->csRegistry()->listKeys(); + KisIDList::iterator i = colorSpaces.tqfind(KisID("WET","")); + if (i != colorSpaces.end()) { + colorSpaces.remove(i); + } + m_page->cmbColorSpaces->setIDList(colorSpaces); + m_page->cmbColorSpaces->setCurrent(image->colorSpace()->id()); + + fillCmbProfiles(image->colorSpace()->id()); + + if (image->getProfile()) { + m_page->cmbProfile->setCurrentText(image->getProfile()->productName()); + } + else { + m_page->cmbProfile->setCurrentItem(0); + } + + m_page->sliderOpacity->setEnabled(false); // XXX re-enable when figured out a way to do this + m_page->opacityPanel->hide(); + m_page->lblOpacity->hide(); + + m_page->cmbColor->setEnabled(false); // XXX re-enable when figured out a way to do this + m_page->cmbColor->hide(); + m_page->lblColor->hide(); + + connect(m_page->cmbColorSpaces, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(fillCmbProfiles(const KisID &))); + + +} + +KisDlgImageProperties::~KisDlgImageProperties() +{ + delete m_page; +} + +int KisDlgImageProperties::imageWidth() +{ + return m_page->intWidth->value(); +} + +int KisDlgImageProperties::imageHeight() +{ + return m_page->intHeight->value(); +} + +int KisDlgImageProperties::opacity() +{ + return m_page->sliderOpacity->value(); +} + +TQString KisDlgImageProperties::imageName() +{ + return m_page->txtName->text(); +} + +double KisDlgImageProperties::resolution() +{ + return m_page->doubleResolution->value(); +} + +TQString KisDlgImageProperties::description() +{ + return m_page->txtDescription->text(); +} + +KisColorSpace * KisDlgImageProperties::colorSpace() +{ + return KisMetaRegistry::instance()->csRegistry()->getColorSpace(m_page->cmbColorSpaces->currentItem(), m_page->cmbProfile->currentText()); +} + +KisProfile * KisDlgImageProperties::profile() +{ + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( m_image->colorSpace()->id() ); + TQ_UINT32 index = m_page->cmbProfile->currentItem(); + + if (index < profileList.count()) { + return profileList.at(index); + } else { + return 0; + } +} + +// XXX: Copy & paste from kis_dlg_create_img -- refactor to separate class +void KisDlgImageProperties::fillCmbProfiles(const KisID & s) +{ + + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + m_page->cmbProfile->clear(); + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page->cmbProfile->insertItem((*it)->productName()); + } + + +} + +#include "kis_dlg_image_properties.moc" + diff --git a/chalk/ui/kis_dlg_image_properties.h b/chalk/ui/kis_dlg_image_properties.h new file mode 100644 index 00000000..934adc05 --- /dev/null +++ b/chalk/ui/kis_dlg_image_properties.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DLG_IMAGE_PROPERTIES_H_ +#define KIS_DLG_IMAGE_PROPERTIES_H_ + +#include + +#include + +class WdgNewImage; +class TQButtonGroup; +class KisID; + +class KisDlgImageProperties : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + KisDlgImageProperties(KisImageSP image, + TQWidget *tqparent = 0, + const char *name = 0); + virtual ~KisDlgImageProperties(); + + int imageWidth(); + int imageHeight(); + int opacity(); + TQString imageName(); + double resolution(); + TQString description(); + KisColorSpace * colorSpace(); + KisProfile * profile(); + +private slots: + + void fillCmbProfiles(const KisID &); + +private: + + WdgNewImage * m_page; + KisImageSP m_image; +}; + + + +#endif // KIS_DLG_IMAGE_PROPERTIES_H_ + diff --git a/chalk/ui/kis_dlg_layer_properties.cc b/chalk/ui/kis_dlg_layer_properties.cc new file mode 100644 index 00000000..68df970b --- /dev/null +++ b/chalk/ui/kis_dlg_layer_properties.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kis_global.h" +#include "squeezedcombobox.h" +#include "wdglayerproperties.h" +#include "kis_dlg_layer_properties.h" +#include "kis_cmb_composite.h" +#include "kis_cmb_idlist.h" +#include "kis_profile.h" +#include "kis_int_spinbox.h" +#include "kis_colorspace.h" + +KisDlgLayerProperties::KisDlgLayerProperties(const TQString& deviceName, + TQ_INT32 opacity, + const KisCompositeOp& compositeOp, + const KisColorSpace * colorSpace, + TQWidget *tqparent, const char *name, WFlags f) + : super(tqparent, name, f, name, Ok | Cancel) +{ + m_page = new WdgLayerProperties(this); + m_page->tqlayout()->setMargin(0); + + opacity = int((opacity * 100.0) / 255 + 0.5); + + setCaption(i18n("Layer Properties")); + setMainWidget(m_page); + + m_page->editName->setText(deviceName); + connect( m_page->editName, TQT_SIGNAL( textChanged ( const TQString & ) ), this, TQT_SLOT( slotNameChanged( const TQString & ) ) ); + + m_page->cmbColorSpaces->setCurrent(colorSpace->id()); + m_page->cmbColorSpaces->setEnabled(false); + + TQString profilename; + if (KisProfile* profile = const_cast(colorSpace)->getProfile()) + profilename = profile->productName(); + m_page->cmbProfile->insertItem(profilename); + m_page->cmbProfile->setEnabled(false); + + m_page->intOpacity->setRange(0, 100, 13); + m_page->intOpacity->setValue(opacity); + + m_page->cmbComposite->setCompositeOpList(colorSpace->userVisiblecompositeOps()); + m_page->cmbComposite->setCurrentItem(compositeOp); + + slotNameChanged( m_page->editName->text() ); +} + +KisDlgLayerProperties::~KisDlgLayerProperties() +{ +} + +void KisDlgLayerProperties::slotNameChanged( const TQString &_text ) +{ + enableButtonOK( !_text.isEmpty() ); +} + +TQString KisDlgLayerProperties::getName() const +{ + return m_page->editName->text(); +} + +int KisDlgLayerProperties::getOpacity() const +{ + TQ_INT32 opacity = m_page->intOpacity->value(); + + if (!opacity) + return 0; + + opacity = int((opacity * 255.0) / 100 + 0.5); + if(opacity>255) + opacity=255; + return opacity; +} + +KisCompositeOp KisDlgLayerProperties::getCompositeOp() const +{ + return m_page->cmbComposite->currentItem(); +} + +#include "kis_dlg_layer_properties.moc" diff --git a/chalk/ui/kis_dlg_layer_properties.h b/chalk/ui/kis_dlg_layer_properties.h new file mode 100644 index 00000000..c2b2a5e0 --- /dev/null +++ b/chalk/ui/kis_dlg_layer_properties.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DLG_LAYER_PROPERTIES_H_ +#define KIS_DLG_LAYER_PROPERTIES_H_ + +#include + +class TQWidget; +class WdgLayerProperties; +class KisCompositeOp; +class KisColorSpace; + +class KisDlgLayerProperties : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + KisDlgLayerProperties(const TQString& deviceName, + TQ_INT32 opacity, + const KisCompositeOp& compositeOp, + const KisColorSpace * colorSpace, + TQWidget *tqparent = 0, const char *name = 0, WFlags f = 0); + + virtual ~KisDlgLayerProperties(); + + TQString getName() const; + TQ_INT32 getOpacity() const; + KisCompositeOp getCompositeOp() const; + +protected slots: + void slotNameChanged( const TQString & ); + +private: + WdgLayerProperties * m_page; +}; + +#endif // KIS_DLG_LAYER_PROPERTIES_H_ + diff --git a/chalk/ui/kis_dlg_new_layer.cc b/chalk/ui/kis_dlg_new_layer.cc new file mode 100644 index 00000000..a0a97a7e --- /dev/null +++ b/chalk/ui/kis_dlg_new_layer.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000 Michael Koch + * Copyright (c) 2000 Patrick Julien + * Copyright (c) 2004 Boudewijn Remot + * Copyright (c) 2006 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_factory.h" +#include "kis_global.h" +#include "kis_cmb_composite.h" +#include "kis_cmb_idlist.h" +#include "squeezedcombobox.h" +#include "kis_dlg_new_layer.h" +#include +#include "kis_colorspace_factory_registry.h" +#include "kis_profile.h" +#include "kis_colorspace.h" +#include "wdglayerproperties.h" +#include "kis_int_spinbox.h" + +NewLayerDialog::NewLayerDialog(const KisID colorSpaceID, + const TQString & profilename, + const TQString & deviceName, + TQWidget *tqparent, + const char *name) + : super(tqparent, name, true, "", Ok | Cancel) +{ + m_page = new WdgLayerProperties(this); + m_page->tqlayout()->setMargin(0); + + setCaption(i18n("New Layer")); + + setMainWidget(m_page); + + // Name + m_page->editName->setText(deviceName); + + // Opacity + m_page->intOpacity->setRange(0, 100, 13); + m_page->intOpacity->setValue(100); + + // ColorSpace + m_page->cmbColorSpaces->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + m_page->cmbColorSpaces->setCurrentText(colorSpaceID.id()); + connect(m_page->cmbColorSpaces, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(fillCmbProfiles(const KisID &))); + connect(m_page->cmbColorSpaces, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(fillCmbComposite(const KisID &))); + + // Init profiles + fillCmbProfiles(m_page->cmbColorSpaces->currentItem()); + m_page->cmbProfile->setCurrentText(profilename); + + // Init composite op + fillCmbComposite(m_page->cmbColorSpaces->currentItem()); + +/* + connect( m_page->editName, TQT_SIGNAL( textChanged ( const TQString & ) ), this, TQT_SLOT( slotNameChanged( const TQString & ) ) ); + + slotNameChanged( m_page->editName->text() ); +*/ +} + +void NewLayerDialog::setColorSpaceEnabled(bool enabled) +{ + m_page->cmbProfile->setEnabled(enabled); + m_page->cmbColorSpaces->setEnabled(enabled); +} + +void NewLayerDialog::fillCmbProfiles(const KisID & s) +{ + m_page->cmbProfile->clear(); + + if (!KisMetaRegistry::instance()->csRegistry()->exists(s)) { + return; + } + + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + if (csf == 0) return; + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page->cmbProfile->insertItem((*it)->productName()); + } + m_page->cmbProfile->setCurrentText(csf->defaultProfile()); +} + +void NewLayerDialog::fillCmbComposite(const KisID & s) +{ + m_page->cmbComposite->clear(); + + if (!KisMetaRegistry::instance()->csRegistry()->exists(s)) { + return; + } + + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(s,""); + if (cs) { + m_page->cmbComposite->setCompositeOpList(cs->userVisiblecompositeOps()); + } +} + +int NewLayerDialog::opacity() const +{ + TQ_INT32 opacity = m_page->intOpacity->value(); + + if (!opacity) + return 0; + + opacity = int((opacity * 255.0) / 100 + 0.5); + if(opacity>255) + opacity=255; + return opacity; +} + +KisCompositeOp NewLayerDialog::compositeOp() const +{ + return m_page->cmbComposite->currentItem(); +} + +KisID NewLayerDialog::colorSpaceID() const +{ + return m_page->cmbColorSpaces->currentItem(); +} + +TQString NewLayerDialog::layerName() const +{ + return m_page->editName->text(); +} + +TQString NewLayerDialog::profileName() const +{ + return m_page->cmbProfile-> currentText(); +} + +#include "kis_dlg_new_layer.moc" + diff --git a/chalk/ui/kis_dlg_new_layer.h b/chalk/ui/kis_dlg_new_layer.h new file mode 100644 index 00000000..b484e1dc --- /dev/null +++ b/chalk/ui/kis_dlg_new_layer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Michael Koch + * Copyright (c) 2000 Patrick Julien + * Copyright (c) 2006 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DLG_NEW_LAYER_H_ +#define KIS_DLG_NEW_LAYER_H_ + +#include + +#include "kis_composite_op.h" +#include + +class TQWidget; +class KisPaintDevice; +class WdgLayerProperties; + +class NewLayerDialog : public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + NewLayerDialog(const KisID colorSpace, + const TQString & profilename, + const TQString & deviceName, + TQWidget *tqparent = 0, + const char *name = 0); + + TQString layerName() const; + KisCompositeOp compositeOp() const; + TQ_INT32 opacity() const; + KisID colorSpaceID() const; + TQString profileName() const; + + void setColorSpaceEnabled(bool enabled); + +private slots: + void fillCmbProfiles(const KisID & s); + void fillCmbComposite(const KisID & s); + +private: + WdgLayerProperties * m_page; +}; + +#endif // KIS_DLG_NEW_LAYER_H_ + diff --git a/chalk/ui/kis_dlg_preferences.cc b/chalk/ui/kis_dlg_preferences.cc new file mode 100644 index 00000000..9f82c0d7 --- /dev/null +++ b/chalk/ui/kis_dlg_preferences.cc @@ -0,0 +1,821 @@ +/* + * preferencesdlg.cc - part of KImageShop + * + * Copyright (c) 1999 Michael Koch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_GL +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "squeezedcombobox.h" +#include "kis_cmb_idlist.h" +#include "kis_colorspace.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_cursor.h" +#include "kis_config.h" +#include "kis_dlg_preferences.h" +#include "kis_factory.h" +#include "kis_id.h" +#include "kis_meta_registry.h" +#include "kis_profile.h" + +#include "kis_canvas.h" + +#include "wdgcolorsettings.h" +#include "wdgperformancesettings.h" +#include "wdggeneralsettings.h" + +// for the performance update +#include "tiles/kis_tilemanager.h" + +GeneralTab::GeneralTab( TQWidget *_parent, const char *_name ) + : WdgGeneralSettings( _parent, _name ) +{ + + KisConfig cfg; + + m_cmbtqCursorShape->setCurrentItem(cfg.cursorStyle()); + grpDockability->setButton(cfg.dockability()); + numDockerFontSize->setValue((int)cfg.dockerFontSize()); +} + +void GeneralTab::setDefault() +{ + KisConfig cfg; + + m_cmbtqCursorShape->setCurrentItem( cfg.getDefaultCursorStyle()); + grpDockability->setButton(cfg.getDefaultDockability()); + numDockerFontSize->setValue((int)(cfg.getDefaultDockerFontSize())); +} + +enumCursorStyle GeneralTab::cursorStyle() +{ + return (enumCursorStyle)m_cmbtqCursorShape->currentItem(); +} + +enumKoDockability GeneralTab::dockability() +{ + return (enumKoDockability)grpDockability->selectedId(); +} + +float GeneralTab::dockerFontSize() +{ + return (float)numDockerFontSize->value(); +} + +//--------------------------------------------------------------------------------------------------- + +ColorSettingsTab::ColorSettingsTab(TQWidget *tqparent, const char *name ) + : TQWidget(tqparent, name) +{ + // XXX: Make sure only profiles that fit the specified color model + // are shown in the profile combos + + TQGridLayout * l = new TQGridLayout( this, 1, 1, KDialog::marginHint(), KDialog::spacingHint()); + l->setMargin(0); + m_page = new WdgColorSettings(this); + l->addWidget( m_page, 0, 0); + + KisConfig cfg; + + m_page->cmbWorkingColorSpace->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + m_page->cmbWorkingColorSpace->setCurrentText(cfg.workingColorSpace()); + + m_page->cmbPrintingColorSpace->setIDList(KisMetaRegistry::instance()->csRegistry()->listKeys()); + m_page->cmbPrintingColorSpace->setCurrentText(cfg.printerColorSpace()); + + refillMonitorProfiles(KisID("RGBA", "")); + refillPrintProfiles(KisID(cfg.printerColorSpace(), "")); + + if(m_page->cmbMonitorProfile->tqcontains(cfg.monitorProfile())) + m_page->cmbMonitorProfile->setCurrentText(cfg.monitorProfile()); + if(m_page->cmbPrintProfile->contains(cfg.printerProfile())) + m_page->cmbPrintProfile->setCurrentText(cfg.printerProfile()); + m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation()); + m_page->grpPasteBehaviour->setButton(cfg.pasteBehaviour()); + m_page->cmbMonitorIntent->setCurrentItem(cfg.renderIntent()); + + connect(m_page->cmbPrintingColorSpace, TQT_SIGNAL(activated(const KisID &)), + this, TQT_SLOT(refillPrintProfiles(const KisID &))); +} + +void ColorSettingsTab::setDefault() +{ + m_page->cmbWorkingColorSpace->setCurrentText("RGBA"); + + m_page->cmbPrintingColorSpace->setCurrentText("CMYK"); + refillPrintProfiles(KisID("CMYK", "")); + + m_page->chkBlackpoint->setChecked(false); + m_page->cmbMonitorIntent->setCurrentItem(INTENT_PERCEPTUAL); + m_page->grpPasteBehaviour->setButton(2); +} + + +void ColorSettingsTab::refillMonitorProfiles(const KisID & s) +{ + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + + m_page->cmbMonitorProfile->clear(); + + if ( !csf ) + return; + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + if ((*it)->deviceClass() == icSigDisplayClass) + m_page->cmbMonitorProfile->insertItem((*it)->productName()); + } + + m_page->cmbMonitorProfile->setCurrentText(csf->defaultProfile()); +} + +void ColorSettingsTab::refillPrintProfiles(const KisID & s) +{ + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry()->get(s); + + m_page->cmbPrintProfile->clear(); + + if ( !csf ) + return; + + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + if ((*it)->deviceClass() == icSigOutputClass) + m_page->cmbPrintProfile->insertItem((*it)->productName()); + } + + m_page->cmbPrintProfile->setCurrentText(csf->defaultProfile()); +} + +//--------------------------------------------------------------------------------------------------- + +PerformanceTab::PerformanceTab(TQWidget *tqparent, const char *name ) + : WdgPerformanceSettings(tqparent, name) +{ + // XXX: Make sure only profiles that fit the specified color model + // are shown in the profile combos + + KisConfig cfg; + + // it's scaled from 0 - 6, but the config is in 0 - 300 + m_swappiness->setValue(cfg.swappiness() / 50); + m_maxTiles->setValue(cfg.maxTilesInMem()); +} + +void PerformanceTab::setDefault() +{ + m_swappiness->setValue(3); + m_maxTiles->setValue(500); +} + +//--------------------------------------------------------------------------------------------------- + +TabletSettingsTab::TabletSettingsTab( TQWidget *tqparent, const char *name) + : WdgTabletSettings( tqparent, name ) +{ +#ifdef EXTENDED_X11_TABLET_SUPPORT + initTabletDevices(); +#else + grpTabletDevices->hide(); +#endif +} + +void TabletSettingsTab::setDefault() +{ +} + +void TabletSettingsTab::applySettings() +{ + +#ifdef EXTENDED_X11_TABLET_SUPPORT + applyTabletDeviceSettings(); +#endif +} + +#ifdef EXTENDED_X11_TABLET_SUPPORT +TabletSettingsTab::DeviceSettings::DeviceSettings(KisCanvasWidget::X11TabletDevice *tabletDevice, bool enabled, + TQ_INT32 xAxis, TQ_INT32 yAxis, TQ_INT32 pressureAxis, + TQ_INT32 xTiltAxis, TQ_INT32 yTiltAxis, TQ_INT32 wheelAxis, + TQ_INT32 toolIDAxis, TQ_INT32 serialNumberAxis) + : m_tabletDevice(tabletDevice), + m_enabled(enabled), + m_xAxis(xAxis), + m_yAxis(yAxis), + m_pressureAxis(pressureAxis), + m_xTiltAxis(xTiltAxis), + m_yTiltAxis(yTiltAxis), + m_wheelAxis(wheelAxis), + m_toolIDAxis(toolIDAxis), + m_serialNumberAxis(serialNumberAxis) +{ +} + +TabletSettingsTab::DeviceSettings::DeviceSettings() + : m_tabletDevice(0), + m_enabled(false), + m_xAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_yAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_pressureAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_xTiltAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_yTiltAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_wheelAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_toolIDAxis(KisCanvasWidget::X11TabletDevice::NoAxis), + m_serialNumberAxis(KisCanvasWidget::X11TabletDevice::NoAxis) +{ +} + +void TabletSettingsTab::DeviceSettings::applySettings() +{ + m_tabletDevice->setEnabled(enabled()); + m_tabletDevice->setXAxis(xAxis()); + m_tabletDevice->setYAxis(yAxis()); + m_tabletDevice->setPressureAxis(pressureAxis()); + m_tabletDevice->setXTiltAxis(xTiltAxis()); + m_tabletDevice->setYTiltAxis(yTiltAxis()); + m_tabletDevice->setWheelAxis(wheelAxis()); + m_tabletDevice->setToolIDAxis(toolIDAxis()); + m_tabletDevice->setSerialNumberAxis(serialNumberAxis()); + m_tabletDevice->writeSettingsToConfig(); +} + +void TabletSettingsTab::DeviceSettings::setEnabled(bool enabled) +{ + m_enabled = enabled; +} + +bool TabletSettingsTab::DeviceSettings::enabled() const +{ + return m_enabled; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::numAxes() const +{ + return m_tabletDevice->numAxes(); +} + +void TabletSettingsTab::DeviceSettings::setXAxis(TQ_INT32 axis) +{ + m_xAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setYAxis(TQ_INT32 axis) +{ + m_yAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setPressureAxis(TQ_INT32 axis) +{ + m_pressureAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setXTiltAxis(TQ_INT32 axis) +{ + m_xTiltAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setYTiltAxis(TQ_INT32 axis) +{ + m_yTiltAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setWheelAxis(TQ_INT32 axis) +{ + m_wheelAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setToolIDAxis(TQ_INT32 axis) +{ + m_toolIDAxis = axis; +} + +void TabletSettingsTab::DeviceSettings::setSerialNumberAxis(TQ_INT32 axis) +{ + m_serialNumberAxis = axis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::xAxis() const +{ + return m_xAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::yAxis() const +{ + return m_yAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::pressureAxis() const +{ + return m_pressureAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::xTiltAxis() const +{ + return m_xTiltAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::yTiltAxis() const +{ + return m_yTiltAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::wheelAxis() const +{ + return m_wheelAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::toolIDAxis() const +{ + return m_toolIDAxis; +} + +TQ_INT32 TabletSettingsTab::DeviceSettings::serialNumberAxis() const +{ + return m_serialNumberAxis; +} + +TabletSettingsTab::TabletDeviceSettingsDialog::TabletDeviceSettingsDialog(const TQString& deviceName, DeviceSettings settings, + TQWidget *tqparent, const char *name) + : super(tqparent, name, true, "", Ok | Cancel) +{ + setCaption(i18n("Configure %1").tqarg(deviceName)); + + m_page = new WdgTabletDeviceSettings(this); + + setMainWidget(m_page); + resize(m_page->tqsizeHint()); + + for (TQ_INT32 axis = 0; axis < settings.numAxes(); axis++) { + TQString axisString; + + axisString.setNum(axis); + + m_page->cbX->insertItem(axisString); + m_page->cbY->insertItem(axisString); + m_page->cbPressure->insertItem(axisString); + m_page->cbXTilt->insertItem(axisString); + m_page->cbYTilt->insertItem(axisString); + m_page->cbWheel->insertItem(axisString); +// m_page->cbToolID->insertItem(axisString); +// m_page->cbSerialNumber->insertItem(axisString); + } + + m_page->cbX->insertItem(i18n("None")); + m_page->cbY->insertItem(i18n("None")); + m_page->cbPressure->insertItem(i18n("None")); + m_page->cbXTilt->insertItem(i18n("None")); + m_page->cbYTilt->insertItem(i18n("None")); + m_page->cbWheel->insertItem(i18n("None")); +// m_page->cbToolID->insertItem(i18n("None")); +// m_page->cbSerialNumber->insertItem(i18n("None")); + + if (settings.xAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbX->setCurrentItem(settings.xAxis()); + } else { + m_page->cbX->setCurrentItem(settings.numAxes()); + } + + if (settings.yAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbY->setCurrentItem(settings.yAxis()); + } else { + m_page->cbY->setCurrentItem(settings.numAxes()); + } + + if (settings.pressureAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbPressure->setCurrentItem(settings.pressureAxis()); + } else { + m_page->cbPressure->setCurrentItem(settings.numAxes()); + } + + if (settings.xTiltAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbXTilt->setCurrentItem(settings.xTiltAxis()); + } else { + m_page->cbXTilt->setCurrentItem(settings.numAxes()); + } + + if (settings.yTiltAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbYTilt->setCurrentItem(settings.yTiltAxis()); + } else { + m_page->cbYTilt->setCurrentItem(settings.numAxes()); + } + + if (settings.wheelAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { + m_page->cbWheel->setCurrentItem(settings.wheelAxis()); + } else { + m_page->cbWheel->setCurrentItem(settings.numAxes()); + } + +// if (settings.toolIDAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { +// m_page->cbToolID->setCurrentItem(settings.toolIDAxis()); +// } else { +// m_page->cbToolID->setCurrentItem(settings.numAxes()); +// } +// +// if (settings.serialNumberAxis() != KisCanvasWidget::X11TabletDevice::NoAxis) { +// m_page->cbSerialNumber->setCurrentItem(settings.serialNumberAxis()); +// } else { +// m_page->cbSerialNumber->setCurrentItem(settings.numAxes()); +// } + + m_settings = settings; +} + +TabletSettingsTab::TabletDeviceSettingsDialog::~TabletDeviceSettingsDialog() +{ + delete m_page; +} + +TabletSettingsTab::DeviceSettings TabletSettingsTab::TabletDeviceSettingsDialog::settings() +{ + const TQ_INT32 noAxis = m_settings.numAxes(); + + if (m_page->cbX->currentItem() != noAxis ) { + m_settings.setXAxis(m_page->cbX->currentItem()); + } else { + m_settings.setXAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + + if (m_page->cbY->currentItem() != noAxis ) { + m_settings.setYAxis(m_page->cbY->currentItem()); + } else { + m_settings.setYAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + + if (m_page->cbPressure->currentItem() != noAxis ) { + m_settings.setPressureAxis(m_page->cbPressure->currentItem()); + } else { + m_settings.setPressureAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + + if (m_page->cbXTilt->currentItem() != noAxis ) { + m_settings.setXTiltAxis(m_page->cbXTilt->currentItem()); + } else { + m_settings.setXTiltAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + + if (m_page->cbYTilt->currentItem() != noAxis ) { + m_settings.setYTiltAxis(m_page->cbYTilt->currentItem()); + } else { + m_settings.setYTiltAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + + if (m_page->cbWheel->currentItem() != noAxis ) { + m_settings.setWheelAxis(m_page->cbWheel->currentItem()); + } else { + m_settings.setWheelAxis(KisCanvasWidget::X11TabletDevice::NoAxis); + } + +// if (m_page->cbToolID->currentItem() != noAxis ) { +// m_settings.setToolIDAxis(m_page->cbToolID->currentItem()); +// } else { +// m_settings.setToolIDAxis(KisCanvasWidget::X11TabletDevice::NoAxis); +// } +// +// if (m_page->cbSerialNumber->currentItem() != noAxis ) { +// m_settings.setSerialNumberAxis(m_page->cbSerialNumber->currentItem()); +// } else { +// m_settings.setSerialNumberAxis(KisCanvasWidget::X11TabletDevice::NoAxis); +// } + + return m_settings; +} + +void TabletSettingsTab::initTabletDevices() +{ + connect(cbTabletDevice, TQT_SIGNAL(activated(int)), TQT_SLOT(slotActivateDevice(int))); + connect(chkEnableTabletDevice, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetDeviceEnabled(bool))); + connect(btnConfigureTabletDevice, TQT_SIGNAL(clicked()), TQT_SLOT(slotConfigureDevice())); + + KisCanvasWidget::X11XIDTabletDeviceMap& tabletDevices = KisCanvasWidget::tabletDeviceMap(); + + cbTabletDevice->clear(); + + if (!tabletDevices.empty()) { + KisCanvasWidget::X11XIDTabletDeviceMap::iterator it; + + for (it = tabletDevices.begin(); it != tabletDevices.end(); ++it) { + KisCanvasWidget::X11TabletDevice& device = (*it).second; + + m_deviceSettings.append(DeviceSettings(&device, device.enabled(), device.xAxis(), device.yAxis(), + device.pressureAxis(), device.xTiltAxis(), device.yTiltAxis(), device.wheelAxis(), + device.toolIDAxis(), device.serialNumberAxis())); + cbTabletDevice->insertItem(device.name()); + } + slotActivateDevice(0); + } else { + cbTabletDevice->insertItem(i18n("No devices detected")); + cbTabletDevice->setEnabled(false); + chkEnableTabletDevice->setEnabled(false); + btnConfigureTabletDevice->setEnabled(false); + } +} + +void TabletSettingsTab::slotActivateDevice(int deviceIndex) +{ + bool deviceEnabled = m_deviceSettings[deviceIndex].enabled(); + + chkEnableTabletDevice->setChecked(deviceEnabled); + slotSetDeviceEnabled(deviceEnabled); +} + +void TabletSettingsTab::slotSetDeviceEnabled(bool enabled) +{ + btnConfigureTabletDevice->setEnabled(enabled); + m_deviceSettings[cbTabletDevice->currentItem()].setEnabled(enabled); +} + +void TabletSettingsTab::slotConfigureDevice() +{ + TabletDeviceSettingsDialog dialog(cbTabletDevice->currentText(), m_deviceSettings[cbTabletDevice->currentItem()], + this, "TabletDeviceSettings"); + + if (dialog.exec() == TQDialog::Accepted) + { + m_deviceSettings[cbTabletDevice->currentItem()] = dialog.settings(); + } +} + +void TabletSettingsTab::applyTabletDeviceSettings() +{ + for (TQ_UINT32 deviceIndex = 0; deviceIndex < m_deviceSettings.count(); ++deviceIndex) { + m_deviceSettings[deviceIndex].applySettings(); + } +} + +#else // EXTENDED_X11_TABLET_SUPPORT + +// Fix compilation. tqmoc seems to not see the undefined symbol needed +// for these slots to be declared. +void TabletSettingsTab::slotActivateDevice(int /*deviceIndex*/) +{ +} + +void TabletSettingsTab::slotSetDeviceEnabled(bool /*enabled*/) +{ +} + +void TabletSettingsTab::slotConfigureDevice() +{ +} + +void TabletSettingsTab::applyTabletDeviceSettings() +{ +} + +#endif + +//--------------------------------------------------------------------------------------------------- + +DisplaySettingsTab::DisplaySettingsTab( TQWidget *tqparent, const char *name) + : WdgDisplaySettings( tqparent, name ) +{ +#ifdef HAVE_GL + KisConfig cfg; + + if (!TQGLFormat::hasOpenGL()) { + cbUseOpenGL->setEnabled(false); + //cbUseOpenGLShaders->setEnabled(false); + } else { + cbUseOpenGL->setChecked(cfg.useOpenGL()); + //cbUseOpenGLShaders->setChecked(cfg.useOpenGLShaders()); + //cbUseOpenGLShaders->setEnabled(cfg.useOpenGL()); + } +#else + cbUseOpenGL->setEnabled(false); + //cbUseOpenGLShaders->setEnabled(false); +#endif + + connect(cbUseOpenGL, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotUseOpenGLToggled(bool))); +} + +void DisplaySettingsTab::setDefault() +{ + cbUseOpenGL->setChecked(false); + //cbUseOpenGLShaders->setChecked(false); + //cbUseOpenGLShaders->setEnabled(false); +} + +void DisplaySettingsTab::slotUseOpenGLToggled(bool /*isChecked*/) +{ + //cbUseOpenGLShaders->setEnabled(isChecked); +} + +//--------------------------------------------------------------------------------------------------- +GridSettingsTab::GridSettingsTab(TQWidget* tqparent) : WdgGridSettingsBase(tqparent) +{ + KisConfig cfg; + selectMainStyle->setCurrentItem(cfg.getGridMainStyle()); + selectSubdivisionStyle->setCurrentItem(cfg.getGridSubdivisionStyle()); + +#if KDE_IS_VERSION(3,4,0) + colorMain->setDefaultColor( TQColor( 99, 99, 99 ) ); + colorSubdivision->setDefaultColor( TQColor( 200, 200, 200 ) ); +#endif + colorMain->setColor(cfg.getGridMainColor()); + colorSubdivision->setColor(cfg.getGridSubdivisionColor()); + + intHSpacing->setValue( cfg.getGridHSpacing() ); + intVSpacing->setValue( cfg.getGridVSpacing() ); + intSubdivision->setValue( cfg.getGridSubdivisions()); + intOffsetX->setValue( cfg.getGridOffsetX()); + intOffsetY->setValue( cfg.getGridOffsetY()); + + linkSpacingToggled(true); + connect(bnLinkSpacing, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(linkSpacingToggled( bool ))); + + connect(intHSpacing, TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxHSpacingChanged(int))); + connect(intVSpacing, TQT_SIGNAL(valueChanged(int)),this,TQT_SLOT(spinBoxVSpacingChanged(int))); + + +} + +void GridSettingsTab::setDefault() +{ + KisConfig cfg; + selectMainStyle->setCurrentItem(0); + selectSubdivisionStyle->setCurrentItem(1); + + colorMain->setColor(TQColor(99,99,99)); + colorSubdivision->setColor(TQColor(199,199,199)); + + intHSpacing->setValue( 10 ); + intVSpacing->setValue( 10 ); + intSubdivision->setValue( 1 ); + intOffsetX->setValue( 0 ); + intOffsetY->setValue( 0 ); +} + +void GridSettingsTab::spinBoxHSpacingChanged(int v) +{ + if(m_linkSpacing) + { + intVSpacing->setValue(v); + } +} + +void GridSettingsTab::spinBoxVSpacingChanged(int v ) +{ + if(m_linkSpacing) + { + intHSpacing->setValue(v); + } +} + + +void GridSettingsTab::linkSpacingToggled(bool b) +{ + m_linkSpacing = b; + + KoImageResource kir; + if (b) { + bnLinkSpacing->setPixmap(kir.chain()); + } + else { + bnLinkSpacing->setPixmap(kir.chainBroken()); + } +} + + +//--------------------------------------------------------------------------------------------------- + +PreferencesDialog::PreferencesDialog( TQWidget* tqparent, const char* name ) + : KDialogBase( IconList, i18n("Preferences"), Ok | Cancel | Help | Default /*| Apply*/, Ok, tqparent, name, true, true ) +{ + TQVBox *vbox; + + vbox = addVBoxPage( i18n( "General"), i18n( "General"), BarIcon( "misc", KIcon::SizeMedium )); + m_general = new GeneralTab( vbox ); +#ifdef HAVE_GL + vbox = addVBoxPage ( i18n( "Display" ), i18n( "Display" ), BarIcon( "kscreensaver", KIcon::SizeMedium )); + m_displaySettings = new DisplaySettingsTab( vbox ); +#endif + vbox = addVBoxPage( i18n( "Color Management"), i18n( "Color"), BarIcon( "colorize", KIcon::SizeMedium )); + m_colorSettings = new ColorSettingsTab( vbox ); + + vbox = addVBoxPage( i18n( "Performance"), i18n( "Performance"), BarIcon( "fork", KIcon::SizeMedium )); + m_performanceSettings = new PerformanceTab ( vbox ); + + vbox = addVBoxPage ( i18n( "Tablet" ), i18n( "Tablet" ), BarIcon( "tablet", KIcon::SizeMedium )); + m_tabletSettings = new TabletSettingsTab( vbox ); + + vbox = addVBoxPage ( i18n( "Grid" ), i18n( "Grid" ), BarIcon( "grid", KIcon::SizeMedium )); + m_gridSettings = new GridSettingsTab( vbox ); + +} + +PreferencesDialog::~PreferencesDialog() +{ +} + +void PreferencesDialog::slotDefault() +{ + m_general->setDefault(); + m_colorSettings->setDefault(); + m_tabletSettings->setDefault(); + m_performanceSettings->setDefault(); +#ifdef HAVE_GL + m_displaySettings->setDefault(); +#endif + m_gridSettings->setDefault(); +} + +bool PreferencesDialog::editPreferences() +{ + PreferencesDialog* dialog; + + dialog = new PreferencesDialog(); + bool baccept = ( dialog->exec() == Accepted ); + if( baccept ) + { + KisConfig cfg; + cfg.setCursorStyle(dialog->m_general->cursorStyle()); + cfg.setDockability( dialog->m_general->dockability() ); + cfg.setDockerFontSize( dialog->m_general->dockerFontSize() ); + + // Color settings + cfg.setMonitorProfile( dialog->m_colorSettings->m_page->cmbMonitorProfile->currentText()); + cfg.setWorkingColorSpace( dialog->m_colorSettings->m_page->cmbWorkingColorSpace->currentText()); + cfg.setPrinterColorSpace( dialog->m_colorSettings->m_page->cmbPrintingColorSpace->currentText()); + cfg.setPrinterProfile( dialog->m_colorSettings->m_page->cmbPrintProfile->currentText()); + + cfg.setUseBlackPointCompensation( dialog->m_colorSettings->m_page->chkBlackpoint->isChecked()); + cfg.setPasteBehaviour( dialog->m_colorSettings->m_page->grpPasteBehaviour->selectedId()); + cfg.setRenderIntent( dialog->m_colorSettings->m_page->cmbMonitorIntent->currentItem()); + + // it's scaled from 0 - 6, but the config is in 0 - 300 + cfg.setSwappiness(dialog->m_performanceSettings->m_swappiness->value() * 50); + cfg.setMaxTilesInMem(dialog->m_performanceSettings->m_maxTiles->value()); + // let the tile manager know + KisTileManager::instance()->configChanged(); + + dialog->m_tabletSettings->applySettings(); + +#ifdef HAVE_GL + cfg.setUseOpenGL(dialog->m_displaySettings->cbUseOpenGL->isChecked()); + //cfg.setUseOpenGLShaders(dialog->m_displaySettings->cbUseOpenGLShaders->isChecked()); +#endif + + // Grid settings + cfg.setGridMainStyle( dialog->m_gridSettings->selectMainStyle->currentItem() ); + cfg.setGridSubdivisionStyle( dialog->m_gridSettings->selectSubdivisionStyle->currentItem() ); + + cfg.setGridMainColor( dialog->m_gridSettings->colorMain->color() ); + cfg.setGridSubdivisionColor(dialog->m_gridSettings->colorSubdivision->color() ); + + cfg.setGridHSpacing( dialog->m_gridSettings->intHSpacing->value( )); + cfg.setGridVSpacing( dialog->m_gridSettings->intVSpacing->value( )); + cfg.setGridSubdivisions( dialog->m_gridSettings->intSubdivision->value( )); + cfg.setGridOffsetX( dialog->m_gridSettings->intOffsetX->value( )); + cfg.setGridOffsetY( dialog->m_gridSettings->intOffsetY->value( )); + + } + delete dialog; + return baccept; +} + +#include "kis_dlg_preferences.moc" diff --git a/chalk/ui/kis_dlg_preferences.h b/chalk/ui/kis_dlg_preferences.h new file mode 100644 index 00000000..61f4a586 --- /dev/null +++ b/chalk/ui/kis_dlg_preferences.h @@ -0,0 +1,277 @@ +/* + * preferencesdlg.h - part of KImageShop^WChalk + * + * Copyright (c) 1999 Michael Koch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __preferencesdlg_h__ +#define __preferencesdlg_h__ + +#include + +#include + +#include + +#include "kis_canvas.h" + +#include "wdggeneralsettings.h" +#include "wdgtabletsettings.h" +#include "wdgtabletdevicesettings.h" +#include "wdgperformancesettings.h" +#include "wdgdisplaysettings.h" +#include "wdggridsettings.h" + +class TQLineEdit; +class TQCheckBox; +class KURLRequester; +class WdgColorSettings; +class KisCmbIDList; +class KisID; + +/** + * "General"-tab for preferences dialog + */ +class GeneralTab : public WdgGeneralSettings +{ + Q_OBJECT + TQ_OBJECT + +public: + + GeneralTab( TQWidget *tqparent = 0, const char *name = 0 ); + + enumCursorStyle cursorStyle(); + enumKoDockability dockability(); + float dockerFontSize(); + + void setDefault(); + +}; + +//======================= + +class ColorSettingsTab : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + +public: + + ColorSettingsTab( TQWidget *tqparent = 0, const char * name = 0 ); + +private slots: + + void refillMonitorProfiles(const KisID & s); + void refillPrintProfiles(const KisID & s); + +public: + void setDefault(); + WdgColorSettings * m_page; +}; + + +/** + * "Performance"-tab for preferences dialog + */ +class PerformanceTab : public WdgPerformanceSettings +{ +Q_OBJECT + TQ_OBJECT + +public: + PerformanceTab( TQWidget *tqparent = 0, const char *name = 0 ); + +public: + void setDefault(); +}; + +//======================= + + +/** + * Tablet settings tab for preferences dialog + */ +class TabletSettingsTab : public WdgTabletSettings +{ +Q_OBJECT + TQ_OBJECT + +public: + TabletSettingsTab( TQWidget *tqparent = 0, const char *name = 0 ); + +public: + void setDefault(); + void applySettings(); + +private slots: + void slotActivateDevice(int deviceIndex); + void slotSetDeviceEnabled(bool enabled); + void slotConfigureDevice(); + void applyTabletDeviceSettings(); + +#ifdef EXTENDED_X11_TABLET_SUPPORT + +private: + class DeviceSettings { + public: + DeviceSettings(KisCanvasWidget::X11TabletDevice *tabletDevice, bool enabled, + TQ_INT32 xAxis, TQ_INT32 yAxis, TQ_INT32 pressureAxis, + TQ_INT32 xTiltAxis, TQ_INT32 yTiltAxis, TQ_INT32 wheelAxis, + TQ_INT32 toolIDAxis, TQ_INT32 serialNumberAxis); + DeviceSettings(); + + void applySettings(); + + void setEnabled(bool enabled); + bool enabled() const; + + TQ_INT32 numAxes() const; + + void setXAxis(TQ_INT32 axis); + void setYAxis(TQ_INT32 axis); + void setPressureAxis(TQ_INT32 axis); + void setXTiltAxis(TQ_INT32 axis); + void setYTiltAxis(TQ_INT32 axis); + void setWheelAxis(TQ_INT32 axis); + void setToolIDAxis(TQ_INT32 axis); + void setSerialNumberAxis(TQ_INT32 axis); + + TQ_INT32 xAxis() const; + TQ_INT32 yAxis() const; + TQ_INT32 pressureAxis() const; + TQ_INT32 xTiltAxis() const; + TQ_INT32 yTiltAxis() const; + TQ_INT32 wheelAxis() const; + TQ_INT32 toolIDAxis() const; + TQ_INT32 serialNumberAxis() const; + + private: + KisCanvasWidget::X11TabletDevice *m_tabletDevice; + + bool m_enabled; + TQ_INT32 m_xAxis; + TQ_INT32 m_yAxis; + TQ_INT32 m_pressureAxis; + TQ_INT32 m_xTiltAxis; + TQ_INT32 m_yTiltAxis; + TQ_INT32 m_wheelAxis; + TQ_INT32 m_toolIDAxis; + TQ_INT32 m_serialNumberAxis; + }; + + class TabletDeviceSettingsDialog : public KDialogBase { + typedef KDialogBase super; + + public: + TabletDeviceSettingsDialog(const TQString& deviceName, + DeviceSettings settings, + TQWidget *tqparent = 0, + const char *name = 0); + virtual ~TabletDeviceSettingsDialog(); + + DeviceSettings settings(); + + private: + WdgTabletDeviceSettings *m_page; + DeviceSettings m_settings; + }; + + void initTabletDevices(); + + TQValueVector m_deviceSettings; +#endif +}; + +//======================= + + +/** + * Display settings tab for preferences dialog + */ +class DisplaySettingsTab : public WdgDisplaySettings +{ +Q_OBJECT + TQ_OBJECT + +public: + DisplaySettingsTab( TQWidget *tqparent = 0, const char *name = 0 ); + +public: + void setDefault(); +protected slots: + void slotUseOpenGLToggled(bool isChecked); +}; + +//======================= + + +/** + * Grid settings tab for preferences dialog + */ +class GridSettingsTab : public WdgGridSettingsBase { + Q_OBJECT + TQ_OBJECT + public: + GridSettingsTab(TQWidget* tqparent); + public: + void setDefault(); + private slots: + void linkSpacingToggled(bool); + void spinBoxHSpacingChanged(int ); + void spinBoxVSpacingChanged(int ); + private: + bool m_linkSpacing; +}; + +//======================= + + +/** + * Preferences dialog of KImageShop^WKrayon^WChalk + */ +class PreferencesDialog : public KDialogBase +{ + Q_OBJECT + TQ_OBJECT + +public: + + static bool editPreferences(); + + +protected: + + PreferencesDialog( TQWidget *tqparent = 0, const char *name = 0 ); + ~PreferencesDialog(); + +protected: + + GeneralTab* m_general; + ColorSettingsTab* m_colorSettings; + PerformanceTab* m_performanceSettings; + TabletSettingsTab * m_tabletSettings; + DisplaySettingsTab * m_displaySettings; + GridSettingsTab* m_gridSettings; + +protected slots: + + void slotDefault(); + +}; + +#endif diff --git a/chalk/ui/kis_doc.cc b/chalk/ui/kis_doc.cc new file mode 100644 index 00000000..e60e6524 --- /dev/null +++ b/chalk/ui/kis_doc.cc @@ -0,0 +1,1171 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2000 John Califf + * Copyright (c) 2001 Toshitaka Fujioka + * Copyright (c) 2002, 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// TQt +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KOffice +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include +#include +#include "kis_annotation.h" +#include "kis_types.h" +#include "kis_config.h" +#include "kis_debug_areas.h" +#include "kis_doc.h" +#include "kis_factory.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_nameserver.h" +#include "kis_painter.h" +#include "kis_selection.h" +#include "kis_fill_painter.h" +#include "kis_command.h" +#include "kis_view.h" +#include "kis_colorspace.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_profile.h" +#include "kis_id.h" +#include "kis_part_layer.h" +#include "kis_doc_iface.h" +#include "kis_paint_device_action.h" +#include "kis_custom_image_widget.h" +#include "kis_load_visitor.h" +#include "kis_save_visitor.h" +#include "kis_savexml_visitor.h" + +static const char *CURRENT_DTD_VERSION = "1.3"; + +/** + * Mime type for this app - not same as file type, but file types + * can be associated with a mime type and are opened with applications + * associated with the same mime type + */ +#define APP_MIMETYPE "application/x-chalk" + +/** + * Mime type for native file format + */ +#define NATIVE_MIMETYPE "application/x-kra" + +namespace { + class KisCommandImageMv : public KisCommand { + typedef KisCommand super; + + public: + KisCommandImageMv(KisDoc *doc, + KisUndoAdapter *adapter, + const TQString& name, + const TQString& oldName) : super(i18n("Rename Image"), adapter) + { + m_doc = doc; + m_name = name; + m_oldName = oldName; + } + + virtual ~KisCommandImageMv() + { + } + + virtual void execute() + { + adapter()->setUndo(false); + m_doc->renameImage(m_oldName, m_name); + adapter()->setUndo(true); + } + + virtual void unexecute() + { + adapter()->setUndo(false); + m_doc->renameImage(m_name, m_oldName); + adapter()->setUndo(true); + } + + private: + KisDoc *m_doc; + TQString m_name; + TQString m_oldName; + }; + +} + +KisDoc::KisDoc(TQWidget *tqparentWidget, const char *widgetName, TQObject *tqparent, const char *name, bool singleViewMode) : + super(tqparentWidget, widgetName, tqparent, name, singleViewMode) +{ + + m_undo = false; + m_dcop = 0; + m_cmdHistory = 0; + m_nserver = 0; + m_currentImage = 0; + m_currentMacro = 0; + m_macroNestDepth = 0; + m_ioProgressBase = 0; + m_ioProgressTotalSteps = 0; + + setInstance( KisFactory::instance(), false ); + setTemplateType( "chalk_template" ); + + init(); + + if (name) + dcopObject(); +} + +KisDoc::~KisDoc() +{ + delete m_cmdHistory; + delete m_nserver; + m_undoListeners.setAutoDelete(false); + delete m_dcop; +} + +TQCString KisDoc::mimeType() const +{ + return APP_MIMETYPE; +} + +DCOPObject *KisDoc::dcopObject() +{ + if (!m_dcop) { + m_dcop = new KisDocIface(this); + Q_CHECK_PTR(m_dcop); + } + return m_dcop; +} + +bool KisDoc::initDoc(InitDocFlags flags, TQWidget* tqparentWidget) +{ + if (!init()) + return false; + + bool ok = false; + + TQString file; + KoTemplateChooseDia::DialogType dlgtype; + + if (flags != KoDocument::InitDocFileNew) { + dlgtype = KoTemplateChooseDia::Everything; + } else { + dlgtype = KoTemplateChooseDia::OnlyTemplates; + } + + KoTemplateChooseDia::ReturnType ret = + KoTemplateChooseDia::choose(KisFactory::instance(), + file, + dlgtype, + "chalk_template", + tqparentWidget); + setUndo(false); + + if (ret == KoTemplateChooseDia::Template) { + resetURL(); + ok = loadNativeFormat( file ); + setEmpty(); + ok = true; + + } else if (ret == KoTemplateChooseDia::File) { + KURL url( file ); + ok = openURL(url); + } else if (ret == KoTemplateChooseDia::Empty) { + setEmpty(); + ok = true; + } + + setModified(false); + KisConfig cfg; + setUndo(cfg.undoEnabled()); + + return ok; +} + +void KisDoc::openExistingFile(const TQString& file) +{ + setUndo(false); + + KoDocument::openExistingFile(file); + + setUndo(true); +} + +void KisDoc::openTemplate(const TQString& file) +{ + setUndo(false); + + KoDocument::openTemplate(file); + + setUndo(true); +} + +bool KisDoc::init() +{ + if (m_cmdHistory) { + delete m_cmdHistory; + m_cmdHistory = 0; + } + + if (m_nserver) { + delete m_nserver; + m_nserver = 0; + } + + m_cmdHistory = new KoCommandHistory(actionCollection(), true); + Q_CHECK_PTR(m_cmdHistory); + + connect(m_cmdHistory, TQT_SIGNAL(documentRestored()), this, TQT_SLOT(slotDocumentRestored())); + connect(m_cmdHistory, TQT_SIGNAL(commandExecuted(KCommand *)), this, TQT_SLOT(slotCommandExecuted(KCommand *))); + setUndo(true); + + m_nserver = new KisNameServer(i18n("Image %1"), 1); + Q_CHECK_PTR(m_nserver); + + if (!KisMetaRegistry::instance()->csRegistry()->exists(KisID("RGBA",""))) { + KMessageBox::sorry(0, i18n("No colorspace modules loaded: cannot run Chalk")); + return false; + } + + m_undoListeners.setAutoDelete(false); + + return true; +} + +TQDomDocument KisDoc::saveXML() +{ + TQDomDocument doc = createDomDocument("DOC", CURRENT_DTD_VERSION); + TQDomElement root = doc.documentElement(); + + root.setAttribute("editor", "Chalk"); + root.setAttribute("depth", sizeof(TQ_UINT8)); + root.setAttribute("syntaxVersion", "1"); + + root.appendChild(saveImage(doc, m_currentImage)); + + return doc; +} + +bool KisDoc::loadOasis( const TQDomDocument&, KoOasisStyles&, const TQDomDocument&, KoStore* ) +{ + //XXX: todo (and that includes defining an OASIS format for layered 2D raster data!) + return false; +} + + +bool KisDoc::saveOasis( KoStore*, KoXmlWriter* ) +{ + //XXX: todo (and that includes defining an OASIS format for layered 2D raster data!) + return false; +} + +bool KisDoc::loadXML(TQIODevice *, const TQDomDocument& doc) +{ + TQDomElement root; + TQString attr; + TQDomNode node; + KisImageSP img; + + if (!init()) + return false; + if (doc.doctype().name() != "DOC") + return false; + root = doc.documentElement(); + attr = root.attribute("syntaxVersion"); + if (attr.toInt() > 1) + return false; + if ((attr = root.attribute("depth")).isNull()) + return false; + m_conversionDepth = attr.toInt(); + + if (!root.hasChildNodes()) { + return false; // XXX used to be: return slotNewImage(); + } + + setUndo(false); + + for (node = root.firstChild(); !node.isNull(); node = node.nextSibling()) { + if (node.isElement()) { + if (node.nodeName() == "IMAGE") { + TQDomElement elem = node.toElement(); + if (!(img = loadImage(elem))) + return false; + m_currentImage = img; + } else { + return false; + } + } + } + + emit loadingFinished(); + return true; +} + +bool KisDoc::loadChildren(KoStore* store) { + TQPtrListIterator it(tqchildren()); + for( ; it.current(); ++it ) { + if (!it.current()->loadDocument(store)) { + return false; + } + } + return true; +} + +TQDomElement KisDoc::saveImage(TQDomDocument& doc, KisImageSP img) +{ + TQDomElement image = doc.createElement("IMAGE"); + + Q_ASSERT(img); + image.setAttribute("name", img->name()); + image.setAttribute("mime", "application/x-kra"); + image.setAttribute("width", img->width()); + image.setAttribute("height", img->height()); + image.setAttribute("colorspacename", img->colorSpace()->id().id()); + image.setAttribute("description", img->description()); + // XXX: Save profile as blob inside the image, instead of the product name. + if (img->getProfile() && img->getProfile()-> valid()) + image.setAttribute("profile", img->getProfile()->productName()); + image.setAttribute("x-res", img->xRes()); + image.setAttribute("y-res", img->yRes()); + + TQ_UINT32 count=0; + KisSaveXmlVisitor visitor(doc, image, count, true); + + m_currentImage->rootLayer()->accept(visitor); + + return image; +} + +KisImageSP KisDoc::loadImage(const TQDomElement& element) +{ + + KisConfig cfg; + TQString attr; + TQDomNode node; + TQDomNode child; + KisImageSP img; + TQString name; + TQ_INT32 width; + TQ_INT32 height; + TQString description; + TQString profileProductName; + double xres; + double yres; + TQString colorspacename; + KisColorSpace * cs; + + if ((attr = element.attribute("mime")) == NATIVE_MIMETYPE) { + if ((name = element.attribute("name")).isNull()) + return 0; + if ((attr = element.attribute("width")).isNull()) + return 0; + width = attr.toInt(); + if ((attr = element.attribute("height")).isNull()) + return 0; + height = attr.toInt(); + + description = element.attribute("description"); + + if ((attr = element.attribute("x-res")).isNull()) + xres = 100.0; + xres = attr.toDouble(); + + if ((attr = element.attribute("y-res")).isNull()) + yres = 100.0; + yres = attr.toDouble(); + + if ((colorspacename = element.attribute("colorspacename")).isNull()) + { + // An old file: take a reasonable default. + // Chalk didn't support anything else in those + // days anyway. + colorspacename = "RGBA"; + } + + // A hack for an old colorspacename + if (colorspacename == "Grayscale + Alpha") + colorspacename = "GRAYA"; + + if ((profileProductName = element.attribute("profile")).isNull()) { + // no mention of profile so get default profile + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,""); + } + else { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename, profileProductName); + } + + if (cs == 0) { + kdWarning(DBG_AREA_FILE) << "Could not open colorspace\n"; + return 0; + } + + img = new KisImage(this, width, height, cs, name); + img->blockSignals(true); // Don't send out signals while we're building the image + Q_CHECK_PTR(img); + connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() )); + img->setDescription(description); + img->setResolution(xres, yres); + + loadLayers(element, img, img->rootLayer().data()); + + } + + img->notifyImageLoaded(); + + return img; +} + +void KisDoc::loadLayers(const TQDomElement& element, KisImageSP img, KisGroupLayerSP tqparent) +{ + TQDomNode node = element.firstChild(); + TQDomNode child; + + if(!node.isNull()) + { + if (node.isElement()) { + if (node.nodeName() == "LAYERS") { + for (child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { + KisLayerSP layer = loadLayer(child.toElement(), img); + + if (!layer) { + kdWarning(DBG_AREA_FILE) << "Could not load layer\n"; + } + else { + img->nextLayerName(); // Make sure the nameserver is current with the number of layers. + img->addLayer(layer, tqparent, 0); + } + } + } + } + } +} + +KisLayerSP KisDoc::loadLayer(const TQDomElement& element, KisImageSP img) +{ + // Nota bene: If you add new properties to layers, you should + // ALWAYS define a default value in case the property is not + // present in the layer definition: this helps a LOT with backward + // compatibilty. + TQString attr; + TQString name; + TQ_INT32 x; + TQ_INT32 y; + TQ_INT32 opacity; + bool visible; + bool locked; + + if ((name = element.attribute("name")).isNull()) + return 0; + + if ((attr = element.attribute("x")).isNull()) + return 0; + x = attr.toInt(); + + if ((attr = element.attribute("y")).isNull()) + return 0; + + y = attr.toInt(); + + if ((attr = element.attribute("opacity")).isNull()) + return 0; + + if ((opacity = attr.toInt()) < 0 || opacity > TQ_UINT8_MAX) + opacity = OPACITY_OPAQUE; + + + TQString compositeOpName = element.attribute("compositeop"); + KisCompositeOp compositeOp; + + if (compositeOpName.isNull()) { + compositeOp = COMPOSITE_OVER; + } else { + compositeOp = KisCompositeOp(compositeOpName); + } + + if (!compositeOp.isValid()) { + return 0; + } + + if ((attr = element.attribute("visible")).isNull()) + attr = "1"; + + visible = attr == "0" ? false : true; + + if ((attr = element.attribute("locked")).isNull()) + attr = "0"; + + locked = attr == "0" ? false : true; + + // Now find out the layer type and do specific handling + if ((attr = element.attribute("layertype")).isNull()) + return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp) ; + + if(attr == "paintlayer") + return loadPaintLayer(element, img, name, x, y, opacity, visible, locked, compositeOp); + + if(attr == "grouplayer") + return loadGroupLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data(); + + if(attr == "adjustmentlayer") + return loadAdjustmentLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data(); + + if(attr == "partlayer") + return loadPartLayer(element, img, name, x, y, opacity, visible, locked, compositeOp).data(); + + kdWarning(DBG_AREA_FILE) << "Specified layertype is not recognised\n"; + return 0; +} + + +KisLayerSP KisDoc::loadPaintLayer(const TQDomElement& element, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, + TQ_INT32 opacity, bool visible, bool locked, KisCompositeOp compositeOp) +{ + TQString attr; + KisPaintLayerSP layer; + KisColorSpace * cs; + + TQString colorspacename; + TQString profileProductName; + + if ((colorspacename = element.attribute("colorspacename")).isNull()) + cs = img->colorSpace(); + else + // use default profile - it will be replaced later in completLoading + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(colorspacename,""); + + layer = new KisPaintLayer(img, name, opacity, cs); + Q_CHECK_PTR(layer); + + layer->setCompositeOp(compositeOp); + layer->setVisible(visible); + layer->setLocked(locked); + layer->setX(x); + layer->setY(y); + + if ((element.attribute("filename")).isNull()) + m_layerFilenames[layer.data()] = name; + else + m_layerFilenames[layer.data()] = TQString(element.attribute("filename")); + + if ((attr = element.attribute("hastqmask")).isNull()) + attr = "0"; + + if (attr == "1") { + // We add a tqmask, but we'll fill in the actual tqmask later in completeLoading with the visitor + layer->createMask(); + } + + + // Load exif info + for( TQDomNode node = element.firstChild(); !node.isNull(); node = node.nextSibling() ) + { + TQDomElement e = node.toElement(); + if ( !e.isNull() && e.tagName() == "ExifInfo" ) + { + layer->paintDevice()->exifInfo()->load(e); + } + } + return layer.data(); +} + +KisGroupLayerSP KisDoc::loadGroupLayer(const TQDomElement& element, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp) +{ + TQString attr; + KisGroupLayerSP layer; + + layer = new KisGroupLayer(img, name, opacity); + Q_CHECK_PTR(layer); + + layer->setCompositeOp(compositeOp); + layer->setVisible(visible); + layer->setLocked(locked); + layer->setX(x); + layer->setY(y); + + loadLayers(element, img, layer); + + return layer; +} + +KisAdjustmentLayerSP KisDoc::loadAdjustmentLayer(const TQDomElement& element, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp) +{ + TQString attr; + KisAdjustmentLayerSP layer; + TQString filtername; + + if ((filtername = element.attribute("filtername")).isNull()) { + // XXX: Invalid adjustmentlayer! We should warn about it! + kdWarning(DBG_AREA_FILE) << "No filter in adjustment layer" << endl; + return 0; + } + + KisFilter * f = KisFilterRegistry::instance()->get(filtername); + if (!f) { + kdWarning(DBG_AREA_FILE) << "No filter for filtername " << filtername << "\n"; + return 0; // XXX: We don't have this filter. We should warn about it! + } + + KisFilterConfiguration * kfc = f->configuration(); + + // We'll load the configuration and the selection later. + layer = new KisAdjustmentLayer(img, name, kfc, 0); + Q_CHECK_PTR(layer); + + layer->setCompositeOp(compositeOp); + layer->setVisible(visible); + layer->setLocked(locked); + layer->setX(x); + layer->setY(y); + layer->setOpacity(opacity); + + if ((element.attribute("filename")).isNull()) + m_layerFilenames[layer.data()] = name; + else + m_layerFilenames[layer.data()] = TQString(element.attribute("filename")); + + return layer; +} + +KisPartLayerSP KisDoc::loadPartLayer(const TQDomElement& element, KisImageSP img, + TQString name, TQ_INT32 /*x*/, TQ_INT32 /*y*/, TQ_INT32 opacity, + bool visible, bool locked, + KisCompositeOp compositeOp) { + KisChildDoc* child = new KisChildDoc(this); + TQString filename(element.attribute("filename")); + TQDomElement partElement = element.namedItem("object").toElement(); + + if (partElement.isNull()) { + kdWarning() << "loadPartLayer failed with partElement isNull" << endl; + return 0; + } + + child->load(partElement); + insertChild(child); + + KisPartLayerSP layer = new KisPartLayerImpl(img, child); + Q_CHECK_PTR(layer); + + layer->setCompositeOp(compositeOp); + layer->setVisible(visible); + layer->setLocked(locked); + layer->setOpacity(opacity); + layer->setName(name); + + return layer; +} + +bool KisDoc::completeSaving(KoStore *store) +{ + TQString uri = url().url(); + TQString location; + bool external = isStoredExtern(); + TQ_INT32 totalSteps = 0; + + if (!m_currentImage) return false; + + totalSteps = (m_currentImage)->nlayers(); + + + setIOSteps(totalSteps + 1); + + // Save the layers data + TQ_UINT32 count=0; + KisSaveVisitor visitor(m_currentImage, store, count); + + if(external) + visitor.setExternalUri(uri); + + m_currentImage->rootLayer()->accept(visitor); + + // saving annotations + // XXX this only saves EXIF and ICC info. This would probably need + // a redesign of the dtd of the chalk file to do this more generally correct + // e.g. have tags or so. + KisAnnotationSP annotation = (m_currentImage)->annotation("exif"); + if (annotation) { + location = external ? TQString() : uri; + location += (m_currentImage)->name() + "/annotations/exif"; + if (store->open(location)) { + store->write(annotation->annotation()); + store->close(); + } + } + if (m_currentImage->getProfile()) { + annotation = m_currentImage->getProfile()->annotation(); + + if (annotation) { + location = external ? TQString() : uri; + location += m_currentImage->name() + "/annotations/icc"; + if (store->open(location)) { + store->write(annotation->annotation()); + store->close(); + } + } + } + + IODone(); + return true; +} + +bool KisDoc::completeLoading(KoStore *store) +{ + TQString uri = url().url(); + TQString location; + bool external = isStoredExtern(); + TQ_INT32 totalSteps = 0; + + totalSteps = (m_currentImage)->nlayers(); + + setIOSteps(totalSteps); + + // Load the layers data + KisLoadVisitor visitor(m_currentImage, store, m_layerFilenames); + + if(external) + visitor.setExternalUri(uri); + + m_currentImage->rootLayer()->accept(visitor); + + // annotations + // exif + location = external ? TQString() : uri; + location += (m_currentImage)->name() + "/annotations/exif"; + if (store->hasFile(location)) { + TQByteArray data; + store->open(location); + data = store->read(store->size()); + store->close(); + (m_currentImage)->addAnnotation(new KisAnnotation("exif", "", data)); + } + // icc profile + location = external ? TQString() : uri; + location += (m_currentImage)->name() + "/annotations/icc"; + if (store->hasFile(location)) { + TQByteArray data; + store->open(location); + data = store->read(store->size()); + store->close(); + (m_currentImage)->setProfile(new KisProfile(data)); + } + + IODone(); + + setModified( false ); + setUndo(true); + return true; +} + +TQWidget* KisDoc::createCustomDocumentWidget(TQWidget *tqparent) +{ + + KisConfig cfg; + + int w = cfg.defImgWidth(); + int h = cfg.defImgHeight(); + + TQSize sz = KisClipboard::instance()->clipSize(); + if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { + w = sz.width(); + h = sz.height(); + } + return new KisCustomImageWidget(tqparent, this, w, h, cfg.defImgResolution(), cfg.workingColorSpace(),"unnamed"); +} + + +KoDocument* KisDoc::hitTest(const TQPoint &pos, const TQWMatrix& matrix) { + KoDocument* doc = super::hitTest(pos, matrix); + if (doc && doc != this) { + // We hit a child document. We will only acknowledge we hit it, if the hit child + // is the currently active parts layer. + KisPartLayerImpl* partLayer + = dynamic_cast(currentImage()->activeLayer().data()); + + if (!partLayer) + return this; + + if (doc == partLayer->childDoc()->document()) { + return doc; + } + return this; + } + return doc; +} + +void KisDoc::renameImage(const TQString& oldName, const TQString& newName) +{ + (m_currentImage)->setName(newName); + + if (undo()) + addCommand(new KisCommandImageMv(this, this, newName, oldName)); +} + + +KisImageSP KisDoc::newImage(const TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorstrategy) +{ + if (!init()) + return 0; + + setUndo(false); + + KisImageSP img = new KisImage(this, width, height, colorstrategy, name); + Q_CHECK_PTR(img); + connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() )); + + KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE,colorstrategy); + Q_CHECK_PTR(layer); + + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + KisFillPainter painter; + + painter.begin(layer->paintDevice()); + painter.fillRect(0, 0, width, height, KisColor(TQt::white, cs), OPACITY_OPAQUE); + painter.end(); + + img->addLayer(layer, img->rootLayer(), 0); + img->activate(layer); + + m_currentImage = img; + + setUndo(true); + + return img; +} + +bool KisDoc::newImage(const TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const TQString &imgDescription, const double imgResolution) +{ + if (!init()) + return false; + + KisConfig cfg; + + TQ_UINT8 opacity = OPACITY_OPAQUE;//bgColor.getAlpha(); + KisImageSP img; + KisPaintLayer *layer; + + if (!cs) return false; + + setUndo(false); + + img = new KisImage(this, width, height, cs, name); + Q_CHECK_PTR(img); + connect( img, TQT_SIGNAL( sigImageModified() ), this, TQT_SLOT( slotImageUpdated() )); + img->setResolution(imgResolution, imgResolution); + img->setDescription(imgDescription); + img->setProfile(cs->getProfile()); + + layer = new KisPaintLayer(img, img->nextLayerName(), OPACITY_OPAQUE, cs); + Q_CHECK_PTR(layer); + + KisFillPainter painter; + painter.begin(layer->paintDevice()); + painter.fillRect(0, 0, width, height, bgColor, opacity); + painter.end(); + + TQValueVector actions = KisMetaRegistry::instance() -> + csRegistry()->paintDeviceActionsFor(cs); + for (uint i = 0; i < actions.count(); i++) + actions.at(i)->act(layer->paintDevice(), img->width(), img->height()); + + img->setBackgroundColor(bgColor); + img->addLayer(layer, img->rootLayer(), 0); + img->activate(layer); + + m_currentImage = img; + + cfg.defImgWidth(width); + cfg.defImgHeight(height); + cfg.defImgResolution(imgResolution); + + setUndo(true); + + return true; +} + +KoView* KisDoc::createViewInstance(TQWidget* tqparent, const char *name) +{ + KisView * v = new KisView(this, this, tqparent, name); + Q_CHECK_PTR(v); + + return v; +} + +void KisDoc::paintContent(TQPainter& painter, const TQRect& rc, bool transparent, double zoomX, double zoomY) +{ + KisConfig cfg; + TQString monitorProfileName = cfg.monitorProfile(); + KisProfile * profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + painter.scale(zoomX, zoomY); + TQRect rect = rc & m_currentImage->bounds(); + KisImage::PaintFlags paintFlags; + if (transparent) { + paintFlags = KisImage::PAINT_SELECTION; + } else { + paintFlags = (KisImage::PaintFlags)(KisImage::PAINT_BACKGROUND|KisImage::PAINT_SELECTION); + } + + paintFlags = (KisImage::PaintFlags)(paintFlags | KisImage::PAINT_EMBEDDED_RECT); + + m_currentImage->renderToPainter(rect.left(), rect.top(), rect.right(), rect.bottom(), painter, profile, paintFlags); +} + +void KisDoc::slotImageUpdated() +{ + emit docUpdated(); + setModified(true); +} + +void KisDoc::slotImageUpdated(const TQRect& rect) +{ + emit docUpdated(rect); +} + +void KisDoc::beginMacro(const TQString& macroName) +{ + if (m_undo) { + if (m_macroNestDepth == 0) { + Q_ASSERT(m_currentMacro == 0); + m_currentMacro = new KMacroCommand(macroName); + Q_CHECK_PTR(m_currentMacro); + } + + m_macroNestDepth++; + } +} + +void KisDoc::endMacro() +{ + if (m_undo) { + Q_ASSERT(m_macroNestDepth > 0); + if (m_macroNestDepth > 0) { + m_macroNestDepth--; + + if (m_macroNestDepth == 0) { + Q_ASSERT(m_currentMacro != 0); + + m_cmdHistory->addCommand(m_currentMacro, false); + m_currentMacro = 0; + emit sigCommandExecuted(); + } + } + } +} + +void KisDoc::setCommandHistoryListener(const KisCommandHistoryListener * l) +{ + // Never have more than one instance of a listener around. TQt should prove a Set class for this... + m_undoListeners.removeRef(l); + m_undoListeners.append(l); +} + +void KisDoc::removeCommandHistoryListener(const KisCommandHistoryListener * l) +{ + m_undoListeners.removeRef(l); +} + +KCommand * KisDoc::presentCommand() +{ + return m_cmdHistory->presentCommand(); +} + +void KisDoc::addCommand(KCommand *cmd) +{ + Q_ASSERT(cmd); + + KisCommandHistoryListener* l = 0; + + for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) { + l->notifyCommandAdded(cmd); + } + + setModified(true); + + if (m_undo) { + if (m_currentMacro) + m_currentMacro->addCommand(cmd); + else { + m_cmdHistory->addCommand(cmd, false); + emit sigCommandExecuted(); + } + } else { + kdDebug() << "Deleting command\n"; + delete cmd; + } +} + +void KisDoc::setUndo(bool undo) +{ + m_undo = undo; + if (m_undo && m_cmdHistory->undoLimit() == 50 /*default*/) { + KisConfig cfg; + setUndoLimit( cfg.defUndoLimit() ); + } +} + +TQ_INT32 KisDoc::undoLimit() const +{ + return m_cmdHistory->undoLimit(); +} + +void KisDoc::setUndoLimit(TQ_INT32 limit) +{ + m_cmdHistory->setUndoLimit(limit); +} + +TQ_INT32 KisDoc::redoLimit() const +{ + return m_cmdHistory->redoLimit(); +} + +void KisDoc::setRedoLimit(TQ_INT32 limit) +{ + m_cmdHistory->setRedoLimit(limit); +} + +void KisDoc::slotDocumentRestored() +{ + setModified(false); +} + +void KisDoc::slotCommandExecuted(KCommand *command) +{ + setModified(true); + emit sigCommandExecuted(); + + KisCommandHistoryListener* l = 0; + + for (l = m_undoListeners.first(); l; l = m_undoListeners.next()) { + l->notifyCommandExecuted(command); + } + +} + +void KisDoc::slotUpdate(KisImageSP, TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 w, TQ_UINT32 h) +{ + TQRect rc(x, y, w, h); + + emit docUpdated(rc); +} + +bool KisDoc::undo() const +{ + return m_undo; +} + +void KisDoc::setIOSteps(TQ_INT32 nsteps) +{ + m_ioProgressTotalSteps = nsteps * 100; + m_ioProgressBase = 0; + emitProgress(0); +} + +void KisDoc::IOCompletedStep() +{ + m_ioProgressBase += 100; +} + +void KisDoc::IODone() +{ + emitProgress(-1); +} + +void KisDoc::slotIOProgress(TQ_INT8 percentage) +{ + KApplication *app = KApplication::kApplication(); + + Q_ASSERT(app); + + if (app->hasPendingEvents()) + app->processEvents(); + + int totalPercentage = ((m_ioProgressBase + percentage) * 100) / m_ioProgressTotalSteps; + + emitProgress(totalPercentage); +} + +KisChildDoc * KisDoc::createChildDoc( const TQRect & rect, KoDocument* childDoc ) +{ + KisChildDoc * ch = new KisChildDoc( this, rect, childDoc ); + insertChild( ch ); + ch->document()->setStoreInternal(true); + return ch; +} + +void KisDoc::prepareForImport() +{ + if (m_nserver == 0) + init(); + setUndo(false); +} + +KisImageSP KisDoc::currentImage() +{ + return m_currentImage; +} + +void KisDoc::setCurrentImage(KisImageSP image) +{ + m_currentImage = image; + setUndo(true); + image->notifyImageLoaded(); + emit loadingFinished(); +} + +void KisDoc::initEmpty() +{ + KisConfig cfg; + KisColorSpace * rgb = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + newImage("", cfg.defImgWidth(), cfg.defImgHeight(), rgb); +} + +#include "kis_doc.moc" + diff --git a/chalk/ui/kis_doc.h b/chalk/ui/kis_doc.h new file mode 100644 index 00000000..47eeaa0f --- /dev/null +++ b/chalk/ui/kis_doc.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 1999-2000 Matthias Elter + * Copyright (c) 2001 Toshitaka Fujioka + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DOC_H_ +#define KIS_DOC_H_ + +#include + +#include + +#include "kis_types.h" +#include "kis_undo_adapter.h" + +#include + +class TQImage; +class TQString; + +class DCOPObject; +class KCommand; + +class KoCommandHistory; +class KMacroCommand; + +class KisProfile; +class KisView; +class KisNameServer; +class KisChildDoc; +class KisColorSpace; +class KisColor; +class KisCompositeOp; + +class KRITACORE_EXPORT KisDoc : public KoDocument, private KisUndoAdapter { + + typedef KoDocument super; + Q_OBJECT + TQ_OBJECT + +public: + KisDoc(TQWidget *tqparentWidget = 0, const char *widgetName = 0, TQObject* tqparent = 0, const char* name = 0, bool singleViewMode = false); + virtual ~KisDoc(); + +public: + // Overide KoDocument + virtual bool wantExportConfirmation() const { return false; }; + virtual bool completeLoading(KoStore *store); + virtual bool completeSaving(KoStore*); + virtual DCOPObject* dcopObject(); + virtual bool initDoc(InitDocFlags flags, TQWidget* tqparentWidget=0); + virtual bool loadOasis( const TQDomDocument&, KoOasisStyles&, const TQDomDocument&, KoStore* ); + virtual bool saveOasis( KoStore*, KoXmlWriter* ); + virtual bool loadChildren( KoStore* store); + virtual bool loadXML(TQIODevice *, const TQDomDocument& doc); + virtual TQCString mimeType() const; + virtual TQWidget* createCustomDocumentWidget(TQWidget *tqparent); + virtual KoDocument* hitTest(const TQPoint &pos, const TQWMatrix& matrix = TQWMatrix()); + + /** + * Draw the image embedded in another KOffice document + * + * XXX: Use of transparent, zoomX and zoomY is not supported + * by Chalk because we appear to be doing our zooming + * elsewhere. This may affect KOffice compatibility. + */ + virtual void paintContent(TQPainter& painter, const TQRect& rect, bool /*transparent*/, double /*zoomX*/, double /*zoomY*/); + + virtual TQDomDocument saveXML(); + +public slots: + + + /** + * Initialize an empty document using default values + * @since 1.5 + */ + virtual void initEmpty(); + +private: // Undo adapter + + virtual void setCommandHistoryListener(const KisCommandHistoryListener *); + virtual void removeCommandHistoryListener(const KisCommandHistoryListener *); + + virtual KCommand * presentCommand(); + virtual void addCommand(KCommand *cmd); + virtual void setUndo(bool undo); + virtual bool undo() const; + virtual void beginMacro(const TQString& macroName); + virtual void endMacro(); + + +public: + + + TQ_INT32 undoLimit() const; + void setUndoLimit(TQ_INT32 limit); + + TQ_INT32 redoLimit() const; + void setRedoLimit(TQ_INT32 limit); + + /** + * Create a new image that has this document as a tqparent and + * replace the current image with this image. + */ + bool newImage(const TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * cs, const KisColor &bgColor, const TQString &imgDescription, const double imgResolution); + + /** + * Create a new image that has this document as a tqparent and + * replace the current image with this image. + */ + KisImageSP newImage(const TQString& name, TQ_INT32 width, TQ_INT32 height, KisColorSpace * colorstrategy); + + void renameImage(const TQString& oldName, const TQString& newName); + + + /** + * Adds the specified child document to this document; this + * is not done with KoDocument::insertChild() because that + * is protected and cannot be called from KisView. + */ + KisChildDoc * createChildDoc( const TQRect& rect, KoDocument* childDoc ); + + /** + * Makes an otherwise empty document ready for import/export + */ + void prepareForImport(); + + KisImageSP currentImage(); + + /** + * Set the current image to the specified image and turn undo on. + */ + void setCurrentImage(KisImageSP image); + + KisUndoAdapter * undoAdapter() { return this; } + +public slots: + void slotImageUpdated(); + void slotImageUpdated(const TQRect& rect); + void slotDocumentRestored(); + void slotCommandExecuted(KCommand *command); + +signals: + void docUpdated(); + void docUpdated(TQRect rect); + void loadingFinished(); + + /* + * Emitted every time a command is added to the undo history, or executed + * due to an undo or redo action. + */ + void sigCommandExecuted(); + +protected: + // Overide KoDocument + virtual KoView* createViewInstance(TQWidget *tqparent, const char *name); + +protected slots: + // Overide KoDocument + virtual void openExistingFile(const TQString& file); + virtual void openTemplate(const TQString& file); + +private slots: + void slotUpdate(KisImageSP img, TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 w, TQ_UINT32 h); + void slotIOProgress(TQ_INT8 percentage); + +private: + + TQDomElement saveImage(TQDomDocument& doc, KisImageSP img); + KisImageSP loadImage(const TQDomElement& elem); + void loadLayers(const TQDomElement& element, KisImageSP img, KisGroupLayerSP tqparent); + KisLayerSP loadLayer(const TQDomElement& elem, KisImageSP img); + KisLayerSP loadPaintLayer(const TQDomElement& elem, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisGroupLayerSP loadGroupLayer(const TQDomElement& elem, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisAdjustmentLayerSP loadAdjustmentLayer(const TQDomElement& elem, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, bool visible, bool locked, + KisCompositeOp compositeOp); + KisPartLayerSP loadPartLayer(const TQDomElement& elem, KisImageSP img, + TQString name, TQ_INT32 x, TQ_INT32 y, TQ_INT32 opacity, + bool visible, bool locked, KisCompositeOp compositeOp); + bool init(); + + void setIOSteps(TQ_INT32 nsteps); + void IOCompletedStep(); + void IODone(); + +private: + + bool m_undo; + KoCommandHistory *m_cmdHistory; + TQPtrList m_undoListeners; + KisImageSP m_currentImage; + DCOPObject *m_dcop; + KisNameServer *m_nserver; + KMacroCommand *m_currentMacro; + TQ_INT32 m_macroNestDepth; + TQ_INT32 m_conversionDepth; + int m_ioProgressTotalSteps; + int m_ioProgressBase; + TQMap m_layerFilenames; // temp storage during load + +}; + +#endif // KIS_DOC_H_ + diff --git a/chalk/ui/kis_doc_iface.cc b/chalk/ui/kis_doc_iface.cc new file mode 100644 index 00000000..50af9898 --- /dev/null +++ b/chalk/ui/kis_doc_iface.cc @@ -0,0 +1,67 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_doc_iface.h" +#include + +#include "kis_doc.h" +#include "kis_image.h" + +#include + +KisDocIface::KisDocIface( KisDoc *doc_ ) + : KoDocumentIface( doc_ ) +{ + m_doc = doc_; +} + +DCOPRef KisDocIface::currentImage() +{ + KisImage *img = m_doc->currentImage(); + if( !img ) + return DCOPRef(); + else + return DCOPRef( kapp->dcopClient()->appId(), + img->dcopObject()->objId(), + "KisImageIface"); +} + +int KisDocIface::undoLimit () const +{ + return m_doc->undoLimit(); +} + +void KisDocIface::setUndoLimit(int limit) +{ + m_doc->setUndoLimit(limit); +} + +int KisDocIface::redoLimit() const +{ + return m_doc->redoLimit(); +} + +void KisDocIface::setRedoLimit(int limit) +{ + m_doc->setRedoLimit(limit); +} + +void KisDocIface::renameImage(const TQString& oldName, const TQString& newName) +{ + m_doc->renameImage(oldName,newName); +} diff --git a/chalk/ui/kis_doc_iface.h b/chalk/ui/kis_doc_iface.h new file mode 100644 index 00000000..36c71a5f --- /dev/null +++ b/chalk/ui/kis_doc_iface.h @@ -0,0 +1,50 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_DOC_IFACE_H +#define KIS_DOC_IFACE_H + +#include +#include + +#include +#include +#include + +class KisDoc; + +class KisDocIface : virtual public KoDocumentIface +{ + K_DCOP +public: + KisDocIface( KisDoc *doc_ ); +k_dcop: + virtual DCOPRef currentImage(); + + virtual int undoLimit () const; + virtual void setUndoLimit(int limit); + virtual int redoLimit() const; + virtual void setRedoLimit(int limit); + + virtual void renameImage(const TQString& oldName, const TQString& newName); + +private: + KisDoc *m_doc; +}; + +#endif diff --git a/chalk/ui/kis_double_click_event.h b/chalk/ui/kis_double_click_event.h new file mode 100644 index 00000000..c3447602 --- /dev/null +++ b/chalk/ui/kis_double_click_event.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_DOUBLE_CLICK_EVENT_H_ +#define KIS_DOUBLE_CLICK_EVENT_H_ + +#include "kis_button_event.h" + +class KisDoubleClickEvent : public KisButtonEvent { + typedef KisButtonEvent super; +public: + KisDoubleClickEvent() {} + KisDoubleClickEvent(KisInputDevice device, const KisPoint& pos, const KisPoint& globalPos, double pressure, double xTilt, double yTilt, TQt::ButtonState button, TQt::ButtonState state) : super(DoubleClickEvent, device, pos, globalPos, pressure, xTilt, yTilt, button, state) {} +}; + +#endif // KIS_DOUBLE_CLICK_EVENT_H_ + diff --git a/chalk/ui/kis_double_widget.cc b/chalk/ui/kis_double_widget.cc new file mode 100644 index 00000000..3c13a47e --- /dev/null +++ b/chalk/ui/kis_double_widget.cc @@ -0,0 +1,147 @@ +/* + * kis_double_widget.cc - part of Chalk + * + * Copyright (c) 1999 Carsten Pfeiffer + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include + +#include "kis_double_widget.h" + +KisDoubleWidget::KisDoubleWidget(TQWidget* tqparent, const char* name) + : super(tqparent, name) +{ + init(0, 1); +} + +KisDoubleWidget::KisDoubleWidget(double min, double max, TQWidget* tqparent, const char* name) + : super(tqparent, name) +{ + init(min, max); +} + +KisDoubleWidget::~KisDoubleWidget() +{ +} + +void KisDoubleWidget::init(double min, double max) +{ + m_spinBox = new KDoubleSpinBox(min, max, 0.05, 0, 2, this, "spinbox"); + connect(m_spinBox, TQT_SIGNAL(valueChanged(double)), this, TQT_SLOT(setSliderValue(double))); + + m_slider = new TQSlider(static_cast(min * 100 + 0.5), static_cast(max * 100 + 0.5), 1, 0, Qt::Horizontal, this, "sld"); + connect(m_slider, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(sliderValueChanged(int))); + connect(m_slider, TQT_SIGNAL(sliderPressed()), TQT_SIGNAL(sliderPressed())); + connect(m_slider, TQT_SIGNAL(sliderReleased()), TQT_SIGNAL(sliderReleased())); + + m_layout = new TQHBoxLayout(this, 0, -1, "hbox tqlayout"); + + m_layout->addWidget(m_slider); + m_layout->addSpacing(5); + m_layout->addWidget(m_spinBox); + m_layout->addItem(new TQSpacerItem(5,1,TQSizePolicy::Expanding, TQSizePolicy::Minimum)); +} + +double KisDoubleWidget::value() const +{ + return m_spinBox->value(); +} + +void KisDoubleWidget::setValue(double value) +{ + int intValue; + + if (value < 0) { + intValue = static_cast(value * 100 - 0.5); + } else { + intValue = static_cast(value * 100 + 0.5); + } + m_slider->setValue(intValue); +} + +void KisDoubleWidget::setRange(double min, double max) +{ + m_spinBox->setRange(min, max); + m_slider->setRange(static_cast(min * 100 + 0.5), static_cast(max * 100 + 0.5)); +} + +void KisDoubleWidget::setTickmarks(TQSlider::TickSetting tickSetting) +{ + m_slider->setTickmarks(tickSetting); +} + +void KisDoubleWidget::setTickInterval(double value) +{ + m_slider->setTickInterval(static_cast(value * 100 + 0.5)); +} + +double KisDoubleWidget::tickInterval() const +{ + return m_slider->tickInterval() / 100.0; +} + +void KisDoubleWidget::setSliderValue(double value) +{ + int intValue; + + if (value < 0) { + intValue = static_cast(value * 100 - 0.5); + } else { + intValue = static_cast(value * 100 + 0.5); + } + m_slider->setValue(intValue); + emit valueChanged(value); +} + +void KisDoubleWidget::sliderValueChanged(int value) +{ + m_spinBox->setValue(value / 100.0); +} + +void KisDoubleWidget::setPrecision(int precision) +{ + m_spinBox->setPrecision(precision); +} + +void KisDoubleWidget::setLineStep(double step) +{ + m_spinBox->setLineStep(step); + m_slider->setLineStep(static_cast(step * 100)); +} + +void KisDoubleWidget::setPageStep(double step) +{ + m_slider->setPageStep(static_cast(step * 100)); +} + +void KisDoubleWidget::setTracking(bool tracking) +{ + m_slider->setTracking(tracking); +} + +bool KisDoubleWidget::tracking() const +{ + return m_slider->tracking(); +} + +#include "kis_double_widget.moc" + diff --git a/chalk/ui/kis_double_widget.h b/chalk/ui/kis_double_widget.h new file mode 100644 index 00000000..89a425b7 --- /dev/null +++ b/chalk/ui/kis_double_widget.h @@ -0,0 +1,78 @@ +/* + * kis_double_widget.h - part of Chalk + * + * Copyright (c) 1999 Carsten Pfeiffer + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_DOUBLE_WIDGET_H +#define KIS_DOUBLE_WIDGET_H + +#include +#include + +class TQHBoxLayout; +class KDoubleSpinBox; + +class KisDoubleWidget : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + + typedef TQWidget super; +public: + KisDoubleWidget(TQWidget* tqparent = 0, const char* name = 0); + KisDoubleWidget(double min, double max, TQWidget* tqparent = 0, const char* name = 0); + ~KisDoubleWidget(); + + double value() const; + void setRange(double min, double max); + + void setTickmarks(TQSlider::TickSetting tickMarks); + void setTickInterval(double tickInterval); + double tickInterval() const; + + void setPrecision(int precision); + void setLineStep(double step); + void setPageStep(double step); + + void setTracking(bool tracking); + bool tracking() const; + +signals: + void valueChanged(double); + void sliderPressed(); + void sliderReleased(); + +public slots: + void setValue(double value); + +protected slots: + void setSliderValue(double); + void sliderValueChanged(int); + +private: + void init(double min, double max); + +protected: + TQHBoxLayout* m_layout; + TQSlider* m_slider; + KDoubleSpinBox *m_spinBox; +}; + +#endif // KIS_DOUBLE_WIDGET_H + diff --git a/chalk/ui/kis_event.h b/chalk/ui/kis_event.h new file mode 100644 index 00000000..417a9168 --- /dev/null +++ b/chalk/ui/kis_event.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_EVENT_H_ +#define KIS_EVENT_H_ + +#include + +#include "kis_point.h" +#include "kis_input_device.h" + +class KisEvent { +public: + enum enumEventType { + UnknownEvent, + MoveEvent, + ButtonPressEvent, + ButtonReleaseEvent, + DoubleClickEvent + }; + + KisEvent() : m_type(UnknownEvent), m_device(KisInputDevice::unknown()) {} + KisEvent(enumEventType type, KisInputDevice device, const KisPoint& pos, const KisPoint& globalPos, double pressure, double xTilt, double yTilt, TQt::ButtonState state) : m_type(type), m_device(device), m_pos(pos), m_globalPos(globalPos), m_pressure(pressure), m_xTilt(xTilt), m_yTilt(yTilt), m_state(state) {} + + enumEventType type() const { return m_type; } + KisInputDevice device() const { return m_device; } + KisPoint pos() const { return m_pos; } + double x() const { return m_pos.x(); } + double y() const { return m_pos.y(); } + KisPoint globalPos() const { return m_globalPos; } + double pressure() const { return m_pressure; } + double xTilt() const { return m_xTilt; } + double yTilt() const { return m_yTilt; } + TQt::ButtonState state() const { return m_state; } + +protected: + enumEventType m_type; + KisInputDevice m_device; + KisPoint m_pos; + KisPoint m_globalPos; + double m_pressure; + double m_xTilt; + double m_yTilt; + TQt::ButtonState m_state; +}; + +#endif // KIS_EVENT_H_ + diff --git a/chalk/ui/kis_factory.cc b/chalk/ui/kis_factory.cc new file mode 100644 index 00000000..0924420d --- /dev/null +++ b/chalk/ui/kis_factory.cc @@ -0,0 +1,153 @@ +/* + * kis_factory.cc - part of Krayon + * + * Copyright (c) 1999 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include LCMS_HEADER + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_aboutdata.h" +#include "kis_resourceserver.h" +#include "kis_paintop_registry.h" +#include "kis_filter_registry.h" +#include "kis_tool_registry.h" +#include "kis_doc.h" +#include "kis_brush.h" +#include "kis_imagepipe_brush.h" +#include "kis_gradient.h" +#include "kis_pattern.h" +#include "kis_palette.h" +#include + +#include "kis_factory.h" + +KAboutData* KisFactory::s_aboutData = 0; +KInstance* KisFactory::s_instance = 0; + + + +KisFactory::KisFactory( TQObject* tqparent, const char* name ) + : KoFactory( tqparent, name ) +{ + s_aboutData = newChalkAboutData(); + + (void)instance(); + + // Load extension modules and plugins + KisToolRegistry::instance(); + KisPaintOpRegistry::instance(); + KisFilterRegistry::instance(); + KisResourceServerRegistry::instance(); + + + +} + +KisFactory::~KisFactory() +{ + delete s_aboutData; + s_aboutData = 0L; + delete s_instance; + s_instance = 0L; +} + +/** + * Create the document + */ +KParts::Part* KisFactory::createPartObject( TQWidget *tqparentWidget, + const char *widgetName, TQObject* tqparent, + const char* name, const char* classname, const TQStringList & ) +{ + bool bWantKoDocument = ( strcmp( classname, "KoDocument" ) == 0 ); + + KisDoc *doc = new KisDoc( tqparentWidget, + widgetName, tqparent, name, !bWantKoDocument ); + Q_CHECK_PTR(doc); + + if ( !bWantKoDocument ) + doc->setReadWrite( false ); + + return doc; +} + + +KAboutData* KisFactory::aboutData() +{ + return s_aboutData; +} + +KInstance* KisFactory::instance() +{ + TQString homedir = getenv("HOME"); + + if ( !s_instance ) + { + s_instance = new KInstance(s_aboutData); + Q_CHECK_PTR(s_instance); + + s_instance->dirs()->addResourceType("chalk_template", KStandardDirs::kde_default("data") + "chalk/templates"); + + // XXX: Are these obsolete? + s_instance->dirs()->addResourceType("kis", KStandardDirs::kde_default("data") + "chalk/"); + + s_instance->dirs()->addResourceType("kis_pics", KStandardDirs::kde_default("data") + "chalk/pics/"); + + s_instance->dirs()->addResourceType("kis_images", KStandardDirs::kde_default("data") + "chalk/images/"); + + s_instance->dirs()->addResourceType("toolbars", KStandardDirs::kde_default("data") + "koffice/toolbar/"); + + // Create spec + + s_instance->dirs()->addResourceType("kis_brushes", KStandardDirs::kde_default("data") + "chalk/brushes/"); + s_instance->dirs()->addResourceDir("kis_brushes", "/usr/share/create/brushes/gimp"); + s_instance->dirs()->addResourceDir("kis_brushes", TQDir::homeDirPath() + TQString("/.create/brushes/gimp")); + + s_instance->dirs()->addResourceType("kis_patterns", KStandardDirs::kde_default("data") + "chalk/patterns/"); + s_instance->dirs()->addResourceDir("kis_patterns", "/usr/share/create/patterns/gimp"); + s_instance->dirs()->addResourceDir("kis_patterns", TQDir::homeDirPath() + TQString("/.create/patterns/gimp")); + + s_instance->dirs()->addResourceType("kis_gradients", KStandardDirs::kde_default("data") + "chalk/gradients/"); + s_instance->dirs()->addResourceDir("kis_gradients", "/usr/share/create/gradients/gimp"); + s_instance->dirs()->addResourceDir("kis_gradients", TQDir::homeDirPath() + TQString("/.create/gradients/gimp")); + + s_instance->dirs()->addResourceType("kis_profiles", KStandardDirs::kde_default("data") + "chalk/profiles/"); + s_instance->dirs()->addResourceDir("kis_profiles", "/usr/share/color/icc"); + s_instance->dirs()->addResourceDir("kis_profiles", TQDir::homeDirPath() + TQString("/.icc")); + s_instance->dirs()->addResourceDir("kis_profiles", TQDir::homeDirPath() + TQString("/.color/icc")); + + s_instance->dirs()->addResourceType("kis_palettes", KStandardDirs::kde_default("data") + "chalk/palettes/"); + s_instance->dirs()->addResourceDir("kis_palettes", "/usr/share/create/swatches"); + s_instance->dirs()->addResourceDir("kis_palettes", TQDir::homeDirPath() + TQString("/.create/swatches")); + + // Tell the iconloader about share/apps/koffice/icons + s_instance->iconLoader()->addAppDir("koffice"); + } + + return s_instance; +} + +#include "kis_factory.moc" diff --git a/chalk/ui/kis_factory.h b/chalk/ui/kis_factory.h new file mode 100644 index 00000000..d20070c5 --- /dev/null +++ b/chalk/ui/kis_factory.h @@ -0,0 +1,59 @@ +/* + * kis_factory.h - part of Krayon + * + * Copyright (c) 1999 Matthias Elter + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __kis_factory_h__ +#define __kis_factory_h__ + +#include + +#include + +#include + +#include + +class KInstance; +class KAboutData; + +class KRITACORE_EXPORT KisFactory : public KoFactory +{ + Q_OBJECT + TQ_OBJECT + +public: + KisFactory( TQObject* tqparent = 0, const char* name = 0 ); + ~KisFactory(); + + virtual KParts::Part *createPartObject(TQWidget *tqparentWidget = 0, + const char *widgetName = 0, + TQObject *tqparent = 0, + const char *name = 0, + const char *classname = "KoDocument", + const TQStringList &args = TQStringList() ); + + static KAboutData *aboutData(); + static KInstance *instance(); + +private: + static KInstance *s_instance; + static KAboutData *s_aboutData; +}; + +#endif diff --git a/chalk/ui/kis_filter_manager.cc b/chalk/ui/kis_filter_manager.cc new file mode 100644 index 00000000..a21f49aa --- /dev/null +++ b/chalk/ui/kis_filter_manager.cc @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "tqsignalmapper.h" +#include +#include +#include +#include +#include +#include + +#include +#include "kaction.h" + +#include "kis_part_layer.h" +#include "kis_id.h" +#include "kis_view.h" +#include "kis_doc.h" +#include "kis_filter.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_paint_layer.h" +#include "kis_filter_manager.h" +#include "kis_filter_config_widget.h" +#include "kis_previewwidget.h" +#include "kis_previewdialog.h" +#include "kis_filter_registry.h" +#include "kis_transaction.h" +#include "kis_undo_adapter.h" +#include "kis_previewdialog.h" +#include "kis_previewwidget.h" +#include "kis_painter.h" +#include "kis_selection.h" +#include "kis_id.h" +#include "kis_canvas_subject.h" +#include "kis_doc.h" +#include "kis_transaction.h" +#include + +KisFilterManager::KisFilterManager(KisView * view, KisDoc * doc) + : m_view(view), + m_doc(doc) +{ + // XXX: Store & restore last filter & last filter configuration in session settings + m_reapplyAction = 0; + m_lastFilterConfig = 0; + m_lastDialog = 0; + m_lastFilter = 0; + m_lastWidget = 0; + + m_filterMapper = new TQSignalMapper(this); + + connect(m_filterMapper, TQT_SIGNAL(mapped(int)), this, TQT_SLOT(slotApplyFilter(int))); + +} + +KisFilterManager::~KisFilterManager() +{ + //delete m_reapplyAction; + //delete m_lastFilterConfig; + //delete m_filterMapper; +} + +void KisFilterManager::setup(KActionCollection * ac) +{ + KisFilter * f = 0; + int i = 0; + + // Only create the submenu's we've actually got filters for. + // XXX: Make this list extensible after 1.5 + + KActionMenu * other = 0; + KActionMenu * am = 0; + + m_filterList = KisFilterRegistry::instance()->listKeys(); + + for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) { + f = KisFilterRegistry::instance()->get(*it); + if (!f) break; + + TQString s = f->menuCategory(); + if (s == "adjust" && !m_filterActionMenus.tqfind("adjust")) { + am = new KActionMenu(i18n("Adjust"), ac, "adjust_filters"); + m_filterActionMenus.insert("adjust", am); + } + + else if (s == "artistic" && !m_filterActionMenus.tqfind("artistic")) { + am = new KActionMenu(i18n("Artistic"), ac, "artistic_filters"); + m_filterActionMenus.insert("artistic", am); + } + + else if (s == "blur" && !m_filterActionMenus.tqfind("blur")) { + am = new KActionMenu(i18n("Blur"), ac, "blur_filters"); + m_filterActionMenus.insert("blur", am); + } + + else if (s == "colors" && !m_filterActionMenus.tqfind("colors")) { + am = new KActionMenu(i18n("Colors"), ac, "color_filters"); + m_filterActionMenus.insert("colors", am); + } + + else if (s == "decor" && !m_filterActionMenus.tqfind("decor")) { + am = new KActionMenu(i18n("Decor"), ac, "decor_filters"); + m_filterActionMenus.insert("decor", am); + } + + else if (s == "edge" && !m_filterActionMenus.tqfind("edge")) { + am = new KActionMenu(i18n("Edge Detection"), ac, "edge_filters"); + m_filterActionMenus.insert("edge", am); + } + + else if (s == "emboss" && !m_filterActionMenus.tqfind("emboss")) { + am = new KActionMenu(i18n("Emboss"), ac, "emboss_filters"); + m_filterActionMenus.insert("emboss", am); + } + + else if (s == "enhance" && !m_filterActionMenus.tqfind("enhance")) { + am = new KActionMenu(i18n("Enhance"), ac, "enhance_filters"); + m_filterActionMenus.insert("enhance", am); + } + + else if (s == "map" && !m_filterActionMenus.tqfind("map")) { + am = new KActionMenu(i18n("Map"), ac, "map_filters"); + m_filterActionMenus.insert("map", am); + } + + else if (s == "nonphotorealistic" && !m_filterActionMenus.tqfind("nonphotorealistic")) { + am = new KActionMenu(i18n("Non-photorealistic"), ac, "nonphotorealistic_filters"); + m_filterActionMenus.insert("nonphotorealistic", am); + } + + else if (s == "other" && !m_filterActionMenus.tqfind("other")) { + other = new KActionMenu(i18n("Other"), ac, "misc_filters"); + m_filterActionMenus.insert("other", other); + } + + } + + m_reapplyAction = new KAction(i18n("Apply Filter Again"), + "Ctrl+Shift+F", + this, TQT_SLOT(slotApply()), + ac, "filter_apply_again"); + + m_reapplyAction->setEnabled(false); + + f = 0; + i = 0; + for ( KisIDList::Iterator it = m_filterList.begin(); it != m_filterList.end(); ++it ) { + f = KisFilterRegistry::instance()->get(*it); + + if (!f) break; + + // Create action + KAction * a = new KAction(f->menuEntry(), 0, m_filterMapper, TQT_SLOT(map()), ac, + TQString("chalk_filter_%1").tqarg((*it) . id()).ascii()); + + // Add action to the right submenu + KActionMenu * m = m_filterActionMenus.tqfind( f->menuCategory() ); + if (m) { + m->insert(a); + } + else { + if (!other) { + other = new KActionMenu(i18n("Other"), ac, "misc_filters"); + m_filterActionMenus.insert("other", am); + } + other->insert(a); + } + + // Add filter to list of filters for mapper + m_filterMapper->setMapping( a, i ); + + m_filterActions.append( a ); + ++i; + } +} + +void KisFilterManager::updateGUI() +{ + KisImageSP img = m_view->currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + KisPartLayer * partLayer = dynamic_cast(layer.data()); + + bool enable = !(layer->locked() || !layer->visible() || partLayer); + KisPaintLayerSP player = dynamic_cast( layer.data()); + if(!player) + { + enable = false; + } + m_reapplyAction->setEnabled(m_lastFilterConfig); + if (m_lastFilterConfig) + m_reapplyAction->setText(i18n("Apply Filter Again") + ": " + + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name()); + else + m_reapplyAction->setText(i18n("Apply Filter Again")); + + KAction * a; + int i = 0; + for (a = m_filterActions.first(); a; a = m_filterActions.next() , i++) { + KisFilter* filter = KisFilterRegistry::instance()->get(m_filterList[i]); + if(player && filter->workWith( player->paintDevice()->colorSpace())) + { + a->setEnabled(enable); + } else { + a->setEnabled(false); + } + } + +} + +void KisFilterManager::slotApply() +{ + apply(); +} + +bool KisFilterManager::apply() +{ + if (!m_lastFilter) return false; + + KisImageSP img = m_view->currentImg(); + if (!img) return false; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return false; + + TQApplication::setOverrideCursor( KisCursor::waitCursor() ); + + //Apply the filter + m_lastFilterConfig = m_lastFilter->configuration(m_lastWidget); + + TQRect r1 = dev->extent(); + TQRect r2 = img->bounds(); + + // Filters should work only on the visible part of an image. + TQRect rect = r1.intersect(r2); + + if (dev->hasSelection()) { + TQRect r3 = dev->selection()->selectedExactRect(); + rect = rect.intersect(r3); + } + + m_lastFilter->enableProgress(); + + m_view->progressDisplay()->setSubject(m_lastFilter, true, true); + m_lastFilter->setProgressDisplay( m_view->progressDisplay()); + + KisTransaction * cmd = 0; + if (img->undo()) cmd = new KisTransaction(m_lastFilter->id().name(), dev); + + m_lastFilter->process(dev, dev, m_lastFilterConfig, rect); + m_reapplyAction->setEnabled(m_lastFilterConfig); + if (m_lastFilterConfig) + m_reapplyAction->setText(i18n("Apply Filter Again") + ": " + + KisFilterRegistry::instance()->get(m_lastFilterConfig->name())->id().name()); + + else + m_reapplyAction->setText(i18n("Apply Filter Again")); + + m_lastFilter->disableProgress(); + TQApplication::restoreOverrideCursor(); + + + if (m_lastFilter->cancelRequested()) { + delete m_lastFilterConfig; + if (cmd) { + cmd->unexecute(); + delete cmd; + } + return false; + + } else { + if (dev->tqparentLayer()) dev->tqparentLayer()->setDirty(rect); + m_doc->setModified(true); + if (img->undo() && cmd) img->undoAdapter()->addCommand(cmd); + return true; + } +} + +void KisFilterManager::slotApplyFilter(int i) +{ + KisPreviewDialog * oldDialog = m_lastDialog; + KisFilterConfiguration * oldConfig = m_lastFilterConfig; + KisFilter * oldFilter = m_lastFilter; + + m_lastFilter = KisFilterRegistry::instance()->get(m_filterList[i]); + + if (!m_lastFilter) { + m_lastFilter = oldFilter; + return; + } + + KisImageSP img = m_view->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (dev->colorSpace()->willDegrade(m_lastFilter->colorSpaceIndependence())) { + // Warning bells! + if (m_lastFilter->colorSpaceIndependence() == TO_LAB16) { + if (KMessageBox::warningContinueCancel(m_view, + i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ") + .tqarg(m_lastFilter->id().name()) + .tqarg(dev->colorSpace()->id().name()), + i18n("Filter Will Convert Your Layer Data"), + KGuiItem(i18n("Continue")), + "lab16degradation") != KMessageBox::Continue) return; + + } + else if (m_lastFilter->colorSpaceIndependence() == TO_RGBA8) { + if (KMessageBox::warningContinueCancel(m_view, + i18n("The %1 filter will convert your %2 data to 8-bit RGBA and vice versa. ") + .tqarg(m_lastFilter->id().name()) + .tqarg(dev->colorSpace()->id().name()), + i18n("Filter Will Convert Your Layer Data"), + KGuiItem(i18n("Continue")), + "rgba8degradation") != KMessageBox::Continue) return; + } + } + + m_lastFilter->disableProgress(); + + // Create the config dialog + m_lastDialog = new KisPreviewDialog(m_view, m_lastFilter->id().name().ascii(), true, m_lastFilter->id().name()); + Q_CHECK_PTR(m_lastDialog); + m_lastWidget = m_lastFilter->createConfigurationWidget( (TQWidget*)m_lastDialog->container(), dev ); + + bool accepted = true; + + if( m_lastWidget != 0) + { + connect(m_lastWidget, TQT_SIGNAL(sigPleaseUpdatePreview()), this, TQT_SLOT(slotConfigChanged())); + + m_lastDialog->previewWidget()->slotSetDevice( dev ); + + connect(m_lastDialog->previewWidget(), TQT_SIGNAL(updated()), this, TQT_SLOT(refreshPreview())); + + TQGridLayout *widgetLayout = new TQGridLayout((TQWidget *)m_lastDialog->container(), 1, 1); + + widgetLayout->addWidget(m_lastWidget, 0 , 0); + + m_lastDialog->container()->setMinimumSize(m_lastWidget->tqminimumSize()); + + refreshPreview(); + + if(m_lastDialog->exec() == TQDialog::Rejected ) + { + accepted = false; + } + } + + if (!accepted || !apply()) { + // Override the old configuration + m_lastFilterConfig = oldConfig; + m_lastDialog = oldDialog; + m_lastFilter = oldFilter; + } else { + delete oldDialog; + delete oldConfig; + } + +} + +void KisFilterManager::slotConfigChanged() +{ + if( m_lastDialog == 0 ) + return; + if(m_lastDialog->previewWidget()->getAutoUpdate()) + { + refreshPreview(); + } else { + m_lastDialog->previewWidget()->needUpdate(); + } +} + + +void KisFilterManager::refreshPreview( ) +{ + if( m_lastDialog == 0 ) return; + + KisFilterConfiguration* config = m_lastFilter->configuration(m_lastWidget); + + // The preview widget is in charge of running the filter so it can optimize the performance + m_lastDialog->previewWidget()->runFilter(m_lastFilter, config); +} + + +#include "kis_filter_manager.moc" diff --git a/chalk/ui/kis_filter_manager.h b/chalk/ui/kis_filter_manager.h new file mode 100644 index 00000000..beaf66a2 --- /dev/null +++ b/chalk/ui/kis_filter_manager.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_FILTER_MANAGER_ +#define _KIS_FILTER_MANAGER_ + +#include "tqdict.h" +#include "tqobject.h" +#include "tqptrlist.h" +#include "tqsignalmapper.h" +#include "kactionclasses.h" +#include "kis_image.h" +#include "kis_selection.h" + +#include + +class KAction; +class KisView; +class KisDoc; +class KisFilter; +class KisFilterConfiguration; +class KAction; +class KActionCollection; +class KisPreviewDialog; + +/** + * Create all the filter actions for the specified view and implement re-apply filter + */ +class KRITACORE_EXPORT KisFilterManager : public TQObject { + + Q_OBJECT + TQ_OBJECT + +public: + + KisFilterManager(KisView * tqparent, KisDoc * doc); + ~KisFilterManager(); + + void setup(KActionCollection * ac); + void updateGUI(); + + + bool apply(); + +protected slots: + + void slotApply(); + void slotConfigChanged(); + void slotApplyFilter(int); + void refreshPreview(); + +private: + + KisView * m_view; + KisDoc * m_doc; + + KAction * m_reapplyAction; + + TQPtrList m_filterActions; + + KisFilterConfiguration * m_lastFilterConfig; + KisFilter * m_lastFilter; + KisPreviewDialog * m_lastDialog; + KisFilterConfigWidget * m_lastWidget; + + KisIDList m_filterList; // Map the actions in the signalmapper to the filters + TQSignalMapper * m_filterMapper; + + TQDict m_filterActionMenus; +}; + +#endif diff --git a/chalk/ui/kis_filters_listview.cc b/chalk/ui/kis_filters_listview.cc new file mode 100644 index 00000000..788a787d --- /dev/null +++ b/chalk/ui/kis_filters_listview.cc @@ -0,0 +1,250 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_filters_listview.h" + +#include +#include "tqtimer.h" +#include "tqpainter.h" +#include "tqpixmap.h" + +#include + +#include "kis_types.h" +#include "kis_paint_device.h" +#include "kis_cursor.h" +#include "kis_image.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_filter.h" +#include "kis_filter_strategy.h" +#include "kis_thread_pool.h" + +// ------------------------------------------------ + +KisFiltersThumbnailThread::KisFiltersThumbnailThread(TQIconView * tqparent, KisFiltersIconViewItem * iconItem, KisFilterConfiguration * config, KisFilter * filter, KisPaintDeviceSP dev, const TQRect & bounds, KisProfile * profile) + : m_parent(tqparent) + , m_iconItem(iconItem) + , m_config(config) + , m_filter(filter) + , m_dev(dev) + , m_bounds(bounds) + , m_profile(profile) +{ +} + +KisFiltersThumbnailThread::~KisFiltersThumbnailThread() +{ + m_iconItem->resetThread(); +} + +void KisFiltersThumbnailThread::run() +{ + if (m_canceled) return; + + KisPaintDeviceSP thumbPreview = new KisPaintDevice(*m_dev); + m_filter->disableProgress(); + m_filter->process(thumbPreview, thumbPreview, m_config, m_bounds); + + if (!m_canceled) { + m_pixmap = thumbPreview->convertToTQImage(m_profile); + + tqApp->postEvent(m_parent, new KisThumbnailDoneEvent (m_iconItem, m_pixmap)); + + } +} + +TQPixmap KisFiltersThumbnailThread::pixmap() +{ + return m_pixmap; +} + +void KisFiltersThumbnailThread::cancel() +{ + m_canceled = true; + m_filter->cancel(); + +} + + +// ------------------------------------------------ + +KisFiltersIconViewItem::KisFiltersIconViewItem(TQIconView * tqparent, const TQString & text, const TQPixmap & icon, + KisID id, KisFilter* filter, KisFilterConfiguration* filterConfig, + KisPaintDeviceSP thumb, const TQRect & bounds, KisProfile * profile) + : TQIconViewItem(tqparent, text, icon) + , m_id(id) + , m_filter(filter) + , m_filterconfig(filterConfig) +{ + m_thread = new KisFiltersThumbnailThread(tqparent, this, filterConfig, filter, thumb, bounds, profile); +} + +KisFiltersIconViewItem::~KisFiltersIconViewItem() +{ + if (m_thread) m_thread->cancel(); +} + + +// ------------------------------------------------ + +KisFiltersListView::KisFiltersListView(TQWidget* tqparent, bool filterForAdjustmentLayers, const char* name) + : KIconView(tqparent, name) + , m_original(0) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + init(); +} + +KisFiltersListView::KisFiltersListView(TQWidget * tqparent, const char * name, WFlags f, bool filterForAdjustmentLayers) + : KIconView(tqparent, name, f) + , m_original(0) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + init(); +} + +KisFiltersListView::KisFiltersListView(KisLayerSP layer, TQWidget* tqparent, bool filterForAdjustmentLayers, const char * name) + : KIconView(tqparent, name) + , m_original(0) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + KisPaintLayer* pl = dynamic_cast(layer.data()); + if(pl != 0) + { + m_original = pl->paintDevice(); + buildPreview(); + } + init(); +} + +KisFiltersListView::KisFiltersListView(KisPaintDeviceSP device, TQWidget* tqparent, bool filterForAdjustmentLayers, const char * name) + : KIconView(tqparent, name) + , m_original(device) + , m_profile(0) + , m_filterForAdjustmentLayers(filterForAdjustmentLayers) +{ + buildPreview(); + init(); +} + +void KisFiltersListView::init() +{ + setCaption(i18n("Filters List")); + setItemsMovable(false); + setSelectionMode(TQIconView::Single); + tqsetSizePolicy(TQSizePolicy(TQSizePolicy::Fixed, TQSizePolicy::Expanding )); + setMinimumWidth(160); + +} + +void KisFiltersListView::setLayer(KisLayerSP layer) { + KisPaintLayer* pl = dynamic_cast(layer.data()); + if(pl == 0) + return; + KisPaintDeviceSP npd = pl->paintDevice(); + if(npd!= m_original) + { + m_original = npd; + buildPreview(); + } +} + +void KisFiltersListView::setCurrentFilter(KisID filter) +{ + setCurrentItem(tqfindItem(filter.name())); +} + +void KisFiltersListView::buildPreview() +{ + TQTime t; + if(m_original== 0) + return; + + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + t.start(); + m_thumb = m_original->createThumbnailDevice(150, 150); + + t.start(); + TQRect bounds = m_thumb->exactBounds(); + TQPixmap pm(bounds.width(), bounds.height()); + TQPainter gc(&pm); + gc.fillRect(0, 0, bounds.width(), bounds.height(), backgroundColor()); + gc.end(); + + t.start(); + KisIDList l = KisFilterRegistry::instance()->listKeys(); + KisIDList::iterator it; + it = l.begin(); + // Iterate over the list of filters + for (it = l.begin(); it != l.end(); ++it) { + KisFilterSP f = KisFilterRegistry::instance()->get(*it); + // Check if filter support the preview and work with the current colorspace + if (f->supportsPreview() && f->workWith( m_original->colorSpace() ) ) { + + if (m_filterForAdjustmentLayers) { + kdDebug() << "We're filtering for adj layers, and this filter (" << f->id().name() << ") supports them: " << f->supportsAdjustmentLayers() << endl; + if(!f->supportsAdjustmentLayers()) continue; + } + std::list configlist = f->listOfExamplesConfiguration(m_thumb); + // apply the filter for each of example of configuration + for(std::list::iterator itc = configlist.begin(); + itc != configlist.end(); + itc++) + { + KisFiltersIconViewItem * icon = new KisFiltersIconViewItem( this, (*it).name(), pm, *it, f, *itc, m_thumb, bounds, m_profile ); + //KisThreadPool::instance()->enqueue(icon->thread()); + icon->thread()->runDirectly(); + } + } + } + TQApplication::restoreOverrideCursor(); +} + + +void KisFiltersListView::customEvent(TQCustomEvent * e) +{ + KisThumbnailDoneEvent * ev = dynamic_cast(e); + if (ev) { + TQPixmap * p = ev->m_iconItem->pixmap(); + TQImage img = ev->m_image; + int x, y; + + if (p->width() > img.width()) + x = (p->width() - img.width()) / 2; + else + x = 0; + if (p->height() > img.height()) + y = (p->height() - img.height()) / 2; + else + y = 0; + + TQPainter gc(p); + gc.drawImage(TQPoint(x,y), img); + gc.end(); + + //ev->m_iconItem->setPixmap(TQPixmap(*p)); + arrangeItemsInGrid(); + } +} diff --git a/chalk/ui/kis_filters_listview.h b/chalk/ui/kis_filters_listview.h new file mode 100644 index 00000000..c4979e25 --- /dev/null +++ b/chalk/ui/kis_filters_listview.h @@ -0,0 +1,143 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_FILTERS_LIST_VIEW_H_ +#define _KIS_FILTERS_LIST_VIEW_H_ + +#include + +#include + +#include "kis_id.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_paint_device.h" +#include "kis_thread.h" + +class KisView; +class KisFilter; +class KisFilterConfiguration; +class KisPreviewView; +class KisFiltersIconViewItem; +class KisFiltersListView; +class KisThreadPool; + +class KisThumbnailDoneEvent : public TQCustomEvent +{ +public: + + KisThumbnailDoneEvent(KisFiltersIconViewItem * iconItem, const TQImage & img) + : TQCustomEvent(TQEvent::User + 1969) + , m_iconItem(iconItem) + , m_image(img) {}; + + KisFiltersIconViewItem * m_iconItem; + TQImage m_image; + +}; + + +class KisFiltersThumbnailThread : public KisThread +{ +public: + + KisFiltersThumbnailThread(TQIconView * tqparent, + KisFiltersIconViewItem * iconItem, + KisFilterConfiguration * config, KisFilter * filter, + KisPaintDeviceSP dev, const TQRect & bounds, + KisProfile * profile); + + ~KisFiltersThumbnailThread(); + + virtual void run(); + TQPixmap pixmap(); + void cancel(); + +private: + TQIconView * m_parent; + KisFiltersIconViewItem * m_iconItem; + KisFilterConfiguration * m_config; + KisFilter * m_filter; + KisPaintDeviceSP m_dev; + const TQRect m_bounds; + KisProfile * m_profile; + TQImage m_pixmap; +}; + +class KisFiltersIconViewItem : public TQIconViewItem { +public: + KisFiltersIconViewItem( TQIconView * tqparent, const TQString & text, const TQPixmap & icon, + KisID id, KisFilter* filter, KisFilterConfiguration* filterConfig, + KisPaintDeviceSP thumb, const TQRect & bounds, KisProfile * profile); + + virtual ~KisFiltersIconViewItem(); + KisID id() { return m_id; } + KisFilter* filter() { return m_filter; } + void setFilterConfiguration(KisFilterConfiguration* fc) { m_filterconfig = fc; } + + void resetThread() { m_thread = 0; }; + KisThread * thread() { return m_thread; } + +private: + KisID m_id; + KisFilter* m_filter; + KisFilterConfiguration* m_filterconfig; + KisFiltersThumbnailThread * m_thread; +}; + +class KisFiltersListView : public KIconView { + +public: + explicit KisFiltersListView(TQWidget * tqparent = 0, const char * name = 0, WFlags f = 0, bool filterForAdjustmentLayers = false); + KisFiltersListView(TQWidget* tqparent, bool filterForAdjustmentLayers = false, const char* name = 0); + KisFiltersListView(KisLayerSP layer, TQWidget* tqparent, bool filterForAdjustmentLayers = false, const char * name = 0) KDE_DEPRECATED; + KisFiltersListView(KisPaintDeviceSP layer, TQWidget* tqparent, bool filterForAdjustmentLayers = false, const char * name = 0); + + virtual void customEvent(TQCustomEvent *); + + private: + + void init(); + +public: + void setLayer(KisLayerSP layer) KDE_DEPRECATED; + void setProfile(KisProfile * profile) { m_profile = profile; }; + + inline void setPaintDevice(KisPaintDeviceSP pd) { + if( pd != m_original) + { + m_original = pd; + buildPreview(); + } + } + void buildPreview(); + void setCurrentFilter(KisID filter); + +private: + + KisPaintDeviceSP m_original; + KisImageSP m_imgthumb; + KisPaintDeviceSP m_thumb; + KisProfile * m_profile; + KisThreadPool * threadPool; + bool m_filterForAdjustmentLayers; +}; + +#endif diff --git a/chalk/ui/kis_gradient_chooser.cc b/chalk/ui/kis_gradient_chooser.cc new file mode 100644 index 00000000..7e416ea1 --- /dev/null +++ b/chalk/ui/kis_gradient_chooser.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include + +#include +#include + +#include "kis_global.h" +#include "kis_icon_item.h" +#include "kis_gradient.h" +#include "kis_autogradient.h" + +#include "kis_gradient_chooser.h" + +KisCustomGradientDialog::KisCustomGradientDialog(KisView * view, TQWidget * tqparent, const char *name) + : KDialogBase(tqparent, name, false, i18n("Custom Gradient"), Close) +{ + m_page = new KisAutogradient(this, "autogradient", i18n("Custom Gradient")); + setMainWidget(m_page); + connect(m_page, TQT_SIGNAL(activatedResource(KisResource *)), view, TQT_SLOT(gradientActivated(KisResource*))); +} + +KisGradientChooser::KisGradientChooser(KisView * view, TQWidget *tqparent, const char *name) : super(tqparent, name) +{ + m_lbName = new TQLabel(this); + + m_customGradient = new TQPushButton(i18n("Custom Gradient..."), this, "custom gradient button"); + + KisCustomGradientDialog * autogradient = new KisCustomGradientDialog(view, this, "autogradient"); + connect(m_customGradient, TQT_SIGNAL(clicked()), autogradient, TQT_SLOT(show())); + + TQVBoxLayout *mainLayout = new TQVBoxLayout(this, 2, -1, "main tqlayout"); + + mainLayout->addWidget(m_lbName); + mainLayout->addWidget(chooserWidget(), 10); + mainLayout->addWidget(m_customGradient, 10); + +} + +KisGradientChooser::~KisGradientChooser() +{ +} + +void KisGradientChooser::update(KoIconItem *item) +{ + KisIconItem *kisItem = static_cast(item); + + if (item) { + KisGradient *gradient = static_cast(kisItem->resource()); + + m_lbName->setText(gradient->name()); + } +} + + +#include "kis_gradient_chooser.moc" + diff --git a/chalk/ui/kis_gradient_chooser.h b/chalk/ui/kis_gradient_chooser.h new file mode 100644 index 00000000..fc154f3c --- /dev/null +++ b/chalk/ui/kis_gradient_chooser.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_GRADIENT_CHOOSER_H_ +#define KIS_GRADIENT_CHOOSER_H_ + +#include + +#include "kis_itemchooser.h" + +class TQLabel; +class TQPushButton; +class KisView; + +class KisCustomGradientDialog : public KDialogBase { + + Q_OBJECT + TQ_OBJECT + +public: + + KisCustomGradientDialog(KisView * view, TQWidget * tqparent, const char *name); + +private: + + KisAutogradient * m_page; + +}; + +class KisGradientChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + TQ_OBJECT + +public: + // XXX: On library redesign, remove m_view parameter here, it's just a temporary hack for the autogradient dialog! + KisGradientChooser(KisView * view, TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisGradientChooser(); + +protected: + virtual void update(KoIconItem *item); + +private: + TQLabel *m_lbName; + TQPushButton * m_customGradient; +}; + +#endif // KIS_GRADIENT_CHOOSER_H_ + diff --git a/chalk/ui/kis_gradient_slider_widget.cc b/chalk/ui/kis_gradient_slider_widget.cc new file mode 100644 index 00000000..3777a214 --- /dev/null +++ b/chalk/ui/kis_gradient_slider_widget.cc @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_gradient_slider_widget.h" + +#include + +#include +#include +#include + +#include "kis_autogradient_resource.h" + +#define MARGIN 5 +#define HANDLE_SIZE 10 + +KisGradientSliderWidget::KisGradientSliderWidget(TQWidget *tqparent, const char* name, WFlags f ) + : TQWidget( tqparent, name, f), + m_currentSegment(0), + m_selectedSegment(0), + m_drag(0) +{ + setMinimumHeight(30); + + m_segmentMenu = new KPopupMenu(); + m_segmentMenu->insertItem(i18n("Split Segment"), SPLIT_SEGMENT); + m_segmentMenu->insertItem(i18n("Duplicate Segment"), DUPLICATE_SEGMENT); + m_segmentMenu->insertItem(i18n("Mirror Segment"), MIRROR_SEGMENT); + m_segmentMenu->insertItem(i18n("Remove Segment"), REMOVE_SEGMENT); + connect( m_segmentMenu, TQT_SIGNAL( activated(int) ), TQT_SLOT( slotMenuAction(int) ) ); +} + +void KisGradientSliderWidget::setGradientResource( KisAutogradientResource* agr) +{ + m_autogradientResource = agr; + m_selectedSegment = m_autogradientResource->segmentAt(0.0); + emit sigSelectedSegment( m_selectedSegment ); +} + +void KisGradientSliderWidget::paintEvent ( TQPaintEvent* pe ) +{ + TQWidget::paintEvent( pe ); + TQPixmap pixmap( width(), height() ); + pixmap.fill( tqcolorGroup().background() ); + TQPainter painter( &pixmap ); + painter.setPen( TQt::black ); + painter.drawRect( MARGIN, MARGIN, width() - 2 * MARGIN, height()- 2 * MARGIN - HANDLE_SIZE ); + if(m_autogradientResource) + { + TQImage img = m_autogradientResource->generatePreview(width()- 2* MARGIN - 2, height()- 2* MARGIN - HANDLE_SIZE - 2); + TQPixmap pixmap(img.width(), img.height()); + if (!img.isNull()) { + m_pixmapIO.putImage(&pixmap, 0, 0, &img); + painter.drawPixmap( MARGIN + 1, MARGIN + 1, pixmap, 0, 0, pixmap.width(), pixmap.height()); + } + + painter.fillRect( MARGIN + 1, height()- MARGIN - HANDLE_SIZE, width() - 2 * MARGIN, HANDLE_SIZE, TQBrush( TQt::white ) ); + if( m_selectedSegment ) + { + TQRect selection( tqRound( m_selectedSegment->startOffset()*(double)(width()- 2 * MARGIN - 2) ) + 6, + height()- HANDLE_SIZE - MARGIN, + tqRound( ( m_selectedSegment->endOffset() - m_selectedSegment->startOffset() )*(double)(width()-12) ), + HANDLE_SIZE ); + painter.fillRect( selection, TQBrush( tqcolorGroup().highlight() ) ); + } + + TQPointArray triangle(3); + TQValueVector handlePositions = m_autogradientResource->getHandlePositions(); + int position; + painter.setBrush( TQBrush( TQt::black) ); + for (uint i = 0; i < handlePositions.count(); i++) + { + position = tqRound( handlePositions[i] * (double)( width()-12) ) + 6; + triangle[0] = TQPoint(position, height() - HANDLE_SIZE - MARGIN ); + triangle[1] = TQPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN ); + triangle[2] = TQPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN ); + painter.drawPolygon(triangle); + } + painter.setBrush( TQBrush( TQt::white ) ); + TQValueVector middleHandlePositions = m_autogradientResource->getMiddleHandlePositions(); + for (uint i = 0; i < middleHandlePositions.count(); i++) + { + position = tqRound( middleHandlePositions[i] * (double)(width()-12) ) + 6; + triangle[0] = TQPoint(position, height()-HANDLE_SIZE - MARGIN); + triangle[1] = TQPoint(position + (HANDLE_SIZE / 2 - 2), height() - MARGIN); + triangle[2] = TQPoint(position - (HANDLE_SIZE / 2 - 2), height() - MARGIN); + painter.drawPolygon(triangle); + } + } + bitBlt( this, 0, 0, &pixmap, 0, 0, pixmap.width(), pixmap.height(), TQt::CopyROP); +} + +void KisGradientSliderWidget::mousePressEvent( TQMouseEvent * e ) +{ + TQWidget::mousePressEvent( e ); + if( ( e->y() < MARGIN || e->y() > height() - MARGIN ) || ( e->x() < MARGIN || e->x() > width() - MARGIN ) || e-> button() != Qt::LeftButton ) + return; + double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); + KisGradientSegment* segment = 0; + segment = m_autogradientResource->segmentAt(t); + if(segment != 0) + { + m_currentSegment = segment; + TQRect leftHandle( tqRound(m_currentSegment->startOffset() * (double)(width()-2*MARGIN-2)+ MARGIN - (HANDLE_SIZE/2 - 1 )), + height() - HANDLE_SIZE, + HANDLE_SIZE - 1, + HANDLE_SIZE); + TQRect middleHandle( tqRound(m_currentSegment->middleOffset() * (double)(width()-2*MARGIN-2)+ MARGIN - (HANDLE_SIZE/2 -2) ), + height() - HANDLE_SIZE - MARGIN, + HANDLE_SIZE - 1, + HANDLE_SIZE); + TQRect rightHandle( tqRound(m_currentSegment->endOffset() * (double)(width()-2*MARGIN-2)+ MARGIN - (HANDLE_SIZE/2 - 1 )), + height() - HANDLE_SIZE, + HANDLE_SIZE - 1, + HANDLE_SIZE); + // Change the activation order of the handles to avoid deadlocks + if( t > 0.5 ) + { + if( leftHandle.tqcontains( e->pos() ) ) + m_drag = LEFT_DRAG; + else if( middleHandle.tqcontains( e->pos() ) ) + m_drag = MIDDLE_DRAG; + else if( rightHandle.tqcontains( e->pos() ) ) + m_drag = RIGHT_DRAG; + } + else + { + if( rightHandle.tqcontains( e->pos() ) ) + m_drag = RIGHT_DRAG; + else if( middleHandle.tqcontains( e->pos() ) ) + m_drag = MIDDLE_DRAG; + else if( leftHandle.tqcontains( e->pos() ) ) + m_drag = LEFT_DRAG; + } + + if( m_drag == NO_DRAG ) + { + m_selectedSegment = m_currentSegment; + emit sigSelectedSegment( m_selectedSegment ); + } + } + tqrepaint(false); +} + +void KisGradientSliderWidget::mouseReleaseEvent ( TQMouseEvent * e ) +{ + TQWidget::mouseReleaseEvent( e ); + m_drag = NO_DRAG; +} + +void KisGradientSliderWidget::mouseMoveEvent( TQMouseEvent * e ) +{ + TQWidget::mouseMoveEvent( e ); + if( ( e->y() < MARGIN || e->y() > height() - MARGIN ) || ( e->x() < MARGIN || e->x() > width() - MARGIN ) ) + return; + double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); + switch( m_drag ) + { + case RIGHT_DRAG: + m_autogradientResource->moveSegmentEndOffset( m_currentSegment, t ); + break; + case LEFT_DRAG: + m_autogradientResource->moveSegmentStartOffset( m_currentSegment, t ); + break; + case MIDDLE_DRAG: + m_autogradientResource->moveSegmentMiddleOffset( m_currentSegment, t ); + break; + } + + if ( m_drag != NO_DRAG) + emit sigChangedSegment( m_currentSegment ); + + tqrepaint(false); +} + +void KisGradientSliderWidget::contextMenuEvent( TQContextMenuEvent * e ) +{ + m_segmentMenu->setItemEnabled( REMOVE_SEGMENT, m_autogradientResource->removeSegmentPossible() ); + m_segmentMenu->popup( e->globalPos()); +} + +void KisGradientSliderWidget::slotMenuAction( int id ) +{ + switch( id ) + { + case SPLIT_SEGMENT: + m_autogradientResource->splitSegment( m_selectedSegment ); + break; + case DUPLICATE_SEGMENT: + m_autogradientResource->duplicateSegment( m_selectedSegment ); + break; + case MIRROR_SEGMENT: + m_autogradientResource->mirrorSegment( m_selectedSegment ); + break; + case REMOVE_SEGMENT: + m_selectedSegment = m_autogradientResource->removeSegment( m_selectedSegment ); + break; + } + emit sigSelectedSegment( m_selectedSegment ); + tqrepaint(false); +} + +#include "kis_gradient_slider_widget.moc" diff --git a/chalk/ui/kis_gradient_slider_widget.h b/chalk/ui/kis_gradient_slider_widget.h new file mode 100644 index 00000000..d15ac1c4 --- /dev/null +++ b/chalk/ui/kis_gradient_slider_widget.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * 2004 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_WDG_GRADIENT_SLIDER_H_ +#define _KIS_WDG_GRADIENT_SLIDER_H_ + +#include +#include + +class KPopupMenu; +class KisAutogradientResource; +class KisGradientSegment; + +class KisGradientSliderWidget : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + +public: + KisGradientSliderWidget(TQWidget *tqparent = 0, const char* name = 0, WFlags f = 0); + +public: + virtual void paintEvent ( TQPaintEvent * ); + void setGradientResource( KisAutogradientResource* agr); + KisGradientSegment* selectedSegment() { return m_selectedSegment; }; + +signals: + void sigSelectedSegment(KisGradientSegment*); + void sigChangedSegment(KisGradientSegment*); + +protected: + virtual void mousePressEvent( TQMouseEvent * e ); + virtual void mouseReleaseEvent ( TQMouseEvent * e ); + virtual void mouseMoveEvent( TQMouseEvent * e ); + virtual void contextMenuEvent( TQContextMenuEvent * e ); + +private slots: + void slotMenuAction(int id); + +private: + + enum { + NO_DRAG, + LEFT_DRAG, + RIGHT_DRAG, + MIDDLE_DRAG + }; + + enum { + SPLIT_SEGMENT, + DUPLICATE_SEGMENT, + MIRROR_SEGMENT, + REMOVE_SEGMENT + }; + + KPixmapIO m_pixmapIO; + KisAutogradientResource* m_autogradientResource; + KisGradientSegment* m_currentSegment; + KisGradientSegment* m_selectedSegment; + KPopupMenu* m_segmentMenu; + int m_drag; +}; + +#endif diff --git a/chalk/ui/kis_grid_drawer.cpp b/chalk/ui/kis_grid_drawer.cpp new file mode 100644 index 00000000..f0d0e5f8 --- /dev/null +++ b/chalk/ui/kis_grid_drawer.cpp @@ -0,0 +1,223 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_grid_drawer.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL +#include +#endif + +#include "kis_config.h" +#include "kis_image.h" +#include "kis_perspective_grid.h" +#include "kis_perspective_grid_manager.h" + +Qt::PenStyle GridDrawer::gs2style(TQ_UINT32 s) +{ + switch(s) + { + case 1: + return Qt::DashLine; + case 2: + return Qt::DotLine; + case 3: + return Qt::DashDotLine; + case 4: + return Qt::DashDotDotLine; + default: + return Qt::SolidLine; + } +} + +void GridDrawer::drawPerspectiveGrid(KisImageSP image, const TQRect& /*wr*/, const KisSubPerspectiveGrid* grid) +{ + Q_UNUSED(image); + KisConfig cfg; + TQPen mainPen = TQPen ( cfg.getGridMainColor(), 1, gs2style( cfg.getGridMainStyle() ) ); + TQPen subdivisionPen = TQPen ( cfg.getGridSubdivisionColor(), 1, gs2style( cfg.getGridSubdivisionStyle() ) ); + setPen(subdivisionPen ); + // 1 -> top-left corner + // 2 -> top-right corner + // 3 -> bottom-right corner + // 4 -> bottom-left corner + // d12 line from top-left to top-right + // note that the notion of top-left is purely theorical + KisPerspectiveMath::LineEquation d12 = KisPerspectiveMath::computeLineEquation( grid->topLeft(), grid->topRight() ) ; + KisPoint v12 = KisPoint(*grid->topLeft() - *grid->topRight()); + v12.setX( v12.x() / grid->subdivisions()); v12.setY( v12.y() / grid->subdivisions() ); + KisPerspectiveMath::LineEquation d23 = KisPerspectiveMath::computeLineEquation( grid->topRight(), grid->bottomRight() ); + KisPoint v23 = KisPoint(*grid->topRight() - *grid->bottomRight()); + v23.setX( v23.x() / grid->subdivisions()); v23.setY( v23.y() / grid->subdivisions() ); + KisPerspectiveMath::LineEquation d34 = KisPerspectiveMath::computeLineEquation( grid->bottomRight(), grid->bottomLeft() ); + KisPerspectiveMath::LineEquation d41 = KisPerspectiveMath::computeLineEquation( grid->bottomLeft(), grid->topLeft() ); + + KisPoint horizVanishingPoint = KisPerspectiveMath::computeIntersection(d12,d34); + KisPoint vertVanishingPoint = KisPerspectiveMath::computeIntersection(d23,d41); + + for(uint i = 1; i < static_cast(grid->subdivisions()); i ++) + { + KisPoint pol1 = *grid->topRight() + i * v12; + KisPerspectiveMath::LineEquation d1 = KisPerspectiveMath::computeLineEquation( &pol1, &vertVanishingPoint ); + KisPoint pol1b = KisPerspectiveMath::computeIntersection(d1,d34); + drawLine( pol1.roundTQPoint(), pol1b.roundTQPoint() ); + + KisPoint pol2 = *grid->bottomRight() + i * v23; + KisPerspectiveMath::LineEquation d2 = KisPerspectiveMath::computeLineEquation( &pol2, &horizVanishingPoint ); + KisPoint pol2b = KisPerspectiveMath::computeIntersection(d2,d41); + drawLine( pol2.roundTQPoint(), pol2b.roundTQPoint() ); + } + setPen(mainPen); + drawLine( grid->topLeft(), grid->topRight() ); + drawLine( grid->topRight(), grid->bottomRight() ); + drawLine( grid->bottomRight(), grid->bottomLeft() ); + drawLine( grid->bottomLeft(), grid->topLeft() ); +} + +void GridDrawer::drawGrid(KisImageSP image, const TQRect& wr) +{ + KisConfig cfg; + + TQ_UINT32 offsetx = cfg.getGridOffsetX(); + TQ_UINT32 offsety = cfg.getGridOffsetY(); + TQ_UINT32 hspacing = cfg.getGridHSpacing(); + TQ_UINT32 vspacing = cfg.getGridVSpacing(); + TQ_UINT32 subdivision = cfg.getGridSubdivisions() - 1; + //double ihspsub = hspacing / (double)subdivision; + //double ivspsub = hspacing / (double)subdivision; + + TQ_INT32 imageWidth = image->width(); + TQ_INT32 imageHeight = image->height(); + + // Draw vertical line + TQPen mainPen = TQPen ( cfg.getGridMainColor(), 1, gs2style( cfg.getGridMainStyle() ) ); + TQPen subdivisionPen = TQPen ( cfg.getGridSubdivisionColor(), 1, gs2style( cfg.getGridSubdivisionStyle() ) ); + TQ_UINT32 i = 0; + for( TQ_INT32 x = offsetx; x <= wr.right(); x +=hspacing) + { + if( i == subdivision ) + { + setPen(mainPen); + i = 0; + } else { + setPen(subdivisionPen); + i++; + } + if( x >= wr.x() ) + { + // Always draw the full line otherwise the line stippling varies + // with the location of wr and we get glitchy patterns. + drawLine(x, 0, x, imageHeight); + } + } + // Draw horizontal line + i = 0; + for( TQ_INT32 y = offsety; y <= wr.bottom(); y +=vspacing) + { + if( i == subdivision ) + { + setPen(mainPen); + i = 0; + } else { + setPen(subdivisionPen); + i++; + } + if( y >= wr.y() ) + { + drawLine(0, y, imageWidth, y); + } + } +} + +OpenGLGridDrawer::OpenGLGridDrawer() +{ +#ifdef HAVE_GL + glPushAttrib(GL_ALL_ATTRIB_BITS); +#endif +} + +OpenGLGridDrawer::~OpenGLGridDrawer() +{ +#ifdef HAVE_GL + glPopAttrib(); +#endif +} + +void OpenGLGridDrawer::setPen(const TQPen& pen) +{ +#ifdef HAVE_GL + Qt::PenStyle penStyle = pen.style(); + + if (penStyle == TQt::SolidLine) { + glDisable(GL_LINE_STIPPLE); + } else { + GLushort lineStipple; + + switch (penStyle) { + case TQt::NoPen: + lineStipple = 0; + break; + default: + case TQt::SolidLine: + lineStipple = 0xffff; + break; + case TQt::DashLine: + lineStipple = 0x3fff; + break; + case TQt::DotLine: + lineStipple = 0x3333; + break; + case TQt::DashDotLine: + lineStipple = 0x33ff; + break; + case TQt::DashDotDotLine: + lineStipple = 0x333f; + break; + } + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, lineStipple); + } + + TQColor penColor = pen.color(); + + glColor3ub(penColor.red(), penColor.green(), penColor.blue()); +#else + Q_UNUSED(pen); +#endif +} + +void OpenGLGridDrawer::drawLine(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2) +{ +#ifdef HAVE_GL + glBegin(GL_LINES); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); +#else + Q_UNUSED(x1); + Q_UNUSED(y1); + Q_UNUSED(x2); + Q_UNUSED(y2); +#endif +} diff --git a/chalk/ui/kis_grid_drawer.h b/chalk/ui/kis_grid_drawer.h new file mode 100644 index 00000000..a37fd69e --- /dev/null +++ b/chalk/ui/kis_grid_drawer.h @@ -0,0 +1,71 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_GRID_DRAWER_H +#define KIS_GRID_DRAWER_H + +#include + +#include +#include + +#include "kis_types.h" +#include "kis_point.h" + +class KisSubPerspectiveGrid; + +class GridDrawer { + public: + GridDrawer() {} + virtual ~GridDrawer() {} + + public: + void drawGrid(KisImageSP image, const TQRect& wr); + void drawPerspectiveGrid(KisImageSP image, const TQRect& wr, const KisSubPerspectiveGrid* grid); + + virtual void setPen(const TQPen& pen) = 0; + virtual void drawLine(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2) = 0; + inline void drawLine(const TQPoint& p1, const TQPoint& p2) { drawLine(p1.x(), p1.y(), p2.x(), p2.y() ); } + inline void drawLine(const KisPoint* p1, const KisPoint* p2) { drawLine( p1->roundTQPoint(), p2->roundTQPoint()); } + private: + Qt::PenStyle gs2style(TQ_UINT32 s); +}; + +class TQPainterGridDrawer : public GridDrawer { +public: + TQPainterGridDrawer(TQPainter *p) { m_painter = p; } + + virtual void setPen(const TQPen& pen) { m_painter->setPen(pen); } + virtual void drawLine(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2) { m_painter->drawLine(x1, y1, x2, y2); } + +private: + TQPainter *m_painter; +}; + +class OpenGLGridDrawer : public GridDrawer { +public: + OpenGLGridDrawer(); + virtual ~OpenGLGridDrawer(); + + virtual void setPen(const TQPen& pen); + virtual void drawLine(TQ_INT32 x1, TQ_INT32 y1, TQ_INT32 x2, TQ_INT32 y2); +}; + +#endif diff --git a/chalk/ui/kis_grid_manager.cpp b/chalk/ui/kis_grid_manager.cpp new file mode 100644 index 00000000..53ee931c --- /dev/null +++ b/chalk/ui/kis_grid_manager.cpp @@ -0,0 +1,156 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_grid_manager.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL +#include +#endif + +#include + +#include +#include +#include + + +#include "kis_config.h" +#include "kis_grid_drawer.h" +#include "kis_image.h" +#include "kis_view.h" + +KisGridManager::KisGridManager(KisView * tqparent) + : TQObject(tqparent), m_view(tqparent) +{ + +} + +KisGridManager::~KisGridManager() +{ + +} + +void KisGridManager::setup(KActionCollection * collection) +{ + m_toggleGrid = new KToggleAction(i18n("Show Grid"), "", this, TQT_SLOT(toggleGrid()), collection, "view_toggle_grid"); + m_toggleGrid->setCheckedState(KGuiItem(i18n("Hide Grid"))); + m_toggleGrid->setChecked(false); + + // Fast grid config + m_gridFastConfig1x1 = new KAction(i18n("1x1"), 0, "", this, TQT_SLOT(fastConfig1x1()), collection, "view_fast_grid_1x1"); + m_gridFastConfig2x2 = new KAction(i18n("2x2"), 0, "", this, TQT_SLOT(fastConfig2x2()), collection, "view_fast_grid_2x2"); + m_gridFastConfig5x5 = new KAction(i18n("5x5"), 0, "", this, TQT_SLOT(fastConfig5x5()), collection, "view_fast_grid_5x5"); + m_gridFastConfig10x10 = new KAction(i18n("10x10"), 0, "", this, TQT_SLOT(fastConfig10x10()), collection, "view_fast_grid_10x10"); + m_gridFastConfig20x20 = new KAction(i18n("20x20"), 0, "", this, TQT_SLOT(fastConfig20x20()), collection, "view_fast_grid_20x20"); + m_gridFastConfig40x40 = new KAction(i18n("40x40"), 0, "", this, TQT_SLOT(fastConfig40x40()), collection, "view_fast_grid_40x40"); +} + +void KisGridManager::updateGUI() +{ + +} + +void KisGridManager::toggleGrid() +{ + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig1x1() +{ + KisConfig cfg; + cfg.setGridHSpacing(1); + cfg.setGridVSpacing(1); + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig2x2() +{ + KisConfig cfg; + cfg.setGridHSpacing(2); + cfg.setGridVSpacing(2); + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig5x5() +{ + KisConfig cfg; + cfg.setGridHSpacing(5); + cfg.setGridVSpacing(5); + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig10x10() +{ + KisConfig cfg; + cfg.setGridHSpacing(10); + cfg.setGridVSpacing(10); + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig20x20() +{ + KisConfig cfg; + cfg.setGridHSpacing(20); + cfg.setGridVSpacing(20); + m_view->updateCanvas(); +} + +void KisGridManager::fastConfig40x40() +{ + KisConfig cfg; + cfg.setGridHSpacing(40); + cfg.setGridVSpacing(40); + m_view->updateCanvas(); +} + +void KisGridManager::drawGrid(TQRect wr, TQPainter *p, bool openGL) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + if (image) { + if (m_toggleGrid->isChecked()) + { + GridDrawer *gridDrawer = 0; + + if (openGL) { + gridDrawer = new OpenGLGridDrawer(); + } else { + Q_ASSERT(p); + + if (p) { + gridDrawer = new TQPainterGridDrawer(p); + } + } + + Q_ASSERT(gridDrawer != 0); + + if (gridDrawer) { + gridDrawer->drawGrid(image, wr); + delete gridDrawer; + } + } + } +} + +#include "kis_grid_manager.moc" diff --git a/chalk/ui/kis_grid_manager.h b/chalk/ui/kis_grid_manager.h new file mode 100644 index 00000000..f4708ef0 --- /dev/null +++ b/chalk/ui/kis_grid_manager.h @@ -0,0 +1,65 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_GRID_MANAGER_H +#define KIS_GRID_MANAGER_H + +#include + +#include "kis_types.h" + +class KisView; +class KActionCollection; +class KToggleAction; +class KAction; + +class KisGridManager : public TQObject +{ + Q_OBJECT + TQ_OBJECT + public: + KisGridManager(KisView * tqparent); + ~KisGridManager(); + public: + void setup(KActionCollection * collection); + void drawGrid(TQRect wr, TQPainter *p, bool openGL = false); + public slots: + void updateGUI(); + private slots: + void toggleGrid(); + void fastConfig1x1(); + void fastConfig2x2(); + void fastConfig5x5(); + void fastConfig10x10(); + void fastConfig20x20(); + void fastConfig40x40(); + private: + KisView* m_view; + KToggleAction* m_toggleGrid; + KAction* m_gridConfig; + KAction* m_gridFastConfig1x1; + KAction* m_gridFastConfig2x2; + KAction* m_gridFastConfig5x5; + KAction* m_gridFastConfig10x10; + KAction* m_gridFastConfig20x20; + KAction* m_gridFastConfig40x40; +}; + +#endif diff --git a/chalk/ui/kis_histogram_view.cc b/chalk/ui/kis_histogram_view.cc new file mode 100644 index 00000000..cc4fe59c --- /dev/null +++ b/chalk/ui/kis_histogram_view.cc @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_channelinfo.h" +#include "kis_histogram.h" +#include "kis_global.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_colorspace.h" +#include "kis_histogram_view.h" +#include "kis_basic_histogram_producers.h" +#include "kis_paint_device.h" + +KisHistogramView::KisHistogramView(TQWidget *tqparent, const char *name, WFlags f) + : TQLabel(tqparent, name, f) +{ + // This is needed until we can computationally scale it well. Until then, this is needed + // And when we have it, it won't hurt to have it around + setScaledContents(true); + setFrameShape(TQFrame::Box); // Draw a box around ourselves +} + +KisHistogramView::~KisHistogramView() +{ +} + +void KisHistogramView::setPaintDevice(KisPaintDeviceSP dev) +{ + m_cs = dev->colorSpace(); + + setChannels(); // Sets m_currentProducer to the first in the list + + if (!m_currentProducer) + return; + + m_from = m_currentProducer->viewFrom(); + m_width = m_currentProducer->viewWidth(); + + m_histogram = new KisHistogram(dev, m_currentProducer, LINEAR); + + updateHistogram(); +} + +void KisHistogramView::setHistogram(KisHistogramSP histogram) +{ + m_cs = 0; + m_histogram = histogram; + m_currentProducer = m_histogram->producer(); + m_from = m_currentProducer->viewFrom(); + m_width = m_currentProducer->viewWidth(); + + m_comboInfo.clear(); + m_channelStrings.clear(); + m_channels.clear(); + m_channelToOffset.clear(); + + addProducerChannels(m_currentProducer); + + // Set the currently viewed channel: + m_color = false; + m_channels.append(m_comboInfo.at(1).channel); + m_channelToOffset.append(0); + + updateHistogram(); +} + +void KisHistogramView::setView(double from, double size) +{ + m_from = from; + m_width = size; + if (m_from + m_width > 1.0) + m_from = 1.0 - m_width; + m_histogram->producer()->setView(m_from, m_width); + + m_histogram->updateHistogram(); + updateHistogram(); +} + +KisHistogramProducerSP KisHistogramView::currentProducer() +{ + return m_currentProducer; +} + +TQStringList KisHistogramView::channelStrings() +{ + return m_channelStrings; +} + +KisIDList KisHistogramView::listProducers() +{ + if (m_cs) + return KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs); + return KisIDList(); +} + +void KisHistogramView::setCurrentChannels(const KisID& producerID, TQValueVector channels) +{ + setCurrentChannels( + KisHistogramProducerFactoryRegistry::instance()->get(producerID)->generate(), + channels); +} + +void KisHistogramView::setCurrentChannels(KisHistogramProducerSP producer, TQValueVector channels) +{ + m_currentProducer = producer; + m_currentProducer->setView(m_from, m_width); + m_histogram->setProducer(m_currentProducer); + m_histogram->updateHistogram(); + m_histogram->setChannel(0); // Set a default channel, just being nice + + m_channels.clear(); + m_channelToOffset.clear(); + + if (channels.count() == 0) { + updateHistogram(); + return; + } + + TQValueVector producerChannels = m_currentProducer->channels(); + + for (uint i = 0; i < channels.count(); i++) { + // Also makes sure the channel is actually in the producer's list + for (uint j = 0; j < producerChannels.count(); j++) { + if (channels.at(i)->name() == producerChannels.at(j)->name()) { + m_channelToOffset.append(m_channels.count()); // The first we append maps to 0 + m_channels.append(channels.at(i)); + } + } + } + + updateHistogram(); +} + +bool KisHistogramView::hasColor() +{ + return m_color; +} + +void KisHistogramView::setColor(bool set) +{ + if (set != m_color) { + m_color = set; + updateHistogram(); + } +} + +void KisHistogramView::setActiveChannel(int channel) +{ + ComboboxInfo info = m_comboInfo.at(channel); + if (info.producer.data() != m_currentProducer.data()) { + m_currentProducer = info.producer; + m_currentProducer->setView(m_from, m_width); + m_histogram->setProducer(m_currentProducer); + m_histogram->updateHistogram(); + } + + m_channels.clear(); + m_channelToOffset.clear(); + + if (!m_currentProducer) { + updateHistogram(); + return; + } + + if (info.isProducer) { + m_color = true; + m_channels = m_currentProducer->channels(); + for (uint i = 0; i < m_channels.count(); i++) + m_channelToOffset.append(i); + m_histogram->setChannel(0); // Set a default channel, just being nice + } else { + m_color = false; + TQValueVector channels = m_currentProducer->channels(); + for (uint i = 0; i < channels.count(); i++) { + KisChannelInfo* channel = channels.at(i); + if (channel->name() == info.channel->name()) { + m_channels.append(channel); + m_channelToOffset.append(i); + break; + } + } + } + + updateHistogram(); +} + +void KisHistogramView::setHistogramType(enumHistogramType type) +{ + m_histogram->setHistogramType(type); + updateHistogram(); +} + +void KisHistogramView::setChannels() +{ + m_comboInfo.clear(); + m_channelStrings.clear(); + m_channels.clear(); + m_channelToOffset.clear(); + + KisIDList list = KisHistogramProducerFactoryRegistry::instance()->listKeysCompatibleWith(m_cs); + + if (list.count() == 0) { + // XXX: No native histogram for this colorspace. Using converted RGB. We should have a warning + KisGenericRGBHistogramProducerFactory f; + addProducerChannels(f.generate()); + } else { + for (uint i = 0; i < list.count(); i++) { + KisID id(*(list.at(i))); + addProducerChannels( KisHistogramProducerFactoryRegistry::instance()->get(id)->generate() ); + } + } + + m_currentProducer = m_comboInfo.at(0).producer; + m_color = false; + // The currently displayed channel and its offset + m_channels.append(m_comboInfo.at(1).channel); + m_channelToOffset.append(0); +} + +void KisHistogramView::addProducerChannels(KisHistogramProducerSP producer) { + ComboboxInfo info; + info.isProducer = true; + info.producer = producer; + // channel not used for a producer + TQValueVector channels = info.producer->channels(); + int count = channels.count(); + m_comboInfo.append(info); + m_channelStrings.append(producer->id() . name()); + for (int j = 0; j < count; j++) { + info.isProducer = false; + info.channel = channels.at(j); + m_comboInfo.append(info); + m_channelStrings.append(TQString(" ").append(info.channel->name())); + } +} + +void KisHistogramView::updateHistogram() +{ + TQ_UINT32 height = this->height(); + int selFrom, selTo; // from - to in bins + + if (!m_currentProducer) { // Something's very wrong: no producer for this colorspace to update histogram with! + return; + } + + TQ_INT32 bins = m_histogram->producer()->numberOfBins(); + m_pix = TQPixmap(bins, height); + m_pix.fill(); + TQPainter p(&m_pix); + p.setBrush(TQt::black); + + // Draw the box of the selection, if any + if (m_histogram->hasSelection()) { + double width = m_histogram->selectionTo() - m_histogram->selectionFrom(); + double factor = static_cast(bins) / m_histogram->producer()->viewWidth(); + selFrom = static_cast(m_histogram->selectionFrom() * factor); + selTo = selFrom + static_cast(width * factor); + p.drawRect(selFrom, 0, selTo - selFrom, height); + } else { + // We don't want the drawing to think we're in a selected area + selFrom = -1; + selTo = 2; + } + + TQ_INT32 i = 0; + double highest = 0; + bool blackOnBlack = false; + + // First we iterate once, so that we have the overall maximum. This is a bit inefficient, + // but not too much since the histogram caches the calculations + for (uint chan = 0; chan < m_channels.count(); chan++) { + m_histogram->setChannel(m_channelToOffset.at(chan)); + if ((double)m_histogram->calculations().getHighest() > highest) + highest = (double)m_histogram->calculations().getHighest(); + } + + for (uint chan = 0; chan < m_channels.count(); chan++) { + TQColor color; + m_histogram->setChannel(m_channelToOffset.at(chan)); + + if (m_color) { + color = m_channels.at(chan)->color(); + p.setPen(color); + } else { + color = TQt::black; + } + blackOnBlack = (color == TQt::black); + + if (m_histogram->getHistogramType() == LINEAR) { + double factor = (double)height / highest; + for( i=0; i= selFrom && i < selTo && blackOnBlack) { + p.setPen(TQt::white); + } else { + p.setPen(color); + } + p.drawLine(i, height, i, height - int(m_histogram->getValue(i) * factor)); + } + } else { + double factor = (double)height / (double)log(highest); + for( i = 0; i < bins; ++i ) { + // Same as above + if (i >= selFrom && i < selTo && blackOnBlack) { + p.setPen(TQt::white); + } else { + p.setPen(color); + } + p.drawLine(i, height, i, + height - int(log((double)m_histogram->getValue(i)) * factor)); + } + } + } + + setPixmap(m_pix); +} + +void KisHistogramView::mousePressEvent(TQMouseEvent * e) { + if (e->button() == Qt::RightButton) + emit rightClicked(e->globalPos()); + else + TQLabel::mousePressEvent(e); +} + + +#include "kis_histogram_view.moc" diff --git a/chalk/ui/kis_histogram_view.h b/chalk/ui/kis_histogram_view.h new file mode 100644 index 00000000..6b4524a8 --- /dev/null +++ b/chalk/ui/kis_histogram_view.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_HISTOGRAM_VIEW_ +#define _KIS_HISTOGRAM_VIEW_ + +#include +#include +#include +#include + +#include "kis_types.h" +#include "kis_histogram_producer.h" +#include "kis_histogram.h" + +class KisChannelInfo; + +/** + * This class displays a histogram. It has a list of channels it can select. The easy + * way is to display channelStrings() to the user, and then use a setActiveChannel + * with the integer the same as the one the selected string in that stringlist has. + * If the selected one is a producer, the histogram will automatically display all its + * channels, and color them if that is possible. + * + * You can also set the channels manually, just don't forget that the displayed channels + * all need to belong to the same producer! If you set them manually, don't forget to set + * the (non)usage of color as well. + * + * You can either set this to use a specific layer, or use a specific histogram. With the latter, + * some functionality will disappear, like listProducers(). Setting a histogram will discard + * info on the layer, and setting a layer will discard info on the histogram. + **/ +class KisHistogramView : public TQLabel { + Q_OBJECT + TQ_OBJECT +public: + KisHistogramView(TQWidget *tqparent = 0, const char *name = 0, WFlags f = 0); + virtual ~KisHistogramView(); + + void setPaintDevice(KisPaintDeviceSP dev); + void setHistogram(KisHistogramSP histogram); + void setView(double from, double size); + KisHistogramProducerSP currentProducer(); + TQStringList channelStrings(); + /** Lists all producers currently available */ + KisIDList listProducers(); + /** Sets the currently displayed channels to channels of the producer with producerID as ID*/ + void setCurrentChannels(const KisID& producerID, TQValueVector channels); + /** Be careful, producer will be modified */ + void setCurrentChannels(KisHistogramProducerSP producer, TQValueVector channels); + bool hasColor(); + void setColor(bool set); + +public slots: + void setActiveChannel(int channel); + void setHistogramType(enumHistogramType type); + void updateHistogram(); + +signals: + void rightClicked(const TQPoint& pos); + +protected: + virtual void mousePressEvent(TQMouseEvent * e); + +private: + void setChannels(); + void addProducerChannels(KisHistogramProducerSP producer); + + typedef struct { + bool isProducer; + KisHistogramProducerSP producer; + KisChannelInfo * channel; + } ComboboxInfo; + + TQValueVector m_comboInfo; + TQPixmap m_pix; + KisHistogramSP m_histogram; + KisColorSpace* m_cs; + KisHistogramProducerSP m_currentProducer; + TQValueVector m_channels; + // Maps the channels in m_channels to a real channel offset in the producer->channels() + TQValueVector m_channelToOffset; + TQStringList m_channelStrings; + bool m_color; + double m_from; + double m_width; +}; + +#endif // _KIS_HISTOGRAM_VIEW_ diff --git a/chalk/ui/kis_icon_item.cc b/chalk/ui/kis_icon_item.cc new file mode 100644 index 00000000..339017fc --- /dev/null +++ b/chalk/ui/kis_icon_item.cc @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + +#include "kis_resource.h" +#include "kis_global.h" +#include "kis_icon_item.h" + +#define THUMB_SIZE 30 + +KisIconItem::KisIconItem(KisResource *resource) +{ + m_resource = resource; + validPixmap = false; + validThumb = false; + updatePixmaps(); +} + +KisIconItem::~KisIconItem() +{ +} + +void KisIconItem::updatePixmaps() +{ + validPixmap = false; + validThumb = false; + + if (m_resource && m_resource->valid()) { + TQImage img = m_resource->img(); + + if (img.isNull()) { + m_resource->setValid(false); + m_resource = 0; + return; + } + + if (img.width() > THUMB_SIZE || img.height() > THUMB_SIZE) { + TQImage thumb = img; + TQ_INT32 xsize = THUMB_SIZE; + TQ_INT32 ysize = THUMB_SIZE; + TQ_INT32 picW = thumb.width(); + TQ_INT32 picH = thumb.height(); + + if (picW > picH) { + float yFactor = (float)((float)(float)picH / (float)picW); + + ysize = (TQ_INT32)(yFactor * (float)THUMB_SIZE); + + if (ysize > THUMB_SIZE) + ysize = THUMB_SIZE; + } else if (picW < picH) { + float xFactor = (float)((float)picW / (float)picH); + + xsize = (TQ_INT32)(xFactor * (float)THUMB_SIZE); + + if (xsize > THUMB_SIZE) + xsize = THUMB_SIZE; + } + + thumb = thumb.smoothScale(xsize, ysize); + + if (!thumb.isNull()) { + m_thumb = TQPixmap(thumb); + validThumb = !m_thumb.isNull(); + } + } + + img = img.convertDepth(32); + m_pixmap = TQPixmap(img); + validPixmap = true; + } +} + +TQPixmap& KisIconItem::pixmap() const +{ + return const_cast(m_pixmap); +} + +TQPixmap& KisIconItem::thumbPixmap() const +{ + return const_cast(m_thumb); +} + +KisResource *KisIconItem::resource() const +{ + return m_resource; +} + +int KisIconItem::compare(const KoIconItem *o) const +{ + const KisIconItem *other = dynamic_cast(o); + + if (other != 0) { + return m_resource->name().localeAwareCompare(other->m_resource->name()); + } else { + return 0; + } +} + diff --git a/chalk/ui/kis_icon_item.h b/chalk/ui/kis_icon_item.h new file mode 100644 index 00000000..9e8f1b09 --- /dev/null +++ b/chalk/ui/kis_icon_item.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + +class KisResource; + +class KisIconItem : public KoIconItem { + +public: + KisIconItem(KisResource *resource); + virtual ~KisIconItem(); + + virtual TQPixmap& pixmap() const; + virtual TQPixmap& thumbPixmap() const; + + KisResource *resource() const; + + virtual int compare(const KoIconItem *other) const; + + void updatePixmaps(); + +private: + KisResource *m_resource; + TQPixmap m_pixmap; + TQPixmap m_thumb; +}; + +#endif // KIS_ICON_ITEM_H_ + diff --git a/chalk/ui/kis_iconwidget.cc b/chalk/ui/kis_iconwidget.cc new file mode 100644 index 00000000..3e9ce4f1 --- /dev/null +++ b/chalk/ui/kis_iconwidget.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include "kis_iconwidget.h" + +KisIconWidget::KisIconWidget(TQWidget *tqparent, const char *name) : super(tqparent, name) +{ + m_item = 0; +} + +void KisIconWidget::slotSetItem(KoIconItem& item) +{ + m_item = &item; + update(); +} + +void KisIconWidget::drawButtonLabel(TQPainter *p) +{ + if (m_item) { + const TQPixmap& pix = m_item->pixmap(); + TQ_INT32 x = 2; + TQ_INT32 y = 2; + TQ_INT32 pw = pix.width(); + TQ_INT32 ph = pix.height(); + TQ_INT32 cw = width(); + TQ_INT32 ch = height(); + TQ_INT32 itemWidth = 24; + TQ_INT32 itemHeight = 24; + + if (pw < itemWidth) + x = (cw - pw) / 2; + if (ph < itemHeight) + y = (cw - ph) / 2; + + if (!m_item->hasValidThumb() || (pw <= itemWidth && ph <= itemHeight)) { + p->drawPixmap(x, y, pix, 0, 0, itemWidth, itemHeight); + } else { + const TQPixmap& thumbpix = m_item->thumbPixmap(); + + x = 2; + y = 2; + pw = thumbpix.width(); + ph = thumbpix.height(); + cw = width(); + ch = height(); + + if (pw < itemWidth) + x = (cw - pw) / 2; + + if (ph < itemHeight) + y = (cw - ph) / 2; + + p->drawPixmap(x, y, thumbpix, 0, 0, itemWidth, itemHeight); + } + + p->setPen(gray); + p->drawRect(0, 0, cw + 1, ch + 1); + } +} + +#include "kis_iconwidget.moc" + diff --git a/chalk/ui/kis_iconwidget.h b/chalk/ui/kis_iconwidget.h new file mode 100644 index 00000000..d65cbcbd --- /dev/null +++ b/chalk/ui/kis_iconwidget.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_ICONWIDGET_H_ +#define KIS_ICONWIDGET_H_ + +#include + +class KoIconItem; + +class KisIconWidget : public TQToolButton { + typedef TQToolButton super; + Q_OBJECT + TQ_OBJECT + +/** + * The icon widget is used in the control box where the current color and brush + * are shown. + */ +public: + KisIconWidget(TQWidget *tqparent = 0, const char *name = 0); + +public slots: + void slotSetItem(KoIconItem& item); + +protected: + virtual void drawButtonLabel(TQPainter *gc); + +private: + KoIconItem *m_item; +}; + +#endif // KIS_ICONWIDGET_H_ + diff --git a/chalk/ui/kis_import_catcher.cc b/chalk/ui/kis_import_catcher.cc new file mode 100644 index 00000000..b2d04cab --- /dev/null +++ b/chalk/ui/kis_import_catcher.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "kis_import_catcher.h" +#include "kis_types.h" + +#include "kis_view.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_group_layer.h" + +KisImportCatcher::KisImportCatcher(KURL url, KisImageSP image) + : TQObject() + , m_doc( new KisDoc() ) + , m_image( image ) + , m_url( url ) +{ + m_doc->openURL(url); + if ( !m_doc->isLoading() ) { + slotLoadingFinished(); + } + else { + connect(m_doc, TQT_SIGNAL(loadingFinished()), this, TQT_SLOT(slotLoadingFinished())); + } +} + +void KisImportCatcher::slotLoadingFinished() +{ + KisImageSP importedImage = m_doc->currentImage(); + + if (importedImage) { + KisLayerSP importedImageLayer = importedImage->rootLayer().data(); + + if (importedImageLayer != 0) { + + if (importedImageLayer->numLayers() == 2) { + // Don't import the root if this is not a layered image (1 group layer + // plus 1 other). + importedImageLayer = importedImageLayer->firstChild(); + importedImageLayer->tqparent()->removeLayer(importedImageLayer); + } + + importedImageLayer->setName(m_url.prettyURL()); + + KisGroupLayerSP tqparent = 0; + KisLayerSP currentActiveLayer = m_image->activeLayer(); + + if (currentActiveLayer) { + tqparent = currentActiveLayer->tqparent(); + } + + if (tqparent == 0) { + tqparent = m_image->rootLayer(); + } + + m_image->addLayer(importedImageLayer.data(), tqparent, currentActiveLayer); + } + } + m_doc->deleteLater(); + deleteLater(); +} + + diff --git a/chalk/ui/kis_import_catcher.h b/chalk/ui/kis_import_catcher.h new file mode 100644 index 00000000..6f6923e1 --- /dev/null +++ b/chalk/ui/kis_import_catcher.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_IMPORT_CATCHER_H_ +#define KIS_IMPORT_CATCHER_H_ + +#include + +#include + +#include + +class KisView; +class KisDoc; + +/** + * This small helper class takes an url and an image; tries to import + * the image at the url and shove the layers of the imported image + * into the first image after loading is done. + * + * Caveat: this class calls "delete this", which means that you new + * it and then never touch it again. Thanks you very much. + */ +class KisImportCatcher : TQObject { + + Q_OBJECT + TQ_OBJECT + +public: + + KisImportCatcher(KURL url, KisImageSP image); + +public slots: + + void slotLoadingFinished(); + +private: + KisDoc * m_doc; + KisImage * m_image; + KURL m_url; +}; + +#endif diff --git a/chalk/ui/kis_input_device.cc b/chalk/ui/kis_input_device.cc new file mode 100644 index 00000000..0923c727 --- /dev/null +++ b/chalk/ui/kis_input_device.cc @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_input_device.h" + +#define UNKNOWN_INPUT_DEVICE_ID -1 +#define FIRST_INPUT_DEVICE_ID 0 + +TQ_INT32 KisInputDevice::NextInputDeviceID = FIRST_INPUT_DEVICE_ID; + +KisInputDevice KisInputDevice::Mouse; +KisInputDevice KisInputDevice::Stylus; +KisInputDevice KisInputDevice::Eraser; +KisInputDevice KisInputDevice::Puck; +KisInputDevice KisInputDevice::Unknown(UNKNOWN_INPUT_DEVICE_ID); + +TQValueVector KisInputDevice::InputDevices; + +KisInputDevice::KisInputDevice() +{ + m_id = UNKNOWN_INPUT_DEVICE_ID; +} + +KisInputDevice KisInputDevice::allocateNextDevice() +{ + KisInputDevice inputDevice(NextInputDeviceID); + NextInputDeviceID++; + InputDevices.append(inputDevice); + + return inputDevice; +} + +KisInputDevice KisInputDevice::allocateInputDevice() +{ + allocateDefaultDevicesIfNeeded(); + + return allocateNextDevice(); +} + +void KisInputDevice::allocateDefaultDevicesIfNeeded() +{ + if (NextInputDeviceID == FIRST_INPUT_DEVICE_ID) { + Mouse = allocateNextDevice(); + Stylus = allocateNextDevice(); + Eraser = allocateNextDevice(); + Puck = allocateNextDevice(); + } +} + +TQValueVector KisInputDevice::inputDevices() +{ + allocateDefaultDevicesIfNeeded(); + + return InputDevices; +} + +KisInputDevice KisInputDevice::mouse() +{ + allocateDefaultDevicesIfNeeded(); + return Mouse; +} + +KisInputDevice KisInputDevice::stylus() +{ + allocateDefaultDevicesIfNeeded(); + return Stylus; +} + +KisInputDevice KisInputDevice::eraser() +{ + allocateDefaultDevicesIfNeeded(); + return Eraser; +} + +KisInputDevice KisInputDevice::puck() +{ + allocateDefaultDevicesIfNeeded(); + return Puck; +} + +KisInputDevice KisInputDevice::unknown() +{ + allocateDefaultDevicesIfNeeded(); + return Unknown; +} + diff --git a/chalk/ui/kis_input_device.h b/chalk/ui/kis_input_device.h new file mode 100644 index 00000000..d85d4e3f --- /dev/null +++ b/chalk/ui/kis_input_device.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_INPUT_DEVICE_H_ +#define KIS_INPUT_DEVICE_H_ + +#include + +class KisInputDevice { +public: + KisInputDevice(); + + static KisInputDevice allocateInputDevice(); + static TQValueVector inputDevices(); + + friend inline bool operator==(const KisInputDevice&, const KisInputDevice&); + friend inline bool operator!=(const KisInputDevice&, const KisInputDevice&); + + friend inline bool operator<(const KisInputDevice &, const KisInputDevice &); + friend inline bool operator>(const KisInputDevice &, const KisInputDevice &); + + static KisInputDevice mouse(); // Standard mouse + static KisInputDevice stylus(); // Wacom stylus via TQTabletEvent + static KisInputDevice eraser(); // Wacom eraser via TQTabletEvent + static KisInputDevice puck(); // Wacom puck via TQTabletEvent + static KisInputDevice unknown(); + +private: + KisInputDevice(TQ_INT32 id) : m_id(id) {} + + TQ_INT32 id() const { return m_id; } + + static void allocateDefaultDevicesIfNeeded(); + static KisInputDevice allocateNextDevice(); + +private: + TQ_INT32 m_id; + + static TQ_INT32 NextInputDeviceID; + static TQValueVector InputDevices; + + static KisInputDevice Mouse; + static KisInputDevice Stylus; + static KisInputDevice Eraser; + static KisInputDevice Puck; + static KisInputDevice Unknown; +}; + +inline bool operator==(const KisInputDevice &a, const KisInputDevice &b) +{ + return a.id() == b.id(); +} + +inline bool operator!=(const KisInputDevice &a, const KisInputDevice &b) +{ + return a.id() != b.id(); +} + +inline bool operator<(const KisInputDevice &a, const KisInputDevice &b) +{ + return a.id() < b.id(); +} + + +inline bool operator>(const KisInputDevice &a, const KisInputDevice &b) +{ + return a.id() > b.id(); +} + +#endif // KIS_INPUT_DEVICE_H_ + diff --git a/chalk/ui/kis_int_spinbox.cc b/chalk/ui/kis_int_spinbox.cc new file mode 100644 index 00000000..8dc0e68d --- /dev/null +++ b/chalk/ui/kis_int_spinbox.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2006 Casper Boemann + * + * Requires the TQt widget libraries, available at no cost at + * http://www.troll.no/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_LIMITS_H +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kdialog.h" +#include "knumvalidator.h" +#include "kis_int_spinbox.h" + +class KisIntSpinbox::KisIntSpinboxPrivate { +public: + + KIntSpinBox * m_numinput; + KisPopupSlider *m_slider; + KArrowButton *m_arrow; + int m_prevValue; + TQValidator *m_validator; + TQTimer m_timer; +}; + + +KisIntSpinbox::KisIntSpinbox(TQWidget *tqparent, const char *name) + : TQWidget(tqparent, name) +{ + init(0); +} + +KisIntSpinbox::KisIntSpinbox(const TQString & /*label*/, int val, TQWidget *tqparent, const char *name) + : TQWidget(tqparent, name) +{ + init(val); +} + +void KisIntSpinbox::init(int val) +{ + d = new KisIntSpinboxPrivate( ); + TQBoxLayout * l = new TQHBoxLayout( this ); + + l->insertStretch(0, 1); + d->m_numinput = new KIntSpinBox(0, 100, 1, val, 10, this, "KisIntSpinbox::KIntSpinBox"); + + d->m_numinput->tqsetSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed); + d->m_numinput->setSuffix("%"); + l->addWidget( d->m_numinput ); + + d->m_slider = new KisPopupSlider(0, 100, 10, val, Qt::Horizontal, this); + d->m_slider->setFrameStyle(TQFrame::Panel|TQFrame::Raised); + + d->m_arrow = new KArrowButton(this, Qt::DownArrow); + d->m_arrow->setPopup(d->m_slider); + d->m_arrow->setMaximumHeight( fontMetrics().height() + 4); + d->m_arrow->setEnabled(true); // Why is the arrow still gray? + + l->addWidget( d->m_arrow ); + + d->m_prevValue = val; + setValue(val); + setFocusProxy(d->m_numinput); + tqlayout(); + + connect(d->m_numinput, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(spinboxValueChanged(int))); + connect(d->m_slider, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(sliderValueChanged(int))); + connect(d->m_slider, TQT_SIGNAL(aboutToShow()), TQT_SLOT(slotAboutToShow())); + connect(d->m_slider, TQT_SIGNAL(aboutToHide()), TQT_SLOT(slotAboutToHide())); + + connect(&(d->m_timer), TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTimeout())); +} + +void KisIntSpinbox::spinboxValueChanged(int val) +{ + setValue(val); + d->m_timer.start(300, true); + +} + +void KisIntSpinbox::sliderValueChanged(int val) +{ + setValue(val); + emit valueChanged(val); + emit valueChanged(val, true); +} + +void KisIntSpinbox::setRange(int lower, int upper, int /*step*/) +{ + upper = kMax(upper, lower); + lower = kMin(upper, lower); + d->m_slider->setRange(lower, upper); + + tqlayout(); +} + +void KisIntSpinbox::setMinValue(int min) +{ + setRange(min, maxValue(), d->m_slider->lineStep()); +} + +int KisIntSpinbox::minValue() const +{ + return d->m_slider->minValue(); +} + +void KisIntSpinbox::setMaxValue(int max) +{ + setRange(minValue(), max, d->m_slider->lineStep()); +} + +int KisIntSpinbox::maxValue() const +{ + return d->m_slider->maxValue(); +} + +KisIntSpinbox::~KisIntSpinbox() +{ + delete d; +} + +void KisIntSpinbox::setValue(int val) +{ + d->m_slider->blockSignals(true); + d->m_slider->setValue(val); + d->m_slider->blockSignals(false); + + d->m_numinput->blockSignals(true); + d->m_numinput->setValue(val); + d->m_numinput->blockSignals(false); +} + +int KisIntSpinbox::value() const +{ + return d->m_numinput->value(); // From the numinput: that one isn't in steps of ten +} + +void KisIntSpinbox::setLabel(const TQString & /*label*/) +{ +} + +void KisIntSpinbox::slotAboutToShow() +{ + d->m_prevValue = value(); +} + +void KisIntSpinbox::slotAboutToHide() +{ + if( d->m_prevValue != value() ) + { + emit finishedChanging( d->m_prevValue, value() ); + d->m_prevValue = value(); + } +} + +void KisIntSpinbox::slotTimeout() +{ + emit valueChanged(value()); + emit valueChanged(value(), true); +} +#include "kis_int_spinbox.moc" diff --git a/chalk/ui/kis_int_spinbox.h b/chalk/ui/kis_int_spinbox.h new file mode 100644 index 00000000..a5c4602e --- /dev/null +++ b/chalk/ui/kis_int_spinbox.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2006 Boudewijn Rempt + * Copyright (c) 2006 Casper Boemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_INT_SPINBOX_H_ +#define KIS_INT_SPINBOX_H_ + +#include +#include +#include +#include + +#include + +class TQLabel; +class TQLineEdit; +class TQLayout; +class TQValidator; + +class KisPopupSlider : public TQPopupMenu { + Q_OBJECT + TQ_OBJECT + +public: + + KisPopupSlider(int minValue, int maxValue, int pageStep, int value, Qt::Orientation orientation, TQWidget * tqparent, const char * name = 0) + : TQPopupMenu(tqparent, name) + { + m_slider = new TQSlider(minValue, maxValue, pageStep, value, orientation, this, name); + //m_slider->setTracking(false); + insertItem(m_slider); + connect(m_slider, TQT_SIGNAL(valueChanged(int)), TQT_SIGNAL(valueChanged(int))); + } + void setTickInterval(int i) { m_slider->setTickInterval(i); } + void setRange(int minValue, int maxValue) { m_slider->setRange(minValue, maxValue); } + void setValue(int val) { m_slider->setValue(val); } + void setTickmarks(TQSlider::TickSetting t) { m_slider->setTickmarks(t); } + int lineStep () const{ return m_slider->lineStep(); } + int minValue () const{ return m_slider->minValue(); } + int maxValue () const{ return m_slider->maxValue(); } + int value () const{ return m_slider->value(); } + TQSlider *m_slider; + +signals: + void valueChanged(int); + +}; + +/** + * @short An input widget for integer numbers, consisting of a spinbox and + * a dropdown slider. + * + * KisIntSpinbox combines a TQSpinBox and a dropdown TQSlider + * to make an easy to use control for setting some integer + * parameter. + * + * + */ +class KisIntSpinbox : public TQWidget +{ + + Q_OBJECT + TQ_OBJECT + TQ_PROPERTY( int value READ value WRITE setValue ) + TQ_PROPERTY( int minValue READ minValue WRITE setMinValue ) + TQ_PROPERTY( int maxValue READ maxValue WRITE setMaxValue ) + +public: + + /** + * Constructs an input control for integer values + * with base 10 and initial value 0. + * + * @param tqparent tqparent TQWidget + * @param name internal name for this widget + */ + KisIntSpinbox(TQWidget *tqparent=0, const char *name=0); + /** + * Constructor + * It constructs a TQSpinBox that allows the input of integer numbers + * in the range of -INT_MAX to +INT_MAX. + * To enforce the value being in a range, use setRange(). + * + * @param label the tabel (may contain &, and my be empty) + * @param value initial value for the control + * @param tqparent tqparent TQWidget + * @param name internal name for this widget + */ + KisIntSpinbox(const TQString & label, int value, TQWidget* tqparent=0, const char *name=0); + + /** + * Destructor + * + * + */ + virtual ~KisIntSpinbox(); + + /** + * @return the current value. + */ + int value() const; + + /** + * @param min minimum value + * @param max maximum value + * @param step step size for the TQSlider + */ + void setRange(int min, int max, int step=1); + /** + * Sets the minimum value. + */ + void setMinValue(int min); + /** + * @return the minimum value. + */ + int minValue() const; + /** + * Sets the maximum value. + */ + void setMaxValue(int max); + /** + * @return the maximum value. + */ + int maxValue() const; + + /** + * Sets the spacing of tickmarks for the slider. + * + * @param minor Minor tickmark separation. + * @param major Major tickmark separation. + */ + void setSteps(int minor, int major); + + void setLabel(const TQString & label); + +public slots: + /** + * Sets the value of the control. + */ + void setValue(int); + + + void spinboxValueChanged(int val); + void sliderValueChanged(int val); + + void slotTimeout(); + +signals: + + /** + * Emitted every time the value changes (by calling setValue() or + * by user interaction). + * @param value the new opacity + */ + void valueChanged(int value); + + /** + * Emitted every time the value changes (by calling setValue() or + * by user interaction). + * @param value the new opacity + * @param withSlider whether the value was set by dragging the slider + */ + void valueChanged(int value, bool withSlider); + + /** + * Emitted after the slider has been hidden, if the value was changed while it was shown. + * @param previous the value before the slider was shown + * @param value the value after the slider was hidden + */ + void finishedChanging(int previous, int value); + +private slots: + void slotAboutToShow(); + void slotAboutToHide(); + +private: + void init(int val); + +private: + + class KisIntSpinboxPrivate; + KisIntSpinboxPrivate *d; +}; + +#endif diff --git a/chalk/ui/kis_itemchooser.cc b/chalk/ui/kis_itemchooser.cc new file mode 100644 index 00000000..d418bd2f --- /dev/null +++ b/chalk/ui/kis_itemchooser.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include "kis_itemchooser.h" +#include "kis_global.h" +#include "kis_icon_item.h" + +KisItemChooser::KisItemChooser(TQWidget *tqparent, const char *name) : super(tqparent, name) +{ +/* m_frame = new TQVBox(this); + m_frame->setFrameStyle(TQFrame::Panel | TQFrame::Sunken);*/ + m_chooser = new KoIconChooser(TQSize(30,30), this, "icon_chooser", true); + TQObject::connect(m_chooser, TQT_SIGNAL(selected(KoIconItem*)), this, TQT_SLOT(slotItemSelected(KoIconItem*))); +} + +KisItemChooser::~KisItemChooser() +{ +} + +void KisItemChooser::setCurrent(KoIconItem *item) +{ + m_chooser->setCurrentItem(item); + update(item); +} + +void KisItemChooser::setCurrent(int index) +{ + setCurrent(m_chooser->itemAt(index)); +} + +KoIconItem* KisItemChooser::currentItem() +{ + return m_chooser->currentItem(); +} + +void KisItemChooser::slotItemSelected(KoIconItem *item) +{ + update(item); + emit selected(currentItem()); +} + +void KisItemChooser::addItem(KoIconItem *item) +{ + m_chooser->addItem(item); +} + +void KisItemChooser::addItems(const vKoIconItem& items) +{ + TQPtrListIterator itr(items); + + for (itr.toFirst(); itr.current(); ++itr) + m_chooser->addItem(itr.current()); +} + +TQWidget *KisItemChooser::chooserWidget() const +{ + return m_chooser; +} + +#include "kis_itemchooser.moc" + diff --git a/chalk/ui/kis_itemchooser.h b/chalk/ui/kis_itemchooser.h new file mode 100644 index 00000000..d29aa28d --- /dev/null +++ b/chalk/ui/kis_itemchooser.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2002 Patrick Julein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_ITEM_CHOOSER_H_ +#define KIS_ITEM_CHOOSER_H_ + +#include +#include + +class TQHBox; + +class KoIconChooser; +class KoIconItem; + +typedef TQPtrList vKoIconItem; + +class KisItemChooser : public TQWidget { + typedef TQWidget super; + Q_OBJECT + TQ_OBJECT + +public: + KisItemChooser(TQWidget *tqparent = 0, + const char *name = 0); + virtual ~KisItemChooser(); + + KoIconItem *currentItem(); + void setCurrent(KoIconItem *item); + void setCurrent(int index); + +public slots: + void addItem(KoIconItem *item); + void addItems(const vKoIconItem& items); + +signals: + void selected(KoIconItem *item); + +protected: + virtual void update(KoIconItem *item) = 0; + TQWidget *chooserWidget() const; + +private slots: + void slotItemSelected(KoIconItem *item); + +private: + TQHBox *m_frame; + KoIconChooser *m_chooser; +}; + +#endif // KIS_ITEM_CHOOSER_H_ + diff --git a/chalk/ui/kis_label_cursor_pos.cc b/chalk/ui/kis_label_cursor_pos.cc new file mode 100644 index 00000000..984df6dd --- /dev/null +++ b/chalk/ui/kis_label_cursor_pos.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kis_label_cursor_pos.h" +#include "kis_label_cursor_pos.moc" + +KisLabelCursorPos::KisLabelCursorPos(TQWidget *tqparent, const char *name, WFlags f) : super(tqparent, name, f) +{ + setText("0:0"); + m_doUpdates = true; + + //setMinimumSize( 200, tqparent->height() - 4); +} + +KisLabelCursorPos::~KisLabelCursorPos() +{ +} + +void KisLabelCursorPos::updatePos(TQ_INT32 xpos, TQ_INT32 ypos) +{ + if (m_doUpdates) { + TQString s; + + s.sprintf("%d:%d", xpos, ypos); + setText(s); + } +} + +void KisLabelCursorPos::enter() +{ + m_doUpdates = true; +} + +void KisLabelCursorPos::leave() +{ + m_doUpdates = false; + setText(TQString()); +} + diff --git a/chalk/ui/kis_label_cursor_pos.h b/chalk/ui/kis_label_cursor_pos.h new file mode 100644 index 00000000..392a0b68 --- /dev/null +++ b/chalk/ui/kis_label_cursor_pos.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_LABEL_CURSOR_POS_H_ +#define KIS_LABEL_CURSOR_POS_H_ + +#include + +class KisLabelCursorPos : public TQLabel { + Q_OBJECT + TQ_OBJECT + typedef TQLabel super; + +public: + KisLabelCursorPos(TQWidget *tqparent, const char *name = 0, WFlags f = 0); + virtual ~KisLabelCursorPos(); + +public slots: + void updatePos(TQ_INT32 xpos, TQ_INT32 ypos); + void enter(); + void leave(); + +private: + bool m_doUpdates; + TQ_INT32 m_ypos; +}; + +#endif // KIS_LABEL_CURSOR_POS_H_ + diff --git a/chalk/ui/kis_label_progress.cc b/chalk/ui/kis_label_progress.cc new file mode 100644 index 00000000..c04452f4 --- /dev/null +++ b/chalk/ui/kis_label_progress.cc @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2002 Patrick Julien + * 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_progress_subject.h" +#include "kis_label_progress.h" +#include "kis_cursor.h" + +class EscapeButton : public TQToolButton { + +public: + + EscapeButton(TQWidget * tqparent, const char * name) : TQToolButton(tqparent, name) {}; + + void keyReleaseEvent(TQKeyEvent *e) + { + if (e->key()==TQt::Key_Escape) + emit clicked(); + } +}; + +KisLabelProgress::KisLabelProgress(TQWidget *tqparent, const char *name, WFlags f) : super(tqparent, name, f) +{ + m_subject = 0; + m_modal = false; + + TQHBoxLayout *box = new TQHBoxLayout(this); + box->setAutoAdd(true); + + TQIconSet cancelIconSet = SmallIconSet("stop"); + + m_cancelButton = new EscapeButton(this, "cancel_button"); + m_cancelButton->setIconSet(cancelIconSet); + TQToolTip::add(m_cancelButton, i18n("Cancel")); + connect(m_cancelButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(cancelPressed())); + + m_bar = new KProgress(100, this); +} + +KisLabelProgress::~KisLabelProgress() +{ +} + +void KisLabelProgress::setSubject(KisProgressSubject *subject, bool modal, bool canCancel) +{ + reset(); + + if (subject) { + m_subject = subject; + m_modal = modal; + + connect(subject, TQT_SIGNAL(notifyProgress(int)), this, TQT_SLOT(update(int))); + connect(subject, TQT_SIGNAL(notifyProgressStage(const TQString&, int)), this, TQT_SLOT(updateStage(const TQString&, int))); + connect(subject, TQT_SIGNAL(notifyProgressDone()), this, TQT_SLOT(done())); + connect(subject, TQT_SIGNAL(notifyProgressError()), this, TQT_SLOT(error())); + connect(subject, TQT_SIGNAL(destroyed()), this, TQT_SLOT(subjectDestroyed())); + + show(); + + if (canCancel) { + if (modal) { + kdDebug() << "grabbing 1\n"; + m_cancelButton->grabMouse(); + m_cancelButton->grabKeyboard(); + } + } + else { + m_cancelButton->hide(); + + if (modal) { + // Only visible widgets can grab. + kdDebug() << "grabbing 2\n"; + grabMouse(); + grabKeyboard(); + } + } + + if (modal) { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + } + + m_bar->setValue(0); + } +} + +bool KisLabelProgress::event(TQEvent * e) +{ + + if (!e) return false; + + int type = e->type(); + + switch (type) { + case(KisProgress::ProgressEventBase + 1): + { + KisProgress::UpdateEvent * ue = dynamic_cast(e); + update(ue->m_percent); + break; + } + case(KisProgress::ProgressEventBase + 2): + { + KisProgress::UpdateStageEvent * use = dynamic_cast(e); + updateStage(use->m_stage, use->m_percent); + break; + } + case(KisProgress::ProgressEventBase + 3): + done(); + break; + case(KisProgress::ProgressEventBase + 4): + error(); + break; + case(KisProgress::ProgressEventBase + 5): + subjectDestroyed(); + break; + default: + return TQLabel::event(e); + }; + + return true; +} + +void KisLabelProgress::reset() +{ + if (m_subject) { + m_subject->disconnect(this); + m_subject = 0; + + if (m_modal) { + TQApplication::restoreOverrideCursor(); + } + + m_modal = false; + } + + releaseMouse(); + releaseKeyboard(); + m_cancelButton->releaseMouse(); + m_cancelButton->releaseKeyboard(); + hide(); +} + +void KisLabelProgress::update(int percent) +{ + m_bar->setValue(percent); + + KApplication *app = KApplication::kApplication(); + + app->processEvents(); + // The following is safer, but makes cancel impossible: + //TQApplication::eventLoop()->processEvents(TQEventLoop::ExcludeUserInput | + // TQEventLoop::ExcludeSocketNotifiers); +} + +void KisLabelProgress::updateStage(const TQString&, int percent) +{ + m_bar->setValue(percent); + + KApplication *app = KApplication::kApplication(); + Q_ASSERT(app); + + app->processEvents(); +} + +void KisLabelProgress::cancelPressed() +{ + if (m_subject) { + m_subject->cancel(); + reset(); + } +} + +void KisLabelProgress::subjectDestroyed() +{ + reset(); +} + +void KisLabelProgress::done() +{ + reset(); +} + +void KisLabelProgress::error() +{ + reset(); +} + +#include "kis_label_progress.moc" + diff --git a/chalk/ui/kis_label_progress.h b/chalk/ui/kis_label_progress.h new file mode 100644 index 00000000..a2c42fd9 --- /dev/null +++ b/chalk/ui/kis_label_progress.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2002 Patrick Julien + * 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_LABEL_PROGRESS_H_ +#define KIS_LABEL_PROGRESS_H_ + +#include +#include + +#include "kis_progress_display_interface.h" + +class TQToolButton; +class KProgress; + +class KisLabelProgress : public TQLabel, public KisProgressDisplayInterface { + Q_OBJECT + TQ_OBJECT + typedef TQLabel super; + +public: + KisLabelProgress(TQWidget *tqparent, const char *name = 0, WFlags f = 0); + virtual ~KisLabelProgress(); + +public: + // Implements KisProgressDisplayInterface + void setSubject(KisProgressSubject *subject, bool modal, bool canCancel); + + // Overrides TQLabel::event() + bool event(TQEvent * ev); + +private slots: + virtual void update(int percent); + virtual void updateStage(const TQString& stage, int percent); + virtual void done(); + virtual void error(); + virtual void subjectDestroyed(); + +private slots: + void cancelPressed(); + +private: + void reset(); + + KisProgressSubject *m_subject; + KProgress *m_bar; + TQToolButton *m_cancelButton; + bool m_modal; +}; + +#endif // KIS_LABEL_PROGRESS_H_ + diff --git a/chalk/ui/kis_label_zoom.cc b/chalk/ui/kis_label_zoom.cc new file mode 100644 index 00000000..cd8620d6 --- /dev/null +++ b/chalk/ui/kis_label_zoom.cc @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_label_zoom.h" +#include "kis_label_zoom.moc" + diff --git a/chalk/ui/kis_label_zoom.h b/chalk/ui/kis_label_zoom.h new file mode 100644 index 00000000..e7fad08a --- /dev/null +++ b/chalk/ui/kis_label_zoom.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_LABEL_ZOOM_H_ +#define KIS_LABEL_ZOOM_H_ + +#include + +class KisLabelZoom : public TQLabel { + Q_OBJECT + TQ_OBJECT + + KisLabelZoom( TQWidget *tqparent, const char *name = 0, WFlags f = 0 ) : + TQLabel( tqparent, name, f ) {} + virtual ~KisLabelZoom() {} + +}; + +#endif // KIS_LABEL_ZOOM_H_ + diff --git a/chalk/ui/kis_layerbox.cc b/chalk/ui/kis_layerbox.cc new file mode 100644 index 00000000..703fd3be --- /dev/null +++ b/chalk/ui/kis_layerbox.cc @@ -0,0 +1,675 @@ +/* + * kis_layerbox.cc - part of Chalk aka Krayon aka KimageShop + * + * Copyright (c) 2002 Patrick Julien + * Copyright (C) 2006 Gábor Lehel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_layerlist.h" +#include "kis_cmb_composite.h" +#include "kis_int_spinbox.h" +#include "wdglayerbox.h" +#include "kis_colorspace.h" +#include "kis_paint_device.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_image.h" + +#include "kis_populate_visitor.h" + +#include "kis_layerbox.h" + +KisLayerBox::KisLayerBox(KisCanvasSubject *subject, TQWidget *tqparent, const char *name) + : super(tqparent, name), m_image(0) +{ + TQVBoxLayout *vbox = new TQVBoxLayout(this); + vbox->setAutoAdd(true); + + m_lst = new WdgLayerBox(this); + setMinimumSize(m_lst->tqminimumSizeHint()); + + TQToolTip::add(m_lst->bnAdd, i18n("Create new layer")); + + TQToolTip::add(m_lst->bnDelete, i18n("Remove current layer")); + + TQToolTip::add(m_lst->bnRaise, i18n("Raise current layer")); + m_lst->bnRaise->setEnabled(false); + + m_lst->bnLower->setEnabled(false); + TQToolTip::add(m_lst->bnLower, i18n("Lower current layer")); + + TQToolTip::add(m_lst->bnProperties, i18n("Properties for layer")); + + KIconLoader il( "chalk" ); + + list()->setPreviewsShown(true); + + list()->setFoldersCanBeActive(true); + + list()->addProperty("visible", i18n("Visible"), loadPixmap("visible.png", il, KIcon::SizeSmallMedium), + loadPixmap("novisible.png", il, KIcon::SizeSmallMedium), true); + + list()->addProperty("locked", i18n("Locked"), loadPixmap("locked.png", il, KIcon::SizeSmallMedium), + loadPixmap("unlocked.png", il, KIcon::SizeSmallMedium)); + + + connect(list()->contextMenu(), TQT_SIGNAL(aboutToShow()), TQT_SLOT(slotAboutToShow())); + connect(list(), TQT_SIGNAL(activated(LayerItem*)), + TQT_SLOT(slotLayerActivated(LayerItem*))); + connect(list(), TQT_SIGNAL(displayNameChanged(LayerItem*, const TQString&)), + TQT_SLOT(slotLayerDisplayNameChanged(LayerItem*, const TQString&))); + connect(list(), TQT_SIGNAL(propertyChanged(LayerItem*, const TQString&, bool)), + TQT_SLOT(slotLayerPropertyChanged(LayerItem*, const TQString&, bool))); + connect(list(), TQT_SIGNAL(layerMoved(LayerItem*, LayerItem*, LayerItem*)), + TQT_SLOT(slotLayerMoved(LayerItem*, LayerItem*, LayerItem*))); + connect(list(), TQT_SIGNAL(requestNewLayer(LayerItem*, LayerItem*)), + TQT_SLOT(slotRequestNewLayer(LayerItem*, LayerItem*))); + connect(list(), TQT_SIGNAL(requestNewFolder(LayerItem*, LayerItem*)), + TQT_SLOT(slotRequestNewFolder(LayerItem*, LayerItem*))); + connect(list(), TQT_SIGNAL(requestNewAdjustmentLayer(LayerItem*, LayerItem*)), + TQT_SLOT(slotRequestNewAdjustmentLayer(LayerItem*, LayerItem*))); + connect(list(), TQT_SIGNAL(requestNewObjectLayer(LayerItem*, LayerItem*, const KoDocumentEntry&)), + TQT_SLOT(slotRequestNewObjectLayer(LayerItem*, LayerItem*, const KoDocumentEntry&))); + connect(list(), TQT_SIGNAL(requestRemoveLayer(LayerItem*)), + TQT_SLOT(slotRequestRemoveLayer(LayerItem*))); + connect(list(), TQT_SIGNAL(requestLayerProperties(LayerItem*)), + TQT_SLOT(slotRequestLayerProperties(LayerItem*))); + + m_newLayerMenu = new KPopupMenu(this); + m_lst->bnAdd->setPopup(m_newLayerMenu); + m_lst->bnAdd->setPopupDelay(1); + m_newLayerMenu->insertItem( SmallIconSet( "filenew" ), i18n( "&New Layer..." ), PAINT_LAYER ); + m_newLayerMenu->insertItem( SmallIconSet( "folder" ), i18n( "New &Group Layer..." ), GROUP_LAYER ); + m_newLayerMenu->insertItem( SmallIconSet( "tool_filter" ), i18n( "New &Adjustment Layer..." ), ADJUSTMENT_LAYER ); + m_partLayerAction = new KoPartSelectAction( i18n( "New &Object Layer" ), "gear", TQT_TQOBJECT(this) ); + m_partLayerAction->plug( m_newLayerMenu ); + connect(m_partLayerAction, TQT_SIGNAL(activated()), this, TQT_SLOT(slotAddMenuActivated())); + connect(m_newLayerMenu, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotAddMenuActivated(int))); + + + connect(m_lst->bnDelete, TQT_SIGNAL(clicked()), TQT_SLOT(slotRmClicked())); + connect(m_lst->bnRaise, TQT_SIGNAL(clicked()), TQT_SLOT(slotRaiseClicked())); + connect(m_lst->bnLower, TQT_SIGNAL(clicked()), TQT_SLOT(slotLowerClicked())); + connect(m_lst->bnProperties, TQT_SIGNAL(clicked()), TQT_SLOT(slotPropertiesClicked())); + connect(m_lst->intOpacity, TQT_SIGNAL(valueChanged(int, bool)), TQT_SIGNAL(sigOpacityChanged(int, bool))); + connect(m_lst->intOpacity, TQT_SIGNAL(finishedChanging(int, int)), TQT_SIGNAL(sigOpacityFinishedChanging(int, int))); + connect(m_lst->cmbComposite, TQT_SIGNAL(activated(const KisCompositeOp&)), TQT_SIGNAL(sigItemComposite(const KisCompositeOp&))); + + Q_ASSERT(subject->document() != 0); + + if (subject->document()) { + connect(subject->document(), TQT_SIGNAL(sigCommandExecuted()), TQT_SLOT(updateThumbnails())); + } +} + +KisLayerBox::~KisLayerBox() +{ +} + +KisLayerList* KisLayerBox::list() const +{ + return m_lst->listLayers; +} + +void KisLayerBox::setImage(KisImageSP img) +{ + if (m_image == img) + return; + + if (m_image) + m_image->disconnect(this); + + m_image = img; + + if (img) + { + connect(img, TQT_SIGNAL(sigLayerActivated(KisLayerSP)), this, TQT_SLOT(slotLayerActivated(KisLayerSP))); + connect(img, TQT_SIGNAL(sigLayerAdded(KisLayerSP)), this, TQT_SLOT(slotLayerAdded(KisLayerSP))); + connect(img, TQT_SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, TQT_SLOT(slotLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP))); + connect(img, TQT_SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), + this, TQT_SLOT(slotLayerPropertiesChanged(KisLayerSP))); + connect(img, TQT_SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), + this, TQT_SLOT(slotLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP))); + connect(img, TQT_SIGNAL(sigLayersChanged(KisGroupLayerSP)), this, TQT_SLOT(slotLayersChanged(KisGroupLayerSP))); + connect(img, TQT_SIGNAL(sigLayerUpdated(KisLayerSP, TQRect)), this, TQT_SLOT(slotLayerUpdated(KisLayerSP, TQRect))); + slotLayersChanged(img->rootLayer()); + updateThumbnails(); + } + else + { + clear(); + } +} + +void KisLayerBox::slotLayerActivated(KisLayerSP layer) +{ + if (layer) + list()->setActiveLayer(layer->id()); + else + list()->setActiveLayer(-1); + updateUI(); +} + +void KisLayerBox::slotLayerAdded(KisLayerSP layer) +{ + if (layer.data() == m_image->rootLayer().data() || list()->layer(layer->id())) + return; + + vKisLayerSP layersAdded; + + if (layer->tqparent() == m_image->rootLayer()) + { + KisPopulateVisitor visitor(list()); + layer->accept(visitor); + layersAdded = visitor.layersAdded(); + } + else + { + KisPopulateVisitor visitor(static_cast(list()->layer(layer->tqparent()->id()))); + layer->accept(visitor); + layersAdded = visitor.layersAdded(); + } + + for (vKisLayerSP::iterator it = layersAdded.begin(); it != layersAdded.end(); ++it) { + markModified(*it); + } + updateUI(); +} + +void KisLayerBox::slotLayerRemoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP) +{ + list()->removeLayer(layer->id()); + m_modified.remove(layer->id()); + markModified(wasParent); + updateUI(); +} + +void KisLayerBox::slotLayerMoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP) +{ + int tqparentID = layer->tqparent()->id(); + if (layer->tqparent() == m_image->rootLayer()) + tqparentID = -1; + + int siblingID = -1; + if (layer->prevSibling()) + siblingID = layer->prevSibling()->id(); + + list()->moveLayer(layer->id(), tqparentID, siblingID); + + markModified(layer->tqparent()); + markModified(wasParent); + updateUI(); +} + +void KisLayerBox::slotLayerPropertiesChanged(KisLayerSP layer) +{ + if (KisLayerItem* item = dynamic_cast(list()->layer(layer->id()))) + { + Q_ASSERT(item->layer() == layer.data()); + item->sync(); + updateUI(); + markModified(layer); + } +} + +void KisLayerBox::slotLayersChanged(KisGroupLayerSP rootLayer) +{ + list()->clear(); + KisPopulateVisitor visitor(list()); + for (KisLayerSP layer = rootLayer->firstChild(); layer; layer = layer->nextSibling()) + layer->accept(visitor); + m_modified.clear(); + for (TQListViewItemIterator it(list()->lastItem()); *it; --it) + m_modified.append(static_cast(*it)->id()); + updateUI(); +} + +void KisLayerBox::slotLayerUpdated(KisLayerSP layer, TQRect) +{ + markModified(layer); +} + +void KisLayerBox::slotLayerActivated(LayerItem* item) +{ + if (item) + m_image->activate(m_image->findLayer(item->id())); + else + m_image->activate(0); + updateUI(); +} + +void KisLayerBox::slotLayerDisplayNameChanged(LayerItem* item, const TQString& displayName) +{ + if(KisLayerSP layer = m_image->findLayer(item->id())) + layer->setName(displayName); + updateUI(); +} + +void KisLayerBox::slotLayerPropertyChanged(LayerItem* item, const TQString& name, bool on) +{ + if (KisLayerSP layer = m_image->findLayer(item->id())) + { + if (name == "visible") + layer->setVisible(on); + else if (name == "locked") + layer->setLocked(on); + } +} + +void KisLayerBox::slotLayerMoved(LayerItem* item, LayerItem*, LayerItem*) +{ + KisLayerSP layer = m_image->findLayer(item->id()); + KisGroupLayerSP tqparent; + if( item->tqparent() ) + tqparent = dynamic_cast(m_image->findLayer(item->tqparent()->id()).data()); + if( !tqparent ) + tqparent = m_image->rootLayer(); + KisLayerSP above = 0; + if (item->nextSibling()) + above = m_image->findLayer(item->nextSibling()->id()); + if (layer) + m_image->moveLayer(layer, tqparent.data(), above); + updateUI(); +} + +void KisLayerBox::slotRequestNewLayer(LayerItem* p, LayerItem* after) +{ + KisLayer* l = m_image->rootLayer().data(); + if (p) + l = m_image->findLayer(p->id()).data(); + KisGroupLayerSP tqparent = dynamic_cast(l); + + KisLayerSP above = 0; + if (after && after->nextSibling()) + above = m_image->findLayer(after->nextSibling()->id()); + else if (after) + above = 0; + else if (p && p->firstChild()) + above = tqparent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestLayer(tqparent, above); +} + +void KisLayerBox::slotRequestNewFolder(LayerItem* p, LayerItem* after) +{ + KisLayer* l = m_image->rootLayer().data(); //FIXME I hate copy-pasting like this. + if (p) + l = m_image->findLayer(p->id()).data(); + KisGroupLayerSP tqparent = dynamic_cast(l); + + KisLayerSP above = 0; + if (after && after->nextSibling()) + above = m_image->findLayer(after->nextSibling()->id()); + else if (after) + above = 0; + else if (p && p->firstChild()) + above = tqparent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestGroupLayer(tqparent, above); +} + +void KisLayerBox::slotRequestNewAdjustmentLayer(LayerItem* p, LayerItem* after) +{ + KisLayer* l = m_image->rootLayer().data(); //FIXME here too. + if (p) + l = m_image->findLayer(p->id()).data(); + KisGroupLayerSP tqparent = dynamic_cast(l); + + KisLayerSP above = 0; + if (after && after->nextSibling()) + above = m_image->findLayer(after->nextSibling()->id()); + else if (after) + above = 0; + else if (p && p->firstChild()) + above = tqparent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestAdjustmentLayer(tqparent, above); +} + +void KisLayerBox::slotRequestNewObjectLayer(LayerItem* p, LayerItem* after, const KoDocumentEntry& entry) +{ + KisLayer* l = m_image->rootLayer().data(); //FIXME and here. + if (p) + l = m_image->findLayer(p->id()).data(); + KisGroupLayerSP tqparent = dynamic_cast(l); + + KisLayerSP above = 0; + if (after && after->nextSibling()) + above = m_image->findLayer(after->nextSibling()->id()); + else if (after) + above = 0; + else if (p && p->firstChild()) + above = tqparent->firstChild(); + else if (!p && m_image->rootLayer()->childCount()) + above = m_image->rootLayer()->firstChild(); + emit sigRequestPartLayer(tqparent, above, entry); +} + +void KisLayerBox::slotRequestRemoveLayer(LayerItem* item) +{ + if (KisLayerSP layer = m_image->findLayer(item->id())) { + m_image->removeLayer(layer); + } + updateUI(); +} + +void KisLayerBox::slotRequestLayerProperties(LayerItem* item) +{ + if (KisLayerSP layer = m_image->findLayer(item->id())) + { + emit sigRequestLayerProperties(layer); + } +} + +void KisLayerBox::updateUI() +{ + m_lst->bnDelete->setEnabled(list()->activeLayer()); + m_lst->bnRaise->setEnabled(list()->activeLayer() && (list()->activeLayer()->prevSibling() || list()->activeLayer()->tqparent())); + m_lst->bnLower->setEnabled(list()->activeLayer() && list()->activeLayer()->nextSibling()); + m_lst->intOpacity->setEnabled(list()->activeLayer()); + m_lst->cmbComposite->setEnabled(list()->activeLayer()); + if (m_image) + if (KisLayerSP active = m_image->activeLayer()) + { + if (m_image->activeDevice()) + slotSetColorSpace(m_image->activeDevice()->colorSpace()); + else + slotSetColorSpace(m_image->colorSpace()); + slotSetOpacity(int(float(active->opacity() * 100) / 255 + 0.5)); + slotSetCompositeOp(active->compositeOp()); + } +} + +void KisLayerBox::slotAboutToShow() +{ +} + +void KisLayerBox::slotSetCompositeOp(const KisCompositeOp& compositeOp) +{ + m_lst->cmbComposite->blockSignals(true); + m_lst->cmbComposite->setCurrentItem(compositeOp); + m_lst->cmbComposite->blockSignals(false); +} + +void KisLayerBox::slotSetColorSpace(const KisColorSpace * colorSpace) +{ + m_lst->cmbComposite->blockSignals(true); + m_lst->cmbComposite->setCompositeOpList(colorSpace->userVisiblecompositeOps()); + m_lst->cmbComposite->blockSignals(false); +} + +// range: 0-100 +void KisLayerBox::slotSetOpacity(int opacity) +{ + m_lst->intOpacity->blockSignals(true); + m_lst->intOpacity->setValue(opacity); + m_lst->intOpacity->blockSignals(false); +} + +void KisLayerBox::clear() +{ + list()->clear(); + updateUI(); +} + +void KisLayerBox::slotAddMenuActivated(int type) +{ + if(type == -1) + return; + + KisGroupLayerSP root = m_image->rootLayer(); + KisGroupLayerSP tqparent; + KisLayerSP above; + if (KisLayerSP active = m_image->activeLayer()) + { + tqparent = root; + above = active; + if (active->tqparent()) + tqparent = active->tqparent(); + } + else + { + tqparent = root; + above = m_image->rootLayer()->firstChild(); + } + + switch (type) + { + case PAINT_LAYER: + emit sigRequestLayer(tqparent, above); + break; + case GROUP_LAYER: + emit sigRequestGroupLayer(tqparent, above); + break; + case ADJUSTMENT_LAYER: + emit sigRequestAdjustmentLayer(tqparent, above); + break; + case OBJECT_LAYER: + default: //goddamned TQt doesn't emit activated for default-assigned IDs, so this does nothing + emit sigRequestPartLayer(tqparent, above, m_partLayerAction->documentEntry()); + } +} + +void KisLayerBox::slotRmClicked() +{ + TQValueList l = list()->selectedLayerIDs(); + if (l.count() < 2 && list()->activeLayer() && !l.tqcontains(list()->activeLayer()->id())) + { + l.clear(); + l.append(list()->activeLayer()->id()); + } + + for (int i = 0, n = l.count(); i < n; ++i) + { + m_modified.remove(l[i]); + m_image->removeLayer(m_image->findLayer(l[i])); + } +} + +void KisLayerBox::slotRaiseClicked() +{ + TQValueList l = list()->selectedLayerIDs(); + if (l.count() < 2 && list()->activeLayer() && !l.tqcontains(list()->activeLayer()->id())) + { + l.clear(); + l.append(list()->activeLayer()->id()); + } + + KisLayerSP layer = m_image->findLayer(l.first()); + if( l.count() == 1 && layer == layer->tqparent()->firstChild() && layer->tqparent() != m_image->rootLayer()) + { + if (KisGroupLayerSP grandtqparent = layer->tqparent()->tqparent()) + m_image->moveLayer(layer, grandtqparent, layer->tqparent().data()); + } + else + { + for (int i = 0, n = l.count(); i < n; ++i) + if (KisLayerSP li = m_image->findLayer(l[i])) + if (li->prevSibling()) + m_image->moveLayer(li, li->tqparent(), li->prevSibling()); + } + + if( !l.isEmpty() ) + list()->ensureItemVisible( list()->layer( l.first() ) ); +} + +void KisLayerBox::slotLowerClicked() +{ + TQValueList l = list()->selectedLayers(); + if (l.count() < 2 && list()->activeLayer() && !l.tqcontains(list()->activeLayer())) + { + l.clear(); + l.append(list()->activeLayer()); + } + + for (int i = l.count() - 1; i >= 0; --i) + if (LayerItem *layer = l[i]) + if (layer->nextSibling()) + list()->moveLayer(layer, layer->tqparent(), layer->nextSibling()); + + if( !l.isEmpty() ) + list()->ensureItemVisible( l.last() ); +} + +void KisLayerBox::slotPropertiesClicked() +{ + if (KisLayerSP active = m_image->activeLayer()) + emit sigRequestLayerProperties(active); +} + +void KisLayerBox::updateThumbnails() +{ + bool again = true; + while (m_modified.count() && again) + { + //again = false; + KisLayerItem* item = static_cast(list()->layer(m_modified.last())); + m_modified.pop_back(); + if (!item || !item->updatePreview()) + again = true; + } +} + +void KisLayerBox::setUpdatesAndSignalsEnabled(bool enable) +{ + setUpdatesEnabled(enable); + m_lst->intOpacity->setUpdatesEnabled(enable); + m_lst->cmbComposite->setUpdatesEnabled(enable); + + list()->blockSignals(!enable); + m_lst->intOpacity->blockSignals(!enable); + m_lst->cmbComposite->blockSignals(!enable); +} + + +TQPixmap KisLayerBox::loadPixmap(const TQString& filename, const KIconLoader& + il, int size) +{ + TQPixmap pixmap = il.loadIcon(filename, KIcon::NoGroup, size); + + if (pixmap.isNull()) + KMessageBox::error(0, i18n("Cannot tqfind %1").tqarg(filename), + i18n("Canvas")); + + return pixmap; +} + +void KisLayerBox::markModified(KisLayer* layer) +{ + if( !layer ) + return; + + TQValueList v; + while (layer && layer != m_image->rootLayer().data()) + { + v.append(layer->id()); + layer = layer->tqparent(); + } + for (int i = v.count() - 1; i >= 0; --i) + if (!m_modified.tqcontains(v[i])) + m_modified.append(v[i]); +} + +void KisLayerBox::printChalkLayers() const +{ + static int indent = 0; + static KisLayer *root = 0; + if( !root ) + root = m_image->rootLayer(); + if( !root ) + return; + TQString s = root->name(); + if( dynamic_cast( root ) ) + s = TQString("[%1]").tqarg( s ); + if( m_image->activeLayer().data() == root ) + s.prepend("*"); + kdDebug() << (TQString().fill(' ', indent) + s) << endl; + for (KisLayer* layer = root->firstChild(); layer; layer = layer->nextSibling()) + { + indent += 2; + root = layer; + printChalkLayers(); + indent -= 2; + root = layer->tqparent(); + } +} + +void KisLayerBox::printLayerboxLayers() const +{ + static int indent = 0; + static LayerItem *root = 0; + if( !root ) + { + for (LayerItem* layer = list()->firstChild(); layer; layer = layer->nextSibling()) + { + indent += 2; + root = layer; + printLayerboxLayers(); + indent -= 2; + root = layer->tqparent(); + } + return; + } + TQString s = root->displayName(); + if( root->isFolder() ) + s = TQString("[%1]").tqarg( s ); + if( list()->activeLayer() == root ) + s.prepend("*"); + kdDebug() << (TQString().fill(' ', indent) + s) << endl; + for (LayerItem* layer = root->firstChild(); layer; layer = layer->nextSibling()) + { + indent += 2; + root = layer; + printLayerboxLayers(); + indent -= 2; + root = layer->tqparent(); + } +} + +#include "kis_layerbox.moc" diff --git a/chalk/ui/kis_layerbox.h b/chalk/ui/kis_layerbox.h new file mode 100644 index 00000000..c9d14a88 --- /dev/null +++ b/chalk/ui/kis_layerbox.h @@ -0,0 +1,124 @@ +/* + * kis_layerbox.h - part of Chalk aka Krayon aka KimageShop + * + * Copyright (c) 2002 Patrick Julien + * Copyright (C) 2006 Gábor Lehel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_LAYERBOX_H +#define KIS_LAYERBOX_H + +#include +#include +#include + +#include "kis_types.h" +#include "kis_colorspace.h" + +class WdgLayerBox; +class TQButton; +class TQPainter; +class TQWidget; +class KIconLoader; +class KPopupMenu; +class KoDocumentEntry; +class KisCompositeOp; +class KisLayerList; +class LayerItem; +class KisCanvasSubject; + +class KisLayerBox : public TQFrame { + typedef TQFrame super; + Q_OBJECT + TQ_OBJECT + +public: + KisLayerBox(KisCanvasSubject *subject, TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisLayerBox(); + + void clear(); + void setUpdatesAndSignalsEnabled(bool enable); + void setImage(KisImageSP image); + +public slots: + // connect to KisImage signals + void slotLayerActivated(KisLayerSP layer); + void slotLayerAdded(KisLayerSP layer); + void slotLayerRemoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAboveThis); + void slotLayerMoved(KisLayerSP layer, KisGroupLayerSP wasParent, KisLayerSP wasAboveThis); + void slotLayerPropertiesChanged(KisLayerSP layer); + void slotLayersChanged(KisGroupLayerSP rootLayer); + void slotLayerUpdated(KisLayerSP layer, TQRect rc); + + void slotSetCompositeOp(const KisCompositeOp& compositeOp); + void slotSetOpacity(int opacity); + void slotSetColorSpace(const KisColorSpace * colorSpace); + +signals: + void sigRequestLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void sigRequestGroupLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void sigRequestAdjustmentLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void sigRequestPartLayer(KisGroupLayerSP tqparent, KisLayerSP above, const KoDocumentEntry& entry); + void sigRequestLayerProperties(KisLayerSP layer); + + void sigOpacityChanged(int opacity, bool withSlider); + void sigOpacityFinishedChanging(int previous, int opacity); + void sigItemComposite(const KisCompositeOp&); + +private: + enum LayerTypes { PAINT_LAYER, GROUP_LAYER, ADJUSTMENT_LAYER, OBJECT_LAYER }; + +private slots: + // connect to LayerList signals + void slotLayerActivated(LayerItem* layer); + void slotLayerDisplayNameChanged(LayerItem* layer, const TQString& displayName); + void slotLayerPropertyChanged(LayerItem* layer, const TQString& name, bool on); + void slotLayerMoved(LayerItem* layer, LayerItem* tqparent, LayerItem* after); + void slotRequestNewLayer(LayerItem* tqparent, LayerItem* after); + void slotRequestNewFolder(LayerItem* tqparent, LayerItem* after); + void slotRequestNewAdjustmentLayer(LayerItem* tqparent, LayerItem* after); + void slotRequestNewObjectLayer(LayerItem* tqparent, LayerItem* item, const KoDocumentEntry& entry); + void slotRequestRemoveLayer(LayerItem* layer); + void slotRequestLayerProperties(LayerItem* layer); + + void slotAboutToShow(); + void slotAddMenuActivated(int type = OBJECT_LAYER); + void slotRmClicked(); + void slotRaiseClicked(); + void slotLowerClicked(); + void slotPropertiesClicked(); + + void updateThumbnails(); + +private: + void updateUI(); + TQPixmap loadPixmap(const TQString& filename, const KIconLoader& il, int size); + KisLayerList* list() const; + void markModified(KisLayer *layer); + + KPopupMenu *m_newLayerMenu; + KoPartSelectAction *m_partLayerAction; + KisImageSP m_image; + TQValueList m_modified; + WdgLayerBox *m_lst; + + void printChalkLayers() const; + void printLayerboxLayers() const; +}; + +#endif // KIS_LAYERBOX_H + diff --git a/chalk/ui/kis_layerlist.cc b/chalk/ui/kis_layerlist.cc new file mode 100644 index 00000000..64127d20 --- /dev/null +++ b/chalk/ui/kis_layerlist.cc @@ -0,0 +1,220 @@ +/* + Copyright (c) 2005 Gábor Lehel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_part_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_filter.h" +#include "kis_filter_configuration.h" +#include "kis_filter_registry.h" +#include "kis_layerlist.h" + + +KisLayerList::KisLayerList( TQWidget *tqparent, const char *name ) + : super( tqparent, name ) +{ + m_partLayerAction = new KoPartSelectAction( i18n( "New &Object Layer" ), "gear", TQT_TQOBJECT(this) ); +} + +static const int ADJUSTMENT_LAYER = 5384; //hack? + +void KisLayerList::constructMenu( LayerItem *layer ) +{ + super::constructMenu( layer ); + + contextMenu()->removeItem( MenuItems::NewLayer ); + contextMenu()->removeItem( MenuItems::NewFolder ); + contextMenu()->changeItem( MenuItems::RemoveLayer, i18n( "&Remove Layer" ) ); + + if( layer ) + { + static KPopupMenu submenu; + submenu.clear(); + submenu.insertItem( SmallIconSet( "file" ), i18n( "&Layer..." ), MenuItems::NewLayer ); + submenu.insertItem( SmallIconSet( "folder" ), i18n( "&Group Layer..." ), MenuItems::NewFolder ); + submenu.insertItem( SmallIconSet( "tool_filter" ), i18n( "&Adjustment Layer..." ), ADJUSTMENT_LAYER ); + m_partLayerAction->setText( i18n( "&Object Layer" ) ); + m_partLayerAction->plug( &submenu ); + + contextMenu()->insertItem( SmallIconSet( "filenew" ), i18n( "&New" ), &submenu ); + } + else + { + contextMenu()->insertItem( SmallIconSet( "filenew" ), i18n( "&New Layer..." ), MenuItems::NewLayer ); + contextMenu()->insertItem( SmallIconSet( "folder" ), i18n( "New &Group Layer..." ), MenuItems::NewFolder ); + contextMenu()->insertItem( SmallIconSet( "tool_filter" ), i18n( "New &Adjustment Layer..." ), ADJUSTMENT_LAYER ); + m_partLayerAction->setText( i18n( "New &Object Layer" ) ); + m_partLayerAction->plug( contextMenu() ); + } +} + +void KisLayerList::menuActivated( int id, LayerItem *layer ) +{ + const TQValueList selected = selectedLayers(); + LayerItem *tqparent = ( layer && layer->isFolder() ) ? layer : 0; + LayerItem *after = 0; + if( layer && !tqparent ) + { + tqparent = layer->tqparent(); + after = layer->prevSibling(); + } + switch( id ) + { + case MenuItems::NewLayer: + emit requestNewLayer( tqparent, after ); + emit requestNewLayer( tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::NewFolder: + emit requestNewFolder( tqparent, after ); + emit requestNewFolder( tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + break; + case ADJUSTMENT_LAYER: + emit requestNewAdjustmentLayer( tqparent, after ); + emit requestNewAdjustmentLayer( tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::RemoveLayer: + { + TQValueList ids; + for( int i = 0, n = selected.count(); i < n; ++i ) + { + ids.append( selected[i]->id() ); + emit requestRemoveLayer( selected[i]->id() ); + } + emit requestRemoveLayers( ids ); + } + for( int i = 0, n = selected.count(); i < n; ++i ) + emit requestRemoveLayer( selected[i] ); + emit requestRemoveLayers( selected ); + break; + case MenuItems::LayerProperties: + if( layer ) + { + emit requestLayerProperties( layer ); + emit requestLayerProperties( layer->id() ); + } + break; + default: + if( id >= MenuItems::COUNT && layer ) + super::menuActivated( id, layer ); + else if( id != -1 ) //object layer was selected + { + emit requestNewObjectLayer( tqparent, after, m_partLayerAction->documentEntry() ); + emit requestNewObjectLayer( tqparent ? tqparent->id() : -1, after ? after->id() : -1, m_partLayerAction->documentEntry() ); + } + } +} + +KisLayerItem::KisLayerItem( LayerList* tqparent, KisLayer* layer ) + : super( layer->name(), + tqparent, + layer->prevSibling() ? tqparent->layer( layer->prevSibling()->id() ) : 0, + layer->id() ) + , m_layer( layer ) +{ + init(); +} + +KisLayerItem::KisLayerItem( LayerItem* tqparent, KisLayer* layer ) + : super( layer->name(), + tqparent, + layer->prevSibling() ? tqparent->listView()->layer( layer->prevSibling()->id() ) : 0, + layer->id() ) + , m_layer( layer ) +{ + init(); +} + +void KisLayerItem::init() +{ + setPreviewImage( &m_preview ); + sync(); +} + +KisLayer* KisLayerItem::layer() const +{ + return m_layer; +} + +void KisLayerItem::sync() +{ + setProperty( "visible", layer()->visible() ); + setProperty( "locked", layer()->locked() ); + setDisplayName( layer()->name() ); + update(); +} + +bool KisLayerItem::updatePreview() +{ + m_preview = m_layer->createThumbnail( height()*2, height()*2 ); + m_preview.setAlphaBuffer( true ); + previewChanged(); + return !m_preview.isNull(); +} + +TQString KisLayerItem::tooltip() const +{ + TQString text = super::tooltip(); + text = text.left( text.length() - 8 ); //HACK -- strip the + TQString row = "%1%2"; + text += row.tqarg( i18n( "Opacity:" ) ).tqarg( "%1%" ).tqarg( int( float( m_layer->opacity() * 100 ) / 255 + 0.5 ) ); + text += row.tqarg( i18n( "Composite mode:" ) ).tqarg( m_layer->compositeOp().id().name() ); + if( KisPaintLayer *player = dynamic_cast( m_layer ) ) + { + text += row.tqarg( i18n( "Colorspace:" ) ).tqarg( player->paintDevice()->colorSpace()->id().name() ); + if( KisProfile *profile = player->paintDevice()->colorSpace()->getProfile() ) + text += row.tqarg( i18n( "Profile:" ) ).tqarg( profile->productName() ); + } + if( KisAdjustmentLayer *alayer = dynamic_cast( m_layer ) ) + text += row.tqarg( i18n( "Filter: " ) ).tqarg( KisFilterRegistry::instance()->get( alayer->filter()->name() )->id().name() ); + if( KisPartLayerImpl *player = dynamic_cast( m_layer ) ) { + TQString type = player->docType(); + + if( type.isEmpty() ) { + type = player->childDoc()->document()->instance()->aboutData()->programName(); + } + + text += row.tqarg( i18n( "Document type: " ) ).tqarg( type ); + } + text += ""; + + return text; +} + +TQImage KisLayerItem::tooltipPreview() const +{ + TQImage img = m_layer->createThumbnail( 400, 400 ); + if( img.isNull() ) + return img; //so TQt doesn't complain + img.setAlphaBuffer( true ); + const int size = kMin( 200, kMax( img.width(), img.height() ) ); + return img.smoothScale( size, size, TQ_ScaleMin ); +} + +//void KisLayerItem::paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align ); + +#include "kis_layerlist.moc" diff --git a/chalk/ui/kis_layerlist.h b/chalk/ui/kis_layerlist.h new file mode 100644 index 00000000..f0c587dd --- /dev/null +++ b/chalk/ui/kis_layerlist.h @@ -0,0 +1,80 @@ +/* + Copyright (c) 2005 Gábor Lehel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KIS_LAYERLIST_H +#define KIS_LAYERLIST_H + +#include +#include "layerlist.h" + +class KoPartSelectAction; +class KoDocumentEntry; +class KisLayer; + +class KisLayerList: public LayerList +{ + Q_OBJECT + TQ_OBJECT + typedef LayerList super; + +signals: + void requestNewObjectLayer( LayerItem *tqparent, LayerItem *after, const KoDocumentEntry &entry ); + void requestNewObjectLayer( int tqparentID, int afterID, const KoDocumentEntry &entry ); + void requestNewAdjustmentLayer( LayerItem *tqparent, LayerItem *after ); + void requestNewAdjustmentLayer( int tqparentID, int afterID ); + +public: + KisLayerList( TQWidget *tqparent = 0, const char *name = 0 ); + + virtual void constructMenu( LayerItem *layer ); + virtual void menuActivated( int id, LayerItem *layer ); + + KoPartSelectAction *partLayerAction() const { return m_partLayerAction; } + +private: + KoPartSelectAction *m_partLayerAction; +}; + +class KisLayerItem: public LayerItem +{ + typedef LayerItem super; + +public: + KisLayerItem( LayerList* tqparent, KisLayer* layer ); + KisLayerItem( LayerItem* tqparent, KisLayer* layer ); + + KisLayer* layer() const; + + void sync(); + + /// returns whether any preview was retrieved + bool updatePreview(); + + virtual TQString tooltip() const; + virtual TQImage tooltipPreview() const; + + //virtual void paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align ); + +private: + void init(); + TQImage m_preview; + KisLayer *m_layer; +}; + +#endif diff --git a/chalk/ui/kis_load_visitor.h b/chalk/ui/kis_load_visitor.h new file mode 100644 index 00000000..1997d3bc --- /dev/null +++ b/chalk/ui/kis_load_visitor.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_LOAD_VISITOR_H_ +#define KIS_LOAD_VISITOR_H_ + +#include +#include "kis_types.h" +#include "kis_layer_visitor.h" +#include "kis_image.h" +#include "kis_selection.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_filter_configuration.h" + +#include "kis_datamanager.h" + +class KisLoadVisitor : public KisLayerVisitor { +public: + KisLoadVisitor(KisImageSP img, KoStore *store, TQMap &layerFilenames) : + KisLayerVisitor(), + m_layerFilenames(layerFilenames) + { + m_external = false; + m_img = img; + m_store = store; + } + +public: + void setExternalUri(TQString &uri) + { + m_external = true; + m_uri = uri; + } + + virtual bool visit(KisPaintLayer *layer) + { //connect(*layer->paintDevice(), TQT_SIGNAL(ioProgress(TQ_INT8)), m_img, TQT_SLOT(slotIOProgress(TQ_INT8))); + + TQString location = m_external ? TQString() : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer]; + + // Layer data + if (m_store->open(location)) { + if (!layer->paintDevice()->read(m_store)) { + layer->paintDevice()->disconnect(); + m_store->close(); + //IODone(); + return false; + } + + m_store->close(); + } + + // icc profile + location = m_external ? TQString() : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".icc"; + + if (m_store->hasFile(location)) { + TQByteArray data; + m_store->open(location); + data = m_store->read(m_store->size()); + m_store->close(); + // Create a colorspace with the embedded profile + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(layer->paintDevice()->colorSpace()->id(), + new KisProfile(data)); + // replace the old colorspace + layer->paintDevice()->setData(layer->paintDevice()->dataManager(), cs); + TQRect rc = layer->paintDevice()->extent(); + kdDebug() << "After loading " << layer->name() << " extent is: " << rc.x() << ", " << rc.y() << ", " << rc.width() << ", " << rc.height() << endl; + layer->setDirty(rc); + kdDebug(DBG_AREA_FILE) << "Opened icc information, size is " << data.size() << endl; + } + + // tqmask + if (layer->hasMask()) { // We set this in KisDoc::loadPaintLayer + KisPaintDeviceSP tqmask = layer->getMask(); + location = m_external ? TQString() : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".tqmask"; + + // Layer data + if (m_store->open(location)) { + if (!tqmask->read(m_store)) { + tqmask->disconnect(); + m_store->close(); + //IODone(); + return false; + } + + m_store->close(); + } + layer->setDirty(); // Update the entire layer + } + + return true; + + } + + virtual bool visit(KisGroupLayer *layer) + { + KisLoadVisitor visitor(m_img,m_store ,m_layerFilenames); + + if(m_external) + visitor.setExternalUri(m_uri); + + KisLayerSP child = layer->firstChild(); + + while(child) + { + child->accept(visitor); + child = child->nextSibling(); + } + + layer->setDirty(m_img->bounds()); + return true; + } + + virtual bool visit(KisPartLayer *) + { + return true; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + //connect(*layer->paintDevice(), TQT_SIGNAL(ioProgress(TQ_INT8)), m_img, TQT_SLOT(slotIOProgress(TQ_INT8))); + + // The selection -- if present. If not, we simply cannot open the dratted thing. + TQString location = m_external ? TQString() : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".selection"; + if (m_store->hasFile(location)) { + m_store->open(location); + KisSelectionSP selection = new KisSelection(); + if (!selection->read(m_store)) { + selection->disconnect(); + m_store->close(); + } + else { + layer->setSelection( selection ); + } + m_store->close(); + } + + // filter configuration + location = m_external ? TQString() : m_uri; + location += m_img->name() + "/layers/" + m_layerFilenames[layer] + ".filterconfig"; + + if (m_store->hasFile(location) && layer->filter()) { + TQByteArray data; + m_store->open(location); + data = m_store->read(m_store->size()); + m_store->close(); + if (!data.isNull()) { + KisFilterConfiguration * kfc = layer->filter(); + kfc->fromXML(TQString(data)); + } + } + + return true; + + } + +private: + KisImageSP m_img; + KoStore *m_store; + bool m_external; + TQString m_uri; + TQMap m_layerFilenames; +}; + +#endif // KIS_LOAD_VISITOR_H_ + diff --git a/chalk/ui/kis_matrix_widget.ui b/chalk/ui/kis_matrix_widget.ui new file mode 100644 index 00000000..b989df12 --- /dev/null +++ b/chalk/ui/kis_matrix_widget.ui @@ -0,0 +1,210 @@ + +KisMatrixWidget + + + KisMatrixWidget + + + + 0 + 0 + 191 + 115 + + + + Matrix Widget + + + + unnamed + + + + m11 + + + -99 + + + + + m13 + + + -99 + + + + + m12 + + + -99 + + + + + m23 + + + -99 + + + + + m21 + + + -99 + + + + + m22 + + + -99 + + + 1 + + + + + m31 + + + -99 + + + + + m32 + + + -99 + + + + + m33 + + + -99 + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 41 + + + + + + spacer5 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + + + m11 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m12 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m13 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m21 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m22 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m23 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m31 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m32 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + m33 + valueChanged(int) + KisMatrixWidget + spinboxValueChanged() + + + + m11 + m12 + m13 + m21 + m22 + m23 + m31 + m32 + m33 + + + kis_matrix_widget.ui.h + + + valueChanged() + + + spinboxValueChanged() + + + diff --git a/chalk/ui/kis_matrix_widget.ui.h b/chalk/ui/kis_matrix_widget.ui.h new file mode 100644 index 00000000..f5217af5 --- /dev/null +++ b/chalk/ui/kis_matrix_widget.ui.h @@ -0,0 +1,17 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you want to add, delete, or rename functions or slots, use +** TQt Designer to update this file, preserving your code. +** +** You should not define a constructor or destructor in this file. +** Instead, write your code in functions called init() and destroy(). +** These will automatically be called by the form's constructor and +** destructor. +*****************************************************************************/ + + +void KisMatrixWidget::spinboxValueChanged() +{ + emit valueChanged(); +} diff --git a/chalk/ui/kis_move_event.h b/chalk/ui/kis_move_event.h new file mode 100644 index 00000000..8c99cd10 --- /dev/null +++ b/chalk/ui/kis_move_event.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_MOVE_EVENT_H_ +#define KIS_MOVE_EVENT_H_ + +#include "kis_event.h" + +class KisMoveEvent : public KisEvent { + typedef KisEvent super; +public: + KisMoveEvent() {} + KisMoveEvent(KisInputDevice device, const KisPoint& pos, const KisPoint& globalPos, double pressure, double xTilt, double yTilt, TQt::ButtonState state) : super(MoveEvent, device, pos, globalPos, pressure, xTilt, yTilt, state) {} +}; + +#endif // KIS_MOVE_EVENT_H_ + diff --git a/chalk/ui/kis_multi_bool_filter_widget.cc b/chalk/ui/kis_multi_bool_filter_widget.cc new file mode 100644 index 00000000..2507f1fb --- /dev/null +++ b/chalk/ui/kis_multi_bool_filter_widget.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_multi_bool_filter_widget.h" + +#include +#include +#include + +#include + +KisBoolWidgetParam::KisBoolWidgetParam( bool ninitvalue, TQString nlabel, TQString nname) : + initvalue(ninitvalue), + label(nlabel), + name(nname) +{ + +} + +KisMultiBoolFilterWidget::KisMultiBoolFilterWidget(TQWidget * tqparent, const char * name, const char * caption, vKisBoolWidgetParam iwparam) : + KisFilterConfigWidget( tqparent, name ) +{ + TQ_INT32 m_nbboolWidgets = iwparam.size(); + + this->setCaption(caption); + + TQVBoxLayout *widgetLayout = new TQVBoxLayout(this, m_nbboolWidgets + 1); + + m_boolWidgets = new TQCheckBox*[ m_nbboolWidgets ]; + + for( TQ_INT32 i = 0; i < m_nbboolWidgets; ++i) + { + m_boolWidgets[i] = new TQCheckBox( this, iwparam[i].name.ascii()); + m_boolWidgets[i]->setChecked( iwparam[i].initvalue ); + m_boolWidgets[i]->setText( iwparam[i].label ); + connect(m_boolWidgets[i], TQT_SIGNAL(toggled( bool ) ), TQT_SIGNAL(sigPleaseUpdatePreview())); + widgetLayout->add( m_boolWidgets[i]); + } +// TQSpacerItem * sp = new TQSpacerItem(1, 1); + widgetLayout->addStretch(); +} + + +void KisMultiBoolFilterWidget::setConfiguration(KisFilterConfiguration * config) +{ + + for (int i = 0; i < m_nbboolWidgets; ++i) { + double val = config->getBool(m_boolWidgets[i]->name()); + m_boolWidgets[i]->setChecked(val); + } +} + +#include "kis_multi_bool_filter_widget.moc" diff --git a/chalk/ui/kis_multi_bool_filter_widget.h b/chalk/ui/kis_multi_bool_filter_widget.h new file mode 100644 index 00000000..0e719bee --- /dev/null +++ b/chalk/ui/kis_multi_bool_filter_widget.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005 Michael Thaler + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_MULTI_BOOL_FILTER_WIDGET_H_ +#define _KIS_MULTI_BOOL_FILTER_WIDGET_H_ + +#include + +#include + +#include "koffice_export.h" +#include + +class KIntNumInput; + +struct KisBoolWidgetParam { + KRITA_EXPORT KisBoolWidgetParam( bool ninitvalue, TQString label, TQString name); + bool initvalue; + TQString label; + TQString name; + +}; + +typedef std::vector vKisBoolWidgetParam; + +class KRITA_EXPORT KisMultiBoolFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT +public: + KisMultiBoolFilterWidget(TQWidget * tqparent, const char * name, const char *caption, vKisBoolWidgetParam iwparam); + virtual void setConfiguration(KisFilterConfiguration * cfg); +public: + inline TQ_INT32 nbValues() { return m_nbboolWidgets; }; + inline TQ_INT32 valueAt( TQ_INT32 i ) { return m_boolWidgets[i]->isChecked(); }; +private: + TQCheckBox** m_boolWidgets; + TQ_INT32 m_nbboolWidgets; +}; + +#endif diff --git a/chalk/ui/kis_multi_double_filter_widget.cc b/chalk/ui/kis_multi_double_filter_widget.cc new file mode 100644 index 00000000..9b5d453b --- /dev/null +++ b/chalk/ui/kis_multi_double_filter_widget.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_multi_double_filter_widget.h" + +#include +#include +#include + +#include +#include +#include + +KisDelayedActionDoubleInput::KisDelayedActionDoubleInput(TQWidget * tqparent, const char * name) + : KDoubleNumInput(tqparent, name) +{ + m_timer = new TQTimer(this, name); + connect(m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotValueChanged())); + connect(this, TQT_SIGNAL(valueChanged( double )), TQT_SLOT(slotTimeToUpdate())); +} + +void KisDelayedActionDoubleInput::slotTimeToUpdate() +{ + m_timer->start(50, true); +} + +void KisDelayedActionDoubleInput::slotValueChanged() +{ + emit valueChangedDelayed( value() ); +} + +void KisDelayedActionDoubleInput::cancelDelayedSignal() +{ + m_timer->stop(); +} + +KisDoubleWidgetParam::KisDoubleWidgetParam(double nmin, double nmax, double ninitvalue, TQString nlabel, TQString nname) : + min(nmin), + max(nmax), + initvalue(ninitvalue), + label(nlabel), + name(nname) +{ + +} + +KisMultiDoubleFilterWidget::KisMultiDoubleFilterWidget(TQWidget * tqparent, const char * name, const char * caption, vKisDoubleWidgetParam dwparam) + : KisFilterConfigWidget( tqparent, name ) +{ + TQ_INT32 m_nbdoubleWidgets = dwparam.size(); + + this->setCaption(caption); + + TQGridLayout *widgetLayout = new TQGridLayout(this, m_nbdoubleWidgets + 1, 3); + widgetLayout->setColStretch ( 1, 1 ); + + m_doubleWidgets = new KisDelayedActionDoubleInput*[ m_nbdoubleWidgets ]; + + for( TQ_INT32 i = 0; i < m_nbdoubleWidgets; ++i) + { + m_doubleWidgets[i] = new KisDelayedActionDoubleInput(this, dwparam[i].name.ascii()); + m_doubleWidgets[i]->setRange( dwparam[i].min, dwparam[i].max ); + m_doubleWidgets[i]->setValue( dwparam[i].initvalue ); + m_doubleWidgets[i]->cancelDelayedSignal(); + + connect(m_doubleWidgets[i], TQT_SIGNAL(valueChangedDelayed(double)), TQT_SIGNAL(sigPleaseUpdatePreview())); + + TQLabel* lbl = new TQLabel(dwparam[i].label+":", this); + widgetLayout->addWidget( lbl, i , 0); + + widgetLayout->addWidget( m_doubleWidgets[i], i , 1); + } + TQSpacerItem * sp = new TQSpacerItem(1, 1); + widgetLayout->addItem(sp, m_nbdoubleWidgets, 0); + +} + +void KisMultiDoubleFilterWidget::setConfiguration(KisFilterConfiguration * config) +{ + + for (int i = 0; i < m_nbdoubleWidgets ; ++i) { + double val = config->getDouble(m_doubleWidgets[i]->name()); + m_doubleWidgets[i]->setValue(val); + m_doubleWidgets[i]->cancelDelayedSignal(); + } +} + +#include "kis_multi_double_filter_widget.moc" diff --git a/chalk/ui/kis_multi_double_filter_widget.h b/chalk/ui/kis_multi_double_filter_widget.h new file mode 100644 index 00000000..5351745e --- /dev/null +++ b/chalk/ui/kis_multi_double_filter_widget.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_MULTI_DOUBLE_FILTER_WIDGET_H_ +#define _KIS_MULTI_DOUBLE_FILTER_WIDGET_H_ + +#include +#include +#include +#include "koffice_export.h" + +class KisDelayedActionDoubleInput : public KDoubleNumInput +{ + + Q_OBJECT + TQ_OBJECT + + public: + + KisDelayedActionDoubleInput(TQWidget * tqparent, const char * name); + + void cancelDelayedSignal(); + + private slots: + void slotValueChanged(); + void slotTimeToUpdate(); + + signals: + + void valueChangedDelayed(double value); + + private: + + TQTimer * m_timer; +}; + + +struct KRITA_EXPORT KisDoubleWidgetParam { + KisDoubleWidgetParam( double nmin, double nmax, double ninitvalue, TQString label, TQString nname); + double min; + double max; + double initvalue; + TQString label; + TQString name; +}; + +typedef std::vector vKisDoubleWidgetParam; + +class KRITA_EXPORT KisMultiDoubleFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT +public: + KisMultiDoubleFilterWidget(TQWidget * tqparent, const char * name, const char * caption, vKisDoubleWidgetParam dwparam); + virtual void setConfiguration(KisFilterConfiguration * cfg); +public: + inline TQ_INT32 nbValues() { return m_nbdoubleWidgets; }; + inline double valueAt( TQ_INT32 i ) { return m_doubleWidgets[i]->value(); }; +private: + KisDelayedActionDoubleInput** m_doubleWidgets; + TQ_INT32 m_nbdoubleWidgets; +}; + +#endif diff --git a/chalk/ui/kis_multi_integer_filter_widget.cc b/chalk/ui/kis_multi_integer_filter_widget.cc new file mode 100644 index 00000000..07bfbe2a --- /dev/null +++ b/chalk/ui/kis_multi_integer_filter_widget.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_multi_integer_filter_widget.h" + +#include +#include +#include + +#include +#include + +KisDelayedActionIntegerInput::KisDelayedActionIntegerInput(TQWidget * tqparent, const char * name) + : KIntNumInput(tqparent, name) +{ + m_timer = new TQTimer(this, name); + connect(m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotValueChanged())); + connect(this, TQT_SIGNAL(valueChanged( int )), TQT_SLOT(slotTimeToUpdate())); +} + +void KisDelayedActionIntegerInput::slotTimeToUpdate() +{ + m_timer->start(50, true); +} + +void KisDelayedActionIntegerInput::slotValueChanged() +{ + emit valueChangedDelayed( value() ); +} + +void KisDelayedActionIntegerInput::cancelDelayedSignal() +{ + m_timer->stop(); +} + +KisIntegerWidgetParam::KisIntegerWidgetParam( TQ_INT32 nmin, TQ_INT32 nmax, TQ_INT32 ninitvalue, TQString label, TQString nname) : + min(nmin), + max(nmax), + initvalue(ninitvalue), + label(label), + name(nname) +{ +} + +KisMultiIntegerFilterWidget::KisMultiIntegerFilterWidget(TQWidget * tqparent, + const char * name, + const char * caption, + vKisIntegerWidgetParam iwparam) + : KisFilterConfigWidget( tqparent, name ) +{ + m_nbintegerWidgets = iwparam.size(); + this->setCaption(caption); + + TQGridLayout *widgetLayout = new TQGridLayout(this, m_nbintegerWidgets + 1, 3); + widgetLayout->setColStretch ( 1, 1 ); + + m_integerWidgets = new KisDelayedActionIntegerInput*[ m_nbintegerWidgets ]; + + for( TQ_INT32 i = 0; i < m_nbintegerWidgets; ++i) + { + m_integerWidgets[i] = new KisDelayedActionIntegerInput( this, iwparam[i].name.ascii()); + m_integerWidgets[i]->setRange( iwparam[i].min, iwparam[i].max); + m_integerWidgets[i]->setValue( iwparam[i].initvalue ); + m_integerWidgets[i]->cancelDelayedSignal(); + + connect(m_integerWidgets[i], TQT_SIGNAL(valueChangedDelayed( int )), TQT_SIGNAL(sigPleaseUpdatePreview())); + + TQLabel* lbl = new TQLabel(iwparam[i].label+":", this); + widgetLayout->addWidget( lbl, i , 0); + + widgetLayout->addWidget( m_integerWidgets[i], i , 1); + } + TQSpacerItem * sp = new TQSpacerItem(1, 1); + widgetLayout->addItem(sp, m_nbintegerWidgets, 0); +} + +void KisMultiIntegerFilterWidget::setConfiguration( KisFilterConfiguration * config ) +{ + for (int i = 0; i < nbValues(); ++i) { + KisDelayedActionIntegerInput * w = m_integerWidgets[i]; + if (w) { + int val = config->getInt(m_integerWidgets[i]->name()); + m_integerWidgets[i]->setValue(val); + m_integerWidgets[i]->cancelDelayedSignal(); + } + } +} + +#include "kis_multi_integer_filter_widget.moc" diff --git a/chalk/ui/kis_multi_integer_filter_widget.h b/chalk/ui/kis_multi_integer_filter_widget.h new file mode 100644 index 00000000..a08f4cad --- /dev/null +++ b/chalk/ui/kis_multi_integer_filter_widget.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_MULTI_INTEGER_FILTER_WIDGET_H_ +#define _KIS_MULTI_INTEGER_FILTER_WIDGET_H_ + +#include + +#include +#include +#include "koffice_export.h" + +class KisDelayedActionIntegerInput : public KIntNumInput +{ + + Q_OBJECT + TQ_OBJECT + +public: + + KisDelayedActionIntegerInput(TQWidget * tqparent, const char * name); + + void cancelDelayedSignal(); + +private slots: + void slotValueChanged(); + void slotTimeToUpdate(); + +signals: + + void valueChangedDelayed(int value); + +private: + + TQTimer * m_timer; +}; + + +struct KisIntegerWidgetParam { + KRITA_EXPORT KisIntegerWidgetParam( TQ_INT32 nmin, TQ_INT32 nmax, TQ_INT32 ninitvalue, TQString label, TQString nname); + TQ_INT32 min; + TQ_INT32 max; + TQ_INT32 initvalue; + TQString label; + TQString name; +}; + +typedef std::vector vKisIntegerWidgetParam; + +class KRITA_EXPORT KisMultiIntegerFilterWidget : public KisFilterConfigWidget +{ + Q_OBJECT + TQ_OBJECT +public: + KisMultiIntegerFilterWidget(TQWidget * tqparent, const char * name, const char *caption, vKisIntegerWidgetParam iwparam); + + virtual void setConfiguration(KisFilterConfiguration * config); + +public: + inline TQ_INT32 nbValues() { return m_nbintegerWidgets; }; + inline TQ_INT32 valueAt( TQ_INT32 i ) { return m_integerWidgets[i]->value(); }; + +private: + TQ_INT32 m_nbintegerWidgets; + KisDelayedActionIntegerInput** m_integerWidgets; +}; + +#endif diff --git a/chalk/ui/kis_opengl_canvas.cc b/chalk/ui/kis_opengl_canvas.cc new file mode 100644 index 00000000..ef8f743e --- /dev/null +++ b/chalk/ui/kis_opengl_canvas.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_canvas.h" +#include "kis_opengl_canvas.h" +#include "kis_opengl_canvas_painter.h" + +#ifdef HAVE_GL +KisOpenGLCanvasWidget::KisOpenGLCanvasWidget(TQWidget *tqparent, const char *name, TQGLWidget *sharedContextWidget) + : TQGLWidget(KisOpenGLCanvasFormat, tqparent, name, sharedContextWidget) +{ + if (isSharing()) { + kdDebug(41001) << "Created TQGLWidget with sharing\n"; + } else { + kdDebug(41001) << "Created TQGLWidget with no sharing\n"; + } +} + +KisOpenGLCanvasWidget::~KisOpenGLCanvasWidget() +{ +} + +void KisOpenGLCanvasWidget::paintEvent(TQPaintEvent *e) +{ + TQGLWidget::paintEvent(e); + + widgetGotPaintEvent(e); +} + +void KisOpenGLCanvasWidget::mousePressEvent(TQMouseEvent *e) +{ + widgetGotMousePressEvent(e); +} + +void KisOpenGLCanvasWidget::mouseReleaseEvent(TQMouseEvent *e) +{ + widgetGotMouseReleaseEvent(e); +} + +void KisOpenGLCanvasWidget::mouseDoubleClickEvent(TQMouseEvent *e) +{ + widgetGotMouseDoubleClickEvent(e); +} + +void KisOpenGLCanvasWidget::mouseMoveEvent(TQMouseEvent *e) +{ + widgetGotMouseMoveEvent(e); +} + +void KisOpenGLCanvasWidget::tabletEvent(TQTabletEvent *e) +{ + widgetGotTabletEvent(e); +} + +void KisOpenGLCanvasWidget::enterEvent(TQEvent *e) +{ + widgetGotEnterEvent(e); +} + +void KisOpenGLCanvasWidget::leaveEvent(TQEvent *e) +{ + widgetGotLeaveEvent(e); +} + +void KisOpenGLCanvasWidget::wheelEvent(TQWheelEvent *e) +{ + widgetGotWheelEvent(e); +} + +void KisOpenGLCanvasWidget::keyPressEvent(TQKeyEvent *e) +{ + widgetGotKeyPressEvent(e); +} + +void KisOpenGLCanvasWidget::keyReleaseEvent(TQKeyEvent *e) +{ + widgetGotKeyReleaseEvent(e); +} + +void KisOpenGLCanvasWidget::dragEnterEvent(TQDragEnterEvent *e) +{ + widgetGotDragEnterEvent(e); +} + +void KisOpenGLCanvasWidget::dropEvent(TQDropEvent *e) +{ + widgetGotDropEvent(e); +} + +#ifdef Q_WS_X11 + +bool KisOpenGLCanvasWidget::x11Event(XEvent *event) +{ + return KisCanvasWidget::x11Event(event, x11Display(), winId(), mapToGlobal(TQPoint(0, 0))); +} + +#endif // Q_WS_X11 + +KisCanvasWidgetPainter *KisOpenGLCanvasWidget::createPainter() +{ + return new KisOpenGLCanvasPainter(this); +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) +void KisOpenGLCanvasWidget::selectTabletDeviceEvents() +{ + KisCanvasWidget::selectTabletDeviceEvents(this); +} +#endif + +#endif // HAVE_GL + diff --git a/chalk/ui/kis_opengl_canvas.h b/chalk/ui/kis_opengl_canvas.h new file mode 100644 index 00000000..8ca2b1e3 --- /dev/null +++ b/chalk/ui/kis_opengl_canvas.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_OPENGL_CANVAS_H_ +#define KIS_OPENGL_CANVAS_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL + +#include +#include + +#include "kis_global.h" +#include "kis_canvas.h" + +#ifdef Q_MOC_RUN +#define Q_WS_X11 +#endif // Q_MOC_RUN + +#ifdef Q_WS_X11 +#include +#endif // Q_WS_X11 + +#define KisOpenGLCanvasFormat (TQGL::DoubleBuffer|TQGL::Rgba|TQGL::DirectRendering|TQGL::NoDepthBuffer) + +class KisOpenGLCanvasWidget : public virtual TQGLWidget, public virtual KisCanvasWidget { +public: + KisOpenGLCanvasWidget(TQWidget *tqparent, const char *name, TQGLWidget *sharedContextWidget); + ~KisOpenGLCanvasWidget(); + + virtual KisCanvasWidgetPainter *createPainter(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + virtual void selectTabletDeviceEvents(); +#endif + +protected: + virtual void paintEvent(TQPaintEvent *event); + virtual void mousePressEvent(TQMouseEvent *event); + virtual void mouseReleaseEvent(TQMouseEvent *event); + virtual void mouseDoubleClickEvent(TQMouseEvent *event); + virtual void mouseMoveEvent(TQMouseEvent *event); + virtual void tabletEvent(TQTabletEvent *event); + virtual void enterEvent(TQEvent *event ); + virtual void leaveEvent(TQEvent *event); + virtual void wheelEvent(TQWheelEvent *event); + virtual void keyPressEvent(TQKeyEvent *event); + virtual void keyReleaseEvent(TQKeyEvent *event); + virtual void dragEnterEvent(TQDragEnterEvent *event); + virtual void dropEvent(TQDropEvent *event); +#ifdef Q_WS_X11 + bool x11Event(XEvent *event); +#endif // Q_WS_X11 +}; +#endif // HAVE_GL + +#endif // KIS_OPENGL_CANVAS_H_ + diff --git a/chalk/ui/kis_opengl_canvas_painter.cc b/chalk/ui/kis_opengl_canvas_painter.cc new file mode 100644 index 00000000..6ae12305 --- /dev/null +++ b/chalk/ui/kis_opengl_canvas_painter.cc @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL + +#include + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_opengl_canvas_painter.h" + +KisOpenGLCanvasPainter::KisOpenGLCanvasPainter() +: m_active(false), m_widget(0) +{ +} + +KisOpenGLCanvasPainter::KisOpenGLCanvasPainter(TQGLWidget *widget) + : m_active(true), m_widget(widget) +{ + prepareForDrawing(); +} + +KisOpenGLCanvasPainter::~KisOpenGLCanvasPainter() +{ + if (m_widget) { + if (m_active) { + end(); + } + m_widget->doneCurrent(); + } +} + +bool KisOpenGLCanvasPainter::begin(KisCanvasWidget *canvasWidget, bool /*unclipped*/) +{ + m_widget = dynamic_cast(canvasWidget); + + if (m_widget != 0) { + prepareForDrawing(); + return true; + } else { + return false; + } + return false; +} + +void KisOpenGLCanvasPainter::prepareForDrawing() +{ + if (m_widget != 0) { + m_widget->makeCurrent(); + m_active = true; + save(); + glDrawBuffer(GL_FRONT); + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + glEnable(GL_BLEND); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + m_window = TQRect(0, 0, m_widget->width(), m_widget->height()); + m_viewport = m_window; + updateViewTransformation(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + setPen(m_defaultPen); + } +} + +void KisOpenGLCanvasPainter::updateViewTransformation() +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // We don't set the GL viewport directly from the TQt one as the GL + // has a limited size. Instead we fold it into the projection matrix. + glViewport(0, 0, m_widget->width(), m_widget->height()); + glOrtho(0, m_widget->width(), m_widget->height(), 0, -1, 1); + + glTranslatef(m_viewport.x(), m_viewport.y(), 0.0); + glScalef(static_cast(m_viewport.width()) / m_window.width(), + static_cast(m_viewport.height()) / m_window.height(), + 1.0); + glTranslatef(-m_window.x(), -m_window.y(), 0.0); +} + +bool KisOpenGLCanvasPainter::end() +{ + if (m_active) { + restore(); + m_active = false; + return true; + } else { + return false; + } +} + +void KisOpenGLCanvasPainter::save() +{ + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMatrixMode(GL_TEXTURE); + glPushMatrix(); +} + +void KisOpenGLCanvasPainter::restore() +{ + glPopAttrib(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_TEXTURE); + glPopMatrix(); +} + +void KisOpenGLCanvasPainter::setPenStyle(Qt::PenStyle penStyle) +{ + if (penStyle == TQt::SolidLine) { + glDisable(GL_LINE_STIPPLE); + } else { + GLushort lineStipple; + + switch (penStyle) { + case TQt::NoPen: + lineStipple = 0; + break; + default: + case TQt::DashLine: + lineStipple = 0x3fff; + break; + case TQt::DotLine: + lineStipple = 0x3333; + break; + case TQt::DashDotLine: + lineStipple = 0x33ff; + break; + case TQt::DashDotDotLine: + lineStipple = 0x333f; + break; + } + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, lineStipple); + } +} + +TQFontMetrics KisOpenGLCanvasPainter::fontMetrics() const +{ + return TQFontMetrics(TQFont()); +} + +TQFontInfo KisOpenGLCanvasPainter::fontInfo() const +{ + return TQFontInfo(TQFont()); +} + +const TQFont& KisOpenGLCanvasPainter::font() const +{ + return m_defaultFont; +} + +void KisOpenGLCanvasPainter::setFont(const TQFont& /*font*/) +{ +} + +const TQPen& KisOpenGLCanvasPainter::pen() const +{ + return m_defaultPen; +} + +void KisOpenGLCanvasPainter::setPen(const TQPen& pen) +{ + setPenStyle(pen.style()); +} + +void KisOpenGLCanvasPainter::setPen(Qt::PenStyle penStyle) +{ + setPenStyle(penStyle); +} + +void KisOpenGLCanvasPainter::setPen(const TQColor& /*color*/) +{ +} + +const TQBrush& KisOpenGLCanvasPainter::brush() const +{ + return m_defaultBrush; +} + +void KisOpenGLCanvasPainter::setBrush(const TQBrush& /*brush*/) +{ +} + +void KisOpenGLCanvasPainter::setBrush(TQt::BrushStyle /*brushStyle*/) +{ +} + +void KisOpenGLCanvasPainter::setBrush(const TQColor& /*color*/) +{ +} + +TQPoint KisOpenGLCanvasPainter::pos() const +{ + return TQPoint(); +} + +const TQColor& KisOpenGLCanvasPainter::backgroundColor() const +{ + return m_defaultColor; +} + +void KisOpenGLCanvasPainter::setBackgroundColor(const TQColor& /*color*/) +{ +} + +Qt::BGMode KisOpenGLCanvasPainter::backgroundMode() const +{ + return Qt::TransparentMode; +} + +void KisOpenGLCanvasPainter::setBackgroundMode(Qt::BGMode /*bgMode*/) +{ +} + +TQt::TQt::RasterOp KisOpenGLCanvasPainter::rasterOp() const +{ + return TQt::CopyROP; +} + +void KisOpenGLCanvasPainter::setRasterOp(TQt::RasterOp /*rasterOp*/) +{ +} + +const TQPoint& KisOpenGLCanvasPainter::brushOrigin() const +{ + return m_defaultBrushOrigin; +} + +void KisOpenGLCanvasPainter::setBrushOrigin(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::setBrushOrigin(const TQPoint& /*origin*/) +{ +} + +bool KisOpenGLCanvasPainter::hasViewXForm() const +{ + return false; +} + +bool KisOpenGLCanvasPainter::hasWorldXForm() const +{ + return false; +} + +void KisOpenGLCanvasPainter::setViewXForm(bool /*enable*/) +{ +} + +TQRect KisOpenGLCanvasPainter::window() const +{ + return m_window; +} + +void KisOpenGLCanvasPainter::setWindow(const TQRect& r) +{ + m_window = r; + updateViewTransformation(); +} + +void KisOpenGLCanvasPainter::setWindow(int x, int y, int w, int h) +{ + setWindow(TQRect(x, y, w, h)); +} + +TQRect KisOpenGLCanvasPainter::viewport() const +{ + return m_viewport; +} + +void KisOpenGLCanvasPainter::setViewport(const TQRect& r) +{ + m_viewport = r; + updateViewTransformation(); +} + +void KisOpenGLCanvasPainter::setViewport(int x, int y, int w, int h) +{ + setViewport(TQRect(x, y, w, h)); +} + +void KisOpenGLCanvasPainter::setWorldXForm(bool /*enable*/) +{ +} + +const TQWMatrix& KisOpenGLCanvasPainter::tqworldMatrix() const +{ + return m_defaultWorldMatrix; +} + +void KisOpenGLCanvasPainter::setWorldMatrix(const TQWMatrix& /*matrix*/, bool /*combine*/) +{ +} + +void KisOpenGLCanvasPainter::saveWorldMatrix() +{ +} + +void KisOpenGLCanvasPainter::restoreWorldMatrix() +{ +} + +void KisOpenGLCanvasPainter::scale(double /*sx*/, double /*sy*/) +{ +} + +void KisOpenGLCanvasPainter::shear(double /*sh*/, double /*sv*/) +{ +} + +void KisOpenGLCanvasPainter::rotate(double /*a*/) +{ +} + +void KisOpenGLCanvasPainter::translate(double dx, double dy) +{ + glMatrixMode(GL_MODELVIEW); + glTranslated(dx, dy, 0.0); +} + +void KisOpenGLCanvasPainter::resetXForm() +{ +} + +double KisOpenGLCanvasPainter::translationX() const +{ + return 0; +} + +double KisOpenGLCanvasPainter::translationY() const +{ + return 0; +} + +TQPoint KisOpenGLCanvasPainter::xForm(const TQPoint& point) const +{ + return point; +} + +TQRect KisOpenGLCanvasPainter::xForm(const TQRect& r) const +{ + return r; +} + +TQPointArray KisOpenGLCanvasPainter::xForm(const TQPointArray& pointArray) const +{ + return pointArray; +} + +TQPointArray KisOpenGLCanvasPainter::xForm(const TQPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +TQPoint KisOpenGLCanvasPainter::xFormDev(const TQPoint& point) const +{ + return point; +} + +TQRect KisOpenGLCanvasPainter::xFormDev(const TQRect& r) const +{ + return r; +} + +TQPointArray KisOpenGLCanvasPainter::xFormDev(const TQPointArray& pointArray) const +{ + return pointArray; +} + +TQPointArray KisOpenGLCanvasPainter::xFormDev(const TQPointArray& pointArray, int /*index*/, int /*npoints*/) const +{ + return pointArray; +} + +void KisOpenGLCanvasPainter::setClipping(bool /*enable*/) +{ +} + +bool KisOpenGLCanvasPainter::hasClipping() const +{ + return true; +} + +TQRegion KisOpenGLCanvasPainter::clipRegion(TQPainter::CoordinateMode /*mode*/) const +{ + return TQRegion(); +} + +void KisOpenGLCanvasPainter::setClipRect(const TQRect& /*r*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::setClipRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::setClipRegion(const TQRegion& /*rgn*/, TQPainter::CoordinateMode /*mode*/) +{ +} + +void KisOpenGLCanvasPainter::drawPoint(int x, int y) +{ + glBegin(GL_POINTS); + glVertex2i(x, y); + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPoint(const TQPoint& point) +{ + drawPoint(point.x(), point.y()); +} + +void KisOpenGLCanvasPainter::drawPoints(const TQPointArray& pointArray, int index, int npoints) +{ + int firstPointIndex = index; + + if (firstPointIndex < 0) { + firstPointIndex = 0; + } + if (firstPointIndex > (int)pointArray.count() - 1) { + return; + } + + int lastPointIndex; + + if (npoints < 0) { + lastPointIndex = pointArray.count() - 1; + } else { + lastPointIndex = firstPointIndex + npoints; + if (lastPointIndex > (int)pointArray.count() - 1) { + lastPointIndex = pointArray.count() - 1; + } + } + + glBegin(GL_POINTS); + + for (int pointIndex = firstPointIndex; pointIndex <= lastPointIndex; pointIndex++) { + TQPoint point = pointArray.point(pointIndex); + glVertex2i(point.x(), point.y()); + } + + glEnd(); +} + +void KisOpenGLCanvasPainter::moveTo(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::moveTo(const TQPoint& /*point*/) +{ +} + +void KisOpenGLCanvasPainter::lineTo(int /*x*/, int /*y*/) +{ +} + +void KisOpenGLCanvasPainter::lineTo(const TQPoint& /*point*/) +{ +} + +void KisOpenGLCanvasPainter::drawLine(int x1, int y1, int x2, int y2) +{ + glBegin(GL_LINES); + glVertex2i(x1, y1); + glVertex2i(x2, y2); + glEnd(); +} + +void KisOpenGLCanvasPainter::drawLine(const TQPoint& start, const TQPoint& end) +{ + drawLine(start.x(), start.y(), end.x(), end.y()); +} + +void KisOpenGLCanvasPainter::drawRect(int x, int y, int w, int h) +{ + glBegin(GL_LINES); + + glVertex2i(x, y); + glVertex2i(x + w - 1, y); + + glVertex2i(x + w - 1, y); + glVertex2i(x + w - 1, y + h - 1); + + glVertex2i(x + w - 1, y + h - 1); + glVertex2i(x, y + h - 1); + + glVertex2i(x, y + h - 1); + glVertex2i(x, y); + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawRect(const TQRect& r) +{ + drawRect(r.x(), r.y(), r.width(), r.height()); +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const TQColor& /*bgColor*/) +{ +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(const TQRect& /*r*/) +{ +} + +void KisOpenGLCanvasPainter::drawWinFocusRect(const TQRect& /*r*/, const TQColor& /*bgColor*/) +{ +} + +void KisOpenGLCanvasPainter::drawRoundRect(int x, int y, int w, int h, int /*xRnd*/, int /*yRnd*/) +{ + glBegin(GL_LINES); + + glVertex2i(x, y); + glVertex2i(x + w - 1, y); + + glVertex2i(x + w - 1, y); + glVertex2i(x + w - 1, y + h - 1); + + glVertex2i(x + w - 1, y + h - 1); + glVertex2i(x, y + h - 1); + + glVertex2i(x, y + h - 1); + glVertex2i(x, y); + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawRoundRect(const TQRect& r, int /*xRnd*/, int /*yRnd*/) +{ + drawRoundRect(r.x(), r.y(), r.width(), r.height()); +} + +// void KisOpenGLCanvasPainter::drawRoundRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*xRnd*/, int /*yRnd*/) +// { +// } +// +// void KisOpenGLCanvasPainter::drawRoundRect(const TQRect& /*r*/, int /*xRnd*/, int /*yRnd*/) +// { +// } + +void KisOpenGLCanvasPainter::drawEllipse(int x, int y, int w, int h) +{ + TQRect r(x, y, w, h); + r = r.normalize(); + + TQPointArray points; + + points.makeEllipse(r.x(), r.y(), r.width(), r.height()); + drawPoints(points); +} + +void KisOpenGLCanvasPainter::drawEllipse(const TQRect& r) +{ + drawEllipse(r.x(), r.y(), r.width(), r.height()); +} + +void KisOpenGLCanvasPainter::drawArc(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawArc(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawPie(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawPie(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawChord(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawChord(const TQRect& /*r*/, int /*a*/, int /*alen*/) +{ +} + +void KisOpenGLCanvasPainter::drawLineSegments(const TQPointArray& /*pointArray*/, int /*index*/, int /*nlines*/) +{ +} + +void KisOpenGLCanvasPainter::drawPolyline(const TQPointArray& pointArray, int index, int npoints) +{ + int firstPointIndex = index; + + if (firstPointIndex < 0) { + firstPointIndex = 0; + } + if (firstPointIndex > (int)pointArray.count() - 2) { + return; + } + + int lastPointIndex; + + if (npoints < 0) { + lastPointIndex = pointArray.count() - 1; + } else { + lastPointIndex = firstPointIndex + npoints - 1; + if (lastPointIndex > (int)pointArray.count() - 1) { + lastPointIndex = pointArray.count() - 1; + } + } + + if (firstPointIndex >= lastPointIndex) { + return; + } + + glBegin(GL_LINES); + + for (int pointIndex = firstPointIndex; pointIndex <= lastPointIndex; pointIndex++) { + TQPoint point = pointArray.point(pointIndex); + glVertex2i(point.x(), point.y()); + } + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPolygon(const TQPointArray& /*pointArray*/, bool /*winding*/, int /*index*/, int /*npoints*/) +{ +} + +void KisOpenGLCanvasPainter::drawConvexPolygon(const TQPointArray& /*pointArray*/, int /*index*/, int /*npoints*/) +{ +} + +TQPoint midpoint (const TQPoint& P1, const TQPoint& P2) +{ + TQPoint temp; + temp.setX((P1.x()+P2.x())/2); + temp.setY((P1.y()+P2.y())/2); + return temp; +} + +#define MAX_LEVEL 5 + +void recursiveCurve (const TQPoint& P1, const TQPoint& P2, const TQPoint& P3, + const TQPoint& P4, int level, TQValueList& dest) +{ + if (level > MAX_LEVEL) { + dest.append(midpoint(P1,P4)); + return; + } + + TQPoint L1, L2, L3, L4; + TQPoint H, R1, R2, R3, R4; + + L1 = P1; + L2 = midpoint(P1, P2); + H = midpoint(P2, P3); + R3 = midpoint(P3, P4); + R4 = P4; + L3 = midpoint(L2, H); + R2 = midpoint(R3, H); + L4 = midpoint(L3, R2); + R1 = L4; + recursiveCurve(L1, L2, L3, L4, level + 1, dest); + recursiveCurve(R1, R2, R3, R4, level + 1, dest); +} + +void KisOpenGLCanvasPainter::drawCubicBezier(const TQPointArray& pointArray, int index) +{ + TQPoint P1, P2, P3, P4; + TQValueList dest; + P1 = pointArray[index++]; + P2 = pointArray[index++]; + P3 = pointArray[index++]; + P4 = pointArray[index]; + + recursiveCurve(P1, P2, P3, P4, 1, dest); + + glBegin(GL_LINE_STRIP); + + glVertex2i(P1.x(), P1.y()); + for (TQValueList::iterator it = dest.begin(); it != dest.end(); it++) { + TQPoint point = (*it); + glVertex2i(point.x(), point.y()); + } + glVertex2i(P4.x(), P4.y()); + + glEnd(); +} + +void KisOpenGLCanvasPainter::drawPixmap(int /*x*/, int /*y*/, const TQPixmap& /*pixmap*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const TQPoint& /*point*/, const TQPixmap& /*pixmap*/, const TQRect& /*sr*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const TQPoint& /*point*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::drawPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(int /*x*/, int /*y*/, const TQImage& /*image*/, int /*sx*/, int /*sy*/, int /*sw*/, int /*sh*/, int /*conversionFlags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const TQPoint& /*point*/, const TQImage& /*image*/, const TQRect& /*sr*/, int /*conversionFlags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const TQPoint& /*point*/, const TQImage& /*image*/, int /*conversion_flags*/) +{ +} + +void KisOpenGLCanvasPainter::drawImage(const TQRect& /*r*/, const TQImage& /*image*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(int /*x*/, int /*y*/, int /*w*/, int /*h*/, const TQPixmap& /*pixmap*/, int /*sx*/, int /*sy*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/, const TQPoint& /*point*/) +{ +} + +void KisOpenGLCanvasPainter::drawTiledPixmap(const TQRect& /*r*/, const TQPixmap& /*pixmap*/) +{ +} + +void KisOpenGLCanvasPainter::fillRect(int x, int y, int w, int h, const TQBrush& /*brush*/) +{ + // XXX: Set brush + glRecti(x, y, x + w, y + h); +} + +void KisOpenGLCanvasPainter::fillRect(const TQRect& r, const TQBrush& brush) +{ + fillRect(r.x(), r.y(), r.width(), r.height(), brush); +} + +void KisOpenGLCanvasPainter::eraseRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/) +{ +} + +void KisOpenGLCanvasPainter::eraseRect(const TQRect& /*r*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, const TQString& /*text*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const TQPoint& /*point*/, const TQString& /*text*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, const TQString& /*text*/, int /*pos*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const TQPoint& /*point*/, const TQString& /*text*/, int /*pos*/, int /*len*/, TQPainter::TextDirection /*dir*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQRect */*br*/, TQTextParag **/*intern*/) +{ +} + +void KisOpenGLCanvasPainter::drawText(const TQRect& /*r*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQRect */*br*/, TQTextParag **/*intern*/) +{ +} + +void KisOpenGLCanvasPainter::tqdrawTextItem(int /*x*/, int /*y*/, const TQTextItem& /*ti*/, int /*textflags*/) +{ +} + +void KisOpenGLCanvasPainter::tqdrawTextItem(const TQPoint& /*p*/, const TQTextItem& /*ti*/, int /*textflags*/) +{ +} + +TQRect KisOpenGLCanvasPainter::boundingRect(int /*x*/, int /*y*/, int /*w*/, int /*h*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQTextParag **/*intern*/) +{ + return TQRect(); +} + +TQRect KisOpenGLCanvasPainter::boundingRect(const TQRect& /*r*/, int /*flags*/, const TQString& /*text*/, int /*len*/, TQTextParag **/*intern*/) +{ + return TQRect(); +} + +int KisOpenGLCanvasPainter::tabStops() const +{ + return 0; +} + +void KisOpenGLCanvasPainter::setTabStops(int /*ts*/) +{ +} + +int *KisOpenGLCanvasPainter::tabArray() const +{ + return 0; +} + +void KisOpenGLCanvasPainter::setTabArray(int */*ts*/) +{ +} + +#endif // HAVE_GL + diff --git a/chalk/ui/kis_opengl_canvas_painter.h b/chalk/ui/kis_opengl_canvas_painter.h new file mode 100644 index 00000000..47983ce2 --- /dev/null +++ b/chalk/ui/kis_opengl_canvas_painter.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_OPENGL_CANVAS_PAINTER_H_ +#define KIS_OPENGL_CANVAS_PAINTER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL + +#include +#include +#include + +#include "kis_global.h" +#include "kis_canvas_painter.h" + +class KisOpenGLCanvasPainter : public KisCanvasWidgetPainter { +public: + KisOpenGLCanvasPainter(); + KisOpenGLCanvasPainter(TQGLWidget *widget); + + virtual ~KisOpenGLCanvasPainter(); + + virtual bool begin(KisCanvasWidget *canvasWidget, bool unclipped = false); + + // If we don't have OpenGL, we use the base class's no-op methods. + + virtual bool end(); + + virtual void save(); + virtual void restore(); + + virtual TQFontMetrics fontMetrics() const; + virtual TQFontInfo fontInfo() const; + + virtual const TQFont& font() const; + virtual void setFont(const TQFont&); + virtual const TQPen& pen() const; + virtual void setPen(const TQPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const TQColor&); + virtual const TQBrush&brush() const; + virtual void setBrush(const TQBrush&); + virtual void setBrush(TQt::BrushStyle); + virtual void setBrush(const TQColor&); + virtual TQPoint pos() const; + + virtual const TQColor& backgroundColor() const; + virtual void setBackgroundColor(const TQColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual TQt::RasterOp rasterOp() const; + virtual void setRasterOp(TQt::RasterOp); + virtual const TQPoint& brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const TQPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual TQRect window() const; + virtual void setWindow(const TQRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual TQRect viewport() const; + virtual void setViewport(const TQRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const TQWMatrix&tqworldMatrix() const; + virtual void setWorldMatrix(const TQWMatrix&, bool combine=FALSE); + + virtual void saveWorldMatrix(); + virtual void restoreWorldMatrix(); + + virtual void scale(double sx, double sy); + virtual void shear(double sh, double sv); + virtual void rotate(double a); + + virtual void translate(double dx, double dy); + virtual void resetXForm(); + virtual double translationX() const; + virtual double translationY() const; + + virtual TQPoint xForm(const TQPoint&) const; + virtual TQRect xForm(const TQRect&) const; + virtual TQPointArray xForm(const TQPointArray&) const; + virtual TQPointArray xForm(const TQPointArray&, int index, int npoints) const; + virtual TQPoint xFormDev(const TQPoint&) const; + virtual TQRect xFormDev(const TQRect&) const; + virtual TQPointArray xFormDev(const TQPointArray&) const; + virtual TQPointArray xFormDev(const TQPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual TQRegion clipRegion(TQPainter::CoordinateMode = TQPainter::CoordDevice) const; + virtual void setClipRect(const TQRect&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRegion(const TQRegion&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const TQPoint&); + virtual void drawPoints(const TQPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const TQPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const TQPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const TQPoint&, const TQPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const TQRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const TQColor&bgColor); + virtual void drawWinFocusRect(const TQRect&); + virtual void drawWinFocusRect(const TQRect&, const TQColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const TQRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const TQRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const TQRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const TQRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const TQRect&, int a, int alen); + virtual void drawLineSegments(const TQPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const TQPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const TQPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const TQPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const TQPoint&, const TQPixmap&, const TQRect&sr); + virtual void drawPixmap(const TQPoint&, const TQPixmap&); + virtual void drawPixmap(const TQRect&, const TQPixmap&); + virtual void drawImage(int x, int y, const TQImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, const TQRect&sr, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, int conversion_flags = 0); + virtual void drawImage(const TQRect&, const TQImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const TQPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&, const TQPoint&); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&); + //virtual void drawPicture(const TQPicture&); + //virtual void drawPicture(int x, int y, const TQPicture&); + //virtual void drawPicture(const TQPoint&, const TQPicture&); + + virtual void fillRect(int x, int y, int w, int h, const TQBrush&); + virtual void fillRect(const TQRect&, const TQBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const TQRect&); + + virtual void drawText(int x, int y, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&p, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + virtual void drawText(const TQRect&, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + + virtual void tqdrawTextItem(int x, int y, const TQTextItem&ti, int textflags = 0); + virtual void tqdrawTextItem(const TQPoint& p, const TQTextItem&ti, int textflags = 0); + + virtual TQRect boundingRect(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + virtual TQRect boundingRect(const TQRect&, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + + virtual int tabStops() const; + virtual void setTabStops(int); + virtual int *tabArray() const; + virtual void setTabArray(int *); + +protected: + void prepareForDrawing(); + void updateViewTransformation(); + void setPenStyle(Qt::PenStyle penStyle); + +protected: + TQFont m_defaultFont; + TQPen m_defaultPen; + TQBrush m_defaultBrush; + TQColor m_defaultColor; + TQPoint m_defaultBrushOrigin; + TQWMatrix m_defaultWorldMatrix; + TQRect m_window; + TQRect m_viewport; + bool m_active; + +protected: + TQGLWidget *m_widget; +}; + +#endif // HAVE_GL + +#endif // KIS_OPENGL_CANVAS_PAINTER_H_ + diff --git a/chalk/ui/kis_opengl_image_context.cc b/chalk/ui/kis_opengl_image_context.cc new file mode 100644 index 00000000..6a302192 --- /dev/null +++ b/chalk/ui/kis_opengl_image_context.cc @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL + +#include +#include + +#include "kis_global.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_selection.h" +#include "kis_background.h" +#include "kis_opengl_canvas.h" +#include "kis_opengl_image_context.h" + +using namespace std; + +TQGLWidget *KisOpenGLImageContext::SharedContextWidget = 0; +int KisOpenGLImageContext::SharedContextWidgetRefCount = 0; + +KisOpenGLImageContext::ImageContextMap KisOpenGLImageContext::imageContextMap; + +KisOpenGLImageContext::KisOpenGLImageContext() +{ + m_image = 0; + m_monitorProfile = 0; + m_exposure = 0; +} + +KisOpenGLImageContext::~KisOpenGLImageContext() +{ + kdDebug(41001) << "Destroyed KisOpenGLImageContext\n"; + + --SharedContextWidgetRefCount; + kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl; + + if (SharedContextWidgetRefCount == 0) { + + kdDebug(41001) << "Deleting shared context widget\n"; + delete SharedContextWidget; + SharedContextWidget = 0; + } + + imageContextMap.erase(m_image); +} + +KisOpenGLImageContext::KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile) +{ + kdDebug(41001) << "Created KisOpenGLImageContext\n"; + + m_image = image; + m_monitorProfile = monitorProfile; + m_exposure = 0; + m_displaySelection = true; + + if (SharedContextWidget == 0) { + kdDebug(41001) << "Creating shared context widget\n"; + + SharedContextWidget = new TQGLWidget(KisOpenGLCanvasFormat); + } + + ++SharedContextWidgetRefCount; + + kdDebug(41001) << "Shared context widget ref count now " << SharedContextWidgetRefCount << endl; + + SharedContextWidget->makeCurrent(); + glGenTextures(1, &m_backgroundTexture); + generateBackgroundTexture(); + + GLint max_texture_size; + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + + m_imageTextureTileWidth = TQMIN(PREFERRED_IMAGE_TEXTURE_WIDTH, max_texture_size); + m_imageTextureTileHeight = TQMIN(PREFERRED_IMAGE_TEXTURE_HEIGHT, max_texture_size); + + createImageTextureTiles(); + + connect(m_image, TQT_SIGNAL(sigImageUpdated(TQRect)), + TQT_SLOT(slotImageUpdated(TQRect))); + connect(m_image, TQT_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)), + TQT_SLOT(slotImageSizeChanged(TQ_INT32, TQ_INT32))); + + updateImageTextureTiles(m_image->bounds()); +} + +KisOpenGLImageContextSP KisOpenGLImageContext::getImageContext(KisImageSP image, KisProfile *monitorProfile) +{ + if (imageCanShareImageContext(image)) { + ImageContextMap::iterator it = imageContextMap.find(image); + + if (it != imageContextMap.end()) { + + kdDebug(41001) << "Sharing image context from map\n"; + + KisOpenGLImageContextSP context = (*it).second; + context->setMonitorProfile(monitorProfile); + + return context; + } else { + KisOpenGLImageContext *imageContext = new KisOpenGLImageContext(image, monitorProfile); + imageContextMap[image] = imageContext; + + kdDebug(41001) << "Added shareable context to map\n"; + + return imageContext; + } + } else { + kdDebug(41001) << "Creating non-shareable image context\n"; + + return new KisOpenGLImageContext(image, monitorProfile); + } +} + +bool KisOpenGLImageContext::imageCanShareImageContext(KisImageSP image) +{ + if (image->colorSpace()->hasHighDynamicRange()) { + //XXX: and we don't have shaders... + return false; + } else { + return true; + } +} + +TQGLWidget *KisOpenGLImageContext::sharedContextWidget() const +{ + return SharedContextWidget; +} + +void KisOpenGLImageContext::updateImageTextureTiles(const TQRect& rect) +{ + //kdDebug() << "updateImageTextureTiles " << rect << endl; + + TQRect updateRect = rect & m_image->bounds(); + + if (!updateRect.isEmpty()) { + + SharedContextWidget->makeCurrent(); + + int firstColumn = updateRect.left() / m_imageTextureTileWidth; + int lastColumn = updateRect.right() / m_imageTextureTileWidth; + int firstRow = updateRect.top() / m_imageTextureTileHeight; + int lastRow = updateRect.bottom() / m_imageTextureTileHeight; + + for (int column = firstColumn; column <= lastColumn; column++) { + for (int row = firstRow; row <= lastRow; row++) { + + TQRect tileRect(column * m_imageTextureTileWidth, row * m_imageTextureTileHeight, + m_imageTextureTileWidth, m_imageTextureTileHeight); + + TQRect tileUpdateRect = tileRect & updateRect; + + glBindTexture(GL_TEXTURE_2D, imageTextureTile(tileRect.x(), tileRect.y())); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + TQImage tileUpdateImage = m_image->convertToTQImage(tileUpdateRect.left(), tileUpdateRect.top(), + tileUpdateRect.right(), tileUpdateRect.bottom(), + m_monitorProfile, m_exposure); + + if (m_displaySelection) { + if (m_image->activeLayer() != 0) { + m_image->activeLayer()->paintSelection(tileUpdateImage, + tileUpdateRect.x(), tileUpdateRect.y(), + tileUpdateRect.width(), tileUpdateRect.height()); + } + } + + if (tileUpdateRect.width() == m_imageTextureTileWidth && tileUpdateRect.height() == m_imageTextureTileHeight) { + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0, + GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits()); + } else { + int xOffset = tileUpdateRect.x() - tileRect.x(); + int yOffset = tileUpdateRect.y() - tileRect.y(); + + glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, tileUpdateRect.width(), tileUpdateRect.height(), + GL_BGRA, GL_UNSIGNED_BYTE, tileUpdateImage.bits()); + } + + GLenum error = glGetError (); + + if (error != GL_NO_ERROR) + { + kdDebug(41001) << "Error loading texture: " << endl; + } + } + } + } +} + +KisColorSpace* KisOpenGLImageContext::textureColorSpaceForImageColorSpace(KisColorSpace */*imageColorSpace*/) +{ + return KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA", ""), ""); +} + +void KisOpenGLImageContext::setMonitorProfile(KisProfile *monitorProfile) +{ + if (monitorProfile != m_monitorProfile) { + m_monitorProfile = monitorProfile; + generateBackgroundTexture(); + updateImageTextureTiles(m_image->bounds()); + } +} + +void KisOpenGLImageContext::setHDRExposure(float exposure) +{ + if (exposure != m_exposure) { + m_exposure = exposure; + + if (m_image->colorSpace()->hasHighDynamicRange()) { + //XXX: and we are not using shaders... + updateImageTextureTiles(m_image->bounds()); + } + } +} + +void KisOpenGLImageContext::generateBackgroundTexture() +{ + SharedContextWidget->makeCurrent(); + + glBindTexture(GL_TEXTURE_2D, m_backgroundTexture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + TQImage backgroundImage = m_image->background()->patternTile(); + + // XXX: temp. + Q_ASSERT(backgroundImage.width() == BACKGROUND_TEXTURE_WIDTH); + Q_ASSERT(backgroundImage.height() == BACKGROUND_TEXTURE_HEIGHT); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, BACKGROUND_TEXTURE_WIDTH, BACKGROUND_TEXTURE_HEIGHT, 0, + GL_BGRA, GL_UNSIGNED_BYTE, backgroundImage.bits()); +} + +GLuint KisOpenGLImageContext::backgroundTexture() const +{ + return m_backgroundTexture; +} + +int KisOpenGLImageContext::imageTextureTileIndex(int x, int y) const +{ + int column = x / m_imageTextureTileWidth; + int row = y / m_imageTextureTileHeight; + + return column + (row * m_numImageTextureTileColumns); +} + +GLuint KisOpenGLImageContext::imageTextureTile(int pixelX, int pixelY) const +{ + TQ_INT32 textureTileIndex = imageTextureTileIndex(pixelX, pixelY); + + textureTileIndex = CLAMP(textureTileIndex, 0, ((TQ_INT32)m_imageTextureTiles.count()) - 1); + + return m_imageTextureTiles[textureTileIndex]; +} + +int KisOpenGLImageContext::imageTextureTileWidth() const +{ + return m_imageTextureTileWidth; +} + +int KisOpenGLImageContext::imageTextureTileHeight() const +{ + return m_imageTextureTileHeight; +} + +void KisOpenGLImageContext::createImageTextureTiles() +{ + SharedContextWidget->makeCurrent(); + + destroyImageTextureTiles(); + + m_numImageTextureTileColumns = (m_image->width() + m_imageTextureTileWidth - 1) / m_imageTextureTileWidth; + int numImageTextureTileRows = (m_image->height() + m_imageTextureTileHeight - 1) / m_imageTextureTileHeight; + int numImageTextureTiles = m_numImageTextureTileColumns * numImageTextureTileRows; + + m_imageTextureTiles.resize(numImageTextureTiles); + glGenTextures(numImageTextureTiles, &(m_imageTextureTiles[0])); + + //XXX: will be float/half with shaders + #define RGBA_BYTES_PER_PIXEL 4 + + TQByteArray emptyTilePixelData(m_imageTextureTileWidth * m_imageTextureTileHeight * RGBA_BYTES_PER_PIXEL); + emptyTilePixelData.fill(0); + + for (int tileIndex = 0; tileIndex < numImageTextureTiles; ++tileIndex) { + + glBindTexture(GL_TEXTURE_2D, m_imageTextureTiles[tileIndex]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_imageTextureTileWidth, m_imageTextureTileHeight, 0, + GL_BGRA, GL_UNSIGNED_BYTE, &emptyTilePixelData[0]); + } +} + +void KisOpenGLImageContext::destroyImageTextureTiles() +{ + if (!m_imageTextureTiles.empty()) { + SharedContextWidget->makeCurrent(); + glDeleteTextures(m_imageTextureTiles.count(), &(m_imageTextureTiles[0])); + m_imageTextureTiles.clear(); + } +} + +void KisOpenGLImageContext::update(const TQRect& imageRect) +{ + updateImageTextureTiles(imageRect); +} + +void KisOpenGLImageContext::setSelectionDisplayEnabled(bool enable) +{ + m_displaySelection = enable; +} + +void KisOpenGLImageContext::slotImageUpdated(TQRect rc) +{ + TQRect r = rc & m_image->bounds(); + + updateImageTextureTiles(r); + emit sigImageUpdated(r); +} + +void KisOpenGLImageContext::slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h) +{ + createImageTextureTiles(); + updateImageTextureTiles(m_image->bounds()); + + emit sigSizeChanged(w, h); +} + +#include "kis_opengl_image_context.moc" + +#endif // HAVE_GL + diff --git a/chalk/ui/kis_opengl_image_context.h b/chalk/ui/kis_opengl_image_context.h new file mode 100644 index 00000000..03833cd2 --- /dev/null +++ b/chalk/ui/kis_opengl_image_context.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_OPENGL_IMAGE_CONTEXT_H_ +#define KIS_OPENGL_IMAGE_CONTEXT_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_GL + +#include + +#include +#include +#include + +#include + +#include "kis_types.h" + +class TQRegion; + +class KisOpenGLImageContext; +typedef KSharedPtr KisOpenGLImageContextSP; +class KisColorSpace; + +class KRITACORE_EXPORT KisOpenGLImageContext : public TQObject , public KShared { + + Q_OBJECT + TQ_OBJECT + +public: + static KisOpenGLImageContextSP getImageContext(KisImageSP image, KisProfile *monitorProfile); + + KisOpenGLImageContext(); + virtual ~KisOpenGLImageContext(); + +public: + // In order to use the image textures, the caller must pass + // the sharedContextWidget() as the shareWidget argument to the + // TQGLWidget constructor. + TQGLWidget *sharedContextWidget() const; + + void setMonitorProfile(KisProfile *profile); + void setHDRExposure(float exposure); + + GLuint backgroundTexture() const; + + static const int BACKGROUND_TEXTURE_WIDTH = 32; + static const int BACKGROUND_TEXTURE_HEIGHT = 32; + + // Get the image texture tile containing the point (pixelX, pixelY). + GLuint imageTextureTile(int pixelX, int pixelY) const; + + int imageTextureTileWidth() const; + int imageTextureTileHeight() const; + + /** + * Select selection visualisation rendering. + * + * @param enable Set to true to enable selection visualisation rendering. + */ + void setSelectionDisplayEnabled(bool enable); + + /** + * Update the image textures for the given image rectangle. + * + * @param imageRect The rectangle to update in image coordinates. + */ + void update(const TQRect& imageRect); + +signals: + /** + * Clients using the KisOpenGLImageContext should connect to the + * following signals rather than to the KisImage's own equivalent + * signals. This ensures that the image textures are always up to date + * when used. + */ + + /** + * Emitted whenever an action has caused the image to be recomposited. + * + * @param rc The rect that has been recomposited. + */ + void sigImageUpdated(TQRect rc); + + /** + * Emitted whenever the image size changes. + * + * @param width New image width + * @param height New image height + */ + void sigSizeChanged(TQ_INT32 width, TQ_INT32 height); + +protected: + KisOpenGLImageContext(KisImageSP image, KisProfile *monitorProfile); + + void generateBackgroundTexture(); + void createImageTextureTiles(); + void destroyImageTextureTiles(); + int imageTextureTileIndex(int x, int y) const; + void updateImageTextureTiles(const TQRect& rect); + + static KisColorSpace* textureColorSpaceForImageColorSpace(KisColorSpace *imageColorSpace); + static bool imageCanShareImageContext(KisImageSP image); + +protected slots: + void slotImageUpdated(TQRect r); + void slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h); + +private: + KisImageSP m_image; + KisProfile *m_monitorProfile; + float m_exposure; + bool m_displaySelection; + + GLuint m_backgroundTexture; + + static const int PREFERRED_IMAGE_TEXTURE_WIDTH = 256; + static const int PREFERRED_IMAGE_TEXTURE_HEIGHT = 256; + + TQValueVector m_imageTextureTiles; + int m_imageTextureTileWidth; + int m_imageTextureTileHeight; + int m_numImageTextureTileColumns; + + // We create a single OpenGL context and share it between all views + // in the process. Aptqparently with some OpenGL implementations, only + // one context will be hardware accelerated. + static TQGLWidget *SharedContextWidget; + static int SharedContextWidgetRefCount; + + typedef std::map ImageContextMap; + + static ImageContextMap imageContextMap; +}; + +#endif // HAVE_GL + +#endif // KIS_OPENGL_IMAGE_CONTEXT_H_ + diff --git a/chalk/ui/kis_paintop_box.cc b/chalk/ui/kis_paintop_box.cc new file mode 100644 index 00000000..9f8ac9de --- /dev/null +++ b/chalk/ui/kis_paintop_box.cc @@ -0,0 +1,249 @@ +/* + * kis_paintop_box.cc - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_paintop_box.h" + +KisPaintopBox::KisPaintopBox (KisView * view, TQWidget *tqparent, const char * name) + : super (tqparent, name), + m_canvasController(view->getCanvasController()) +{ +#if KDE_VERSION >= KDE_MAKE_VERSION(3,3,90) + KAcceleratorManager::setNoAccel(this); +#endif + + Q_ASSERT(m_canvasController != 0); + + setCaption(i18n("Painter's Toolchest")); + m_optionWidget = 0; + m_paintops = new TQValueList(); + m_displayedOps = new TQValueList(); + + m_cmbPaintops = new TQComboBox(this, "KisPaintopBox::m_cmbPaintops"); + m_cmbPaintops->setMinimumWidth(150); + TQToolTip::add(m_cmbPaintops, i18n("Styles of painting for the painting tools")); + m_layout = new TQHBoxLayout(this, 1, 1); + m_layout->addWidget(m_cmbPaintops); + + connect(this, TQT_SIGNAL(selected(const KisID &, const KisPaintOpSettings *)), view, TQT_SLOT(paintopActivated(const KisID &, const KisPaintOpSettings *))); + connect(m_cmbPaintops, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotItemSelected(int))); + + // XXX: Let's see... Are all paintops loaded and ready? + KisIDList keys = KisPaintOpRegistry::instance()->listKeys(); + for ( KisIDList::Iterator it = keys.begin(); it != keys.end(); ++it ) { + // add all paintops, and show/hide them afterwards + addItem(*it); + } + + connect(view, TQT_SIGNAL(currentColorSpaceChanged(KisColorSpace*)), + this, TQT_SLOT(colorSpaceChanged(KisColorSpace*))); + connect(view, TQT_SIGNAL(sigInputDeviceChanged(const KisInputDevice&)), + this, TQT_SLOT(slotInputDeviceChanged(const KisInputDevice&))); + + setCurrentPaintop(defaultPaintop(m_canvasController->currentInputDevice())); +} + +KisPaintopBox::~KisPaintopBox() +{ + delete m_paintops; + delete m_displayedOps; +} + +void KisPaintopBox::addItem(const KisID & paintop, const TQString & /*category*/) +{ + m_paintops->append(paintop); +} + +void KisPaintopBox::slotItemSelected(int index) +{ + if ((uint)index > m_displayedOps->count()) { + return; + } + + KisID paintop = *m_displayedOps->at(index); + + setCurrentPaintop(paintop); +} + +void KisPaintopBox::colorSpaceChanged(KisColorSpace *cs) +{ + TQValueList::iterator it = m_paintops->begin(); + TQValueList::iterator end = m_paintops->end(); + m_displayedOps->clear(); + m_cmbPaintops->clear(); + + for ( ; it != end; ++it ) { + if (KisPaintOpRegistry::instance()->userVisible(*it, cs)) { + TQPixmap pm = paintopPixmap(*it); + if (pm.isNull()) { + TQPixmap p = TQPixmap( 16, 16 ); + p.fill(); + m_cmbPaintops->insertItem(p, (*it).name()); + } + else { + m_cmbPaintops->insertItem(pm, (*it).name()); + } + m_displayedOps->append(*it); + } + } + + int index = m_displayedOps->tqfindIndex(currentPaintop()); + + if (index == -1) { + // Must change the paintop as the current one is not supported + // by the new colourspace. + index = 0; + } + + m_cmbPaintops->setCurrentItem( index ); + slotItemSelected( index ); +} + +TQPixmap KisPaintopBox::paintopPixmap(const KisID & paintop) +{ + TQString pixmapName = KisPaintOpRegistry::instance()->pixmap(paintop); + + if (pixmapName.isEmpty()) { + return TQPixmap(); + } + + TQString fname = KisFactory::instance()->dirs()->findResource("kis_images", pixmapName); + + return TQPixmap(fname); +} + +void KisPaintopBox::slotInputDeviceChanged(const KisInputDevice & inputDevice) +{ + KisID paintop; + InputDevicePaintopMap::iterator it = m_currentID.find(inputDevice); + + if (it == m_currentID.end()) { + paintop = defaultPaintop(inputDevice); + } else { + paintop = (*it).second; + } + + int index = m_displayedOps->tqfindIndex(paintop); + + if (index == -1) { + // Must change the paintop as the current one is not supported + // by the new colourspace. + index = 0; + paintop = *m_displayedOps->at(index); + } + + m_cmbPaintops->setCurrentItem(index); + setCurrentPaintop(paintop); +} + +void KisPaintopBox::updateOptionWidget() +{ + if (m_optionWidget != 0) { + m_layout->remove(m_optionWidget); + m_optionWidget->hide(); + m_layout->tqinvalidate(); + } + + const KisPaintOpSettings *settings = paintopSettings(currentPaintop(), m_canvasController->currentInputDevice()); + + if (settings != 0) { + m_optionWidget = settings->widget(); + Q_ASSERT(m_optionWidget != 0); + + m_layout->addWidget(m_optionWidget); + updateGeometry(); + m_optionWidget->show(); + } +} + +const KisID& KisPaintopBox::currentPaintop() +{ + return m_currentID[m_canvasController->currentInputDevice()]; +} + +void KisPaintopBox::setCurrentPaintop(const KisID & paintop) +{ + m_currentID[m_canvasController->currentInputDevice()] = paintop; + + updateOptionWidget(); + + emit selected(paintop, paintopSettings(paintop, m_canvasController->currentInputDevice())); +} + +KisID KisPaintopBox::defaultPaintop(const KisInputDevice& inputDevice) +{ + if (inputDevice == KisInputDevice::eraser()) { + return KisID("eraser",""); + } else { + return KisID("paintbrush",""); + } +} + +const KisPaintOpSettings *KisPaintopBox::paintopSettings(const KisID & paintop, const KisInputDevice & inputDevice) +{ + TQValueVector settingsArray; + InputDevicePaintopSettingsMap::iterator it = m_inputDevicePaintopSettings.find(inputDevice); + + if (it == m_inputDevicePaintopSettings.end()) { + // Create settings for each paintop. + + for (TQValueList::const_iterator pit = m_paintops->begin(); pit != m_paintops->end(); ++pit) { + KisPaintOpSettings *settings = KisPaintOpRegistry::instance()->settings(*pit, this, inputDevice); + settingsArray.append(settings); + if (settings && settings->widget()) { + settings->widget()->hide(); + } + } + m_inputDevicePaintopSettings[inputDevice] = settingsArray; + } else { + settingsArray = (*it).second; + } + + const int index = m_paintops->tqfindIndex(paintop); + if (index >= 0 && index < (int)settingsArray.count()) + return settingsArray[index]; + else + return 0; +} + +#include "kis_paintop_box.moc" + diff --git a/chalk/ui/kis_paintop_box.h b/chalk/ui/kis_paintop_box.h new file mode 100644 index 00000000..90238c78 --- /dev/null +++ b/chalk/ui/kis_paintop_box.h @@ -0,0 +1,104 @@ +/* + * kis_paintop_box.h - part of KImageShop/Krayon/Chalk + * + * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PAINTOP_BOX_H_ +#define KIS_PAINTOP_BOX_H_ + +#include + +#include +#include +#include + +#include "kis_input_device.h" + +class TQString; + +class KWidgetAction; +class KisView; +class KisCanvasController; +class KisID; +class KisColorSpace; + +/** + * This widget presents all paintops that a user can paint with. + * Paintops represent real-world tools or the well-known Shoup + * computer equivalents that do nothing but change color. + * + * XXX: When we have a lot of paintops, replace the listbox + * with a table, and for every category a combobox. + * + * XXX: instead of text, use pretty pictures. + */ +class KisPaintopBox : public TQWidget { + + Q_OBJECT + TQ_OBJECT + + typedef TQWidget super; + +public: + KisPaintopBox (KisView * view, TQWidget * tqparent, const char * name = 0); + + ~KisPaintopBox(); + + +signals: + + void selected(const KisID & id, const KisPaintOpSettings *settings); + +private slots: + + void addItem(const KisID & paintop, const TQString & category = ""); + +private slots: + + void slotItemSelected(int index); + void colorSpaceChanged(KisColorSpace *cs); + void slotInputDeviceChanged(const KisInputDevice & inputDevice); + +private: + TQPixmap paintopPixmap(const KisID & paintop); + void updateOptionWidget(); + const KisID & currentPaintop(); + void setCurrentPaintop(const KisID & paintop); + KisID defaultPaintop(const KisInputDevice& inputDevice); + const KisPaintOpSettings *paintopSettings(const KisID & paintop, const KisInputDevice & inputDevice); + +private: + KisCanvasController *m_canvasController; + TQComboBox * m_cmbPaintops; + TQHBoxLayout * m_layout; + TQWidget * m_optionWidget; + + TQValueList * m_paintops; + TQValueList * m_displayedOps; + + typedef std::map InputDevicePaintopMap; + InputDevicePaintopMap m_currentID; + + typedef std::map > InputDevicePaintopSettingsMap; + InputDevicePaintopSettingsMap m_inputDevicePaintopSettings; +}; + + + +#endif //KIS_PAINTOP_BOX_H_ + diff --git a/chalk/ui/kis_palette_view.cc b/chalk/ui/kis_palette_view.cc new file mode 100644 index 00000000..dfc75eb4 --- /dev/null +++ b/chalk/ui/kis_palette_view.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * (c) 2005 Bart Coppens + * + * Based on already much changed code by Waldo Bastian from KisPaletteWidget + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "kis_palette_view.h" +#include "kis_resource.h" +#include "kis_palette.h" + +KisPaletteView::KisPaletteView(TQWidget *tqparent, const char* name, int minWidth, int cols) + : TQScrollView( tqparent, name ), mMinWidth(minWidth), mCols(cols) +{ + m_cells = 0; + m_currentPalette = 0; + + TQSize cellSize = TQSize( mMinWidth, 50); + + setHScrollBarMode(TQScrollView::AlwaysOff); + setVScrollBarMode(TQScrollView::AlwaysOn); + + TQSize minSize = TQSize(verticalScrollBar()->width(), 0); + minSize += TQSize(frameWidth(), 0); + minSize += TQSize(cellSize); + + setMinimumSize(minSize); + tqsetSizePolicy(TQSizePolicy(TQSizePolicy::Ignored, TQSizePolicy::Ignored)); +} + +KisPaletteView::~KisPaletteView() +{ +} + +KisPalette* KisPaletteView::palette() const +{ + return m_currentPalette; +} + +void KisPaletteView::setPalette(KisPalette* palette) +{ + m_currentPalette = palette; + delete m_cells; + + int rows = (m_currentPalette->nColors() + mCols -1 ) / mCols; + + if (rows < 1) rows = 1; + + m_cells = new KColorCells(viewport(), rows, mCols); + Q_CHECK_PTR(m_cells); + + m_cells->setShading(false); + m_cells->setAcceptDrags(false); + + TQSize cellSize = TQSize( mMinWidth, mMinWidth * rows / mCols); + m_cells->setFixedSize( cellSize ); + + for( int i = 0; i < m_currentPalette->nColors(); i++) + { + TQColor c = m_currentPalette->getColor(i).color; + m_cells->setColor( i, c ); + } + + connect(m_cells, TQT_SIGNAL(colorSelected(int)), + TQT_SLOT(slotColorCellSelected(int))); + + connect(m_cells, TQT_SIGNAL(colorDoubleClicked(int)), + TQT_SLOT(slotColorCellDoubleClicked(int)) ); + + addChild( m_cells ); + m_cells->show(); + updateScrollBars(); +} + +void KisPaletteView::slotColorCellSelected( int col ) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + if (!m_currentPalette || (col >= m_currentPalette->nColors())) + return; + + m_currentEntry = m_currentPalette->getColor(col); + emit colorSelected(KisColor(m_currentPalette->getColor(col).color, cs)); + emit colorSelected(m_currentPalette->getColor(col).color); +} + +void KisPaletteView::slotColorCellDoubleClicked( int col ) +{ + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + if (!m_currentPalette || (col >= m_currentPalette->nColors())) + return; + + emit colorDoubleClicked(KisColor(m_currentPalette->getColor(col).color, cs), + m_currentPalette->getColor(col).name); +} + +#include "kis_palette_view.moc" + diff --git a/chalk/ui/kis_palette_view.h b/chalk/ui/kis_palette_view.h new file mode 100644 index 00000000..79b3e0b0 --- /dev/null +++ b/chalk/ui/kis_palette_view.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005 Bart Coppens + * (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_PALETTE_VIEW_H__ +#define __KIS_PALETTE_VIEW_H__ + +#include +#include "kis_palette.h" + +class KListBox; +class KisPalette; +class KColorCells; +class KisResource; +class KisColor; + +/** + * A scrolling view that lists a single KisPalette + */ +class KisPaletteView : public TQScrollView +{ + Q_OBJECT + TQ_OBJECT +public: + KisPaletteView(TQWidget *tqparent, const char* name = 0, int minWidth=210, int cols = 16); + virtual ~KisPaletteView(); + + KisPalette* palette() const; + /// Might return the default constructed entry... + KisPaletteEntry currentEntry() const { return m_currentEntry; } + +public slots: + void setPalette(KisPalette* p); + +signals: + void colorSelected(const KisColor &); + void colorSelected(const TQColor &); + void colorDoubleClicked(const KisColor &, const TQString &); + +protected slots: + void slotColorCellSelected( int ); + void slotColorCellDoubleClicked( int ); + +protected: + KisPalette* m_currentPalette; + KColorCells* m_cells; + KisPaletteEntry m_currentEntry; + int mMinWidth; + int mCols; + + friend class KisPaletteWidget; // Because it calls slotColorCellSelected from a FIXME +}; + +#endif + diff --git a/chalk/ui/kis_palette_widget.cc b/chalk/ui/kis_palette_widget.cc new file mode 100644 index 00000000..a8305337 --- /dev/null +++ b/chalk/ui/kis_palette_widget.cc @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "kis_palette_widget.h" +#include "kis_resource.h" +#include "kis_palette.h" +#include "kis_palette_view.h" + +KisPaletteWidget::KisPaletteWidget( TQWidget *tqparent, int minWidth, int cols) + : TQWidget( tqparent ), mMinWidth(minWidth), mCols(cols) +{ + init = false; + + m_currentPalette = 0; + + TQVBoxLayout *tqlayout = new TQVBoxLayout( this ); + + combo = new TQComboBox( false, this ); + combo->setFocusPolicy( TQ_ClickFocus ); + tqlayout->addWidget(combo); + + m_view = new KisPaletteView(this, 0, minWidth, cols); + tqlayout->addWidget( m_view ); + + //setFixedSize(tqsizeHint()); + + connect(combo, TQT_SIGNAL(activated(const TQString &)), + this, TQT_SLOT(slotSetPalette(const TQString &))); + connect(m_view, TQT_SIGNAL(colorSelected(const KisColor &)), + this, TQT_SIGNAL(colorSelected(const KisColor &))); + connect(m_view, TQT_SIGNAL(colorSelected(const TQColor &)), + this, TQT_SIGNAL(colorSelected(const TQColor &))); + connect(m_view, TQT_SIGNAL(colorDoubleClicked(const KisColor &, const TQString &)), + this, TQT_SIGNAL(colorDoubleClicked(const KisColor &, const TQString &))); +} + +KisPaletteWidget::~KisPaletteWidget() +{ +} + +TQString KisPaletteWidget::palette() const +{ + return combo->currentText(); +} + + +// 2000-02-12 Espen Sand +// Set the color in two steps. The setPalette() slot will not emit a signal +// with the current color setting. The reason is that setPalette() is used +// by the color selector dialog on startup. In the color selector dialog +// we normally want to display a startup color which we specify +// when the dialog is started. The slotSetPalette() slot below will +// set the palette and then use the information to emit a signal with the +// new color setting. It is only used by the combobox widget. +// +void KisPaletteWidget::slotSetPalette( const TQString &_paletteName ) +{ + setPalette( _paletteName ); + m_view->slotColorCellSelected(0); // FIXME: We need to save the current value!! +} + + +void KisPaletteWidget::setPalette( const TQString &_paletteName ) +{ + TQString paletteName( _paletteName); + + m_currentPalette = m_namedPaletteMap[paletteName]; + + if (combo->currentText() != paletteName) + { + bool found = false; + for(int i = 0; i < combo->count(); i++) + { + if (combo->text(i) == paletteName) + { + combo->setCurrentItem(i); + found = true; + break; + } + } + if (!found) + { + combo->insertItem(paletteName); + combo->setCurrentItem(combo->count()-1); + } + } + + m_view->setPalette(m_currentPalette); +} + +void KisPaletteWidget::slotAddPalette(KisResource * palette) +{ + KisPalette * p = dynamic_cast(palette); + + m_namedPaletteMap.insert(palette->name(), p); + + combo->insertItem(palette->name()); + + if (!init) { + combo->setCurrentItem(0); + setPalette(combo ->currentText()); + init = true; + } +} + + +#include "kis_palette_widget.moc" + diff --git a/chalk/ui/kis_palette_widget.h b/chalk/ui/kis_palette_widget.h new file mode 100644 index 00000000..6323b0a7 --- /dev/null +++ b/chalk/ui/kis_palette_widget.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_PALETTE_WIDGET_H__ +#define __KIS_PALETTE_WIDGET_H__ + +#include +#include "kis_palette_view.h" + +class TQComboBox; +class TQLineEdit; +class KListBox; +class KisPalette; +class KisResource; +class KisColor; + +/** + * A color palette in table form. + * + * This is copied, mostly, from KPaletteTable in KColorDialog, original + * @author was Waldo Bastian -- much has changed, though, + * to work with KisPalettes and the resource server. + */ +class KisPaletteWidget : public TQWidget +{ + Q_OBJECT + TQ_OBJECT +public: + KisPaletteWidget( TQWidget *tqparent, int minWidth=210, int cols = 16); + virtual ~KisPaletteWidget(); + + TQString palette() const; + KisPaletteEntry currentEntry() const { return m_view->currentEntry(); } + +public slots: + void setPalette(const TQString &paletteName); + +signals: + void colorSelected(const KisColor &); + void colorSelected(const TQColor&); + void colorDoubleClicked( const KisColor &, const TQString &); + +protected slots: + void slotSetPalette( const TQString &_paletteName ); + +public slots: + // Called by the resource server whenever a palette is loaded. + void slotAddPalette(KisResource * palette); + +protected: + void readNamedColor( void ); + +protected: + KisPaletteView* m_view; + TQDict m_namedPaletteMap; + KisPalette * m_currentPalette; + TQComboBox *combo; + TQScrollView *sv; + int mMinWidth; + int mCols; + bool init; +}; + +#endif + diff --git a/chalk/ui/kis_part_layer.cc b/chalk/ui/kis_part_layer.cc new file mode 100644 index 00000000..401721b5 --- /dev/null +++ b/chalk/ui/kis_part_layer.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * (c) 2005 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "tqpaintdevice.h" +#include "tqpixmap.h" +#include "tqimage.h" +#include "tqpainter.h" + +#include + +#include "KoDocument.h" +#include "KoDocumentChild.h" +#include "KoFrame.h" +#include "KoView.h" + +#include "kis_layer.h" +#include "kis_types.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_part_layer.h" +#include "kis_group_layer.h" +#include "kis_factory.h" +#include "kis_paint_device.h" +#include + +KisChildDoc::KisChildDoc ( KisDoc * kisDoc, const TQRect & rect, KoDocument * childDoc ) + : KoDocumentChild( kisDoc, childDoc, rect ) + , m_doc(kisDoc) + , m_partLayer(0) +{ +} + + +KisChildDoc::KisChildDoc ( KisDoc * kisDoc ) + : KoDocumentChild( kisDoc) + , m_partLayer(0) +{ +} + +KisChildDoc::~KisChildDoc () +{ + // XXX doesn't this get deleted by itself or by anything else? Certainly looks so + // (otherwise I get a double deletion of a TQObject, and chalk crashes) + //delete m_doc; +} + + +KisPartLayerImpl::KisPartLayerImpl(KisImageSP img, KisChildDoc * doc) + : super(img, i18n("Embedded Document"), OPACITY_OPAQUE), m_doc(doc) +{ + m_cache = new KisPaintDevice( + KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), name().latin1() ); + m_activated = false; +} + +KisPartLayerImpl::~KisPartLayerImpl() +{ +} + +KisLayerSP KisPartLayerImpl::clone() const { + return new KisPartLayerImpl(image(), childDoc()); +} + +// Called when the layer is made active +void KisPartLayerImpl::childActivated(KoDocumentChild* child) +{ + // Clear the image, so that if we move the part while activated, no ghosts show up + if (!m_activated && child == m_doc) { + TQRect rect = extent(); + m_activated = true; + setDirty(rect); + TQPtrList views = child->tqparentDocument()->views(); + Q_ASSERT(views.count()); + // XXX iterate over views + connect(views.at(0), TQT_SIGNAL(activated(bool)), + this, TQT_SLOT(childDeactivated(bool))); + } +} + +// Called when another layer is made inactive +void KisPartLayerImpl::childDeactivated(bool activated) +{ + // We probably changed, notify the image that it needs to tqrepaint where we currently updated + // We use the original tqgeometry + if (m_activated && !activated /* no clue, but debugging suggests it is false here */) { + TQPtrList views = m_doc->tqparentDocument()->views(); + Q_ASSERT(views.count()); + views.at(0)->disconnect(TQT_SIGNAL(activated(bool))); + m_activated = false; + setDirty(m_doc->tqgeometry()); + } +} + +void KisPartLayerImpl::setX(TQ_INT32 x) { + TQRect rect = m_doc->tqgeometry(); + + // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here, + // since the part is not necesarily started at (0,0) + rect.moveBy(x - this->x(), 0); + m_doc->setGeometry(rect); +} + +void KisPartLayerImpl::setY(TQ_INT32 y) { + TQRect rect = m_doc->tqgeometry(); + + // KisPaintDevice::move moves to absolute coordinates, not relative. Work around that here, + // since the part is not necesarily started at (0,0) + rect.moveBy(0, y - this->y()); + m_doc->setGeometry(rect); +} + +void KisPartLayerImpl::paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) { + uchar *j = img.bits(); + TQRect rect = m_doc->tqgeometry(); + + for (int y2 = y; y2 < h + y; ++y2) { + for (int x2 = x; x2 < w + x; ++x2) { + if (!rect.tqcontains(x2, y2)) { + TQ_UINT8 g = (*(j + 0) + *(j + 1 ) + *(j + 2 )) / 9; + *(j+0) = 165+g; + *(j+1) = 128+g; + *(j+2) = 128+g; + } + j+=4; + } + } + +} + +KisPaintDeviceSP KisPartLayerImpl::prepareProjection(KisPaintDeviceSP projection, const TQRect& r) +{ + if (!m_doc || !m_doc->document() || m_activated) return 0; + + m_cache->clear(); + + TQRect intersection(r.intersect(exactBounds())); + if (intersection.isEmpty()) + return m_cache; + // XXX: have a look at the comments and see if they still truthfully represent the code :/ + + // We know the embedded part's size through the ChildDoc + // We move it to (0,0), since that is what we will start painting from in paintEverything. + TQRect embedRect(intersection); + embedRect.moveBy(- exactBounds().x(), - exactBounds().y()); + TQRect paintRect(exactBounds()); + paintRect.moveBy(- exactBounds().x(), - exactBounds().y()); + + TQPixmap pm1(projection->convertToTQImage(0 /*srgb XXX*/, + intersection.x(), intersection.y(), + intersection.width(), intersection.height())); + TQPixmap pm2(extent().width(), extent().height()); + copyBlt(&pm2, embedRect.x(), embedRect.y(), &pm1, + 0, 0, embedRect.width(), embedRect.height()); + TQPainter painter(&pm2); + painter.setClipRect(embedRect); + + // KWord's KWPartFrameSet::drawFrameContents has some interesting remarks concerning + // the semantics of the paintEverything call. + // Since a Chalk Device really is displaysize/zoom agnostic, caring about zoom is not + // really as important here. What we paint at the moment, is just (0,0)x(w,h) + // Paint transparent, no zoom: + m_doc->document()->paintEverything(painter, paintRect, true); + + copyBlt(&pm1, 0, 0, &pm2, + embedRect.x(), embedRect.y(), embedRect.width(), embedRect.height()); + TQImage qimg = pm1.convertToImage(); + + //assume the part is sRGB for now, and that "" is sRGB + // And we need to paint offsetted + m_cache->convertFromTQImage(qimg, "", intersection.left(), intersection.top()); + + return m_cache; +} + +TQImage KisPartLayerImpl::createThumbnail(TQ_INT32 w, TQ_INT32 h) { + TQRect bounds(exactBounds()); + TQPixmap pm(w, h); + TQPainter painter(&pm); + + painter.fillRect(0, 0, w, h, TQt::white); + + painter.scale(w / bounds.width(), h / bounds.height()); + m_doc->document()->paintEverything(painter, bounds); + TQImage qimg = pm.convertToImage(); + + return qimg; +} + +bool KisPartLayerImpl::saveToXML(TQDomDocument doc, TQDomElement elem) +{ + TQDomElement embeddedElement = doc.createElement("layer"); + embeddedElement.setAttribute("name", name()); + + // x and y are loaded from the rect element in the embedded object tag + embeddedElement.setAttribute("x", 0); + embeddedElement.setAttribute("y", 0); + + embeddedElement.setAttribute("opacity", opacity()); + embeddedElement.setAttribute("compositeop", compositeOp().id().id()); + embeddedElement.setAttribute("visible", visible()); + embeddedElement.setAttribute("locked", locked()); + embeddedElement.setAttribute("layertype", "partlayer"); + elem.appendChild(embeddedElement); + + TQDomElement objectElem = childDoc()->save(doc); + embeddedElement.appendChild(objectElem); + + return true; +} + +KisConnectPartLayerVisitor::KisConnectPartLayerVisitor(KisImageSP img, KisView* view, bool mode) + : m_img(img), m_view(view), m_connect(mode) +{ +} + +bool KisConnectPartLayerVisitor::visit(KisGroupLayer *layer) { + KisLayerSP child = layer->lastChild(); + + while (child) { + child->accept(*this); + child = child->prevSibling(); + } + + return true; +} + +bool KisConnectPartLayerVisitor::visit(KisPartLayer *layer) { + if (m_connect) { + TQObject::connect(m_view, TQT_SIGNAL(childActivated(KoDocumentChild*)), + layer, TQT_SLOT(childActivated(KoDocumentChild*))); + } else { + TQObject::disconnect(m_view, TQT_SIGNAL(childActivated(KoDocumentChild*)), layer, 0 ); + } + + return true; +} + +bool KisConnectPartLayerVisitor::visit(KisPaintLayer*) { + return true; +} + +bool KisConnectPartLayerVisitor::visit(KisAdjustmentLayer*) { + return true; +} + +#include "kis_part_layer.moc" diff --git a/chalk/ui/kis_part_layer.h b/chalk/ui/kis_part_layer.h new file mode 100644 index 00000000..65026139 --- /dev/null +++ b/chalk/ui/kis_part_layer.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_PART_LAYER_ +#define _KIS_PART_LAYER_ + +#include + +#include +#include + +#include "kis_paint_layer.h" +#include "kis_types.h" +#include "kis_doc.h" +#include "kis_part_layer_iface.h" +#include "kis_view.h" +#include "kis_layer_visitor.h" + +class KoFrame; +class KoDocument; + + +/** + * The child document is responsible for saving and loading the embedded layers. + */ +class KisChildDoc : public KoDocumentChild +{ + +public: + KisChildDoc ( KisDoc * kisDoc, const TQRect& rect, KoDocument * childDoc ); + KisChildDoc ( KisDoc * kisDdoc ); + + virtual ~KisChildDoc(); + + KisDoc * tqparent() const { return m_doc; } + + void setPartLayer (KisPartLayerSP layer) { m_partLayer = layer; } + + KisPartLayerSP partLayer() const { return m_partLayer; } +protected: + + KisDoc * m_doc; + KisPartLayerSP m_partLayer; +}; + + +/** + * A PartLayer is a layer that contains a KOffice Part like a KWord document + * or a KSpread spreadsheet. Or whatever. A Karbon drawing. + * + * The part is rendered into an RBGA8 paint device so we can composite it with + * the other layers. + * + * When it is activated (see activate()), it draws a rectangle around itself on the kisdoc, + * whereas when it is deactivated (deactivate()), it removes that rectangle and commits + * the child to the paint device. + * + * Embedded parts should get loaded and saved to the Native Chalk Fileformat natively. + */ +class KisPartLayerImpl : public KisPartLayer { + Q_OBJECT + TQ_OBJECT + typedef KisPartLayer super; +public: + KisPartLayerImpl(KisImageSP img, KisChildDoc * doc); + virtual ~KisPartLayerImpl(); + + virtual KisLayerSP clone() const; + + /// Called when the layer is made active + virtual void activate() {} + + /// Called when another layer is made inactive + virtual void deactivate() {} + + /// Returns the childDoc so that we can access the doc from other places, if need be (KisDoc) + virtual KisChildDoc* childDoc() const { return m_doc; } + + void setDocType(const TQString& type) { m_docType = type; } + TQString docType() const { return m_docType; } + + virtual void setX(TQ_INT32 x); + virtual void setY(TQ_INT32 y); + virtual TQ_INT32 x() const { return m_doc->tqgeometry() . x(); } + virtual TQ_INT32 y() const { return m_doc->tqgeometry() . y(); } //m_paintLayer->y(); } + virtual TQRect extent() const { return m_doc->tqgeometry(); } + virtual TQRect exactBounds() const { return m_doc->tqgeometry(); } + + virtual TQImage createThumbnail(TQ_INT32 w, TQ_INT32 h); + + virtual bool accept(KisLayerVisitor& visitor) { + return visitor.visit(this); + } + + virtual KisPaintDeviceSP prepareProjection(KisPaintDeviceSP projection, const TQRect& r); + + virtual void paintSelection(TQImage &img, TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + + virtual bool saveToXML(TQDomDocument doc, TQDomElement elem); +private slots: + /// Repaints our device with the data from the embedded part + //void tqrepaint(); + /// When we activate the embedding, we clear ourselves + void childActivated(KoDocumentChild* child); + void childDeactivated(bool activated); + + +private: + // KisPaintLayerSP m_paintLayer; + KisPaintDeviceSP m_cache; + KoFrame * m_frame; // The widget that holds the editable view of the embedded part + KisChildDoc * m_doc; // The sub-document + TQString m_docType; + bool m_activated; +}; + +/** + * Visitor that connects all partlayers in an image to a KisView's signals + */ +class KisConnectPartLayerVisitor : public KisLayerVisitor { + KisImageSP m_img; + KisView* m_view; + bool m_connect; // connects, or disconnects signals +public: + KisConnectPartLayerVisitor(KisImageSP img, KisView* view, bool mode); + virtual ~KisConnectPartLayerVisitor() {} + + virtual bool visit(KisPaintLayer *layer); + virtual bool visit(KisGroupLayer *layer); + virtual bool visit(KisPartLayer *layer); + virtual bool visit(KisAdjustmentLayer *layer); +}; + +#endif // _KIS_PART_LAYER_ diff --git a/chalk/ui/kis_part_layer_handler.cc b/chalk/ui/kis_part_layer_handler.cc new file mode 100644 index 00000000..f062e4a1 --- /dev/null +++ b/chalk/ui/kis_part_layer_handler.cc @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_canvas.h" +#include // kis_canvas.h does X11 stuff + +#include +#include + +#include "kis_cursor.h" +#include "kis_canvas_painter.h" +#include "kis_move_event.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_group_layer.h" +#include "kis_part_layer_handler.h" + +KisPartLayerHandler::KisPartLayerHandler(KisView* view, const KoDocumentEntry& entry, + KisGroupLayerSP tqparent, KisLayerSP above) + : m_parent(tqparent), m_above(above), m_view(view), m_entry(entry) { + m_started = false; + view->getCanvasController()->setCanvasCursor( KisCursor::selectCursor() ); +} + +void KisPartLayerHandler::done() { + emit handlerDone(); // We will get deleted by the view +} + +void KisPartLayerHandler::gotMoveEvent(KisMoveEvent* event) { + if (!m_started) { + emit sigGotMoveEvent(event); + return; + } + + KisCanvasPainter painter(m_view->getCanvasController()->kiscanvas()); + painter.setRasterOp( NotROP ); + + // erase old lines + TQRect r(m_start, m_end); + r = r.normalize(); + if (!r.isEmpty()) + painter.drawRect(r); + + m_end = event->pos().roundTQPoint(); + r = TQRect(m_start, m_end).normalize(); + + painter.drawRect(r); + painter.end(); +} + +void KisPartLayerHandler::gotButtonPressEvent(KisButtonPressEvent* event) { + m_start = event->pos().roundTQPoint(); + m_end = m_start; + m_started = true; +} + +void KisPartLayerHandler::gotButtonReleaseEvent(KisButtonReleaseEvent* event) { + if (!m_started) { + done(); + return; + } + + m_end = event->pos().roundTQPoint(); + + TQRect r(m_start, m_end); + + m_view->insertPart(r.normalize(), m_entry, m_parent, m_above); + // We will get deleted by the view through the above +} + +void KisPartLayerHandler::gotKeyPressEvent(TQKeyEvent* event) { + if (event->key() == Key_Escape) { + done(); + } else { + emit sigGotKeyPressEvent(event); + } +} + +#include "kis_part_layer_handler.moc" diff --git a/chalk/ui/kis_part_layer_handler.h b/chalk/ui/kis_part_layer_handler.h new file mode 100644 index 00000000..746b23d9 --- /dev/null +++ b/chalk/ui/kis_part_layer_handler.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2006 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PART_LAYER_HANDLER_ +#define KIS_PART_LAYER_HANDLER_ + +#include +#include // KoDocumentEntry + +#include "kis_types.h" +#include "kis_doc.h" +#include "kis_view.h" + +class TQKeyEvent; + +class KisPartLayerHandler : public TQObject { +Q_OBJECT + TQ_OBJECT +public: + KisPartLayerHandler(KisView* view, const KoDocumentEntry& entry, + KisGroupLayerSP tqparent, KisLayerSP above); +signals: + void sigGotMoveEvent(KisMoveEvent* event); + void sigGotKeyPressEvent(TQKeyEvent* event); + void handlerDone(); + +protected slots: + + void gotMoveEvent(KisMoveEvent* event); + void gotButtonPressEvent(KisButtonPressEvent* event); + void gotButtonReleaseEvent(KisButtonReleaseEvent* event); + void gotKeyPressEvent(TQKeyEvent* event); +protected: + void done(); + KisGroupLayerSP m_parent; + KisLayerSP m_above; + KisView* m_view; + KoDocumentEntry m_entry; + TQPoint m_start; + TQPoint m_end; + bool m_started; +}; + +#endif // KIS_PART_LAYER_HANDLER diff --git a/chalk/ui/kis_pattern_chooser.cc b/chalk/ui/kis_pattern_chooser.cc new file mode 100644 index 00000000..f19200bf --- /dev/null +++ b/chalk/ui/kis_pattern_chooser.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include "kis_colorspace.h" +#include "kis_pattern_chooser.h" +#include "kis_global.h" +#include "kis_icon_item.h" +#include "kis_pattern.h" + +KisPatternChooser::KisPatternChooser(TQWidget *tqparent, const char *name) : super(tqparent, name) +{ + m_lbName = new TQLabel(this); + + TQVBoxLayout *mainLayout = new TQVBoxLayout(this, 2, -1, "main tqlayout"); + + mainLayout->addWidget(m_lbName); + mainLayout->addWidget(chooserWidget(), 10); +} + +KisPatternChooser::~KisPatternChooser() +{ +} + +void KisPatternChooser::update(KoIconItem *item) +{ + KisIconItem *kisItem = static_cast(item); + + if (item) { + KisPattern *pattern = static_cast(kisItem->resource()); + + TQString text = TQString("%1 (%2 x %3)").tqarg(pattern->name()).tqarg(pattern->width()).tqarg(pattern->height()); + + m_lbName->setText(text); + } +} + +#include "kis_pattern_chooser.moc" + diff --git a/chalk/ui/kis_pattern_chooser.h b/chalk/ui/kis_pattern_chooser.h new file mode 100644 index 00000000..b7a61080 --- /dev/null +++ b/chalk/ui/kis_pattern_chooser.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PATTERN_CHOOSER_H_ +#define KIS_PATTERN_CHOOSER_H_ + +#include "kis_itemchooser.h" + +class TQLabel; + +class KisPatternChooser : public KisItemChooser { + typedef KisItemChooser super; + Q_OBJECT + TQ_OBJECT + +public: + KisPatternChooser(TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisPatternChooser(); + +protected: + virtual void update(KoIconItem *item); + +private: + TQLabel *m_lbName; +}; + +#endif // KIS_PATTERN_CHOOSER_H_ + diff --git a/chalk/ui/kis_perspective_grid_manager.cpp b/chalk/ui/kis_perspective_grid_manager.cpp new file mode 100644 index 00000000..c454af80 --- /dev/null +++ b/chalk/ui/kis_perspective_grid_manager.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_perspective_grid_manager.h" + +#include +#include +#include + +#include "kis_image.h" +#include "kis_grid_drawer.h" +#include "kis_perspective_grid.h" +#include "kis_view.h" + +KisPerspectiveGridManager::KisPerspectiveGridManager(KisView * tqparent) + : TQObject() + , m_toggleEdition(false) + , m_view(tqparent) +{ + +} + + +KisPerspectiveGridManager::~KisPerspectiveGridManager() +{ + +} + +void KisPerspectiveGridManager::updateGUI() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + + if (image ) { + KisPerspectiveGrid* pGrid = image->perspectiveGrid(); + m_toggleGrid->setEnabled( pGrid->hasSubGrids()); + } +} + +void KisPerspectiveGridManager::setup(KActionCollection * collection) +{ + kdDebug() << "KisPerspectiveGridManager::setup(KActionCollection * collection)" << endl; + m_toggleGrid = new KToggleAction(i18n("Show Perspective Grid"), "", this, TQT_SLOT(toggleGrid()), collection, "view_toggle_perspective_grid"); + m_toggleGrid->setCheckedState(KGuiItem(i18n("Hide Perspective Grid"))); + m_toggleGrid->setChecked(false); + m_gridClear = new KAction(i18n("Clear Perspective Grid"), 0, "", this, TQT_SLOT(clearPerspectiveGrid()), collection, "view_clear_perspective_grid"); +} + +void KisPerspectiveGridManager::setGridVisible(bool t) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + + if (t && image ) { + KisPerspectiveGrid* pGrid = image->perspectiveGrid(); + if( pGrid->hasSubGrids()) + { + m_toggleGrid->setChecked(true); + } + } else { + m_toggleGrid->setChecked(false); + } + m_view->refreshKisCanvas(); +} + + +void KisPerspectiveGridManager::toggleGrid() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + + if (image && m_toggleGrid->isChecked()) { + KisPerspectiveGrid* pGrid = image->perspectiveGrid(); + + if(!pGrid->hasSubGrids()) + { + KMessageBox::error(0, i18n("Before displaying the perspective grid, you need to initialize it with the perspective grid tool"), i18n("No Perspective Grid to Display") ); + m_toggleGrid->setChecked(false); + } + } + m_view->updateCanvas(); +} + +void KisPerspectiveGridManager::clearPerspectiveGrid() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (image ) { + image->perspectiveGrid()->clearSubGrids(); + m_view->updateCanvas(); + m_toggleGrid->setChecked(false); + m_toggleGrid->setEnabled(false); + } +} + +void KisPerspectiveGridManager::startEdition() +{ + m_toggleEdition = true; + m_toggleGrid->setEnabled( false ); + if( m_toggleGrid->isChecked() ) + m_view->updateCanvas(); +} + +void KisPerspectiveGridManager::stopEdition() +{ + m_toggleEdition = false; + m_toggleGrid->setEnabled( true ); + if( m_toggleGrid->isChecked() ) + m_view->updateCanvas(); +} + +void KisPerspectiveGridManager::drawGrid(TQRect wr, TQPainter *p, bool openGL ) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + + + if (image && m_toggleGrid->isChecked() && !m_toggleEdition) { + KisPerspectiveGrid* pGrid = image->perspectiveGrid(); + + GridDrawer *gridDrawer = 0; + + if (openGL) { + gridDrawer = new OpenGLGridDrawer(); + } else { + Q_ASSERT(p); + + if (p) { + gridDrawer = new TQPainterGridDrawer(p); + } + } + + Q_ASSERT(gridDrawer != 0); + + for( TQValueList::const_iterator it = pGrid->begin(); it != pGrid->end(); ++it) + { + gridDrawer->drawPerspectiveGrid(image, wr, *it ); + } + delete gridDrawer; + } +} + + +#include "kis_perspective_grid_manager.moc" diff --git a/chalk/ui/kis_perspective_grid_manager.h b/chalk/ui/kis_perspective_grid_manager.h new file mode 100644 index 00000000..85954ba4 --- /dev/null +++ b/chalk/ui/kis_perspective_grid_manager.h @@ -0,0 +1,55 @@ +/* + * This file is part of Chalk + * + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PERSPECTIVE_GRID_MANAGER_H +#define KIS_PERSPECTIVE_GRID_MANAGER_H + +#include + +class KAction; +class KActionCollection; +class KToggleAction; +class KisView; + +class KisPerspectiveGridManager : public TQObject +{ + Q_OBJECT + TQ_OBJECT + public: + KisPerspectiveGridManager(KisView * tqparent); + ~KisPerspectiveGridManager(); + void setup(KActionCollection * collection); + void drawGrid(TQRect wr, TQPainter *p, bool openGL = false); + void startEdition(); + void stopEdition(); + void setGridVisible(bool t); + public slots: + void updateGUI(); + void clearPerspectiveGrid(); + private slots: + void toggleGrid(); + private: + bool m_toggleEdition; + KisView* m_view; + KToggleAction* m_toggleGrid; + KAction* m_gridClear; +}; + +#endif diff --git a/chalk/ui/kis_populate_visitor.h b/chalk/ui/kis_populate_visitor.h new file mode 100644 index 00000000..d228137a --- /dev/null +++ b/chalk/ui/kis_populate_visitor.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005 Gábor Lehel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_POPULATE_VISITOR_H +#define KIS_POPULATE_VISITOR_H + +#include +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_part_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_layerlist.h" + + +/** + * This visitor walks over the layer tree to fill + * the layer box. + */ +class KisPopulateVisitor: public KisLayerVisitor +{ + public: + KisPopulateVisitor(KisLayerList* widget) + : m_widget(widget) + , m_parent(0) + { } + + KisPopulateVisitor(KisLayerItem* tqparent) + : m_widget(tqparent->listView()) + , m_parent(tqparent) + { } + + virtual bool visit(KisPaintLayer* layer) + { + if (!layer->temporary()) + add(layer); + return true; + } + + virtual bool visit(KisPartLayer* layer) + { + add(layer)->setPixmap(0, SmallIcon("gear", 16)); + return true; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + add(layer)->setPixmap(0, SmallIcon("tool_filter", 16)); + return true; + } + + virtual bool visit(KisGroupLayer* layer) + { + KisLayerItem* item = add(layer); + item->makeFolder(); + KisPopulateVisitor visitor(item); + for (KisLayerSP l = layer->firstChild(); l; l = l->nextSibling()) + l->accept(visitor); + + vKisLayerSP childLayersAdded = visitor.layersAdded(); + + for (vKisLayerSP::iterator it = childLayersAdded.begin(); it != childLayersAdded.end(); ++it) { + m_layersAdded.append(*it); + } + + return true; + } + + vKisLayerSP layersAdded() const + { + return m_layersAdded; + } + + private: + LayerList* m_widget; + KisLayerItem* m_parent; + vKisLayerSP m_layersAdded; + + KisLayerItem* add(KisLayer* layer) + { + if (!layer) return 0; + + KisImageSP img = layer->image(); + if (!img) return 0; + + KisLayerItem *item; + if (m_parent) { + item = new KisLayerItem(m_parent, layer); + } + else { + item = new KisLayerItem(m_widget, layer); + } + if (layer == img->activeLayer()) { + item->setActive(); + } + m_layersAdded.append(layer); + return item; + } +}; + +#endif diff --git a/chalk/ui/kis_previewdialog.cc b/chalk/ui/kis_previewdialog.cc new file mode 100644 index 00000000..fdeb872a --- /dev/null +++ b/chalk/ui/kis_previewdialog.cc @@ -0,0 +1,46 @@ +/* + * kis_previewdialog.cc - part of Chalk + * + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include "kis_previewwidget.h" +#include "kis_previewdialog.h" + +KisPreviewDialog::KisPreviewDialog( TQWidget * tqparent, const char * name, bool modal, const TQString &caption) + : super (tqparent, name, modal, caption, Ok | Cancel, Ok) +{ + TQHBox* tqlayout = new TQHBox(this); + tqlayout->setSpacing( 6 ); + + m_containerFrame = new TQFrame( tqlayout, "container" ); + + m_preview = new KisPreviewWidget( tqlayout, "previewWidget" ); + + setMainWidget(tqlayout); +} + +KisPreviewDialog::~KisPreviewDialog() +{ + +} + +#include "kis_previewdialog.moc" diff --git a/chalk/ui/kis_previewdialog.h b/chalk/ui/kis_previewdialog.h new file mode 100644 index 00000000..9f268d44 --- /dev/null +++ b/chalk/ui/kis_previewdialog.h @@ -0,0 +1,45 @@ +/* + * kis_previewdialog.h -- part of Chalk + * + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_PREVIEWDIALOG_H +#define KIS_PREVIEWDIALOG_H + +#include + +class KisPreviewWidget; +class TQFrame; + +class KisPreviewDialog: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + TQ_OBJECT + +public: + KisPreviewDialog( TQWidget* tqparent = 0, const char* name = 0, bool modal = false, const TQString &caption=TQString()); + ~KisPreviewDialog(); + + KisPreviewWidget* previewWidget() { return m_preview; } + TQFrame* container() { return m_containerFrame; } +private: + KisPreviewWidget* m_preview; + TQFrame* m_containerFrame; +}; + +#endif diff --git a/chalk/ui/kis_previewwidget.cc b/chalk/ui/kis_previewwidget.cc new file mode 100644 index 00000000..c9c2a766 --- /dev/null +++ b/chalk/ui/kis_previewwidget.cc @@ -0,0 +1,409 @@ +/* + * kis_previewwidget.cc - part of Chalk + * + * Copyright (c) 2001 John Califf + * Copyright (c) 2004 Bart Coppens + * Copyright (c) 2005 Cyrille Berger + * Copyright (c) 2007 Ben Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_previewwidgetbase.h" +#include "kis_previewwidget.h" +#include "imageviewer.h" + +static const int ZOOM_PAUSE = 100; +static const int FILTER_PAUSE = 500; +static const double ZOOM_FACTOR = 1.1; + +KisPreviewWidget::KisPreviewWidget( TQWidget* tqparent, const char* name ) + : PreviewWidgetBase( tqparent, name ) + , m_autoupdate(true) + , m_previewIsDisplayed(true) + , m_scaledOriginal() + , m_dirtyOriginal(true) + , m_origDevice(new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temp")) + , m_scaledPreview() + , m_dirtyPreview(true) + , m_previewDevice(new KisPaintDevice(KisMetaRegistry::instance()->csRegistry()->getRGB8(), "temp")) + , m_scaledImage(NULL) + , m_filterZoom(1.0) + , m_zoom(-1.0) + , m_profile(NULL) + , m_progress( 0 ) + , m_zoomTimer(new TQTimer(this)) + , m_filterTimer(new TQTimer(this)) + , m_firstFilter(true) + , m_firstZoom(true) +{ + btnZoomIn->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag+", KIcon::MainToolbar, 16 )); + connect(btnZoomIn, TQT_SIGNAL(clicked()), this, TQT_SLOT(zoomIn())); + btnZoomOut->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag-", KIcon::MainToolbar, 16 )); + connect(btnZoomOut, TQT_SIGNAL(clicked()), this, TQT_SLOT(zoomOut())); + btnUpdate->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "reload", KIcon::MainToolbar, 16 )); + connect(btnUpdate, TQT_SIGNAL(clicked()), this, TQT_SLOT(forceUpdate())); + + connect(radioBtnPreview, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(setPreviewDisplayed(bool))); + + connect(checkBoxAutoUpdate, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetAutoUpdate(bool))); + btnZoomOneToOne->setIconSet(KGlobal::instance()->iconLoader()->loadIconSet( "viewmag1", KIcon::MainToolbar, 16 )); + connect(btnZoomOneToOne, TQT_SIGNAL(clicked()), this, TQT_SLOT(zoomOneToOne())); + + m_progress = new KisLabelProgress(frmProgress); + m_progress->setMaximumHeight(fontMetrics().height() ); + TQVBoxLayout *vbox = new TQVBoxLayout( frmProgress ); + vbox->addWidget(m_progress); + m_progress->hide(); + + connect(m_zoomTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(updateZoom())); + connect(m_filterTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(runFilterHelper())); + +/* kToolBar1->insertLineSeparator(); + kToolBar1->insertButton("reload",2, true, i18n("Update")); + connect(kToolBar1->getButton(2),TQT_SIGNAL(clicked()),this,TQT_SLOT(forceUpdate())); + + kToolBar1->insertButton("",3, true, i18n("Auto Update")); + connect(kToolBar1->getButton(3),TQT_SIGNAL(clicked()),this,TQT_SLOT(toggleAutoUpdate())); + + kToolBar1->insertButton("",4, true, i18n("Switch")); + connect(kToolBar1->getButton(4),TQT_SIGNAL(clicked()),this,TQT_SLOT(toggleImageDisplayed()));*/ +// these currently don't yet work, reenable when they do work :) (TZ-12-2005) +// TODO reenable these +// kToolBar1->insertButton("",5, true, i18n("Popup Original and Preview")); +} + +KisPreviewWidget::~KisPreviewWidget() { } + +void KisPreviewWidget::forceUpdate() +{ + if(m_previewIsDisplayed) + { + m_groupBox->setTitle(m_origDevice->name()); + emit updated(); + } +} + +void KisPreviewWidget::slotSetDevice(KisPaintDeviceSP dev) +{ + Q_ASSERT( dev ); + + if (!dev) return; + + m_origDevice = dev; + m_previewDevice = dev; + m_filterZoom = 1.0; + + KisConfig cfg; + TQString monitorProfileName = cfg.monitorProfile(); + m_profile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + + TQRect r = dev->exactBounds(); + + m_groupBox->setTitle(i18n("Preview: ") + dev->name()); + m_previewIsDisplayed = true; + + m_zoom = -1.0; + zoomChanged(double(m_preview->width()) / double(r.width()) ); +} + +void KisPreviewWidget::updateZoom() +{ + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + + if(m_previewIsDisplayed) + { + if(m_dirtyPreview) + { + TQSize r = m_previewDevice->extent().size(); + int w = r.width(), h = r.height(); + int sw = int(ceil(m_zoom * w / m_filterZoom)); + int sh = int(ceil(m_zoom * h / m_filterZoom)); + m_dirtyPreview = false; + m_scaledPreview = m_previewDevice->convertToTQImage(m_profile, 0, 0, w, h); + m_scaledPreview = m_scaledPreview.scale(sw,sh, TQ_ScaleMax); // Use scale instead of smoothScale for speed up + } + m_preview->setImage(m_scaledPreview); + } else + { + if(m_dirtyOriginal) + { + TQSize r = m_origDevice->extent().size(); + int w = r.width(), h = r.height(); + int sw = int(ceil(m_zoom * w)); + int sh = int(ceil(m_zoom * h)); + m_dirtyOriginal = false; + m_scaledOriginal = m_origDevice->convertToTQImage(m_profile, 0, 0, w, h); + m_scaledOriginal = m_scaledOriginal.scale(sw,sh, TQ_ScaleMax); // Use scale instead of smoothScale for speed up + } + m_preview->setImage(m_scaledOriginal); + } + + TQApplication::restoreOverrideCursor(); +} + +void KisPreviewWidget::slotSetAutoUpdate(bool set) { + m_autoupdate = set; +} + +void KisPreviewWidget::wheelEvent(TQWheelEvent * e) +{ + if (e->delta() > 0) { + zoomIn(); + } else { + zoomOut(); + } + e->accept(); +} + +void KisPreviewWidget::setPreviewDisplayed(bool v) +{ + if(v != m_previewIsDisplayed) + { + m_previewIsDisplayed = v; + if(m_previewIsDisplayed) { + m_groupBox->setTitle(i18n("Preview: ") + m_origDevice->name()); + } else { + m_groupBox->setTitle(i18n("Original: ") + m_origDevice->name()); + } + // Call directly without any pause because there is no scaling + updateZoom(); + } +} + +void KisPreviewWidget::needUpdate() +{ + if(m_previewIsDisplayed) + m_groupBox->setTitle(i18n("Preview (needs update)")); +} + +bool KisPreviewWidget::getAutoUpdate() const { + return m_autoupdate; +} + +void KisPreviewWidget::zoomChanged(const double zoom) +{ + // constrain the zoom + double tZoom = zoom; + if(zoom <= 1./8.) { tZoom = 1./8.; } + if(zoom > 8.) { tZoom = 8.; } + + if(tZoom != m_zoom) + { + m_zoom = tZoom; + m_dirtyOriginal = true; + m_dirtyPreview = true; + + if(m_firstZoom) { + m_firstZoom = false; + updateZoom(); + } else { + m_zoomTimer->start(ZOOM_PAUSE, true); + } + } +} + +void KisPreviewWidget::zoomIn() { + zoomChanged(m_zoom * ZOOM_FACTOR); +} + +void KisPreviewWidget::zoomOut() { + zoomChanged(m_zoom / ZOOM_FACTOR); +} + +void KisPreviewWidget::zoomOneToOne() { + zoomChanged(1.0); +} + +static inline void cropDevice(KisPaintDevice * device, const double & zoom) { + TQRect r = device->exactBounds(); + r.setX(int(zoom * r.x()) ); + r.setY(int(zoom * r.y()) ); + r.setWidth(int(zoom * r.width()) ); + r.setHeight(int(zoom * r.height()) ); + device->crop(r); +} + +class MyCropVisitor : public KisLayerVisitor { + const double m_zoom; + +public: + MyCropVisitor(const double & z) : m_zoom(z) { } + virtual ~MyCropVisitor() { } + + virtual bool visit(KisPaintLayer *layer) { + KisPaintDeviceSP device = layer->paintDevice(); + ::cropDevice(device.data(), m_zoom); + // Make sure we have a tight fit for the selection + if(device->hasSelection()) { + ::cropDevice(device->selection().data(), m_zoom); + } + + return true; + } + virtual bool visit(KisGroupLayer *layer) { + for(KisLayerSP l = layer->firstChild(); l; l = l->nextSibling()) { + l->accept(*this); + } + return true; + } + virtual bool visit(KisPartLayer *) { return true; } + virtual bool visit(KisAdjustmentLayer *) { return true; } +}; + +void KisPreviewWidget::runFilter(KisFilter * filter, KisFilterConfiguration * config) { + if(!filter) return; + if(!config) return; + + m_filter = filter; + m_config = config; + + if(m_firstFilter) { + m_firstFilter = false; + runFilterHelper(); + } else { + m_filterTimer->start(FILTER_PAUSE, true); + } +} + +/** + * XXX: Fix the situations which m_origDevice is NOT associated with a image. + * If it comes from a adjustment layer or projection or thumbnail. Currently, nothing happens + */ +void KisPreviewWidget::runFilterHelper() { + + m_filterZoom = m_zoom; + // Dont scale more then 1.0 so we don't waste time in preview widget for large scaling. + if(m_filterZoom > 1.0) { + m_filterZoom = 1.0; + } + + KisPaintDeviceSP scaledDevice; + KisHermiteFilterStrategy strategy; + + // Copy the image and scale + if (m_origDevice->image()) + { + m_scaledImage = new KisImage(*m_origDevice->image()); + if(!m_origDevice->tqparentLayer()) return; + TQString layerName = m_origDevice->tqparentLayer()->name(); + KisPaintLayerSP pl = ::tqqt_cast(m_scaledImage->findLayer(layerName)); + if(!pl) return; + scaledDevice = pl->paintDevice(); + + KisSelectionSP select; + if(scaledDevice->hasSelection()) + { + select = new KisSelection(*scaledDevice->selection()); + scaledDevice->deselect(); + } + // Scale + m_scaledImage->setUndoAdapter(NULL); + m_scaledImage->scale(m_filterZoom, m_filterZoom, NULL, &strategy); + // Scale the selection + if(select) + { + KisPaintDeviceSP t = select.data(); + KisTransformWorker tw(t, m_filterZoom, m_filterZoom, + 0.0, 0.0, 0.0, 0, 0, NULL, &strategy); + tw.run(); + scaledDevice->setSelection(select); + select->setParentLayer(scaledDevice->tqparentLayer()); + } + + // Crop by the zoom value instead of cropping by rectangle. It gives better results + MyCropVisitor v(m_filterZoom); + m_scaledImage->rootLayer()->accept(v); + } else + { + scaledDevice = new KisPaintDevice(*m_origDevice); + KisSelectionSP select; + if(scaledDevice->hasSelection()) + { + select = new KisSelection(*scaledDevice->selection()); + scaledDevice->deselect(); + } + KisTransformWorker tw(scaledDevice, m_filterZoom, m_filterZoom, + 0.0, 0.0, 0.0, 0, 0, NULL, &strategy); + tw.run(); + // Scale the selection + if(select) + { + KisPaintDeviceSP t = select.data(); + KisTransformWorker tw(t, m_filterZoom, m_filterZoom, + 0.0, 0.0, 0.0, 0, 0, NULL, &strategy); + tw.run(); + scaledDevice->setSelection(select); + ::cropDevice(select.data(), m_filterZoom); + } + ::cropDevice(scaledDevice.data(), m_filterZoom); + } + + m_previewDevice = new KisPaintDevice(*scaledDevice); + + // Setup the progress display + m_filter->enableProgress(); + m_progress->setSubject(m_filter, true, true); + m_filter->setProgressDisplay(m_progress); + m_filter->process(scaledDevice, m_previewDevice, m_config, scaledDevice->exactBounds()); + m_filter->disableProgress(); + + m_dirtyPreview = true; + + if(m_firstZoom) { + m_firstZoom = false; + updateZoom(); + } else { + m_zoomTimer->start(ZOOM_PAUSE, true); + } +} + +#include "kis_previewwidget.moc" diff --git a/chalk/ui/kis_previewwidget.h b/chalk/ui/kis_previewwidget.h new file mode 100644 index 00000000..bcdf437e --- /dev/null +++ b/chalk/ui/kis_previewwidget.h @@ -0,0 +1,141 @@ +/* + * kis_previewwidget.h - part of Chalk + * + * Copyright (c) 2001 John Califf + * Copyright (c) 2004 Bart Coppens + * Copyright (c) 2005 Cyrille Berger + * Copyright (c) 2007 Benjamin Schleimer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef __kis_previewwidget_h__ +#define __kis_previewwidget_h__ + +#include +#include + +#include "kis_types.h" + +#include "kis_previewwidgetbase.h" + +class TQWidget; +class KisProfile; +class KisFilter; +class KisFilterConfiguration; +class TQTimer; +class KisLabelProgress; + +/** + * A widget that can be used by plugins to show a preview of the effect of the + * plugin to the user. This is a convenience class thand handily packs a source and a + * preview view together with a zoom button. + * It would be nice if every plugin that needs to show a preview + * (maybe not those that create a new image) would use this. This can prevent the distracting + * effect the GIMP has with a different preview for almost every filter. + */ +class KisPreviewWidget : public PreviewWidgetBase +{ + Q_OBJECT + TQ_OBJECT + +public: + /** Constructs the widget */ + KisPreviewWidget( TQWidget* tqparent = 0, const char* name = 0 ); + virtual ~KisPreviewWidget(); + + /** returns if the preview is automatically updated */ + bool getAutoUpdate() const; + + void wheelEvent(TQWheelEvent * e); + + /** Instructs the KisPreviewWidget to eventually update the preview. + * KisPreviewWidget delays the actual running of the filter for 500ms + * so if the user is changing a configuration setting, it won't run multiple time. + * @param filter to run on the image + * @config to use when filtering. + */ + void runFilter(KisFilter * filter, KisFilterConfiguration * config); + +public slots: + + /** Sets the preview to use the layer specified as argument */ + void slotSetDevice(KisPaintDeviceSP dev); + + /** Enables or disables the automatically updating of the preview */ + void slotSetAutoUpdate(bool set); + + /** Toggle between display preview and display original */ + void setPreviewDisplayed(bool v); + + /** use to indicate that the preview need to be updated. */ + void needUpdate(); + +signals: + /** This is emitted when the position or zoom factor of the widget has changed */ + void updated(); + +private slots: + + void zoomIn(); + void zoomOut(); + void zoomOneToOne(); + + /** + * Called when the "Force Update" button is clicked + */ + void forceUpdate(); + + /** + * Updates the zoom and redisplays either the original or the preview (filtered) image + */ + void updateZoom(); + + /** Internal method which actually runs the filter + */ + void runFilterHelper(); + +private: + /** + * Recalculates the zoom factor + */ + void zoomChanged(const double zoom); + + bool m_autoupdate; /// Flag indicating that the widget should auto update whenever a setting is changed + bool m_previewIsDisplayed; /// Flag indicating whether the filtered or original image is displayed + + TQImage m_scaledOriginal; /// TQImage copy of the original image + bool m_dirtyOriginal; /// flag indicating that the original image is dirty + KisPaintDeviceSP m_origDevice; /// Pointer to the original image + + TQImage m_scaledPreview; /// TQImage copy of the filtered image + bool m_dirtyPreview; /// flag indicating that the preview image is dirty + KisPaintDeviceSP m_previewDevice; /// Pointer to the preview image + KisImageSP m_scaledImage; /// Scaled image copied from the original + + double m_filterZoom; /// Zoom amount when the filtering occurred + double m_zoom; /// Current zoom amount + KisProfile * m_profile; /// the color profile to use when converting to TQImage + + KisLabelProgress *m_progress; /// Progress bar of the preview. + + TQTimer * m_zoomTimer; /// Timer used to update the view whenever the zoom changes + TQTimer * m_filterTimer; /// Timer used to update the view whenever the filter changes + KisFilter * m_filter; /// Filter used + KisFilterConfiguration * m_config; /// Configuration used + bool m_firstFilter; /// Flag to determine if we should delay the first filter or not + bool m_firstZoom; /// Flag to determine if we should delay the first zoom or not +}; + +#endif diff --git a/chalk/ui/kis_previewwidgetbase.ui b/chalk/ui/kis_previewwidgetbase.ui new file mode 100644 index 00000000..6ee64019 --- /dev/null +++ b/chalk/ui/kis_previewwidgetbase.ui @@ -0,0 +1,271 @@ + +PreviewWidgetBase + + + PreviewWidgetBase + + + + 0 + 0 + 588 + 500 + + + + + 7 + 7 + 0 + 0 + + + + + 0 + 0 + + + + + unnamed + + + 0 + + + + m_groupBox + + + Preview + + + + unnamed + + + + m_preview + + + + 7 + 7 + 0 + 0 + + + + + 200 + 150 + + + + + 1000 + 1000 + + + + + + + + tqlayout4 + + + + unnamed + + + + buttonGroup1 + + + GroupBoxPanel + + + + + + + unnamed + + + + radioBtnPreview + + + Pr&eview + + + true + + + Preview modified layer + + + + + radioBtnOriginal + + + Ori&ginal + + + Show original layer + + + + + + + tqlayout5 + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + btnZoomOut + + + + + + + + + Zoom Out + + + + + btnZoomIn + + + + + + + + + Zoom In + + + + + btnZoomOneToOne + + + + + + + + + 1 : 1 + + + + + btnUpdate + + + + + + + + + Update preview + + + + + + + checkBoxAutoUpdate + + + &Autoupdate + + + true + + + Automatically update the preview whenever the filter settings change + + + + + + + frmProgress + + + NoFrame + + + Raised + + + + + + + + + ImageViewer +
imageviewer.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 + moved(QPoint) + moving(QPoint) + startMoving(QPoint) + zoomIn() + slot() + zoomOut() + slot() + slot() + slotMoving(QPoint) + slotMoved(QPoint) + slot() + slotStartMoving(QPoint) +
+
+ + + 789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f + + + + + imageviewer.h + kpushbutton.h + kpushbutton.h + kpushbutton.h + kpushbutton.h + +
diff --git a/chalk/ui/kis_qpaintdevice_canvas.cc b/chalk/ui/kis_qpaintdevice_canvas.cc new file mode 100644 index 00000000..1f7def2d --- /dev/null +++ b/chalk/ui/kis_qpaintdevice_canvas.cc @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_qpaintdevice_canvas.h" +#include "kis_qpaintdevice_canvas_painter.h" +#include + +KisTQPaintDeviceCanvasWidget::KisTQPaintDeviceCanvasWidget(TQWidget *tqparent, const char *name) + : TQWidget(tqparent, name) +{ +} + +KisTQPaintDeviceCanvasWidget::~KisTQPaintDeviceCanvasWidget() +{ +} + +void KisTQPaintDeviceCanvasWidget::paintEvent(TQPaintEvent *e) +{ + widgetGotPaintEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::mousePressEvent(TQMouseEvent *e) +{ + widgetGotMousePressEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::mouseReleaseEvent(TQMouseEvent *e) +{ + widgetGotMouseReleaseEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::mouseDoubleClickEvent(TQMouseEvent *e) +{ + widgetGotMouseDoubleClickEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::mouseMoveEvent(TQMouseEvent *e) +{ + widgetGotMouseMoveEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::tabletEvent(TQTabletEvent *e) +{ + widgetGotTabletEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::enterEvent(TQEvent *e) +{ + widgetGotEnterEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::leaveEvent(TQEvent *e) +{ + widgetGotLeaveEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::wheelEvent(TQWheelEvent *e) +{ + widgetGotWheelEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::keyPressEvent(TQKeyEvent *e) +{ + widgetGotKeyPressEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::keyReleaseEvent(TQKeyEvent *e) +{ + widgetGotKeyReleaseEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::dragEnterEvent(TQDragEnterEvent *e) +{ + widgetGotDragEnterEvent(e); +} + +void KisTQPaintDeviceCanvasWidget::dropEvent(TQDropEvent *e) +{ + widgetGotDropEvent(e); +} + +#ifdef Q_WS_X11 + +bool KisTQPaintDeviceCanvasWidget::x11Event(XEvent *event) +{ + return KisCanvasWidget::x11Event(event, x11Display(), winId(), mapToGlobal(TQPoint(0, 0))); +} + +#endif // Q_WS_X11 + +KisCanvasWidgetPainter *KisTQPaintDeviceCanvasWidget::createPainter() +{ + return new KisTQPaintDeviceCanvasPainter(TQT_TQPAINTDEVICE(this)); +} + +#if defined(EXTENDED_X11_TABLET_SUPPORT) +void KisTQPaintDeviceCanvasWidget::selectTabletDeviceEvents() +{ + KisCanvasWidget::selectTabletDeviceEvents(this); +} +#endif + diff --git a/chalk/ui/kis_qpaintdevice_canvas.h b/chalk/ui/kis_qpaintdevice_canvas.h new file mode 100644 index 00000000..ae688248 --- /dev/null +++ b/chalk/ui/kis_qpaintdevice_canvas.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TQPAINTDEVICE_CANVAS_H_ +#define KIS_TQPAINTDEVICE_CANVAS_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "kis_global.h" +#include "kis_canvas.h" + +#ifdef Q_MOC_RUN +#define Q_WS_X11 +#endif // Q_MOC_RUN + +#ifdef Q_WS_X11 +#include +#endif // Q_WS_X11 + +class KisTQPaintDeviceCanvasWidget : public virtual TQWidget, public virtual KisCanvasWidget { +public: + KisTQPaintDeviceCanvasWidget(TQWidget *tqparent = 0, const char *name = 0); + ~KisTQPaintDeviceCanvasWidget(); + + virtual KisCanvasWidgetPainter *createPainter(); + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + virtual void selectTabletDeviceEvents(); +#endif + +protected: + virtual void paintEvent(TQPaintEvent *event); + virtual void mousePressEvent(TQMouseEvent *event); + virtual void mouseReleaseEvent(TQMouseEvent *event); + virtual void mouseDoubleClickEvent(TQMouseEvent *event); + virtual void mouseMoveEvent(TQMouseEvent *event); + virtual void tabletEvent(TQTabletEvent *event); + virtual void enterEvent(TQEvent *event ); + virtual void leaveEvent(TQEvent *event); + virtual void wheelEvent(TQWheelEvent *event); + virtual void keyPressEvent(TQKeyEvent *event); + virtual void keyReleaseEvent(TQKeyEvent *event); + virtual void dragEnterEvent(TQDragEnterEvent *event); + virtual void dropEvent(TQDropEvent *event); +#ifdef Q_WS_X11 + bool x11Event(XEvent *event); +#endif // Q_WS_X11 +}; + +#endif // KIS_TQPAINTDEVICE_CANVAS_H_ + diff --git a/chalk/ui/kis_qpaintdevice_canvas_painter.cc b/chalk/ui/kis_qpaintdevice_canvas_painter.cc new file mode 100644 index 00000000..4233bc11 --- /dev/null +++ b/chalk/ui/kis_qpaintdevice_canvas_painter.cc @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details.g + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_qpaintdevice_canvas_painter.h" + +KisTQPaintDeviceCanvasPainter::KisTQPaintDeviceCanvasPainter() +{ +} + +KisTQPaintDeviceCanvasPainter::KisTQPaintDeviceCanvasPainter(const TQPaintDevice *paintDevice) + : m_painter(const_cast(paintDevice)) +{ +} + +KisTQPaintDeviceCanvasPainter::~KisTQPaintDeviceCanvasPainter() +{ +} + +bool KisTQPaintDeviceCanvasPainter::begin(KisCanvasWidget *canvasWidget, bool unclipped) +{ + TQWidget *widget = dynamic_cast(canvasWidget); + + if (widget != 0) { + return m_painter.tqbegin(TQT_TQPAINTDEVICE(widget), unclipped); + } else { + return false; + } +} + +bool KisTQPaintDeviceCanvasPainter::begin(const TQPaintDevice* paintDevice, bool unclipped) +{ + return m_painter.tqbegin(const_cast(paintDevice), unclipped); +} + +bool KisTQPaintDeviceCanvasPainter::end() +{ + return m_painter.end(); +} + +void KisTQPaintDeviceCanvasPainter::save() +{ + m_painter.save(); +} + +void KisTQPaintDeviceCanvasPainter::restore() +{ + m_painter.restore(); +} + +TQFontMetrics KisTQPaintDeviceCanvasPainter::fontMetrics() const +{ + return m_painter.fontMetrics(); +} + +TQFontInfo KisTQPaintDeviceCanvasPainter::fontInfo() const +{ + return m_painter.fontInfo(); +} + +const TQFont& KisTQPaintDeviceCanvasPainter::font() const +{ + return m_painter.font(); +} + +void KisTQPaintDeviceCanvasPainter::setFont(const TQFont& font) +{ + m_painter.setFont(font); +} + +const TQPen& KisTQPaintDeviceCanvasPainter::pen() const +{ + return m_painter.pen(); +} + +void KisTQPaintDeviceCanvasPainter::setPen(const TQPen& pen) +{ + m_painter.setPen(pen); +} + +void KisTQPaintDeviceCanvasPainter::setPen(Qt::PenStyle penStyle) +{ + m_painter.setPen(penStyle); +} + +void KisTQPaintDeviceCanvasPainter::setPen(const TQColor& color) +{ + m_painter.setPen(color);; +} + +const TQBrush& KisTQPaintDeviceCanvasPainter::brush() const +{ + return m_painter.brush(); +} + +void KisTQPaintDeviceCanvasPainter::setBrush(const TQBrush& brush) +{ + m_painter.setBrush(brush); +} + +void KisTQPaintDeviceCanvasPainter::setBrush(TQt::BrushStyle brushStyle) +{ + m_painter.setBrush(brushStyle); +} + +void KisTQPaintDeviceCanvasPainter::setBrush(const TQColor& color) +{ + m_painter.setBrush(color); +} + +TQPoint KisTQPaintDeviceCanvasPainter::pos() const +{ + return m_painter.pos(); +} + +const TQColor& KisTQPaintDeviceCanvasPainter::backgroundColor() const +{ + return m_painter.backgroundColor(); +} + +void KisTQPaintDeviceCanvasPainter::setBackgroundColor(const TQColor& color) +{ + m_painter.setBackgroundColor(color); +} + +Qt::BGMode KisTQPaintDeviceCanvasPainter::backgroundMode() const +{ + return m_painter.backgroundMode(); +} + +void KisTQPaintDeviceCanvasPainter::setBackgroundMode(Qt::BGMode bgMode) +{ + m_painter.setBackgroundMode(bgMode); +} + +TQt::RasterOp KisTQPaintDeviceCanvasPainter::rasterOp() const +{ + return m_painter.rasterOp(); +} + +void KisTQPaintDeviceCanvasPainter::setRasterOp(TQt::RasterOp rasterOp) +{ + m_painter.setRasterOp(rasterOp); +} + +const TQPoint& KisTQPaintDeviceCanvasPainter::brushOrigin() const +{ + return m_painter.brushOrigin(); +} + +void KisTQPaintDeviceCanvasPainter::setBrushOrigin(int x, int y) +{ + m_painter.setBrushOrigin(x, y); +} + +void KisTQPaintDeviceCanvasPainter::setBrushOrigin(const TQPoint& origin) +{ + m_painter.setBrushOrigin(origin); +} + +bool KisTQPaintDeviceCanvasPainter::hasViewXForm() const +{ + return m_painter.hasViewXForm(); +} + +bool KisTQPaintDeviceCanvasPainter::hasWorldXForm() const +{ + return m_painter.hasWorldXForm(); +} + +void KisTQPaintDeviceCanvasPainter::setViewXForm(bool enable) +{ + m_painter.setViewXForm(enable); +} + +TQRect KisTQPaintDeviceCanvasPainter::window() const +{ + return m_painter.window(); +} + +void KisTQPaintDeviceCanvasPainter::setWindow(const TQRect& r) +{ + m_painter.setWindow(r); +} + +void KisTQPaintDeviceCanvasPainter::setWindow(int x, int y, int w, int h) +{ + m_painter.setWindow(x, y, w, h); +} + +TQRect KisTQPaintDeviceCanvasPainter::viewport() const +{ + return m_painter.viewport(); +} + +void KisTQPaintDeviceCanvasPainter::setViewport(const TQRect& r) +{ + m_painter.setViewport(r); +} + +void KisTQPaintDeviceCanvasPainter::setViewport(int x, int y, int w, int h) +{ + m_painter.setViewport(x, y, w, h); +} + +void KisTQPaintDeviceCanvasPainter::setWorldXForm(bool enable) +{ + m_painter.setWorldXForm(enable); +} + +const TQWMatrix& KisTQPaintDeviceCanvasPainter::tqworldMatrix() const +{ + return m_painter.tqworldMatrix(); +} + +void KisTQPaintDeviceCanvasPainter::setWorldMatrix(const TQWMatrix& matrix, bool combine) +{ + m_painter.setWorldMatrix(matrix, combine); +} + +void KisTQPaintDeviceCanvasPainter::saveWorldMatrix() +{ + m_painter.saveWorldMatrix(); +} + +void KisTQPaintDeviceCanvasPainter::restoreWorldMatrix() +{ + m_painter.restoreWorldMatrix(); +} + +void KisTQPaintDeviceCanvasPainter::scale(double sx, double sy) +{ + m_painter.scale(sx, sy); +} + +void KisTQPaintDeviceCanvasPainter::shear(double sh, double sv) +{ + m_painter.shear(sh, sv); +} + +void KisTQPaintDeviceCanvasPainter::rotate(double a) +{ + m_painter.rotate(a); +} + +void KisTQPaintDeviceCanvasPainter::translate(double dx, double dy) +{ + m_painter.translate(dx, dy); +} + +void KisTQPaintDeviceCanvasPainter::resetXForm() +{ + m_painter.resetXForm(); +} + +double KisTQPaintDeviceCanvasPainter::translationX() const +{ + return m_painter.translationX(); +} + +double KisTQPaintDeviceCanvasPainter::translationY() const +{ + return m_painter.translationY(); +} + +TQPoint KisTQPaintDeviceCanvasPainter::xForm(const TQPoint& point) const +{ + return m_painter.xForm(point); +} + +TQRect KisTQPaintDeviceCanvasPainter::xForm(const TQRect& r) const +{ + return m_painter.xForm(r); +} + +TQPointArray KisTQPaintDeviceCanvasPainter::xForm(const TQPointArray& pointArray) const +{ + return m_painter.xForm(pointArray); +} + +TQPointArray KisTQPaintDeviceCanvasPainter::xForm(const TQPointArray& pointArray, int index, int npoints) const +{ + return m_painter.xForm(pointArray, index, npoints); +} + +TQPoint KisTQPaintDeviceCanvasPainter::xFormDev(const TQPoint& point) const +{ + return m_painter.xFormDev(point); +} + +TQRect KisTQPaintDeviceCanvasPainter::xFormDev(const TQRect& r) const +{ + return m_painter.xFormDev(r); +} + +TQPointArray KisTQPaintDeviceCanvasPainter::xFormDev(const TQPointArray& pointArray) const +{ + return m_painter.xFormDev(pointArray); +} + +TQPointArray KisTQPaintDeviceCanvasPainter::xFormDev(const TQPointArray& pointArray, int index, int npoints) const +{ + return m_painter.xFormDev(pointArray, index, npoints); +} + +void KisTQPaintDeviceCanvasPainter::setClipping(bool enable) +{ + m_painter.setClipping(enable); +} + +bool KisTQPaintDeviceCanvasPainter::hasClipping() const +{ + return m_painter.hasClipping(); +} + +TQRegion KisTQPaintDeviceCanvasPainter::clipRegion(TQPainter::CoordinateMode mode) const +{ + return m_painter.clipRegion(mode); +} + +void KisTQPaintDeviceCanvasPainter::setClipRect(const TQRect& r, TQPainter::CoordinateMode mode) +{ + m_painter.setClipRect(r, mode); +} + +void KisTQPaintDeviceCanvasPainter::setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode mode) +{ + m_painter.setClipRect(x, y, w, h, mode); +} + +void KisTQPaintDeviceCanvasPainter::setClipRegion(const TQRegion& rgn, TQPainter::CoordinateMode mode) +{ + m_painter.setClipRegion(rgn, mode); +} + +void KisTQPaintDeviceCanvasPainter::drawPoint(int x, int y) +{ + m_painter.drawPoint(x, y); +} + +void KisTQPaintDeviceCanvasPainter::drawPoint(const TQPoint& point) +{ + m_painter.drawPoint(point); +} + +void KisTQPaintDeviceCanvasPainter::drawPoints(const TQPointArray& pointArray, int index, int npoints) +{ + m_painter.drawPoints(pointArray, index, npoints); +} + +void KisTQPaintDeviceCanvasPainter::moveTo(int x, int y) +{ + m_painter.moveTo(x, y); +} + +void KisTQPaintDeviceCanvasPainter::moveTo(const TQPoint& point) +{ + m_painter.moveTo(point); +} + +void KisTQPaintDeviceCanvasPainter::lineTo(int x, int y) +{ + m_painter.lineTo(x, y); +} + +void KisTQPaintDeviceCanvasPainter::lineTo(const TQPoint& point) +{ + m_painter.lineTo(point); +} + +void KisTQPaintDeviceCanvasPainter::drawLine(int x1, int y1, int x2, int y2) +{ + m_painter.drawLine(x1, y1, x2, y2); +} + +void KisTQPaintDeviceCanvasPainter::drawLine(const TQPoint& start, const TQPoint& end) +{ + m_painter.drawLine(start, end); +} + +void KisTQPaintDeviceCanvasPainter::drawRect(int x, int y, int w, int h) +{ + m_painter.drawRect(x, y, w, h); +} + +void KisTQPaintDeviceCanvasPainter::drawRect(const TQRect& r) +{ + m_painter.drawRect(r); +} + +void KisTQPaintDeviceCanvasPainter::drawWinFocusRect(int x, int y, int w, int h) +{ + m_painter.drawWinFocusRect(x, y, w, h); +} + +void KisTQPaintDeviceCanvasPainter::drawWinFocusRect(int x, int y, int w, int h, const TQColor& bgColor) +{ + m_painter.drawWinFocusRect(x, y, w, h, bgColor); +} + +void KisTQPaintDeviceCanvasPainter::drawWinFocusRect(const TQRect& r) +{ + m_painter.drawWinFocusRect(r); +} + +void KisTQPaintDeviceCanvasPainter::drawWinFocusRect(const TQRect& r, const TQColor& bgColor) +{ + m_painter.drawWinFocusRect(r, bgColor); +} + +void KisTQPaintDeviceCanvasPainter::drawRoundRect(int x, int y, int w, int h, int xRnd, int yRnd) +{ + m_painter.drawRoundRect(x, y, w, h, xRnd, yRnd); +} + +void KisTQPaintDeviceCanvasPainter::drawRoundRect(const TQRect& r, int xRnd, int yRnd) +{ + m_painter.drawRoundRect(r, xRnd, yRnd); +} + +void KisTQPaintDeviceCanvasPainter::drawEllipse(int x, int y, int w, int h) +{ + m_painter.drawEllipse(x, y, w, h); +} + +void KisTQPaintDeviceCanvasPainter::drawEllipse(const TQRect& r) +{ + m_painter.drawEllipse(r); +} + +void KisTQPaintDeviceCanvasPainter::drawArc(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawArc(x, y, w, h, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawArc(const TQRect& r, int a, int alen) +{ + m_painter.drawArc(r, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawPie(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawPie(x, y, w, h, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawPie(const TQRect& r, int a, int alen) +{ + m_painter.drawPie(r, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawChord(int x, int y, int w, int h, int a, int alen) +{ + m_painter.drawChord(x, y, w, h, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawChord(const TQRect& r, int a, int alen) +{ + m_painter.drawChord(r, a, alen); +} + +void KisTQPaintDeviceCanvasPainter::drawLineSegments(const TQPointArray& pointArray, int index, int nlines) +{ + m_painter.drawLineSegments(pointArray, index, nlines); +} + +void KisTQPaintDeviceCanvasPainter::drawPolyline(const TQPointArray& pointArray, int index, int npoints) +{ + m_painter.tqdrawPolyline(pointArray, index, npoints); +} + +void KisTQPaintDeviceCanvasPainter::drawPolygon(const TQPointArray& pointArray, bool winding, int index, int npoints) +{ + m_painter.tqdrawPolygon(pointArray, winding, index, npoints); +} + +void KisTQPaintDeviceCanvasPainter::drawConvexPolygon(const TQPointArray& pointArray, int index, int npoints) +{ + m_painter.tqdrawConvexPolygon(pointArray, index, npoints); +} + +void KisTQPaintDeviceCanvasPainter::drawCubicBezier(const TQPointArray& pointArray, int index) +{ + m_painter.drawCubicBezier(pointArray, index); +} + +void KisTQPaintDeviceCanvasPainter::drawPixmap(int x, int y, const TQPixmap& pixmap, int sx, int sy, int sw, int sh) +{ + m_painter.drawPixmap(x, y, pixmap, sx, sy, sw, sh); +} + +void KisTQPaintDeviceCanvasPainter::drawPixmap(const TQPoint& point, const TQPixmap& pixmap, const TQRect& sr) +{ + m_painter.drawPixmap(point, pixmap, sr); +} + +void KisTQPaintDeviceCanvasPainter::drawPixmap(const TQPoint& point, const TQPixmap& pixmap) +{ + m_painter.drawPixmap(point, pixmap); +} + +void KisTQPaintDeviceCanvasPainter::drawPixmap(const TQRect& r, const TQPixmap& pixmap) +{ + m_painter.drawPixmap(r, pixmap); +} + +void KisTQPaintDeviceCanvasPainter::drawImage(int x, int y, const TQImage& image, int sx, int sy, int sw, int sh, int conversionFlags) +{ + m_painter.drawImage(x, y, image, sx, sy, sw, sh, conversionFlags); +} + +void KisTQPaintDeviceCanvasPainter::drawImage(const TQPoint& point, const TQImage& image, const TQRect& sr, int conversionFlags) +{ + m_painter.drawImage(point, image, sr, conversionFlags); +} + +void KisTQPaintDeviceCanvasPainter::drawImage(const TQPoint& point, const TQImage& image, int conversion_flags) +{ + m_painter.drawImage(point, image, conversion_flags); +} + +void KisTQPaintDeviceCanvasPainter::drawImage(const TQRect& r, const TQImage& image) +{ + m_painter.drawImage(r, image); +} + +void KisTQPaintDeviceCanvasPainter::drawTiledPixmap(int x, int y, int w, int h, const TQPixmap& pixmap, int sx, int sy) +{ + m_painter.drawTiledPixmap(x, y, w, h, pixmap, sx, sy); +} + +void KisTQPaintDeviceCanvasPainter::drawTiledPixmap(const TQRect& r, const TQPixmap& pixmap, const TQPoint& point) +{ + m_painter.drawTiledPixmap(r, pixmap, point); +} + +void KisTQPaintDeviceCanvasPainter::drawTiledPixmap(const TQRect& r, const TQPixmap& pixmap) +{ + m_painter.drawTiledPixmap(r, pixmap); +} + +void KisTQPaintDeviceCanvasPainter::fillRect(int x, int y, int w, int h, const TQBrush& brush) +{ + m_painter.fillRect(x, y, w, h, brush); +} + +void KisTQPaintDeviceCanvasPainter::fillRect(const TQRect& r, const TQBrush& brush) +{ + m_painter.fillRect(r, brush); +} + +void KisTQPaintDeviceCanvasPainter::eraseRect(int x, int y, int w, int h) +{ + m_painter.eraseRect(x, y, w, h); +} + +void KisTQPaintDeviceCanvasPainter::eraseRect(const TQRect& r) +{ + m_painter.eraseRect(r); +} + +void KisTQPaintDeviceCanvasPainter::drawText(int x, int y, const TQString& text, int len, TQPainter::TextDirection dir) +{ + m_painter.drawText(x, y, text, len, dir); +} + +void KisTQPaintDeviceCanvasPainter::drawText(const TQPoint& point, const TQString& text, int len, TQPainter::TextDirection dir) +{ + m_painter.drawText(point, text, len, dir); +} + +void KisTQPaintDeviceCanvasPainter::drawText(int x, int y, const TQString& text, int pos, int len, TQPainter::TextDirection dir) +{ + m_painter.drawText(x, y, text, pos, len, dir); +} + +void KisTQPaintDeviceCanvasPainter::drawText(const TQPoint& point, const TQString& text, int pos, int len, TQPainter::TextDirection dir) +{ + m_painter.drawText(point, text, pos, len, dir); +} + +void KisTQPaintDeviceCanvasPainter::drawText(int x, int y, int w, int h, int flags, const TQString& text, int len, TQRect *br, TQTextParag **intern) +{ +#ifdef USE_QT4 + printf("[WARNING] KisTQPaintDeviceCanvasPainter::drawText partially implemented\n\r"); + m_painter.drawText(x, y, w, h, flags, text, len, br); +#else // USE_QT4 + m_painter.drawText(x, y, w, h, flags, text, len, br, intern); +#endif // USE_QT4 +} + +void KisTQPaintDeviceCanvasPainter::drawText(const TQRect& r, int flags, const TQString& text, int len, TQRect *br, TQTextParag **intern) +{ +#ifdef USE_QT4 + printf("[WARNING] KisTQPaintDeviceCanvasPainter::drawText partially implemented\n\r"); + m_painter.drawText(r, flags, text, len, br); +#else // USE_QT4 + m_painter.drawText(r, flags, text, len, br, intern); +#endif // USE_QT4 +} + +void KisTQPaintDeviceCanvasPainter::tqdrawTextItem(int x, int y, const TQTextItem& ti, int textflags) +{ + m_painter.tqdrawTextItem(x, y, ti, textflags); +} + +void KisTQPaintDeviceCanvasPainter::tqdrawTextItem(const TQPoint& p, const TQTextItem& ti, int textflags) +{ + m_painter.tqdrawTextItem(p, ti, textflags); +} + +TQRect KisTQPaintDeviceCanvasPainter::boundingRect(int x, int y, int w, int h, int flags, const TQString& text, int len, TQTextParag **intern) +{ +#ifdef USE_QT4 + printf("[WARNING] KisTQPaintDeviceCanvasPainter::boundingRect partially implemented\n\r"); + return m_painter.boundingRect(x, y, w, h, flags, text, len); +#else // USE_QT4 + return m_painter.boundingRect(x, y, w, h, flags, text, len, intern); +#endif // USE_QT4 +} + +TQRect KisTQPaintDeviceCanvasPainter::boundingRect(const TQRect& r, int flags, const TQString& text, int len, TQTextParag **intern) +{ +#ifdef USE_QT4 + printf("[WARNING] KisTQPaintDeviceCanvasPainter::boundingRect partially implemented\n\r"); + return m_painter.boundingRect(r, flags, text, len); +#else // USE_QT4 + return m_painter.boundingRect(r, flags, text, len, intern); +#endif // USE_QT4 +} + +int KisTQPaintDeviceCanvasPainter::tabStops() const +{ + return m_painter.tabStops(); +} + +void KisTQPaintDeviceCanvasPainter::setTabStops(int ts) +{ + m_painter.setTabStops(ts); +} + +int *KisTQPaintDeviceCanvasPainter::tabArray() const +{ + return m_painter.tabArray(); +} + +void KisTQPaintDeviceCanvasPainter::setTabArray(int *ts) +{ + m_painter.setTabArray(ts); +} + + diff --git a/chalk/ui/kis_qpaintdevice_canvas_painter.h b/chalk/ui/kis_qpaintdevice_canvas_painter.h new file mode 100644 index 00000000..0dca7322 --- /dev/null +++ b/chalk/ui/kis_qpaintdevice_canvas_painter.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TQPAINTDEVICE_CANVAS_PAINTER_H_ +#define KIS_TQPAINTDEVICE_CANVAS_PAINTER_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "kis_global.h" +#include "kis_canvas_painter.h" + +class KisTQPaintDeviceCanvasPainter : public KisCanvasWidgetPainter { +public: + KisTQPaintDeviceCanvasPainter(); + KisTQPaintDeviceCanvasPainter(const TQPaintDevice *paintDevice); + virtual ~KisTQPaintDeviceCanvasPainter(); + + bool begin(const TQPaintDevice* paintDevice, bool unclipped = false); + + virtual bool begin(KisCanvasWidget *canvasWidget, bool unclipped = false); + virtual bool end(); + + virtual void save(); + virtual void restore(); + + virtual TQFontMetrics fontMetrics() const; + virtual TQFontInfo fontInfo() const; + + virtual const TQFont& font() const; + virtual void setFont(const TQFont&); + virtual const TQPen& pen() const; + virtual void setPen(const TQPen&); + virtual void setPen(Qt::PenStyle); + virtual void setPen(const TQColor&); + virtual const TQBrush&brush() const; + virtual void setBrush(const TQBrush&); + virtual void setBrush(TQt::BrushStyle); + virtual void setBrush(const TQColor&); + virtual TQPoint pos() const; + + virtual const TQColor&backgroundColor() const; + virtual void setBackgroundColor(const TQColor&); + virtual Qt::BGMode backgroundMode() const; + virtual void setBackgroundMode(Qt::BGMode); + virtual TQt::RasterOp rasterOp() const; + virtual void setRasterOp(TQt::RasterOp); + virtual const TQPoint&brushOrigin() const; + virtual void setBrushOrigin(int x, int y); + virtual void setBrushOrigin(const TQPoint&); + + virtual bool hasViewXForm() const; + virtual bool hasWorldXForm() const; + + virtual void setViewXForm(bool); + virtual TQRect window() const; + virtual void setWindow(const TQRect&); + virtual void setWindow(int x, int y, int w, int h); + virtual TQRect viewport() const; + virtual void setViewport(const TQRect&); + virtual void setViewport(int x, int y, int w, int h); + + virtual void setWorldXForm(bool); + virtual const TQWMatrix&tqworldMatrix() const; + virtual void setWorldMatrix(const TQWMatrix&, bool combine=FALSE); + + virtual void saveWorldMatrix(); + virtual void restoreWorldMatrix(); + + virtual void scale(double sx, double sy); + virtual void shear(double sh, double sv); + virtual void rotate(double a); + + virtual void translate(double dx, double dy); + virtual void resetXForm(); + virtual double translationX() const; + virtual double translationY() const; + + virtual TQPoint xForm(const TQPoint&) const; + virtual TQRect xForm(const TQRect&) const; + virtual TQPointArray xForm(const TQPointArray&) const; + virtual TQPointArray xForm(const TQPointArray&, int index, int npoints) const; + virtual TQPoint xFormDev(const TQPoint&) const; + virtual TQRect xFormDev(const TQRect&) const; + virtual TQPointArray xFormDev(const TQPointArray&) const; + virtual TQPointArray xFormDev(const TQPointArray&, int index, int npoints) const; + + virtual void setClipping(bool); + virtual bool hasClipping() const; + virtual TQRegion clipRegion(TQPainter::CoordinateMode = TQPainter::CoordDevice) const; + virtual void setClipRect(const TQRect&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRect(int x, int y, int w, int h, TQPainter::CoordinateMode = TQPainter::CoordDevice); + virtual void setClipRegion(const TQRegion&, TQPainter::CoordinateMode = TQPainter::CoordDevice); + + virtual void drawPoint(int x, int y); + virtual void drawPoint(const TQPoint&); + virtual void drawPoints(const TQPointArray& a, int index=0, int npoints=-1); + virtual void moveTo(int x, int y); + virtual void moveTo(const TQPoint&); + virtual void lineTo(int x, int y); + virtual void lineTo(const TQPoint&); + virtual void drawLine(int x1, int y1, int x2, int y2); + virtual void drawLine(const TQPoint&, const TQPoint&); + virtual void drawRect(int x, int y, int w, int h); + virtual void drawRect(const TQRect&); + virtual void drawWinFocusRect(int x, int y, int w, int h); + virtual void drawWinFocusRect(int x, int y, int w, int h, const TQColor&bgColor); + virtual void drawWinFocusRect(const TQRect&); + virtual void drawWinFocusRect(const TQRect&, const TQColor&bgColor); + virtual void drawRoundRect(int x, int y, int w, int h, int = 25, int = 25); + virtual void drawRoundRect(const TQRect&, int = 25, int = 25); + virtual void drawEllipse(int x, int y, int w, int h); + virtual void drawEllipse(const TQRect&); + virtual void drawArc(int x, int y, int w, int h, int a, int alen); + virtual void drawArc(const TQRect&, int a, int alen); + virtual void drawPie(int x, int y, int w, int h, int a, int alen); + virtual void drawPie(const TQRect&, int a, int alen); + virtual void drawChord(int x, int y, int w, int h, int a, int alen); + virtual void drawChord(const TQRect&, int a, int alen); + virtual void drawLineSegments(const TQPointArray&, int index=0, int nlines=-1); + virtual void drawPolyline(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawPolygon(const TQPointArray&, bool winding=FALSE, int index=0, int npoints=-1); + virtual void drawConvexPolygon(const TQPointArray&, int index=0, int npoints=-1); + virtual void drawCubicBezier(const TQPointArray&, int index=0); + virtual void drawPixmap(int x, int y, const TQPixmap&, int sx=0, int sy=0, int sw=-1, int sh=-1); + virtual void drawPixmap(const TQPoint&, const TQPixmap&, const TQRect&sr); + virtual void drawPixmap(const TQPoint&, const TQPixmap&); + virtual void drawPixmap(const TQRect&, const TQPixmap&); + virtual void drawImage(int x, int y, const TQImage&, int sx = 0, int sy = 0, int sw = -1, int sh = -1, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, const TQRect&sr, int conversionFlags = 0); + virtual void drawImage(const TQPoint&, const TQImage&, int conversion_flags = 0); + virtual void drawImage(const TQRect&, const TQImage&); + virtual void drawTiledPixmap(int x, int y, int w, int h, const TQPixmap&, int sx=0, int sy=0); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&, const TQPoint&); + virtual void drawTiledPixmap(const TQRect&, const TQPixmap&); + //virtual void drawPicture(const TQPicture&); + //virtual void drawPicture(int x, int y, const TQPicture&); + //virtual void drawPicture(const TQPoint&, const TQPicture&); + + virtual void fillRect(int x, int y, int w, int h, const TQBrush&); + virtual void fillRect(const TQRect&, const TQBrush&); + virtual void eraseRect(int x, int y, int w, int h); + virtual void eraseRect(const TQRect&); + + virtual void drawText(int x, int y, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&, const TQString&, int len = -1, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + virtual void drawText(const TQPoint&p, const TQString&, int pos, int len, TQPainter::TextDirection dir = TQPainter::Auto); + + virtual void drawText(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + virtual void drawText(const TQRect&, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **intern=0); + + virtual void tqdrawTextItem(int x, int y, const TQTextItem&ti, int textflags = 0); + virtual void tqdrawTextItem(const TQPoint& p, const TQTextItem&ti, int textflags = 0); + + virtual TQRect boundingRect(int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + virtual TQRect boundingRect(const TQRect&, int flags, const TQString&, int len = -1, TQTextParag **intern=0); + + virtual int tabStops() const; + virtual void setTabStops(int); + virtual int *tabArray() const; + virtual void setTabArray(int *); + +protected: + TQPainter m_painter; +}; + +#endif // KIS_TQPAINTDEVICE_CANVAS_PAINTER_H_ + diff --git a/chalk/ui/kis_resource_mediator.cc b/chalk/ui/kis_resource_mediator.cc new file mode 100644 index 00000000..204a1033 --- /dev/null +++ b/chalk/ui/kis_resource_mediator.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include + +#include "kdebug.h" + +#include "kis_icon_item.h" +#include "kis_resource.h" +#include "kis_itemchooser.h" +#include "kis_resourceserver.h" +#include "kis_resource_mediator.h" + +KisResourceMediator::KisResourceMediator(KisItemChooser *chooser, + TQObject *tqparent, + const char *name) : super(tqparent, name), m_chooser(chooser) +{ + Q_ASSERT(chooser); + m_activeItem = 0; + + connect(m_chooser, TQT_SIGNAL(selected(KoIconItem*)), TQT_SLOT(setActiveItem(KoIconItem*))); +} + +KisResourceMediator::~KisResourceMediator() +{ +} + +void KisResourceMediator::connectServer(KisResourceServerBase* rServer) +{ + // Add the initially loaded items + TQValueList resources = rServer->resources(); + TQValueList::iterator it; + for ( it = resources.begin(); it != resources.end(); ++it ) + rServerAddedResource( *it ); + + // And connect to the server permanently, so that we may recieve updates afterwards + connect(rServer, TQT_SIGNAL(resourceAdded(KisResource*)), + this, TQT_SLOT(rServerAddedResource(KisResource*))); +} + +KisResource *KisResourceMediator::currentResource() const +{ + if (m_activeItem) { + Q_ASSERT(dynamic_cast(m_activeItem)); + return static_cast(m_activeItem)->resource(); + } + + return 0; +} + +KisIconItem *KisResourceMediator::itemFor(KisResource *r) const +{ + if(m_items.tqcontains(r)) + { + return m_items[r]; + } + return 0; +} + +KisResource *KisResourceMediator::resourceFor(KoIconItem *item) const +{ + KisIconItem *kisitem = dynamic_cast(item); + + return kisitem ? kisitem->resource() : 0; +} + +KisResource *KisResourceMediator::resourceFor(KisIconItem *item) const +{ + return item ? item->resource() : 0; +} + +TQWidget *KisResourceMediator::chooserWidget() const +{ + return m_chooser; +} + +void KisResourceMediator::setActiveItem(KoIconItem *item) +{ + KisIconItem *kisitem = dynamic_cast(item); + + if (kisitem) { + m_activeItem = kisitem; + m_chooser->setCurrent(item); + emit activatedResource(kisitem ? kisitem->resource() : 0); + } +} + +void KisResourceMediator::rServerAddedResource(KisResource *resource) +{ + if (resource && resource->valid()) { + + KisIconItem *item = new KisIconItem(resource); + Q_CHECK_PTR(item); + + m_items[resource] = item; + + m_chooser->addItem(item); + if (m_activeItem == 0) setActiveItem(item); + } +} + +#include "kis_resource_mediator.moc" + diff --git a/chalk/ui/kis_resource_mediator.h b/chalk/ui/kis_resource_mediator.h new file mode 100644 index 00000000..b224d25c --- /dev/null +++ b/chalk/ui/kis_resource_mediator.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RESOURCE_MEDIATOR_H_ +#define KIS_RESOURCE_MEDIATOR_H_ + +#include +#include +#include + +class KoIconItem; +class KisItemChooser; +class KisIconItem; +class KisResource; +class KisResourceServerBase; + +/** + * A resource mediator manages access to resources like + * gradients. brushes, patterns and palettes. + * For every view, a new resource mediator is created for every + * resource type. + */ +class KisResourceMediator : public TQObject { + Q_OBJECT + TQ_OBJECT + typedef TQObject super; + +public: + KisResourceMediator(KisItemChooser *chooser, + TQObject *tqparent = 0, + const char *name = 0); + virtual ~KisResourceMediator(); + +public: + void connectServer(KisResourceServerBase* rServer); + KisResource *currentResource() const; + KisIconItem *itemFor(KisResource *r) const; + KisResource *resourceFor(KoIconItem *item) const; + KisResource *resourceFor(KisIconItem *item) const; + TQWidget *chooserWidget() const; + +public slots: + + void setActiveItem(KoIconItem *item); + +signals: + void activatedResource(KisResource *r); + +private slots: + void rServerAddedResource(KisResource *resource); + +private: + KisItemChooser *m_chooser; + TQMap m_items; + KoIconItem *m_activeItem; +}; + +#endif // KIS_RESOURCE_MEDIATOR_H_ + diff --git a/chalk/ui/kis_resourceserver.cc b/chalk/ui/kis_resourceserver.cc new file mode 100644 index 00000000..d464e1bc --- /dev/null +++ b/chalk/ui/kis_resourceserver.cc @@ -0,0 +1,199 @@ +/* + * kis_resourceserver.cc - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_resource.h" +#include "kis_factory.h" +#include "kis_generic_registry.h" +#include "kis_resourceserver.h" +#include "kis_brush.h" +#include "kis_imagepipe_brush.h" +#include "kis_gradient.h" +#include "kis_pattern.h" +#include "kis_palette.h" +#include + +KisResourceServerBase::KisResourceServerBase(TQString type) + : m_type(type), m_loaded(false) +{ +} + +KisResourceServerBase::~KisResourceServerBase() +{ +} + +void KisResourceServerBase::loadResources(TQStringList filenames) +{ + TQStringList uniqueFiles; + + while( !filenames.empty() ) + { + + TQString front = *filenames.begin(); + filenames.pop_front(); + + TQString fname = TQFileInfo(front).fileName(); + //ebug() << "Loading " << fname << "\n"; + // XXX: Don't load resources with the same filename. Actually, we should look inside + // the resource to find out whether they are really the same, but for now this + // will prevent the same brush etc. showing up twice. + if (uniqueFiles.empty() || uniqueFiles.tqfind(fname) == uniqueFiles.end()) { + uniqueFiles.append(fname); + KisResource *resource; + resource = createResource(front); + if(resource->load() && resource->valid()) + { + m_resources.append(resource); + Q_CHECK_PTR(resource); + emit resourceAdded(resource); + } + else { + delete resource; + } + } + } + m_loaded = true; +} + +TQValueList KisResourceServerBase::resources() +{ + if(!m_loaded) { + return TQValueList(); + } + + return m_resources; +} + +void KisResourceServerBase::addResource(KisResource* resource) +{ + if (!resource->valid()) { + kdWarning(41001) << "Tried to add an invalid resource!" << endl; + return; + } + + m_resources.append(resource); + emit resourceAdded(resource); +} + + +class ResourceLoaderThread : public TQThread { + +public: + + ResourceLoaderThread(KisResourceServerBase * server, TQStringList files) + : TQThread() + , m_server(server) + , m_fileNames( files ) + { + } + + + void run() + { + m_server->loadResources(m_fileNames); + } + +private: + + KisResourceServerBase * m_server; + TQStringList m_fileNames; + +}; + +TQStringList getFileNames( TQString extensions, TQString type ) +{ + TQStringList extensionList = TQStringList::split(":", extensions); + TQStringList fileNames; + + TQStringList::Iterator it; + for ( it = extensionList.begin(); it != extensionList.end(); ++it ) { + TQString s = (*it); + fileNames += KisFactory::instance()->dirs()->findAllResources(type.ascii(), (*it)); + } + return fileNames; +} + + +KisResourceServerRegistry *KisResourceServerRegistry::m_singleton = 0; + +KisResourceServerRegistry::KisResourceServerRegistry() +{ + + KisResourceServer* brushServer = new KisResourceServer("kis_brushes"); + ResourceLoaderThread t1 (brushServer, getFileNames( "*.gbr","kis_brushes" )); + t1.start(); + + KisResourceServer* imagePipeBrushServer = new KisResourceServer("kis_brushes"); + ResourceLoaderThread t2 (imagePipeBrushServer, getFileNames( "*.gih", "kis_brushes")); + t2.start(); + + KisResourceServer* patternServer = new KisResourceServer("kis_patterns"); + ResourceLoaderThread t3 (patternServer, getFileNames("*.pat", "kis_patterns")); + t3.start(); + + KisResourceServer* gradientServer = new KisResourceServer("kis_gradients"); + ResourceLoaderThread t4 (gradientServer, getFileNames(KoGradientManager::filters().join( ":" ), "kis_gradients")); + t4.start(); + + + KisResourceServer* paletteServer = new KisResourceServer("kis_palettes"); + ResourceLoaderThread t5 (paletteServer, getFileNames("*.gpl:*.pal:*.act", "kis_palettes") ); + t5.start(); + + t1.wait(); + t2.wait(); + t3.wait(); + t4.wait(); + t5.wait(); + + add( KisID( "BrushServer", ""), brushServer ); + add( KisID( "ImagePipeBrushServer", ""), imagePipeBrushServer ); + add( KisID( "PatternServer", ""), patternServer ); + add( KisID( "GradientServer", ""), gradientServer ); + add( KisID( "PaletteServer", ""), paletteServer ); + +} + +KisResourceServerRegistry::~KisResourceServerRegistry() +{ +} + +KisResourceServerRegistry* KisResourceServerRegistry::instance() +{ + if(KisResourceServerRegistry::m_singleton == 0) + { + KisResourceServerRegistry::m_singleton = new KisResourceServerRegistry(); + } + return KisResourceServerRegistry::m_singleton; +} + + +#include "kis_resourceserver.moc" + diff --git a/chalk/ui/kis_resourceserver.h b/chalk/ui/kis_resourceserver.h new file mode 100644 index 00000000..ab3de04e --- /dev/null +++ b/chalk/ui/kis_resourceserver.h @@ -0,0 +1,91 @@ +/* + * kis_resourceserver.h - part of KImageShop + * + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2003 Patrick Julien + * Copyright (c) 2005 Sven Langkamp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RESOURCESERVER_H_ +#define KIS_RESOURCESERVER_H_ + +#include +#include + +#include "kis_generic_registry.h" + +class KisResource; + +class KisResourceServerBase : public TQObject { + Q_OBJECT + TQ_OBJECT +public: + KisResourceServerBase(TQString type); + virtual ~KisResourceServerBase(); + + void loadResources(TQStringList filenames); + /// Adds an already loaded resource to the server + void addResource(KisResource* resource); + TQValueList resources(); + TQString type() { return m_type; }; + +signals: + void resourceAdded(KisResource*); + +protected: + virtual KisResource* createResource( TQString filename ) = 0; + +private: + TQValueList m_resources; + TQString m_type; + + bool m_loaded; + +}; + + +template class KisResourceServer : public KisResourceServerBase { + typedef KisResourceServerBase super; + +public: + KisResourceServer(TQString type) :super( type ) {} + virtual ~KisResourceServer(){} + +private: + KisResource* createResource( TQString filename ){return new T(filename);} +}; + + + + +class KisResourceServerRegistry : public KisGenericRegistry +{ + +public: + virtual ~KisResourceServerRegistry(); + + static KisResourceServerRegistry* instance(); + +private: + KisResourceServerRegistry(); + KisResourceServerRegistry(const KisResourceServerRegistry&); + KisResourceServerRegistry operator=(const KisResourceServerRegistry&); + + static KisResourceServerRegistry *m_singleton; +}; + + +#endif // KIS_RESOURCESERVER_H_ diff --git a/chalk/ui/kis_ruler.cc b/chalk/ui/kis_ruler.cc new file mode 100644 index 00000000..6b0eea80 --- /dev/null +++ b/chalk/ui/kis_ruler.cc @@ -0,0 +1,367 @@ +/* + * Kivio - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * Copyright (C) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include + +#include "kdebug.h" + +#include "kis_ruler.h" + +#define MARKER_WIDTH 1 +#define MARKER_HEIGHT RULER_THICKNESS + +const char *KisRuler::m_nums[] = { + "70 7 2 1", + " c Black", + "X c None", + "XX XXXXXX XXXX XXXX XXXXXX XXX XXXX XXX XXX XXXX XX", + "X XXX XXXX XXX XXX XX XXX XXXX XXX XXXXXXX XXXXXXXXX XX XXX XX XXX X", + "X XXX XXXXX XXXXXXX XXXXXX XXX X XXX XXXXXX XXXXXXXXX XXX XXX XX XXX X", + "X XXX XXXXX XXXXX XXXXX XXX XX XXX XXX XXXXXX XXXX XXXX X", + "X XXX XXXXX XXXX XXXXXXXXX XX XXXXXX XX XXX XXXX XXXX XXX XXXXXX X", + "X XXX XXXXX XXX XXXXXX XXX XXXXX XXXXXXX XX XXX XXXX XXXX XXX XXXXX XX", + "XX XXXXXX XXX XXX XXXXXX XXX XXXX XXXXX XXXXX XXXX XXX" +}; + +KisRuler::KisRuler(Qt::Orientation o, TQWidget *tqparent, const char *name) : super(tqparent, name, WRepaintNoErase | WResizeNoErase), m_pixmapNums(m_nums) +{ + setBackgroundMode(NoBackground); + setFrameStyle(Box | Sunken); + setLineWidth(1); + setMidLineWidth(0); + m_orientation = o; + m_unit = KoUnit::U_PT; + m_zoom = 1.0; + m_firstVisible = 0; + m_pixmapBuffer = 0; + m_currentPosition = -1; + + if (m_orientation == Qt::Horizontal) { + setFixedHeight(RULER_THICKNESS); + initMarker(MARKER_WIDTH, MARKER_HEIGHT); + } else { + setFixedWidth(RULER_THICKNESS); + initMarker(MARKER_HEIGHT, MARKER_WIDTH); + } +} + +KisRuler::~KisRuler() +{ + delete m_pixmapBuffer; +} + +void KisRuler::initMarker(TQ_INT32 w, TQ_INT32 h) +{ + TQPainter p; + + m_pixmapMarker.resize(w, h); + p.begin(&m_pixmapMarker); + p.setPen(blue); + p.eraseRect(0, 0, w, h); + p.drawLine(0, 0, w - 1, h - 1); + p.end(); +} + +void KisRuler::recalculateSize() +{ + TQ_INT32 w; + TQ_INT32 h; + + if (m_pixmapBuffer) { + delete m_pixmapBuffer; + m_pixmapBuffer = 0; + } + + if (m_orientation == Qt::Horizontal) { + w = width(); + h = RULER_THICKNESS; + } else { + w = RULER_THICKNESS; + h = height(); + } + + m_pixmapBuffer = new TQPixmap(w, h); + Q_CHECK_PTR(m_pixmapBuffer); + + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); +} + +KoUnit::Unit KisRuler::unit() const +{ + return m_unit; +} + +void KisRuler::setUnit(KoUnit::Unit u) +{ + m_unit = u; + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); + update(); +} + +void KisRuler::setZoom(double zoom) +{ + m_zoom = zoom; + recalculateSize(); + drawRuler(); + updatePointer(m_currentPosition, m_currentPosition); + update(); +} + +void KisRuler::updatePointer(TQ_INT32 x, TQ_INT32 y) +{ + if (m_pixmapBuffer) { + if (m_orientation == Qt::Horizontal) { + if (m_currentPosition != -1) + tqrepaint(m_currentPosition, 1, MARKER_WIDTH, MARKER_HEIGHT); + + if (x != -1) { + bitBlt(this, x, 1, &m_pixmapMarker, 0, 0, MARKER_WIDTH, MARKER_HEIGHT); + m_currentPosition = x; + } + } else { + if (m_currentPosition != -1) + tqrepaint(1, m_currentPosition, MARKER_HEIGHT, MARKER_WIDTH); + + if (y != -1) { + bitBlt(this, 1, y, &m_pixmapMarker, 0, 0, MARKER_HEIGHT, MARKER_WIDTH); + m_currentPosition = y; + } + } + } +} + +void KisRuler::updateVisibleArea(TQ_INT32 xpos, TQ_INT32 ypos) +{ + if (m_orientation == Qt::Horizontal) + m_firstVisible = xpos; + else + m_firstVisible = ypos; + + drawRuler(); + update(); + updatePointer(m_currentPosition, m_currentPosition); +} + +void KisRuler::paintEvent(TQPaintEvent *e) +{ + if (m_pixmapBuffer) { + const TQRect& rect = e->rect(); + + bitBlt(this, rect.topLeft(), m_pixmapBuffer, rect); + super::paintEvent(e); + } +} + +void KisRuler::drawRuler() +{ + TQPainter p; + TQString buf; + TQ_INT32 st1 = 0; + TQ_INT32 st2 = 0; + TQ_INT32 st3 = 0; + TQ_INT32 st4 = 0; + + if (!m_pixmapBuffer) + return; + + p.begin(m_pixmapBuffer); + p.setPen(tqcolorGroup().text()); + p.setBackgroundColor(tqcolorGroup().base()); + p.eraseRect(0, 0, m_pixmapBuffer->width(), m_pixmapBuffer->height()); + + switch (m_unit) { + case KoUnit::U_PT: + case KoUnit::U_MM: + case KoUnit::U_DD: + case KoUnit::U_CC: + st1 = 1; + st2 = 5; + st3 = 10; + st4 = 25; + break; + case KoUnit::U_CM: + case KoUnit::U_PI: + case KoUnit::U_INCH: + default: + st1 = 1; + st2 = 2; + st3 = 5; + st4 = 10; + } + + bool s1 = KoUnit::fromUserValue(st1, m_unit) * m_zoom > 3.0; + bool s2 = KoUnit::fromUserValue(st2, m_unit) * m_zoom > 3.0; + bool s3 = KoUnit::fromUserValue(st3, m_unit) * m_zoom > 3.0; + bool s4 = KoUnit::fromUserValue(st4, m_unit) * m_zoom > 3.0; + + float cx = KoUnit::fromUserValue(100, m_unit) / m_zoom; + TQ_INT32 step = tqRound(cx); + + if (step < 5) { + step = 1; + } else if (step < 10) { + step = 5; + } else if (step < 25) { + step = 10; + } else if (step < 50) { + step = 25; + } else if (step < 100) { + step = 50; + } else if (step < 250) { + step = 100; + } else if (step < 500) { + step = 250; + } else if (step < 1000) { + step = 500; + } else if (step < 2500) { + step = 1000; + } else if (step < 5000) { + step = 2500; + } else if (step < 10000) { + step = 5000; + } else if (step < 25000) { + step = 10000; + } else if (step < 50000) { + step = 25000; + } else if (step < 100000) { + step = 50000; + } else { + step = 100000; + } + + TQ_INT32 start = (TQ_INT32)(KoUnit::fromUserValue(m_firstVisible, m_unit) / m_zoom); + TQ_INT32 pos = 0; + + if (m_orientation == Qt::Horizontal) { + do { + pos = (TQ_INT32)(KoUnit::fromUserValue(start, m_unit) * m_zoom - m_firstVisible); + + if (!s3 && s4 && start % st4 == 0) + p.drawLine(pos, RULER_THICKNESS - 9, pos, RULER_THICKNESS); + + if (s3 && start % st3 == 0) + p.drawLine(pos, RULER_THICKNESS - 9, pos, RULER_THICKNESS); + + if (s2 && start % st2 == 0) + p.drawLine(pos, RULER_THICKNESS - 7, pos, RULER_THICKNESS); + + if (s1 && start % st1 == 0) + p.drawLine(pos, RULER_THICKNESS - 5, pos, RULER_THICKNESS); + + if (start % step == 0) { + buf.setNum(TQABS(start)); + drawNums(&p, pos, 4, buf, true); + } + + start++; + } while (pos < m_pixmapBuffer->width()); + } else { + do { + pos = (TQ_INT32)(KoUnit::fromUserValue(start, m_unit) * m_zoom - m_firstVisible); + + if (!s3 && s4 && start % st4 == 0) + p.drawLine(RULER_THICKNESS - 9, pos, RULER_THICKNESS, pos); + + if (s3 && start % st3 == 0) + p.drawLine(RULER_THICKNESS - 9, pos, RULER_THICKNESS, pos); + + if (s2 && start % st2 == 0) + p.drawLine(RULER_THICKNESS - 7, pos, RULER_THICKNESS, pos); + + if (s1 && start % st1 == 0) + p.drawLine(RULER_THICKNESS - 5, pos, RULER_THICKNESS, pos); + + if (start % step == 0) { + buf.setNum(TQABS(start)); + drawNums(&p, 4, pos, buf, false); + } + + start++; + } while (pos < m_pixmapBuffer->height()); + } + + p.end(); +} + +void KisRuler::resizeEvent(TQResizeEvent *) +{ + recalculateSize(); +} + +void KisRuler::styleChange(TQStyle& oldStyle) +{ + Q_UNUSED(oldStyle); + updateGeometry(); + drawRuler(); +} + +void KisRuler::paletteChange(const TQPalette& oldPalette) +{ + Q_UNUSED(oldPalette); + drawRuler(); +} + +void KisRuler::show() +{ + if (m_orientation == Qt::Horizontal) { + setFixedHeight(RULER_THICKNESS); + initMarker(MARKER_WIDTH, MARKER_HEIGHT); + } else { + setFixedWidth(RULER_THICKNESS); + initMarker(MARKER_HEIGHT, MARKER_WIDTH); + } + + super::show(); +} + +void KisRuler::hide() +{ + /* + if (m_orientation == Qt::Horizontal) + setFixedHeight(1); + else + setFixedWidth(1); + */ + super::hide(); +} + +void KisRuler::drawNums(TQPainter *p, TQ_INT32 x, TQ_INT32 y, TQString& num, bool orientationHoriz) +{ + if (orientationHoriz) + x -= 7; + else + y -= 8; + + for (TQ_UINT32 k = 0; k < num.length(); k++) { + TQ_INT32 st = num.at(k).digitValue() * 7; + + p->drawPixmap(x, y, m_pixmapNums, st, 0, 7, 7); + + if (orientationHoriz) + x += 7; + else + y += 8; + } +} + +#include "kis_ruler.moc" + diff --git a/chalk/ui/kis_ruler.h b/chalk/ui/kis_ruler.h new file mode 100644 index 00000000..6c8dd46d --- /dev/null +++ b/chalk/ui/kis_ruler.h @@ -0,0 +1,81 @@ +/* + * Kivio - Visual Modelling and Flowcharting + * Copyright (C) 2000-2001 theKompany.com & Dave Marotti + * Copyright (C) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_RULER_H_ +#define KIS_RULER_H_ + +#include +#include +#include + +// XXX: Make this look more like the KOffice ruler -- the KOffice +// ruler is not quite suited to Chalk. Also: start units with 0, +// print every 100 units. + +#define RULER_THICKNESS 20 + +class TQPainter; + +class KisRuler : public TQFrame { + Q_OBJECT + TQ_OBJECT + typedef TQFrame super; + +public: + KisRuler(Qt::Orientation, TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisRuler(); + +public: + KoUnit::Unit unit() const; + +public slots: + void setZoom(double zoom); + void updatePointer(TQ_INT32 x, TQ_INT32 y); + void updateVisibleArea(TQ_INT32 xpos, TQ_INT32 ypos); + void setUnit(KoUnit::Unit u); + void hide(); + void show(); + +protected: + virtual void paintEvent(TQPaintEvent *e); + virtual void resizeEvent(TQResizeEvent *e); + virtual void styleChange(TQStyle& oldStyle); + virtual void paletteChange(const TQPalette& oldPalette); + + void recalculateSize(); + void drawRuler(); + void initMarker(TQ_INT32 w, TQ_INT32 h); + void drawNums(TQPainter *gc, TQ_INT32 x, TQ_INT32 y, TQString& num, bool orientationHoriz); + +private: + KoUnit::Unit m_unit; + Qt::Orientation m_orientation; + TQ_INT32 m_firstVisible; + TQ_INT32 m_currentPosition; + TQPixmap *m_pixmapBuffer; + TQPixmap m_pixmapMarker; + TQPixmap m_pixmapNums; + double m_zoom; + +private: + static const char *m_nums[]; +}; + +#endif // KIS_RULER_H_ + diff --git a/chalk/ui/kis_save_visitor.h b/chalk/ui/kis_save_visitor.h new file mode 100644 index 00000000..ce668a53 --- /dev/null +++ b/chalk/ui/kis_save_visitor.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_SAVE_VISITOR_H_ +#define KIS_SAVE_VISITOR_H_ + +#include +#include "kis_types.h" +#include "kis_layer_visitor.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" + +class KisSaveVisitor : public KisLayerVisitor { +public: + KisSaveVisitor(KisImageSP img, KoStore *store, TQ_UINT32 &count) : + KisLayerVisitor(), + m_count(count) + { + m_external = false; + m_img = img; + m_store = store; + } + +public: + void setExternalUri(TQString &uri) + { + m_external = true; + m_uri = uri; + } + + virtual bool visit(KisPaintLayer *layer) + { + //connect(*layer->paintDevice(), TQT_SIGNAL(ioProgress(TQ_INT8)), m_img, TQT_SLOT(slotIOProgress(TQ_INT8))); + + TQString location = m_external ? TQString() : m_uri; + location += m_img->name() + TQString("/layers/layer%1").tqarg(m_count); + + // Layer data + if (m_store->open(location)) { + if (!layer->paintDevice()->write(m_store)) { + layer->paintDevice()->disconnect(); + m_store->close(); + //IODone(); + return false; + } + + m_store->close(); + } + + if (layer->paintDevice()->colorSpace()->getProfile()) { + KisAnnotationSP annotation = layer->paintDevice()->colorSpace()->getProfile()->annotation(); + + if (annotation) { + // save layer profile + location = m_external ? TQString() : m_uri; + location += m_img->name() + TQString("/layers/layer%1").tqarg(m_count) + ".icc"; + + if (m_store->open(location)) { + m_store->write(annotation->annotation()); + m_store->close(); + } + } + } + + if (layer->hasMask()) { + KisPaintDeviceSP tqmask = layer->getMask(); + + if (tqmask) { + // save layer profile + location = m_external ? TQString() : m_uri; + location += m_img->name() + TQString("/layers/layer%1").tqarg(m_count) + ".tqmask"; + + if (m_store->open(location)) { + if (!tqmask->write(m_store)) { + tqmask->disconnect(); + m_store->close(); + return false; + } + + m_store->close(); + } + } + } + + m_count++; + return true; + } + + virtual bool visit(KisGroupLayer *layer) + { + KisSaveVisitor visitor(m_img, m_store, m_count); + + if(m_external) + visitor.setExternalUri(m_uri); + + KisLayerSP child = layer->firstChild(); + + while(child) + { + child->accept(visitor); + child = child->nextSibling(); + } + return true; + } + + virtual bool visit(KisPartLayer *) + { + return true; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + + if (layer->selection()) { + TQString location = m_external ? TQString() : m_uri; + location += m_img->name() + TQString("/layers/layer%1").tqarg(m_count) + ".selection"; + + // Layer data + if (m_store->open(location)) { + if (!layer->selection()->write(m_store)) { + layer->selection()->disconnect(); + m_store->close(); + //IODone(); + return false; + } + m_store->close(); + } + } + + if (layer->filter()) { + TQString location = m_external ? TQString() : m_uri; + location = m_external ? TQString() : m_uri; + location += m_img->name() + TQString("/layers/layer%1").tqarg(m_count) + ".filterconfig"; + + if (m_store->open(location)) { + TQString s = layer->filter()->toString(); + m_store->write(s.utf8(), tqstrlen(s.utf8())); + m_store->close(); + } + } + m_count++; + return true; + } + +private: + KisImageSP m_img; + KoStore *m_store; + bool m_external; + TQString m_uri; + TQ_UINT32 &m_count; +}; + +#endif // KIS_SAVE_VISITOR_H_ + diff --git a/chalk/ui/kis_savexml_visitor.h b/chalk/ui/kis_savexml_visitor.h new file mode 100644 index 00000000..52c0dc80 --- /dev/null +++ b/chalk/ui/kis_savexml_visitor.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2005 Casper Boemann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_SAVEXML_VISITOR_H_ +#define KIS_SAVEXML_VISITOR_H_ + +#include + +#include "kis_adjustment_layer.h" +#include "kis_exif_info.h" +#include "kis_group_layer.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_layer_visitor.h" +#include "kis_paint_layer.h" +#include "kis_types.h" + +class KisSaveXmlVisitor : public KisLayerVisitor { +public: + KisSaveXmlVisitor(TQDomDocument doc, TQDomElement element, TQ_UINT32 &count, bool root=false) : + KisLayerVisitor(), + m_doc(doc), + m_count(count), + m_root(root) + { + m_elem = element; + } + +public: + virtual bool visit(KisPaintLayer *layer) + { + TQDomElement layerElement = m_doc.createElement("layer"); + + layerElement.setAttribute("name", layer->name()); + layerElement.setAttribute("x", layer->x()); + layerElement.setAttribute("y", layer->y()); + layerElement.setAttribute("opacity", layer->opacity()); + layerElement.setAttribute("compositeop", layer->compositeOp().id().id()); + layerElement.setAttribute("visible", layer->visible()); + layerElement.setAttribute("locked", layer->locked()); + layerElement.setAttribute("layertype", "paintlayer"); + layerElement.setAttribute("filename", TQString("layer%1").tqarg(m_count)); + layerElement.setAttribute("colorspacename", layer->paintDevice()->colorSpace()->id().id()); + layerElement.setAttribute("hastqmask", layer->hasMask()); + m_elem.appendChild(layerElement); + + if(layer->paintDevice()->hasExifInfo()) + { + TQDomElement exifElmt = layer->paintDevice()->exifInfo()->save(m_doc); + layerElement.appendChild(exifElmt); + } + m_count++; + return true; + } + + virtual bool visit(KisGroupLayer *layer) + { + TQDomElement layerElement; + + if(m_root) // if this is the root we fake so not to save it + layerElement = m_elem; + else + { + layerElement = m_doc.createElement("layer"); + + layerElement.setAttribute("name", layer->name()); + layerElement.setAttribute("x", layer->x()); + layerElement.setAttribute("y", layer->y()); + layerElement.setAttribute("opacity", layer->opacity()); + layerElement.setAttribute("compositeop", layer->compositeOp().id().id()); + layerElement.setAttribute("visible", layer->visible()); + layerElement.setAttribute("locked", layer->locked()); + layerElement.setAttribute("layertype", "grouplayer"); + + m_elem.appendChild(layerElement); + } + + TQDomElement elem = m_doc.createElement("LAYERS"); + + layerElement.appendChild(elem); + + KisSaveXmlVisitor visitor(m_doc, elem, m_count); + + KisLayerSP child = layer->firstChild(); + + while(child) + { + child->accept(visitor); + child = child->nextSibling(); + } + return true; + } + + virtual bool visit(KisPartLayer* layer) + { + bool ok = layer->saveToXML(m_doc, m_elem); + return ok; + } + + virtual bool visit(KisAdjustmentLayer* layer) + { + TQDomElement layerElement = m_doc.createElement("layer"); + + layerElement.setAttribute("name", layer->name()); + layerElement.setAttribute("filtername", layer->filter()->name()); + layerElement.setAttribute("filterversion", layer->filter()->version()); + layerElement.setAttribute("opacity", layer->opacity()); + layerElement.setAttribute("compositeop", layer->compositeOp().id().id()); + layerElement.setAttribute("visible", layer->visible()); + layerElement.setAttribute("locked", layer->locked()); + layerElement.setAttribute("layertype", "adjustmentlayer"); + layerElement.setAttribute("filename", TQString("layer%1").tqarg(m_count)); + layerElement.setAttribute("x", layer->x()); + layerElement.setAttribute("y", layer->y()); + m_elem.appendChild(layerElement); + + m_count++; + return true; + } + +private: + TQDomDocument m_doc; + TQDomElement m_elem; + TQ_UINT32 &m_count; + bool m_root; +}; + +#endif // KIS_SAVEXML_VISITOR_H_ + diff --git a/chalk/ui/kis_selection_manager.cc b/chalk/ui/kis_selection_manager.cc new file mode 100644 index 00000000..3caba5e7 --- /dev/null +++ b/chalk/ui/kis_selection_manager.cc @@ -0,0 +1,1643 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_cursor.h" +#include "kis_part_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_clipboard.h" +#include "kis_types.h" +#include "kis_view.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_selection.h" +#include "kis_selection_manager.h" +#include "kis_painter.h" +#include "kis_iterators_pixel.h" +#include "kis_iteratorpixeltrait.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_paint_device.h" +#include "kis_channelinfo.h" +#include "kis_dlg_apply_profile.h" +#include "kis_config.h" +#include "kis_debug_areas.h" +#include "kis_transaction.h" +#include "kis_undo_adapter.h" +#include "kis_selected_transaction.h" +#include "kis_convolution_painter.h" +#include "kis_integer_maths.h" +#include "kis_fill_painter.h" +#include "kis_canvas.h" + +KisSelectionManager::KisSelectionManager(KisView * tqparent, KisDoc * doc) + : m_parent(tqparent), + m_doc(doc), + m_copy(0), + m_cut(0), + m_paste(0), + m_pasteNew(0), + m_cutToNewLayer(0), + m_selectAll(0), + m_deselect(0), + m_clear(0), + m_reselect(0), + m_invert(0), + m_toNewLayer(0), + m_feather(0), + m_border(0), + m_expand(0), + m_smooth(0), + m_contract(0), + m_similar(0), + m_transform(0), + m_load(0), + m_save(0), + m_fillForegroundColor(0), + m_fillBackgroundColor(0), + m_fillPattern(0) +{ + m_pluginActions.setAutoDelete(true); + m_clipboard = KisClipboard::instance(); +} + +KisSelectionManager::~KisSelectionManager() +{ + m_pluginActions.clear(); +} + + +void KisSelectionManager::setup(KActionCollection * collection) +{ + // XXX: setup shortcuts! + + m_cut = KStdAction::cut(this, + TQT_SLOT(cut()), + collection, + "cut"); + + m_copy = KStdAction::copy(this, + TQT_SLOT(copy()), + collection, + "copy"); + + m_paste = KStdAction::paste(this, + TQT_SLOT(paste()), + collection, + "paste"); + + m_pasteNew = new KAction(i18n("Paste into &New Image"), + 0, 0, + this, TQT_SLOT(pasteNew()), + collection, + "paste_new"); + + + m_selectAll = KStdAction::selectAll(this, + TQT_SLOT(selectAll()), + collection, + "select_all"); + + m_deselect = KStdAction::deselect(this, + TQT_SLOT(deselect()), + collection, + "deselect"); + + + m_clear = KStdAction::clear(this, + TQT_SLOT(clear()), + collection, + "clear"); + + m_reselect = new KAction(i18n("&Reselect"), + 0, "Ctrl+Shift+D", + this, TQT_SLOT(reselect()), + collection, "reselect"); + + m_invert = new KAction(i18n("&Invert"), + 0, "Ctrl+I", + this, TQT_SLOT(invert()), + collection, "invert"); + + + m_toNewLayer = new KAction(i18n("Copy Selection to New Layer"), + 0, "Ctrl+J", + this, TQT_SLOT(copySelectionToNewLayer()), + collection, "copy_selection_to_new_layer"); + + + m_cutToNewLayer = new KAction(i18n("Cut Selection to New Layer"), + 0, "Ctrl+Shift+J", + this, TQT_SLOT(cutToNewLayer()), + collection, "cut_selection_to_new_layer"); + + m_feather = new KAction(i18n("Feather"), + 0, "Ctrl+Alt+D", + this, TQT_SLOT(feather()), + collection, "feather"); + + m_fillForegroundColor = new KAction(i18n("Fill with Foreground Color"), + "Alt+backspace", this, + TQT_SLOT(fillForegroundColor()), + collection, + "fill_selection_foreground_color"); + m_fillBackgroundColor = new KAction(i18n("Fill with Background Color"), + "backspace", this, + TQT_SLOT(fillBackgroundColor()), + collection, + "fill_selection_background_color"); + m_fillPattern = new KAction(i18n("Fill with Pattern"), + 0, this, + TQT_SLOT(fillPattern()), + collection, + "fill_selection_pattern"); + + m_toggleDisplaySelection = new KToggleAction(i18n("Display Selection"), "Ctrl+h", this, TQT_SLOT(toggleDisplaySelection()), collection, "toggle_display_selection"); + m_toggleDisplaySelection->setCheckedState(KGuiItem(i18n("Hide Selection"))); + m_toggleDisplaySelection->setChecked(true); + + m_border = + new KAction(i18n("Border..."), + 0, 0, + this, TQT_SLOT(border()), + collection, "border"); + m_expand = + new KAction(i18n("Expand..."), + 0, 0, + this, TQT_SLOT(expand()), + collection, "expand"); + + m_smooth = + new KAction(i18n("Smooth..."), + 0, 0, + this, TQT_SLOT(smooth()), + collection, "smooth"); + + + m_contract = + new KAction(i18n("Contract..."), + 0, 0, + this, TQT_SLOT(contract()), + collection, "contract"); + m_similar = + new KAction(i18n("Similar"), + 0, 0, + this, TQT_SLOT(similar()), + collection, "similar"); + + + m_transform + = new KAction(i18n("Transform..."), + 0, 0, + this, TQT_SLOT(transform()), + collection, "transform_selection"); + + +// m_load +// = new KAction(i18n("Load..."), +// 0, 0, +// this, TQT_SLOT(load()), +// collection, "load_selection"); +// +// +// m_save +// = new KAction(i18n("Save As..."), +// 0, 0, +// this, TQT_SLOT(save()), +// collection, "save_selection"); + + TQClipboard *cb = TQApplication::tqclipboard(); + connect(cb, TQT_SIGNAL(dataChanged()), TQT_SLOT(clipboardDataChanged())); +} + +void KisSelectionManager::clipboardDataChanged() +{ + updateGUI(); +} + + +void KisSelectionManager::addSelectionAction(KAction * action) +{ + m_pluginActions.append(action); +} + + +void KisSelectionManager::updateGUI() +{ + Q_ASSERT(m_parent); + Q_ASSERT(m_clipboard); + + if (m_parent == 0) { + // "Eek, no tqparent! + return; + } + + if (m_clipboard == 0) { + // Eek, no clipboard! + return; + } + + KisImageSP img = m_parent->currentImg(); + KisLayerSP l = 0; + KisPaintDeviceSP dev = 0; + + bool enable = false; + if (img && img->activeDevice() && img->activeLayer()) { + l = img->activeLayer(); + dev = img->activeDevice(); + + + KisPartLayer * partLayer = dynamic_cast(l.data()); + KisAdjustmentLayer * adjLayer = dynamic_cast(l.data()); + + enable = l && dev&& dev->hasSelection() && !l->locked() && l->visible() && (partLayer==0); + + if(dev && !adjLayer) + m_reselect->setEnabled( dev->selectionDeselected() ); + if (adjLayer) // There's no reselect for adjustment layers + m_reselect->setEnabled(false); + } + + m_cut->setEnabled(enable); + m_cutToNewLayer->setEnabled(enable); + m_selectAll->setEnabled(img != 0); + m_deselect->setEnabled(enable); + m_clear->setEnabled(enable); + m_fillForegroundColor->setEnabled(enable); + m_fillBackgroundColor->setEnabled(enable); + m_fillPattern->setEnabled(enable); + m_invert->setEnabled(enable); + + m_feather->setEnabled(enable); + + m_border->setEnabled(enable); + m_expand->setEnabled(enable); + m_smooth->setEnabled(enable); + m_contract->setEnabled(enable); + m_similar->setEnabled(enable); + m_transform->setEnabled(enable); +// m_load->setEnabled(enable); +// m_save->setEnabled(enable); + + + KAction * a; + for (a = m_pluginActions.first(); a; a = m_pluginActions.next()) { + a->setEnabled(img != 0); + } + + // You can copy from locked layers and paste the clip into a new layer, even when + // the current layer is locked. + enable = false; + if (img && l && dev) { + enable = dev->hasSelection() && l->visible(); + } + + m_copy->setEnabled(enable); + m_paste->setEnabled(img != 0 && m_clipboard->hasClip()); + m_pasteNew->setEnabled(img != 0 && m_clipboard->hasClip()); + m_toNewLayer->setEnabled(enable); + + m_parent->updateStatusBarSelectionLabel(); + +} + +void KisSelectionManager::imgSelectionChanged(KisImageSP img) +{ + if (img == m_parent->currentImg()) { + updateGUI(); + } +} + +void KisSelectionManager::cut() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + + copy(); + + KisSelectedTransaction *t = 0; + + if (img->undo()) { + t = new KisSelectedTransaction(i18n("Cut"), dev); + Q_CHECK_PTR(t); + } + + dev->clearSelection(); + dev->deselect(); + dev->emitSelectionChanged(); + + if (img->undo()) { + img->undoAdapter()->addCommand(t); + } +} + +void KisSelectionManager::copy() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + + KisSelectionSP selection = dev->selection(); + + TQRect r = selection->selectedExactRect(); + + KisPaintDeviceSP clip = new KisPaintDevice(dev->colorSpace(), "clip"); + Q_CHECK_PTR(clip); + + KisColorSpace * cs = clip->colorSpace(); + + // TODO if the source is linked... copy from all linked layers?!? + + // Copy image data + KisPainter gc; + gc.begin(clip); + gc.bitBlt(0, 0, COMPOSITE_COPY, dev, r.x(), r.y(), r.width(), r.height()); + gc.end(); + + // Apply selection tqmask. + + for (TQ_INT32 y = 0; y < r.height(); y++) { + KisHLineIteratorPixel layerIt = clip->createHLineIterator(0, y, r.width(), true); + KisHLineIteratorPixel selectionIt = selection->createHLineIterator(r.x(), r.y() + y, r.width(), false); + + while (!layerIt.isDone()) { + + cs->applyAlphaU8Mask( layerIt.rawData(), selectionIt.rawData(), 1 ); + + + ++layerIt; + ++selectionIt; + } + } + + m_clipboard->setClip(clip); + imgSelectionChanged(m_parent->currentImg()); +} + + +KisLayerSP KisSelectionManager::paste() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return 0; + + KisPaintDeviceSP clip = m_clipboard->clip(); + + if (clip) { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + KisPaintLayer *layer = new KisPaintLayer(img, img->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE); + Q_CHECK_PTR(layer); + + TQRect r = clip->exactBounds(); + KisPainter gc; + gc.begin(layer->paintDevice()); + gc.bitBlt(0, 0, COMPOSITE_COPY, clip, r.x(), r.y(), r.width(), r.height()); + gc.end(); + + //figure out where to position the clip + KisCanvasController *cc = m_parent->getCanvasController(); + TQPoint center = cc->viewToWindow(TQPoint(cc->kiscanvas()->width()/2, cc->kiscanvas()->height()/2)); + TQPoint bottomright = cc->viewToWindow(TQPoint(cc->kiscanvas()->width(), cc->kiscanvas()->height())); + if(bottomright.x() > img->width()) + center.setX(img->width()/2); + if(bottomright.y() > img->height()) + center.setY(img->height()/2); + center -= TQPoint(r.width()/2, r.height()/2); + layer->setX(center.x()); + layer->setY(center.y()); + +/*XXX CBR have an idea of asking the user if he is about to paste a clip ion another cs than that of + the image if that is what he want rather than silently converting + if (clip->colorSpace != img ->colorSpace()) + if (dlg->exec() == TQDialog::Accepted) + layer->convertTo(img->colorSpace()); +*/ + TQApplication::restoreOverrideCursor(); + if(img->addLayer(layer, img->activeLayer()->tqparent(), img->activeLayer())) + { + return layer; + } else { + return 0; + } + } + return 0; +} + +void KisSelectionManager::pasteNew() +{ + KisPaintDeviceSP clip = m_clipboard->clip(); + if (!clip) return; + + TQRect r = clip->exactBounds(); + if (r.width() < 1 && r.height() < 1) { + // Don't paste empty clips + return; + } + + const TQCString mimetype = KoDocument::readNativeFormatMimeType(); + KoDocumentEntry entry = KoDocumentEntry::queryByMimeType( mimetype ); + KisDoc * doc = (KisDoc*) entry.createDoc(); + + Q_ASSERT(doc->undoAdapter() != 0); + doc->undoAdapter()->setUndo(false); + + KisImageSP img = new KisImage(doc->undoAdapter(), r.width(), r.height(), clip->colorSpace(), "Pasted"); + KisPaintLayer *layer = new KisPaintLayer(img, clip->name(), OPACITY_OPAQUE, clip->colorSpace()); + + KisPainter p(layer->paintDevice()); + p.bitBlt(0, 0, COMPOSITE_COPY, clip, OPACITY_OPAQUE, r.x(), r.y(), r.width(), r.height()); + p.end(); + + img->addLayer(layer, img->rootLayer(), 0); + doc->setCurrentImage(img); + + doc->undoAdapter()->setUndo(true); + + KoMainWindow *win = new KoMainWindow( doc->instance() ); + win->show(); + win->setRootDocument( doc ); +} + +void KisSelectionManager::selectAll() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + KisSelectedTransaction * t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Select All"), dev); + Q_CHECK_PTR(t); + + // Make adjustment layers behave better + KisAdjustmentLayer* adj = dynamic_cast(img->activeLayer().data()); + if (adj) { + adj->clearSelection(); + adj->selection()->invert(); + } else { + dev->selection()->clear(); + dev->selection()->invert(); + } + dev->setDirty(); + dev->emitSelectionChanged(); + + if (img->undo()) + img->undoAdapter()->addCommand(t); +} + +void KisSelectionManager::deselect() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + KisSelectedTransaction * t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Deselect"), dev); + Q_CHECK_PTR(t); + + // Make adjustment layers behave almost the same (except no reselect) + KisAdjustmentLayer* adj = dynamic_cast(img->activeLayer().data()); + if (adj) { + adj->clearSelection(); + } else { + dev->deselect(); + } + dev->setDirty(); + dev->emitSelectionChanged(); + + if (img->undo()) + img->undoAdapter()->addCommand(t); +} + + +void KisSelectionManager::clear() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + + KisTransaction * t = 0; + + if (img->undo()) { + t = new KisTransaction(i18n("Clear"), dev); + } + + dev->clearSelection(); + dev->setDirty(); + dev->emitSelectionChanged(); + + if (img->undo()) img->undoAdapter()->addCommand(t); +} + +void KisSelectionManager::fill(const KisColor& color, bool fillWithPattern, const TQString& transactionText) +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + + KisSelectionSP selection = dev->selection(); + + KisPaintDeviceSP filled = new KisPaintDevice(dev->colorSpace()); + KisFillPainter painter(filled); + + if (fillWithPattern) { + painter.fillRect(0, 0, img->width(), img->height(), + m_parent->currentPattern()); + } else { + painter.fillRect(0, 0, img->width(), img->height(), color); + } + + painter.end(); + + KisPainter painter2(dev); + + if (img->undo()) painter2.beginTransaction(transactionText); + painter2.bltSelection(0, 0, COMPOSITE_OVER, filled, OPACITY_OPAQUE, + 0, 0, img->width(), img->height()); + + dev->setDirty(); + dev->emitSelectionChanged(); + + if (img->undo()) { + img->undoAdapter()->addCommand(painter2.endTransaction()); + } +} + +void KisSelectionManager::fillForegroundColor() +{ + fill(m_parent->fgColor(), false, i18n("Fill with Foreground Color")); +} + +void KisSelectionManager::fillBackgroundColor() +{ + fill(m_parent->bgColor(), false, i18n("Fill with Background Color")); +} + +void KisSelectionManager::fillPattern() +{ + fill(KisColor(), true, i18n("Fill with Pattern")); +} + +void KisSelectionManager::reselect() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img ->activeDevice(); + if (!dev) return; + + KisSelectedTransaction * t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Reselect"), dev); + Q_CHECK_PTR(t); + + dev->reselect(); // sets hasSelection=true + dev->setDirty(); + dev->emitSelectionChanged(); + + if (img->undo()) + img->undoAdapter()->addCommand(t); +} + + +void KisSelectionManager::invert() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (dev->hasSelection()) { + KisSelectionSP s = dev->selection(); + + KisSelectedTransaction * t = 0; + if (img->undo()) + { + t = new KisSelectedTransaction(i18n("Invert"), dev); + Q_CHECK_PTR(t); + } + + s->invert(); + dev->setDirty(); + dev->emitSelectionChanged(); + + if (t) { + img->undoAdapter()->addCommand(t); + } + } +} + +void KisSelectionManager::copySelectionToNewLayer() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + copy(); + paste(); +} + +void KisSelectionManager::cutToNewLayer() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + cut(); + paste(); +} + + +void KisSelectionManager::feather() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) { + // activate it, but don't do anything with it + dev->selection(); + return; + } + + KisSelectionSP selection = dev->selection(); + KisSelectedTransaction * t = 0; + if (img->undo()) t = new KisSelectedTransaction(i18n("Feather..."), dev); + Q_CHECK_PTR(t); + + + // XXX: we should let gaussian blur & others influence alpha channels as well + // (on demand of the caller) + + KisConvolutionPainter painter(selection.data()); + + KisKernelSP k = new KisKernel(); + k->width = 3; + k->height = 3; + k->factor = 16; + k->offset = 0; + k->data = new TQ_INT32[9]; + k->data[0] = 1; + k->data[1] = 2; + k->data[2] = 1; + k->data[3] = 2; + k->data[4] = 4; + k->data[5] = 2; + k->data[6] = 1; + k->data[7] = 2; + k->data[8] = 1; + + TQRect rect = selection->selectedRect(); + // Make sure we've got enough space around the edges. + rect = TQRect(rect.x() - 3, rect.y() - 3, rect.width() + 6, rect.height() + 6); + rect &= TQRect(0, 0, img->width(), img->height()); + + painter.applyMatrix(k, rect.x(), rect.y(), rect.width(), rect.height(), BORDER_AVOID, KisChannelInfo::FLAG_ALPHA); + painter.end(); + + dev->setDirty(rect); + dev->emitSelectionChanged(); + + if (img->undo()) + img->undoAdapter()->addCommand(t); + +} + +void KisSelectionManager::toggleDisplaySelection() +{ + m_parent->selectionDisplayToggled(displaySelection()); +} + +bool KisSelectionManager::displaySelection() +{ + return m_toggleDisplaySelection->isChecked(); +} +// XXX: Maybe move these esoteric functions to plugins? +void KisSelectionManager::border() {} +void KisSelectionManager::expand() {} +void KisSelectionManager::contract() {} +void KisSelectionManager::similar() {} +void KisSelectionManager::transform() {} +void KisSelectionManager::load() {} +void KisSelectionManager::save() {} + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +void KisSelectionManager::grow (TQ_INT32 xradius, TQ_INT32 yradius) +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + /* + Any bugs in this fuction are probably also in thin_region + Blame all bugs in this function on jaycox@gimp.org + */ + + TQ_UINT8 **buf; // caches the region's pixel data + TQ_UINT8 **max; // caches the largest values for each column + + if (xradius <= 0 || yradius <= 0) + return; + + KisSelectedTransaction *t = 0; + + if (img->undo()) { + t = new KisSelectedTransaction(i18n("Grow"), dev); + Q_CHECK_PTR(t); + } + + max = new TQ_UINT8* [layerSize.width() + 2 * xradius]; + buf = new TQ_UINT8* [yradius + 1]; + for (TQ_INT32 i = 0; i < yradius + 1; i++) + { + buf[i] = new TQ_UINT8[layerSize.width()]; + } + TQ_UINT8* buffer = new TQ_UINT8[ ( layerSize.width() + 2 * xradius ) * ( yradius + 1 ) ]; + for (TQ_INT32 i = 0; i < layerSize.width() + 2 * xradius; i++) + { + if (i < xradius) + max[i] = buffer; + else if (i < layerSize.width() + xradius) + max[i] = &buffer[(yradius + 1) * (i - xradius)]; + else + max[i] = &buffer[(yradius + 1) * (layerSize.width() + xradius - 1)]; + + for (TQ_INT32 j = 0; j < xradius + 1; j++) + max[i][j] = 0; + } + /* offset the max pointer by xradius so the range of the array + is [-xradius] to [region->w + xradius] */ + max += xradius; + + TQ_UINT8* out = new TQ_UINT8[ layerSize.width() ]; // holds the new scan line we are computing + + TQ_INT32* circ = new TQ_INT32[ 2 * xradius + 1 ]; // holds the y coords of the filter's tqmask + computeBorder (circ, xradius, yradius); + + /* offset the circ pointer by xradius so the range of the array + is [-xradius] to [xradius] */ + circ += xradius; + + memset (buf[0], 0, layerSize.width()); + for (TQ_INT32 i = 0; i < yradius && i < layerSize.height(); i++) // load top of image + { + selection->readBytes(buf[i + 1], layerSize.x(), layerSize.y() + i, layerSize.width(), 1); + } + + for (TQ_INT32 x = 0; x < layerSize.width() ; x++) // set up max for top of image + { + max[x][0] = 0; // buf[0][x] is always 0 + max[x][1] = buf[1][x]; // MAX (buf[1][x], max[x][0]) always = buf[1][x] + for (TQ_INT32 j = 2; j < yradius + 1; j++) + { + max[x][j] = MAX(buf[j][x], max[x][j-1]); + } + } + + for (TQ_INT32 y = 0; y < layerSize.height(); y++) + { + rotatePointers (buf, yradius + 1); + if (y < layerSize.height() - (yradius)) + selection->readBytes(buf[yradius], layerSize.x(), layerSize.y() + y + yradius, layerSize.width(), 1); + else + memset (buf[yradius], 0, layerSize.width()); + for (TQ_INT32 x = 0; x < layerSize.width(); x++) /* update max array */ + { + for (TQ_INT32 i = yradius; i > 0; i--) + { + max[x][i] = MAX (MAX (max[x][i - 1], buf[i - 1][x]), buf[i][x]); + } + max[x][0] = buf[0][x]; + } + TQ_INT32 last_max = max[0][circ[-1]]; + TQ_INT32 last_index = 1; + for (TQ_INT32 x = 0; x < layerSize.width(); x++) /* render scan line */ + { + last_index--; + if (last_index >= 0) + { + if (last_max == 255) + out[x] = 255; + else + { + last_max = 0; + for (TQ_INT32 i = xradius; i >= 0; i--) + if (last_max < max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + out[x] = last_max; + } + } + else + { + last_index = xradius; + last_max = max[x + xradius][circ[xradius]]; + for (TQ_INT32 i = xradius - 1; i >= -xradius; i--) + if (last_max < max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + out[x] = last_max; + } + } + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, layerSize.width(), 1); + } + /* undo the offsets to the pointers so we can free the malloced memmory */ + circ -= xradius; + max -= xradius; + //XXXX: replace delete by delete[] where it is necessary to avoid memory leaks! + delete[] circ; + delete[] buffer; + delete[] max; + for (TQ_INT32 i = 0; i < yradius + 1; i++) + delete[] buf[i]; + delete[] buf; + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); + + if (t) { + img->undoAdapter()->addCommand(t); + } +} + +void KisSelectionManager::shrink (TQ_INT32 xradius, TQ_INT32 yradius, bool edge_lock) +{ + + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + /* + pretty much the same as fatten_region only different + blame all bugs in this function on jaycox@gimp.org + */ + /* If edge_lock is true we assume that pixels outside the region + we are passed are identical to the edge pixels. + If edge_lock is false, we assume that pixels outside the region are 0 + */ + TQ_UINT8 **buf; // caches the the region's pixels + TQ_UINT8 **max; // caches the smallest values for each column + TQ_INT32 last_max, last_index; + + if (xradius <= 0 || yradius <= 0) + return; + + max = new TQ_UINT8* [layerSize.width() + 2 * xradius]; + buf = new TQ_UINT8* [yradius + 1]; + for (TQ_INT32 i = 0; i < yradius + 1; i++) + { + buf[i] = new TQ_UINT8[layerSize.width()]; + } + + TQ_INT32 buffer_size = (layerSize.width() + 2 * xradius + 1) * (yradius + 1); + TQ_UINT8* buffer = new TQ_UINT8[buffer_size]; + + if (edge_lock) + memset(buffer, 255, buffer_size); + else + memset(buffer, 0, buffer_size); + + for (TQ_INT32 i = 0; i < layerSize.width() + 2 * xradius; i++) + { + if (i < xradius) + if (edge_lock) + max[i] = buffer; + else + max[i] = &buffer[(yradius + 1) * (layerSize.width() + xradius)]; + else if (i < layerSize.width() + xradius) + max[i] = &buffer[(yradius + 1) * (i - xradius)]; + else + if (edge_lock) + max[i] = &buffer[(yradius + 1) * (layerSize.width() + xradius - 1)]; + else + max[i] = &buffer[(yradius + 1) * (layerSize.width() + xradius)]; + } + if (!edge_lock) + for (TQ_INT32 j = 0 ; j < xradius + 1; j++) max[0][j] = 0; + + // offset the max pointer by xradius so the range of the array is [-xradius] to [region->w + xradius] + max += xradius; + + TQ_UINT8* out = new TQ_UINT8[layerSize.width()]; // holds the new scan line we are computing + + TQ_INT32* circ = new TQ_INT32[2 * xradius + 1]; // holds the y coords of the filter's tqmask + + computeBorder (circ, xradius, yradius); + + // offset the circ pointer by xradius so the range of the array is [-xradius] to [xradius] + circ += xradius; + + for (TQ_INT32 i = 0; i < yradius && i < layerSize.height(); i++) // load top of image + selection->readBytes(buf[i + 1], layerSize.x(), layerSize.y() + i, layerSize.width(), 1); + + if (edge_lock) + memcpy (buf[0], buf[1], layerSize.width()); + else + memset (buf[0], 0, layerSize.width()); + + + for (TQ_INT32 x = 0; x < layerSize.width(); x++) // set up max for top of image + { + max[x][0] = buf[0][x]; + for (TQ_INT32 j = 1; j < yradius + 1; j++) + max[x][j] = MIN(buf[j][x], max[x][j-1]); + } + + for (TQ_INT32 y = 0; y < layerSize.height(); y++) + { + rotatePointers (buf, yradius + 1); + if (y < layerSize.height() - yradius) + selection->readBytes(buf[yradius], layerSize.x(), layerSize.y() + y + yradius, layerSize.width(), 1); + else if (edge_lock) + memcpy (buf[yradius], buf[yradius - 1], layerSize.width()); + else + memset (buf[yradius], 0, layerSize.width()); + + for (TQ_INT32 x = 0 ; x < layerSize.width(); x++) // update max array + { + for (TQ_INT32 i = yradius; i > 0; i--) + { + max[x][i] = MIN (MIN (max[x][i - 1], buf[i - 1][x]), buf[i][x]); + } + max[x][0] = buf[0][x]; + } + last_max = max[0][circ[-1]]; + last_index = 0; + + for (TQ_INT32 x = 0 ; x < layerSize.width(); x++) // render scan line + { + last_index--; + if (last_index >= 0) + { + if (last_max == 0) + out[x] = 0; + else + { + last_max = 255; + for (TQ_INT32 i = xradius; i >= 0; i--) + if (last_max > max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + out[x] = last_max; + } + } + else + { + last_index = xradius; + last_max = max[x + xradius][circ[xradius]]; + for (TQ_INT32 i = xradius - 1; i >= -xradius; i--) + if (last_max > max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + out[x] = last_max; + } + } + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, layerSize.width(), 1); + } + + // undo the offsets to the pointers so we can free the malloced memmory + circ -= xradius; + max -= xradius; + //free the memmory + //XXXX: replace delete by delete[] where it is necessary to avoid memory leaks! + delete[] circ; + delete[] buffer; + delete[] max; + for (TQ_INT32 i = 0; i < yradius + 1; i++) + delete buf[i]; + delete[] buf; + delete[] out; + + dev->setDirty(layerSize); + dev->emitSelectionChanged(); +} + +//Simple convolution filter to smooth a tqmask (1bpp) + +void KisSelectionManager::smooth() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + + TQ_UINT8 *buf[3]; + + TQ_INT32 width = layerSize.width(); + + for (TQ_INT32 i = 0; i < 3; i++) buf[i] = new TQ_UINT8[width + 2]; + + TQ_UINT8* out = new TQ_UINT8[width]; + + // load top of image + selection->readBytes(buf[0] + 1, layerSize.x(), layerSize.y(), width, 1); + + buf[0][0] = buf[0][1]; + buf[0][width + 1] = buf[0][width]; + + memcpy (buf[1], buf[0], width + 2); + + for (TQ_INT32 y = 0; y < layerSize.height(); y++) + { + if (y + 1 < layerSize.height()) + { + selection->readBytes(buf[2] + 1, layerSize.x(), layerSize.y() + y + 1, width, 1); + + buf[2][0] = buf[2][1]; + buf[2][width + 1] = buf[2][width]; + } + else + { + memcpy (buf[2], buf[1], width + 2); + } + + for (TQ_INT32 x = 0 ; x < width; x++) + { + TQ_INT32 value = (buf[0][x] + buf[0][x+1] + buf[0][x+2] + + buf[1][x] + buf[2][x+1] + buf[1][x+2] + + buf[2][x] + buf[1][x+1] + buf[2][x+2]); + + out[x] = value / 9; + } + + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, width, 1); + + rotatePointers (buf, 3); + } + + for (TQ_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +// Erode (radius 1 pixel) a tqmask (1bpp) + +void KisSelectionManager::erode() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + + TQ_UINT8* buf[3]; + + + TQ_INT32 width = layerSize.width(); + + for (TQ_INT32 i = 0; i < 3; i++) + buf[i] = new TQ_UINT8[width + 2]; + + TQ_UINT8* out = new TQ_UINT8[width]; + + // load top of image + selection->readBytes(buf[0] + 1, layerSize.x(), layerSize.y(), width, 1); + + buf[0][0] = buf[0][1]; + buf[0][width + 1] = buf[0][width]; + + memcpy (buf[1], buf[0], width + 2); + + for (TQ_INT32 y = 0; y < layerSize.height(); y++) + { + if (y + 1 < layerSize.height()) + { + selection->readBytes(buf[2] + 1, layerSize.x(), layerSize.y() + y + 1, width, 1); + + buf[2][0] = buf[2][1]; + buf[2][width + 1] = buf[2][width]; + } + else + { + memcpy (buf[2], buf[1], width + 2); + } + + for (TQ_INT32 x = 0 ; x < width; x++) + { + TQ_INT32 min = 255; + + if (buf[0][x+1] < min) min = buf[0][x+1]; + if (buf[1][x] < min) min = buf[1][x]; + if (buf[1][x+1] < min) min = buf[1][x+1]; + if (buf[1][x+2] < min) min = buf[1][x+2]; + if (buf[2][x+1] < min) min = buf[2][x+1]; + + out[x] = min; + } + + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, width, 1); + + rotatePointers (buf, 3); + } + + for (TQ_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +// dilate (radius 1 pixel) a tqmask (1bpp) + +void KisSelectionManager::dilate() +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + + TQ_UINT8* buf[3]; + + TQ_INT32 width = layerSize.width(); + + for (TQ_INT32 i = 0; i < 3; i++) + buf[i] = new TQ_UINT8[width + 2]; + + TQ_UINT8* out = new TQ_UINT8[width]; + + // load top of image + selection->readBytes(buf[0] + 1, layerSize.x(), layerSize.y(), width, 1); + + buf[0][0] = buf[0][1]; + buf[0][width + 1] = buf[0][width]; + + memcpy (buf[1], buf[0], width + 2); + + for (TQ_INT32 y = 0; y < layerSize.height(); y++) + { + if (y + 1 < layerSize.height()) + { + selection->readBytes(buf[2] + 1, layerSize.x(), layerSize.y() + y + 1, width, 1); + + buf[2][0] = buf[2][1]; + buf[2][width + 1] = buf[2][width]; + } + else + { + memcpy (buf[2], buf[1], width + 2); + } + + for (TQ_INT32 x = 0 ; x < width; x++) + { + TQ_INT32 max = 0; + + if (buf[0][x+1] > max) max = buf[0][x+1]; + if (buf[1][x] > max) max = buf[1][x]; + if (buf[1][x+1] > max) max = buf[1][x+1]; + if (buf[1][x+2] > max) max = buf[1][x+2]; + if (buf[2][x+1] > max) max = buf[2][x+1]; + + out[x] = max; + } + + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, width, 1); + + rotatePointers (buf, 3); + } + + for (TQ_INT32 i = 0; i < 3; i++) + delete[] buf[i]; + + delete[] out; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +void KisSelectionManager::border(TQ_INT32 xradius, TQ_INT32 yradius) +{ + KisImageSP img = m_parent->currentImg(); + if (!img) return; + + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (!dev->hasSelection()) return; + KisSelectionSP selection = dev->selection(); + + //determine the layerSize + TQRect layerSize = dev->exactBounds(); + + /* + This function has no bugs, but if you imagine some you can + blame them on jaycox@gimp.org + */ + TQ_UINT8 *buf[3]; + TQ_UINT8 **density; + TQ_UINT8 **transition; + + if (xradius == 1 && yradius == 1) // optimize this case specifically + { + TQ_UINT8* source[3]; + + for (TQ_INT32 i = 0; i < 3; i++) + source[i] = new TQ_UINT8[layerSize.width()]; + + TQ_UINT8* transition = new TQ_UINT8[layerSize.width()]; + + selection->readBytes(source[0], layerSize.x(), layerSize.y(), layerSize.width(), 1); + memcpy (source[1], source[0], layerSize.width()); + if (layerSize.height() > 1) + selection->readBytes(source[2], layerSize.x(), layerSize.y() + 1, layerSize.width(), 1); + else + memcpy (source[2], source[1], layerSize.width()); + + computeTransition (transition, source, layerSize.width()); + selection->writeBytes(transition, layerSize.x(), layerSize.y(), layerSize.width(), 1); + + for (TQ_INT32 y = 1; y < layerSize.height(); y++) + { + rotatePointers (source, 3); + if (y + 1 < layerSize.height()) + selection->readBytes(source[2], layerSize.x(), layerSize.y() + y + 1, layerSize.width(), 1); + else + memcpy(source[2], source[1], layerSize.width()); + computeTransition (transition, source, layerSize.width()); + selection->writeBytes(transition, layerSize.x(), layerSize.y() + y, layerSize.width(), 1); + } + + for (TQ_INT32 i = 0; i < 3; i++) + delete[] source[i]; + delete[] transition; + return; + } + + TQ_INT32* max = new TQ_INT32[layerSize.width() + 2 * xradius]; + for (TQ_INT32 i = 0; i < (layerSize.width() + 2 * xradius); i++) + max[i] = yradius + 2; + max += xradius; + + for (TQ_INT32 i = 0; i < 3; i++) + buf[i] = new TQ_UINT8[layerSize.width()]; + + transition = new TQ_UINT8*[yradius + 1]; + for (TQ_INT32 i = 0; i < yradius + 1; i++) + { + transition[i] = new TQ_UINT8[layerSize.width() + 2 * xradius]; + memset(transition[i], 0, layerSize.width() + 2 * xradius); + transition[i] += xradius; + } + TQ_UINT8* out = new TQ_UINT8[layerSize.width()]; + density = new TQ_UINT8*[2 * xradius + 1]; + density += xradius; + + for (TQ_INT32 x = 0; x < (xradius + 1); x++) // allocate density[][] + { + density[ x] = new TQ_UINT8[2 * yradius + 1]; + density[ x] += yradius; + density[-x] = density[x]; + } + for (TQ_INT32 x = 0; x < (xradius + 1); x++) // compute density[][] + { + double tmpx, tmpy, dist; + TQ_UINT8 a; + + if (x > 0) + tmpx = x - 0.5; + else if (x < 0) + tmpx = x + 0.5; + else + tmpx = 0.0; + + for (TQ_INT32 y = 0; y < (yradius + 1); y++) + { + if (y > 0) + tmpy = y - 0.5; + else if (y < 0) + tmpy = y + 0.5; + else + tmpy = 0.0; + dist = ((tmpy * tmpy) / (yradius * yradius) + + (tmpx * tmpx) / (xradius * xradius)); + if (dist < 1.0) + a = 255 * (TQ_UINT8)(1.0 - sqrt (dist)); + else + a = 0; + density[ x][ y] = a; + density[ x][-y] = a; + density[-x][ y] = a; + density[-x][-y] = a; + } + } + selection->readBytes(buf[0], layerSize.x(), layerSize.y(), layerSize.width(), 1); + memcpy (buf[1], buf[0], layerSize.width()); + if (layerSize.height() > 1) + selection->readBytes(buf[2], layerSize.x(), layerSize.y() + 1, layerSize.width(), 1); + else + memcpy (buf[2], buf[1], layerSize.width()); + computeTransition (transition[1], buf, layerSize.width()); + + for (TQ_INT32 y = 1; y < yradius && y + 1 < layerSize.height(); y++) // set up top of image + { + rotatePointers (buf, 3); + selection->readBytes(buf[2], layerSize.x(), layerSize.y() + y + 1, layerSize.width(), 1); + computeTransition (transition[y + 1], buf, layerSize.width()); + } + for (TQ_INT32 x = 0; x < layerSize.width(); x++) // set up max[] for top of image + { + max[x] = -(yradius + 7); + for (TQ_INT32 j = 1; j < yradius + 1; j++) + if (transition[j][x]) + { + max[x] = j; + break; + } + } + for (TQ_INT32 y = 0; y < layerSize.height(); y++) // main calculation loop + { + rotatePointers (buf, 3); + rotatePointers (transition, yradius + 1); + if (y < layerSize.height() - (yradius + 1)) + { + selection->readBytes(buf[2], layerSize.x(), layerSize.y() + y + yradius + 1, layerSize.width(), 1); + computeTransition (transition[yradius], buf, layerSize.width()); + } + else + memcpy (transition[yradius], transition[yradius - 1], layerSize.width()); + + for (TQ_INT32 x = 0; x < layerSize.width(); x++) // update max array + { + if (max[x] < 1) + { + if (max[x] <= -yradius) + { + if (transition[yradius][x]) + max[x] = yradius; + else + max[x]--; + } + else + if (transition[-max[x]][x]) + max[x] = -max[x]; + else if (transition[-max[x] + 1][x]) + max[x] = -max[x] + 1; + else + max[x]--; + } + else + max[x]--; + if (max[x] < -yradius - 1) + max[x] = -yradius - 1; + } + TQ_UINT8 last_max = max[0][density[-1]]; + TQ_INT32 last_index = 1; + for (TQ_INT32 x = 0 ; x < layerSize.width(); x++) // render scan line + { + last_index--; + if (last_index >= 0) + { + last_max = 0; + for (TQ_INT32 i = xradius; i >= 0; i--) + if (max[x + i] <= yradius && max[x + i] >= -yradius && density[i][max[x+i]] > last_max) + { + last_max = density[i][max[x + i]]; + last_index = i; + } + out[x] = last_max; + } + else + { + last_max = 0; + for (TQ_INT32 i = xradius; i >= -xradius; i--) + if (max[x + i] <= yradius && max[x + i] >= -yradius && density[i][max[x + i]] > last_max) + { + last_max = density[i][max[x + i]]; + last_index = i; + } + out[x] = last_max; + } + if (last_max == 0) + { + TQ_INT32 i; + for (i = x + 1; i < layerSize.width(); i++) + { + if (max[i] >= -yradius) + break; + } + if (i - x > xradius) + { + for (; x < i - xradius; x++) + out[x] = 0; + x--; + } + last_index = xradius; + } + } + selection->writeBytes(out, layerSize.x(), layerSize.y() + y, layerSize.width(), 1); + } + delete [] out; + + for (TQ_INT32 i = 0; i < 3; i++) + delete buf[i]; + + max -= xradius; + delete[] max; + + for (TQ_INT32 i = 0; i < yradius + 1; i++) + { + transition[i] -= xradius; + delete transition[i]; + } + delete[] transition; + + for (TQ_INT32 i = 0; i < xradius + 1 ; i++) + { + density[i] -= yradius; + delete density[i]; + } + density -= xradius; + delete[] density; + + dev->setDirty(); + dev->emitSelectionChanged(); +} + +#define RINT(x) floor ((x) + 0.5) + +void KisSelectionManager::computeBorder (TQ_INT32 *circ, TQ_INT32 xradius, TQ_INT32 yradius) +{ + Q_ASSERT(xradius != 0); + TQ_INT32 i; + TQ_INT32 diameter = xradius * 2 + 1; + double tmp; + + for (i = 0; i < diameter; i++) + { + if (i > xradius) + tmp = (i - xradius) - 0.5; + else if (i < xradius) + tmp = (xradius - i) - 0.5; + else + tmp = 0.0; + + circ[i] = (TQ_INT32) RINT (yradius / (double) xradius * sqrt (xradius * xradius - tmp * tmp)); + } +} + +void KisSelectionManager::rotatePointers (TQ_UINT8 **p, TQ_UINT32 n) +{ + TQ_UINT32 i; + TQ_UINT8 *tmp; + + tmp = p[0]; + + for (i = 0; i < n - 1; i++) p[i] = p[i + 1]; + + p[i] = tmp; +} + +void KisSelectionManager::computeTransition (TQ_UINT8* transition, TQ_UINT8** buf, TQ_INT32 width) +{ + TQ_INT32 x = 0; + + if (width == 1) + { + if (buf[1][x] > 127 && (buf[0][x] < 128 || buf[2][x] < 128)) + transition[x] = 255; + else + transition[x] = 0; + return; + } + if (buf[1][x] > 127) + { + if ( buf[0][x] < 128 || buf[0][x + 1] < 128 || + buf[1][x + 1] < 128 || + buf[2][x] < 128 || buf[2][x + 1] < 128 ) + transition[x] = 255; + else + transition[x] = 0; + } + else + transition[x] = 0; + for (TQ_INT32 x = 1; x < width - 1; x++) + { + if (buf[1][x] >= 128) + { + if (buf[0][x - 1] < 128 || buf[0][x] < 128 || buf[0][x + 1] < 128 || + buf[1][x - 1] < 128 || buf[1][x + 1] < 128 || + buf[2][x - 1] < 128 || buf[2][x] < 128 || buf[2][x + 1] < 128) + transition[x] = 255; + else + transition[x] = 0; + } + else + transition[x] = 0; + } + if (buf[1][x] >= 128) + { + if (buf[0][x - 1] < 128 || buf[0][x] < 128 || + buf[1][x - 1] < 128 || + buf[2][x - 1] < 128 || buf[2][x] < 128) + transition[x] = 255; + else + transition[x] = 0; + } + else + transition[x] = 0; +} + +#include "kis_selection_manager.moc" diff --git a/chalk/ui/kis_selection_manager.h b/chalk/ui/kis_selection_manager.h new file mode 100644 index 00000000..fb33218e --- /dev/null +++ b/chalk/ui/kis_selection_manager.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_SELECTION_MANAGER_ +#define KIS_SELECTION_MANAGER_ + +#include "tqobject.h" +#include "tqptrlist.h" + +#include "kis_image.h" +#include + +class KAction; +class KisView; +class KisDoc; +class KisClipboard; + +/** + * The selection manager is responsible selections + * and the clipboard. + */ +class KRITACORE_EXPORT KisSelectionManager : public TQObject { + + Q_OBJECT + TQ_OBJECT + +public: + + KisSelectionManager(KisView * tqparent, KisDoc * doc); + virtual ~KisSelectionManager(); + + void setup(KActionCollection * collection); + + void addSelectionAction(KAction * action); + +public: + /** + * This function return if the selection should be displayed + */ + bool displaySelection(); + +public slots: + + void updateGUI(); + void imgSelectionChanged(KisImageSP img); + void clipboardDataChanged(); + + void cut(); + void copy(); + KisLayerSP paste(); + void pasteNew(); + void cutToNewLayer(); + void selectAll(); + void deselect(); + void clear(); + void fillForegroundColor(); + void fillBackgroundColor(); + void fillPattern(); + void reselect(); + void invert(); + void copySelectionToNewLayer(); + void feather(); + void border(); + void expand(); + void contract(); + void smooth(); + void similar(); + void transform(); + void load(); + void save(); + void toggleDisplaySelection(); + +public: + void grow (TQ_INT32 xradius, TQ_INT32 yradius); + void shrink (TQ_INT32 xradius, TQ_INT32 yradius, bool edge_lock); + void border(TQ_INT32 xradius, TQ_INT32 yradius); + // the following functions are needed for the siox tool + // they might be also usefull on its own + void erode(); + void dilate(); + +private: + void fill(const KisColor& color, bool fillWithPattern, const TQString& transactionText); + + void computeBorder (TQ_INT32 *circ, TQ_INT32 xradius, TQ_INT32 yradius); + inline void rotatePointers (TQ_UINT8 **p, TQ_UINT32 n); + void computeTransition (TQ_UINT8* transition, TQ_UINT8** buf, TQ_INT32 width); + + KisView * m_parent; + KisDoc * m_doc; + + KisClipboard * m_clipboard; + + KAction *m_copy; + KAction *m_cut; + KAction *m_paste; + KAction *m_pasteNew; + KAction *m_cutToNewLayer; + KAction *m_selectAll; + KAction *m_deselect; + KAction *m_clear; + KAction *m_reselect; + KAction *m_invert; + KAction *m_toNewLayer; + KAction *m_feather; + KAction *m_border; + KAction *m_expand; + KAction *m_smooth; + KAction *m_contract; + KAction *m_similar; + KAction *m_transform; + KAction *m_load; + KAction *m_save; + KAction *m_fillForegroundColor; + KAction *m_fillBackgroundColor; + KAction *m_fillPattern; + KToggleAction *m_toggleDisplaySelection; + + TQPtrList m_pluginActions; + +}; + +#endif // KIS_SELECTION_MANAGER_ diff --git a/chalk/ui/kis_selection_options.cc b/chalk/ui/kis_selection_options.cc new file mode 100644 index 00000000..f94ff17f --- /dev/null +++ b/chalk/ui/kis_selection_options.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "wdgselectionoptions.h" +#include "kis_selection_options.h" +#include "kis_types.h" +#include "kis_layer.h" +#include "kis_image.h" +#include "kis_selection.h" +#include "kis_paint_device.h" + +KisSelectionOptions::KisSelectionOptions(TQWidget *tqparent, KisCanvasSubject * subject) + : super(tqparent), + m_subject(subject) +{ + m_page = new WdgSelectionOptions(this); + Q_CHECK_PTR(m_page); + + TQVBoxLayout * l = new TQVBoxLayout(this); + l->addWidget(m_page); + + connect(m_page->cmbAction, TQT_SIGNAL(activated(int)), this, TQT_SIGNAL(actionChanged(int))); +} + +KisSelectionOptions::~KisSelectionOptions() +{ +} + +int KisSelectionOptions::action() +{ + return m_page->cmbAction->currentItem(); +} + +void KisSelectionOptions::slotActivated() +{ + + if (!m_subject) return; + KisImageSP img = m_subject->currentImg(); + if (!img) return; + KisPaintDeviceSP dev = img->activeDevice(); + if (!dev) return; + + if (dev->hasSelection()) { + } +} + +#include "kis_selection_options.moc" diff --git a/chalk/ui/kis_selection_options.h b/chalk/ui/kis_selection_options.h new file mode 100644 index 00000000..e8168d04 --- /dev/null +++ b/chalk/ui/kis_selection_options.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KIS_SELECTION_OPTIONS_H__ +#define __KIS_SELECTION_OPTIONS_H__ + +#include + +#include "koffice_export.h" + +class KisCanvasSubject; +class WdgSelectionOptions; + +/** + */ +class KRITAUI_EXPORT KisSelectionOptions : public TQWidget +{ + + Q_OBJECT + TQ_OBJECT + + typedef TQWidget super; + +public: + KisSelectionOptions( TQWidget *tqparent, KisCanvasSubject * subject); + virtual ~KisSelectionOptions(); + + int action(); + +signals: + void actionChanged(int); + +public slots: + void slotActivated(); + +private: + WdgSelectionOptions * m_page; + KisCanvasSubject* m_subject; +}; + +#endif + diff --git a/chalk/ui/kis_text_brush.cc b/chalk/ui/kis_text_brush.cc new file mode 100644 index 00000000..ef376373 --- /dev/null +++ b/chalk/ui/kis_text_brush.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include "kis_text_brush.h" + +void KisTextBrushResource::updateBrush() +{ + TQFontMetrics metric(m_font); + int w = metric.width(m_txt); + int h = metric.height(); + TQPixmap px(w,h); + TQPainter p; + p.begin(&px); + p.setFont( m_font ); + p.fillRect(0,0, w, h, TQt::white); + p.setPen(TQt::black); + p.drawText(0, metric.ascent(), m_txt ); + p.end(); + setImage(px.convertToImage ()); +} + +KisTextBrush::KisTextBrush(TQWidget *tqparent, const char* name, const TQString& caption) + : KisWdgTextBrush(tqparent, name), + m_textBrushResource(new KisTextBrushResource()) +{ + setCaption(caption); + connect((TQObject*)lineEdit, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(rebuildTextBrush())); + connect((TQObject*)bnFont, TQT_SIGNAL(clicked()), this, TQT_SLOT(getFont())); + m_font = font(); + rebuildTextBrush(); +} + + +void KisTextBrush::getFont() +{ + KFontDialog::getFont( m_font, false/*, TQWidget* tqparent! */ ); + rebuildTextBrush(); +} + +void KisTextBrush::rebuildTextBrush() +{ + lblFont->setText(TQString(m_font.family() + ", %1").tqarg(m_font.pointSize())); + lblFont->setFont(m_font); + m_textBrushResource->setFont(m_font); + m_textBrushResource->setText(lineEdit->text()); + m_textBrushResource->updateBrush(); + emit(activatedResource(m_textBrushResource)); +} + +#include "kis_text_brush.moc" diff --git a/chalk/ui/kis_text_brush.h b/chalk/ui/kis_text_brush.h new file mode 100644 index 00000000..3c8835de --- /dev/null +++ b/chalk/ui/kis_text_brush.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TEXT_BRUSH_H_ +#define _KIS_TEXT_BRUSH_H_ + +#include "wdgtextbrush.h" +#include "kis_brush.h" + +class KisTextBrushResource : public KisBrush +{ + public: + KisTextBrushResource() : KisBrush("") + { + setBrushType(MASK); + } + KisTextBrushResource(const TQString& txt, const TQFont& font) : KisBrush("") + { + setFont(font); + setText(txt); + updateBrush(); + setBrushType(MASK); + }; + public: + virtual bool load() { return false; }; + void setText(const TQString& txt) { m_txt = txt; }; + void setFont(const TQFont& font) { m_font = font; }; + void updateBrush(); + private: + TQFont m_font; + TQString m_txt; +}; + +class KisTextBrush : public KisWdgTextBrush +{ + Q_OBJECT + TQ_OBJECT +public: + KisTextBrush(TQWidget *tqparent, const char* name, const TQString& caption); + +signals: + void activatedResource(KisResource *r); + +private slots: + void rebuildTextBrush(); + void getFont(); + +private: + KisTextBrushResource* m_textBrushResource; + TQFont m_font; +}; + + + + +#endif diff --git a/chalk/ui/kis_tool.cc b/chalk/ui/kis_tool.cc new file mode 100644 index 00000000..5aee554b --- /dev/null +++ b/chalk/ui/kis_tool.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2002, 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "kis_tool.h" +#include "kis_tool.moc" + + +class KisTool::KisToolPrivate +{ +public: + TQString uiname; + TQLabel * optionWidget; +}; + +KisTool::KisTool(const TQString & name) +{ + m_action = 0; + m_ownAction = false; + d = new KisToolPrivate(); + d->uiname = name; + d->optionWidget = 0; +} + +KisTool::~KisTool() +{ + if (m_ownAction) { + delete m_action; + m_action = 0; + } + delete d; +} + +TQWidget* KisTool::createOptionWidget(TQWidget* tqparent) +{ + + d->optionWidget = new TQLabel(i18n("No options for %1.").tqarg(d->uiname), tqparent); + d->optionWidget->setCaption(d->uiname); + d->optionWidget->tqsetAlignment(TQt::AlignCenter); + return d->optionWidget; +} + +TQWidget* KisTool::optionWidget() +{ + return d->optionWidget; +} + diff --git a/chalk/ui/kis_tool.h b/chalk/ui/kis_tool.h new file mode 100644 index 00000000..c8f2d349 --- /dev/null +++ b/chalk/ui/kis_tool.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1999 Matthias Elter + * Copyright (c) 2002, 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_H_ +#define KIS_TOOL_H_ + +#include +#include + +#include +#include + +#include "kis_shared_ptr_vector.h" +#include "kis_canvas_observer.h" + +class TQCursor; +class TQEvent; +class TQKeyEvent; +class TQRect; +class TQWidget; +class KActionCollection; +class KRadioAction; +class KDialog; +class KisBrush; +class KisGradient; +class KisPattern; +class KisButtonPressEvent; +class KisButtonReleaseEvent; +class KisDoubleClickEvent; +class KisMoveEvent; +class KisCanvasPainter; + +enum enumToolType { + TOOL_SHAPE = 0, // Geometric tqshapes like ellipses and lines + TOOL_FREEHAND = 1, // Freehand drawing tools + TOOL_TRANSFORM = 2, // Tools that transform the layer + TOOL_FILL = 3, // Tools that fill parts of the canvas + TOOL_VIEW = 4, // Tools that affect the canvas: pan, zoom, etc. + TOOL_SELECT = 5 + +}; + +const TQ_UINT8 NUMBER_OF_TOOLTYPES = 6; + +class KisTool : public TQObject, public KisCanvasObserver, public KShared { + Q_OBJECT + TQ_OBJECT + +public: + KisTool(const TQString & name); + virtual ~KisTool(); + +public: + + virtual void paint(KisCanvasPainter& gc) = 0; + virtual void paint(KisCanvasPainter& gc, const TQRect& rc) = 0; + + /** + * This function is called after the creation of a tool to create the KAction corresponding + * to the tool. + * + * The code should look like : + * @code + * + * @endcode + */ + virtual void setup(KActionCollection *collection) = 0; + + virtual void buttonPress(KisButtonPressEvent *e) = 0; + virtual void move(KisMoveEvent *e) = 0; + virtual void buttonRelease(KisButtonReleaseEvent *e) = 0; + virtual void doubleClick(KisDoubleClickEvent *e) = 0; + virtual void keyPress(TQKeyEvent *e) = 0; + virtual void keyRelease(TQKeyEvent *e) = 0; + + virtual TQCursor cursor() = 0; + virtual void setCursor(const TQCursor& cursor) = 0; + /** + * This function is called to create the configuration widget of the tool. + * @param tqparent the tqparent of the widget + */ + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + /** + * @return the current configuration widget. + */ + virtual TQWidget* optionWidget(); + KRadioAction *action() const { return m_action; } + + /** + * Return true if this tool wants auto canvas-scrolling to + * work when this tool is active. + */ + virtual bool wantsAutoScroll() const { return true; } + + // Methods for integration with karbon-style toolbox + virtual TQ_UINT32 priority() { return 0; } + virtual enumToolType toolType() { return TOOL_FREEHAND; } + virtual TQString icon() { return m_action->icon(); } + virtual TQString quickHelp() const { return ""; } + +public slots: + /** + * This slot is called when the tool is selected in the toolbox + */ + virtual void activate() = 0; + + /** + * deactivate is called when the tool gets deactivated because another + * tool is selected. Tools can then clean up after themselves. + */ + virtual void deactivate() = 0; + +private: + KisTool(const KisTool&); + KisTool& operator=(const KisTool&); + +protected: + KRadioAction *m_action; + bool m_ownAction; + +private: + class KisToolPrivate; + KisToolPrivate * d; + +}; + +#endif // KIS_TOOL_H_ + diff --git a/chalk/ui/kis_tool_controller.h b/chalk/ui/kis_tool_controller.h new file mode 100644 index 00000000..f135b86e --- /dev/null +++ b/chalk/ui/kis_tool_controller.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2003 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_CONTROLLER_H_ +#define KIS_TOOL_CONTROLLER_H_ + +class KisTool; + +class KisToolControllerInterface { +public: + KisToolControllerInterface() {}; + virtual ~KisToolControllerInterface() {}; + +public: + virtual void setCurrentTool(KisTool *tool) = 0; + virtual KisTool *currentTool() const = 0; + +private: + KisToolControllerInterface(const KisToolControllerInterface&); + KisToolControllerInterface& operator=(const KisToolControllerInterface&); +}; + +#endif // KIS_TOOL_CONTROLLER_H_ + diff --git a/chalk/ui/kis_tool_dummy.cc b/chalk/ui/kis_tool_dummy.cc new file mode 100644 index 00000000..d8ac04e5 --- /dev/null +++ b/chalk/ui/kis_tool_dummy.cc @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_cursor.h" +#include "kis_tool_dummy.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" + +KisToolDummy::KisToolDummy() + : super(i18n("No Active Tool")) +{ + setName("tool_dummy"); + m_subject = 0; + m_dragging = false; + m_optionWidget = 0; + setCursor(TQCursor::forbiddenCursor); +} + +KisToolDummy::~KisToolDummy() +{ +} + +void KisToolDummy::update(KisCanvasSubject *subject) +{ + m_subject = subject; + super::update(m_subject); +} + +void KisToolDummy::buttonPress(KisButtonPressEvent *e) +{ + if (m_subject && !m_dragging && e->button() == Qt::LeftButton) { + KisCanvasController *controller = m_subject->canvasController(); + + m_origScrollX = controller->horzValue(); + m_origScrollY = controller->vertValue(); + m_dragPos = controller->windowToView(e->pos()); + m_dragging = true; + } +} + +void KisToolDummy::move(KisMoveEvent *e) +{ + if (m_subject && m_dragging) { + KisCanvasController *controller = m_subject->canvasController(); + + KisPoint currPos = controller->windowToView(e->pos()); + KisPoint delta = currPos - m_dragPos; + controller->scrollTo(m_origScrollX - delta.floorX(), m_origScrollY - delta.floorY()); + } +} + +void KisToolDummy::buttonRelease(KisButtonReleaseEvent *e) +{ + if (m_subject && m_dragging && e->button() == Qt::LeftButton) { + m_dragging = false; + } +} + +void KisToolDummy::setup(KActionCollection *collection) +{ + m_action = static_cast(collection->action(name())); + + if (m_action == 0) { + m_action = new KRadioAction(i18n("&Dummy"), "tool_dummy", TQt::SHIFT+TQt::Key_H, this, TQT_SLOT(activate()), collection, name()); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + + +TQWidget* KisToolDummy::createOptionWidget(TQWidget* tqparent) +{ + m_optionWidget = new TQLabel(i18n("Layer is locked or invisible."), tqparent); + m_optionWidget->setCaption(i18n("No Active Tool")); + m_optionWidget->tqsetAlignment(TQt::AlignCenter); + return m_optionWidget; +} + +TQWidget* KisToolDummy::optionWidget() +{ + return m_optionWidget; +} + + +#include "kis_tool_dummy.moc" diff --git a/chalk/ui/kis_tool_dummy.h b/chalk/ui/kis_tool_dummy.h new file mode 100644 index 00000000..d10850e8 --- /dev/null +++ b/chalk/ui/kis_tool_dummy.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2004 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_DUMMY_H_ +#define KIS_TOOL_DUMMY_H_ + +#include "kis_tool_non_paint.h" +#include "kis_tool_factory.h" +#include + +#include "kis_point.h" + +class TQLabel; +class KisCanvasSubject; + +/** + * The dummy tool is activated when a layer does not permit painting + * or any other destructive action. It shows a forbidden cursor, making + * it clear that you really cannot do anything here. + * + * Furthermore, it implements more or less the same things as the pan tool, + * so we can at least move the canvas around. + */ +class KRITATOOL_EXPORT KisToolDummy : public KisToolNonPaint { + + typedef KisToolNonPaint super; + Q_OBJECT + TQ_OBJECT + +public: + KisToolDummy(); + virtual ~KisToolDummy(); + + virtual void update(KisCanvasSubject *subject); + + virtual void setup(KActionCollection *collection); + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + +private: + TQLabel * m_optionWidget; + KisCanvasSubject *m_subject; + KisPoint m_dragPos; + TQ_INT32 m_origScrollX; + TQ_INT32 m_origScrollY; + bool m_dragging; +}; + +class KisToolDummyFactory : public KisToolFactory { + typedef KisToolFactory super; +public: + KisToolDummyFactory() : super() {}; + virtual ~KisToolDummyFactory() {}; + + virtual KisTool * createTool(KActionCollection * ac) { + KisTool * t = new KisToolDummy(); + Q_CHECK_PTR(t); + t->setup(ac); + return t; + } + virtual KisID id() { return KisID("dummy", i18n("Dummy Tool")); } +}; + + +#endif // KIS_TOOL_DUMMY_H_ + diff --git a/chalk/ui/kis_tool_factory.h b/chalk/ui/kis_tool_factory.h new file mode 100644 index 00000000..da1239e3 --- /dev/null +++ b/chalk/ui/kis_tool_factory.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_FACTORY_H_ +#define KIS_TOOL_FACTORY_H_ + +#include + +#include "kis_id.h" +#include "kis_types.h" +#include "kactioncollection.h" + +class KisToolFactory : public KShared +{ + +public: + KisToolFactory() {} + virtual ~KisToolFactory() {}; + + virtual KisTool * createTool(KActionCollection * ac) = 0; + virtual KisID id() { return KisID("Abstract Tool", i18n("Abstract Tool")); } + +}; + +#endif // KIS_TOOL_FACTORY_H_ + diff --git a/chalk/ui/kis_tool_freehand.cc b/chalk/ui/kis_tool_freehand.cc new file mode 100644 index 00000000..fe30eb50 --- /dev/null +++ b/chalk/ui/kis_tool_freehand.cc @@ -0,0 +1,354 @@ +/* + * kis_tool_brush.cc - part of Chalk + * + * Copyright (c) 2003-2004 Boudewijn Rempt + * Copyright (c) 2004 Bart Coppens + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_canvas_subject.h" +#include "kis_undo_adapter.h" +#include "kis_selection.h" +#include "kis_painter.h" +#include "kis_fill_painter.h" +#include "kis_tool_freehand.h" +#include "kis_cursor.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_move_event.h" +#include "kis_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_layer.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_boundary_painter.h" +#include "kis_brush.h" + +KisToolFreehand::KisToolFreehand(TQString transactionText) + : super(transactionText), + m_dragDist ( 0 ), + m_transactionText(transactionText), + m_mode( HOVER ) +{ + m_painter = 0; + m_currentImage = 0; + m_tempLayer = 0; + m_paintIncremental = true; + m_paintOnSelection = false; + m_paintedOutline = false; +} + +KisToolFreehand::~KisToolFreehand() +{ +} + +void KisToolFreehand::update(KisCanvasSubject *subject) +{ + super::update(subject); + m_currentImage = m_subject->currentImg(); +} + +void KisToolFreehand::buttonPress(KisButtonPressEvent *e) +{ + if (!m_subject) return; + + if (!m_subject->currentBrush()) return; + + if (!m_currentImage || !m_currentImage->activeDevice()) return; + + if (e->button() == Qt::LeftButton) { + + m_currentImage->activeDevice()->lock( true ); + kdDebug() << ">>>>>>>>>>>>>>>>>>>Locking paint device\n"; + + // People complain that they can't start brush strokes outside of the image boundaries. + // This makes sense, especially when combined with BUG:132759, so commenting out the + // next line makes sense. + //if (!m_currentImage->bounds().tqcontains(e->pos().floorTQPoint())) return; + + initPaint(e); + paintAt(e->pos(), e->pressure(), e->xTilt(), e->yTilt()); + + m_prevPos = e->pos(); + m_prevPressure = e->pressure(); + m_prevXTilt = e->xTilt(); + m_prevYTilt = e->yTilt(); + + TQRect r = m_painter->dirtyRect(); + if ( r.isValid() ) { + m_dirtyRect = r; + + r = TQRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2); //needed to update selectionvisualization + if (!m_paintOnSelection) { + m_currentImage->activeLayer()->setDirty(r); + } + else { + m_target->setDirty(r); + // Just update the canvas. XXX: After 1.5, find a better way to make sure tools don't set dirty what they didn't touch. + m_subject->canvasController()->updateCanvas( r ); + } + } + } +} + +void KisToolFreehand::buttonRelease(KisButtonReleaseEvent* e) +{ + if (e->button() == Qt::LeftButton && m_mode == PAINT) { + endPaint(); + m_currentImage->activeDevice()->lock( false ); + kdDebug() << ">>>>>>>>>>>>>>>>>>>UNLocking paint device\n"; + + } + KisToolPaint::buttonRelease(e); +} + +void KisToolFreehand::move(KisMoveEvent *e) +{ + if (m_mode == PAINT) { + + paintLine(m_prevPos, m_prevPressure, m_prevXTilt, m_prevYTilt, e->pos(), e->pressure(), e->xTilt(), e->yTilt()); + + m_prevPos = e->pos(); + m_prevPressure = e->pressure(); + m_prevXTilt = e->xTilt(); + m_prevYTilt = e->yTilt(); + + TQRect r = m_painter->dirtyRect(); + + if (r.isValid()) { + m_dirtyRect |= r; + + if (!m_paintOnSelection) { + m_currentImage->activeLayer()->setDirty(r); + } + else { + // Just update the canvas + r = TQRect(r.left()-1, r.top()-1, r.width()+2, r.height()+2); //needed to update selectionvisualization + m_target->setDirty(r); + m_subject->canvasController()->updateCanvas( r ); + } + } + } +} + +void KisToolFreehand::initPaint(KisEvent *) +{ + if (!m_currentImage || !m_currentImage->activeDevice()) return; + + m_mode = PAINT; + m_dragDist = 0; + + // Create painter + KisPaintDeviceSP device; + if (m_currentImage && (device = m_currentImage->activeDevice())) { + + if (m_painter) + delete m_painter; + + if (!m_paintIncremental) { + if (m_currentImage->undo()) + m_currentImage->undoAdapter()->beginMacro(m_transactionText); + + KisLayerSupportsIndirectPainting* layer; + if ((layer = dynamic_cast( + m_currentImage->activeLayer().data()))) { + + // Hack for the painting of single-layered layers using indirect painting, + // because the group layer would not have a correctly synched cache ( + // because of an optimization that would happen, having this layer as + // projection). + KisLayer* l = layer->layer(); + KisPaintLayer* pl = dynamic_cast(l); + if (l->tqparent() && (l->tqparent()->tqparent() == 0) + && (l->tqparent()->childCount() == 1) + && l->tqparent()->paintLayerInducesProjectionOptimization(pl)) { + // If there's a tqmask, device could've been the tqmask. The induce function + // should catch this, but better safe than sorry + l->tqparent()->resetProjection(pl->paintDevice()); + } + + m_target = new KisPaintDevice(m_currentImage->activeLayer(), + device->colorSpace()); + layer->setTemporaryTarget(m_target); + layer->setTemporaryCompositeOp(m_compositeOp); + layer->setTemporaryOpacity(m_opacity); + + if (device->hasSelection()) + m_target->setSelection(device->selection()); + } + } else { + m_target = device; + } + if(m_target->hasSelection()) m_target->selection()->startCachingExactRect(); + m_painter = new KisPainter( m_target ); + Q_CHECK_PTR(m_painter); + m_source = device; + if (currentImage()->undo()) m_painter->beginTransaction(m_transactionText); + } + + m_painter->setPaintColor(m_subject->fgColor()); + m_painter->setBackgroundColor(m_subject->bgColor()); + m_painter->setBrush(m_subject->currentBrush()); + + + // if you're drawing on a temporary layer, the layer already sets this + if (m_paintIncremental) { + m_painter->setCompositeOp(m_compositeOp); + m_painter->setOpacity(m_opacity); + } else { + m_painter->setCompositeOp(COMPOSITE_ALPHA_DARKEN); + m_painter->setOpacity( OPACITY_OPAQUE ); + + } + +/* kdDebug() << "target: " << m_target << "( " << m_target->name() << " )" + << " source: " << m_source << "( " << m_source->name() << " )" + << ", incremental " << m_paintIncremental + << ", paint on selection: " << m_paintOnSelection + << ", active device has selection: " << device->hasSelection() + << ", target has selection: " << m_target->hasSelection() + << endl; +*/ +} + +void KisToolFreehand::endPaint() +{ + m_mode = HOVER; + if (m_currentImage) { + + if (m_painter) { + // If painting in mouse release, make sure painter + // is destructed or end()ed + if (!m_paintIncremental) { + if (m_currentImage->undo()) + m_painter->endTransaction(); + KisPainter painter( m_source ); + painter.setCompositeOp(m_compositeOp); + if (m_currentImage->undo()) + painter.beginTransaction(m_transactionText); + painter.bitBlt(m_dirtyRect.x(), m_dirtyRect.y(), m_compositeOp, m_target, + m_opacity, + m_dirtyRect.x(), m_dirtyRect.y(), + m_dirtyRect.width(), m_dirtyRect.height()); + + KisLayerSupportsIndirectPainting* layer = + dynamic_cast(m_source->tqparentLayer()); + layer->setTemporaryTarget(0); + m_source->tqparentLayer()->setDirty(m_dirtyRect); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + m_currentImage->undoAdapter()->endMacro(); + } + } else { + if (m_currentImage->undo()) + m_currentImage->undoAdapter()->addCommand(m_painter->endTransaction()); + } + } + delete m_painter; + m_painter = 0; + notifyModified(); + if(m_target->hasSelection()) m_target->selection()->stopCachingExactRect(); + } +} + +void KisToolFreehand::paintAt(const KisPoint &pos, + const double pressure, + const double xTilt, + const double yTilt) +{ + painter()->paintAt(pos, pressure, xTilt, yTilt); +} + +void KisToolFreehand::paintLine(const KisPoint & pos1, + const double pressure1, + const double xtilt1, + const double ytilt1, + const KisPoint & pos2, + const double pressure2, + const double xtilt2, + const double ytilt2) +{ + m_dragDist = painter()->paintLine(pos1, pressure1, xtilt1, ytilt1, pos2, pressure2, xtilt2, ytilt2, m_dragDist); +} + + +KisImageSP KisToolFreehand::currentImage() +{ + return m_currentImage; +} + + +void KisToolFreehand::paintOutline(const KisPoint& point) { + if (!m_subject) { + return; + } + + KisCanvasController *controller = m_subject->canvasController(); + + if (currentImage() && !currentImage()->bounds().tqcontains(point.floorTQPoint())) { + if (m_paintedOutline) { + controller->kiscanvas()->update(); + m_paintedOutline = false; + } + return; + } + + KisCanvas *canvas = controller->kiscanvas(); + canvas->tqrepaint(); + + KisBrush *brush = m_subject->currentBrush(); + // There may not be a brush present, and we shouldn't crash in that case + if (brush) { + KisCanvasPainter gc(canvas); + TQPen pen(TQt::SolidLine); + + KisPoint hotSpot = brush->hotSpot(); + + gc.setRasterOp(TQt::NotROP); + gc.setPen(pen); + gc.setViewport(0, 0, static_cast(canvas->width() * m_subject->zoomFactor()), + static_cast(canvas->height() * m_subject->zoomFactor())); + gc.translate((- controller->horzValue()) / m_subject->zoomFactor(), + (- controller->vertValue()) / m_subject->zoomFactor()); + + KisPoint topLeft = point - hotSpot; + + if (m_subject->currentPaintop().id() == "pen") { + // Pen paints on whole pixels only. + topLeft = topLeft.roundTQPoint(); + } + + gc.translate(topLeft.x(), topLeft.y()); + + KisBoundaryPainter::paint(brush->boundary(), gc); + m_paintedOutline = true; + } +} + + +#include "kis_tool_freehand.moc" + diff --git a/chalk/ui/kis_tool_freehand.h b/chalk/ui/kis_tool_freehand.h new file mode 100644 index 00000000..91db5698 --- /dev/null +++ b/chalk/ui/kis_tool_freehand.h @@ -0,0 +1,103 @@ +/* + * kis_tool_brush.h - part of Chalk + * + * Copyright (c) 2003-2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_FREEHAND_H_ +#define KIS_TOOL_FREEHAND_H_ + +#include "kis_types.h" +#include "kis_tool_paint.h" +#include "kis_point.h" +#include "koffice_export.h" + +class KisPainter; +class KisBrush; +class KisEvent; +class KisPaintLayer; + + +class KRITACORE_EXPORT KisToolFreehand : public KisToolPaint { + Q_OBJECT + TQ_OBJECT + typedef KisToolPaint super; + +public: + KisToolFreehand(const TQString transactionText); + virtual ~KisToolFreehand(); + + virtual void update(KisCanvasSubject *subject); + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + + virtual enumToolType toolType() { return TOOL_FREEHAND; } + +protected: + virtual void paintAt(const KisPoint &pos, + const double pressure, + const double xTilt, + const double yTilt); + + virtual void paintLine(const KisPoint & pos1, + const double pressure1, + const double xtilt1, + const double ytilt1, + const KisPoint & pos2, + const double pressure2, + const double xtilt2, + const double ytilt2); + + // XXX: why not make this a protected member attribute for the + // use of subclasses? BSAR. + inline KisPainter * painter() { return m_painter; }; + virtual void initPaint(KisEvent *e); + virtual void endPaint(); + + KisImageSP currentImage(); + + void paintOutline(const KisPoint& point); + +protected: + KisPoint m_prevPos; + double m_prevPressure; + double m_prevXTilt; + double m_prevYTilt; + double m_dragDist; + + bool m_paintIncremental; + bool m_paintOnSelection; + + KisPaintDeviceSP m_target; + KisLayerSP m_tempLayer; + KisPaintDeviceSP m_source; + + TQString m_transactionText; + enumBrushMode m_mode; + KisPainter *m_painter; + + KisImageSP m_currentImage; +private: + bool m_paintedOutline; +}; + + + +#endif // KIS_TOOL_FREEHAND_H_ + diff --git a/chalk/ui/kis_tool_manager.cc b/chalk/ui/kis_tool_manager.cc new file mode 100644 index 00000000..456c60a7 --- /dev/null +++ b/chalk/ui/kis_tool_manager.cc @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "kopalettemanager.h" + +#include "kis_part_layer.h" +#include "kis_tool_manager.h" +#include "kis_tool_registry.h" +#include "kis_tool_dummy.h" +#include "kis_canvas_subject.h" +#include "kis_tool_controller.h" +#include "kis_view.h" +#include "kis_canvas.h" +#include "kis_cursor.h" +#include "KoToolBox.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_input_device.h" + + +KisToolManager::KisToolManager(KisCanvasSubject * tqparent, KisCanvasController * controller) + : m_subject(tqparent), + m_controller(controller) +{ + m_toolBox = 0; + m_oldTool = 0; + m_dummyTool = 0; + m_paletteManager = 0; + m_actionCollection = 0; + m_tools_disabled = false; + setup = false; +} + +KisToolManager::~KisToolManager() +{ + delete m_dummyTool; +} + +void KisToolManager::setUp(KoToolBox * toolbox, KoPaletteManager * paletteManager, KActionCollection * actionCollection) +{ + if (setup) { + resetToolBox( toolbox ); + return; + } + + m_toolBox = toolbox; + m_paletteManager = paletteManager; + m_actionCollection = actionCollection; + + // Dummy tool for when the layer is locked or invisible + if (!m_dummyTool) + m_dummyTool = KisToolDummyFactory().createTool(actionCollection); + + TQValueVector inputDevices = KisInputDevice::inputDevices(); + + for (TQ_UINT32 inputDevice = 0; inputDevice < inputDevices.count(); inputDevice++) { + m_inputDeviceToolSetMap[inputDevices[inputDevice]] = KisToolRegistry::instance()->createTools(actionCollection, m_subject); + } + + m_tools = m_inputDeviceToolSetMap[KisInputDevice::mouse()]; + for (vKisTool_it it = m_tools.begin(); it != m_tools.end(); ++it) { + KisTool * t = *it; + if (!t) continue; + toolbox->registerTool( t->action(), t->toolType(), t->priority() ); + } + + toolbox->setupTools(); + + KisTool * t = findTool("tool_brush"); + if (t) { + t->activate(); + setCurrentTool(t); + } + setup = true; + +} + + + +void KisToolManager::youAintGotNoToolBox() +{ + m_toolBox = 0; + m_oldTool = currentTool(); +} + +void KisToolManager::resetToolBox(KoToolBox * toolbox) +{ + m_toolBox = toolbox; + + m_tools = m_inputDeviceToolSetMap[KisInputDevice::mouse()]; + for (vKisTool_it it = m_tools.begin(); it != m_tools.end(); ++it) { + KisTool * t = *it; + if (!t) continue; + m_toolBox->registerTool( t->action(), t->toolType(), t->priority() ); + } + + toolbox->setupTools(); + +#if 0 // Because I cannot find out how to reset the toolbox so the button is depressed, we reset the tool to brush + setCurrentTool(findTool("tool_brush")); +#else + if (m_oldTool) { + // restore the old current tool + setCurrentTool(m_oldTool); + m_oldTool = 0; + } +#endif + +} + +void KisToolManager::updateGUI() +{ + Q_ASSERT(m_subject); + if (m_subject == 0) { + // "Eek, no tqparent! + return; + } + + if (!m_toolBox) return; + + KisImageSP img = m_subject->currentImg(); + KisLayerSP l = 0; + + bool enable = false; + + + KisPartLayer * partLayer = dynamic_cast(l.data()); + + if (img) { + l = img->activeLayer(); + enable = l && !l->locked() && l->visible() && (partLayer == 0); + } + + m_toolBox->enableTools( enable ); + + KisTool * current = currentTool(); + + // XXX: Fix this properly: changing the visibility of a layer causes this cause to be executed twice! + if (!enable && current != m_dummyTool) { + // Store the current tool + m_oldTool = currentTool(); + // Set the dummy tool + if (!m_dummyTool) { + m_dummyTool = KisToolDummyFactory().createTool(m_actionCollection); + } + setCurrentTool(m_dummyTool); + m_tools_disabled = true; + } + else if (enable && m_tools_disabled) { + m_tools_disabled = false; + if (m_oldTool) { + // restore the old current tool + setCurrentTool(m_oldTool); + m_oldTool = 0; + } + else { + m_oldTool = 0; + KisTool * t = findTool("tool_brush"); + setCurrentTool(t); + } + } +} + +void KisToolManager::setCurrentTool(KisTool *tool) +{ + KisTool *oldTool = currentTool(); + KisCanvas * canvas = (KisCanvas*)m_controller->kiscanvas(); + + + if (oldTool) + { + oldTool->deactivate(); + oldTool->action()->setChecked( false ); + + m_paletteManager->removeWidget(chalk::TOOL_OPTION_WIDGET); + } + + if (tool) { + + if (!tool->optionWidget()) { + tool->createOptionWidget(0); + } + TQWidget * w = tool->optionWidget(); + + if (w) + m_paletteManager->addWidget(w, chalk::TOOL_OPTION_WIDGET, chalk::CONTROL_PALETTE ); + + m_inputDeviceToolMap[m_controller->currentInputDevice()] = tool; + m_controller->setCanvasCursor(tool->cursor()); + + canvas->enableMoveEventCompressionHint(dynamic_cast(tool) != NULL); + + m_subject->notifyObservers(); + + tool->action()->setChecked( true ); + tool->action()->activate(); + m_toolBox->slotSetTool(tool->name()); + } else { + m_inputDeviceToolMap[m_controller->currentInputDevice()] = 0; + m_controller->setCanvasCursor(KisCursor::arrowCursor()); + } + +} + +void KisToolManager::setCurrentTool( const TQString & toolName ) +{ + setCurrentTool(findTool(toolName)); +} + +KisTool * KisToolManager::currentTool() const +{ + InputDeviceToolMap::const_iterator it = m_inputDeviceToolMap.find(m_controller->currentInputDevice()); + + if (it != m_inputDeviceToolMap.end()) { + return (*it).second; + } else { + return 0; + } +} + + +void KisToolManager::setToolForInputDevice(KisInputDevice oldDevice, KisInputDevice newDevice) +{ + InputDeviceToolSetMap::iterator vit = m_inputDeviceToolSetMap.find(oldDevice); + + if (vit != m_inputDeviceToolSetMap.end()) { + vKisTool& oldTools = (*vit).second; + for (vKisTool::iterator it = oldTools.begin(); it != oldTools.end(); ++it) { + KisTool *tool = *it; + KAction *toolAction = tool->action(); + toolAction->disconnect(TQT_SIGNAL(activated()), tool, TQT_SLOT(activate())); + } + } + KisTool *oldTool = currentTool(); + if (oldTool) + { + m_paletteManager->removeWidget(chalk::TOOL_OPTION_WIDGET); + oldTool->deactivate(); + } + + + vit = m_inputDeviceToolSetMap.find(newDevice); + + Q_ASSERT(vit != m_inputDeviceToolSetMap.end()); + + vKisTool& tools = (*vit).second; + + for (vKisTool::iterator it = tools.begin(); it != tools.end(); ++it) { + KisTool *tool = *it; + KAction *toolAction = tool->action(); + connect(toolAction, TQT_SIGNAL(activated()), tool, TQT_SLOT(activate())); + } +} + +void KisToolManager::activateCurrentTool() +{ + KisTool * t = currentTool(); + if (t && t->action()) { + t->action()->activate(); + } +} + +KisTool * KisToolManager::findTool(const TQString &toolName, KisInputDevice inputDevice) const +{ + if (inputDevice == KisInputDevice::unknown()) { + inputDevice = m_controller->currentInputDevice(); + } + + KisTool *tool = 0; + + InputDeviceToolSetMap::const_iterator vit = m_inputDeviceToolSetMap.find(inputDevice); + + Q_ASSERT(vit != m_inputDeviceToolSetMap.end()); + + const vKisTool& tools = (*vit).second; + + for (vKisTool::const_iterator it = tools.begin(); it != tools.end(); ++it) { + KisTool *t = *it; + if (t->name() == toolName) { + tool = t; + break; + } + } + + return tool; +} + + +#include "kis_tool_manager.moc" diff --git a/chalk/ui/kis_tool_manager.h b/chalk/ui/kis_tool_manager.h new file mode 100644 index 00000000..8f04f680 --- /dev/null +++ b/chalk/ui/kis_tool_manager.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TOOL_MANAGER +#define KIS_TOOL_MANAGER + +#include + +#include + +#include "kis_tool_controller.h" +#include "kis_global.h" +#include "kis_tool_types.h" +#include "kis_input_device.h" + +class KoView; +class KisCanvasSubject; +class KisView; +class KisTool; +class KisToolRegistry; +class KisCanvasController; +class KoPaletteManager; +class KoToolBox; + +/** + * This class manages the activation and deactivation of tools for + * each input device. + */ +class KisToolManager : public TQObject, public KisToolControllerInterface { + + Q_OBJECT + TQ_OBJECT + +public: + + KisToolManager(KisCanvasSubject * tqparent, KisCanvasController * controller); + ~KisToolManager(); + +public: + + void setUp(KoToolBox * toolbox, KoPaletteManager * paletteManager, KActionCollection * collection); + + // Called when the toolbox is deleted because the view was made inactive in favour of another view + void youAintGotNoToolBox(); + + void updateGUI(); + + virtual void setCurrentTool(KisTool *tool); + virtual void setCurrentTool(const TQString & toolName); + + virtual KisTool *currentTool() const; + + void setToolForInputDevice(KisInputDevice oldDevice, KisInputDevice newDevice); + + KisTool *findTool(const TQString &toolName, KisInputDevice inputDevice = KisInputDevice::unknown()) const; + + void activateCurrentTool(); + +private: + + void resetToolBox(KoToolBox * toolbox); + +private: + + typedef std::map InputDeviceToolMap; + typedef std::map InputDeviceToolSetMap; + + InputDeviceToolMap m_inputDeviceToolMap; + InputDeviceToolSetMap m_inputDeviceToolSetMap; + + KisCanvasSubject * m_subject; + KisCanvasController * m_controller; + + KoPaletteManager * m_paletteManager; + KActionCollection * m_actionCollection; + + KoToolBox * m_toolBox; + + KisTool * m_oldTool; + KisTool * m_dummyTool; + + vKisTool m_tools; + + bool m_tools_disabled; + bool setup; +}; + + +#endif diff --git a/chalk/ui/kis_tool_non_paint.cc b/chalk/ui/kis_tool_non_paint.cc new file mode 100644 index 00000000..4adccc60 --- /dev/null +++ b/chalk/ui/kis_tool_non_paint.cc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include "kis_image.h" +#include "kis_canvas_subject.h" +#include "kis_canvas_controller.h" +#include "kis_tool_controller.h" +#include "kis_tool_non_paint.h" + +KisToolNonPaint::KisToolNonPaint(const TQString & UIName) + : super(UIName) +{ + m_subject = 0; +} + +KisToolNonPaint::~KisToolNonPaint() +{ +} + +void KisToolNonPaint::update(KisCanvasSubject *subject) +{ + m_subject = subject; +} + +void KisToolNonPaint::paint(KisCanvasPainter&) +{ +} + +void KisToolNonPaint::paint(KisCanvasPainter&, const TQRect&) +{ +} + +void KisToolNonPaint::deactivate() +{ +} + +void KisToolNonPaint::buttonPress(KisButtonPressEvent *) +{ +} + +void KisToolNonPaint::move(KisMoveEvent *) +{ +} + +void KisToolNonPaint::buttonRelease(KisButtonReleaseEvent *) +{ +} + +void KisToolNonPaint::doubleClick(KisDoubleClickEvent *) +{ +} + +void KisToolNonPaint::keyPress(TQKeyEvent *) +{ +} + +void KisToolNonPaint::keyRelease(TQKeyEvent *) +{ +} + +TQCursor KisToolNonPaint::cursor() +{ + return m_cursor; +} + +void KisToolNonPaint::setCursor(const TQCursor& cursor) +{ + m_cursor = cursor; + + if (m_subject) { + KisToolControllerInterface *controller = m_subject->toolController(); + + if (controller && controller->currentTool() == this) { + m_subject->canvasController()->setCanvasCursor(m_cursor); + } + } +} + +void KisToolNonPaint::activate() +{ + if (m_subject) { + KisToolControllerInterface *controller = m_subject->toolController(); + + if (controller) + controller->setCurrentTool(this); + } +} + +void KisToolNonPaint::notifyModified() const +{ + if (m_subject && m_subject->currentImg()) { + + m_subject->currentImg()->setModified(); + } +} + +#include "kis_tool_non_paint.moc" diff --git a/chalk/ui/kis_tool_non_paint.h b/chalk/ui/kis_tool_non_paint.h new file mode 100644 index 00000000..0b618109 --- /dev/null +++ b/chalk/ui/kis_tool_non_paint.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_NON_PAINT_H_ +#define KIS_TOOL_NON_PAINT_H_ + +#include +#include +#include + +#include "kis_global.h" +#include "kis_types.h" +#include "kis_tool.h" +#include + +class TQEvent; +class TQKeyEvent; +class TQPaintEvent; +class TQRect; +class KDialog; +class KisCanvasSubject; + + +class KRITACORE_EXPORT KisToolNonPaint : public KisTool { + + Q_OBJECT + TQ_OBJECT + typedef KisTool super; + +public: + KisToolNonPaint(const TQString & UIName); + virtual ~KisToolNonPaint(); + +// CanvasObserver +public: + virtual void update(KisCanvasSubject *subject); + +// KisTool +public: + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void doubleClick(KisDoubleClickEvent *e); + virtual void keyPress(TQKeyEvent *e); + virtual void keyRelease(TQKeyEvent *e); + + virtual TQCursor cursor(); + virtual void setCursor(const TQCursor& cursor); + + virtual enumToolType toolType() { return TOOL_VIEW; } + +public slots: + virtual void activate(); + virtual void deactivate(); + +protected: + void notifyModified() const; + +protected: + KisCanvasSubject *m_subject; + +private: + TQCursor m_cursor; +}; + +#endif // KIS_TOOL_NON_PAINT_H_ + diff --git a/chalk/ui/kis_tool_paint.cc b/chalk/ui/kis_tool_paint.cc new file mode 100644 index 00000000..d8d19f36 --- /dev/null +++ b/chalk/ui/kis_tool_paint.cc @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kis_button_release_event.h" +#include "kis_canvas_subject.h" +#include "kis_cmb_composite.h" +#include "kis_colorspace.h" +#include "kis_config.h" +#include "kis_cursor.h" +#include "kis_global.h" +#include "kis_image.h" +#include "kis_int_spinbox.h" +#include "kis_paint_device.h" +#include "kis_tool_controller.h" +#include "kis_tool_paint.h" + +KisToolPaint::KisToolPaint(const TQString& UIName) + : super(UIName) +{ + m_subject = 0; + + m_UIName = UIName; + + m_optionWidget = 0; + m_optionWidgetLayout = 0; + + m_lbOpacity = 0; + m_slOpacity = 0; + m_lbComposite= 0; + m_cmbComposite = 0; + + m_opacity = OPACITY_OPAQUE; + m_compositeOp = COMPOSITE_OVER; +} + +KisToolPaint::~KisToolPaint() +{ +} + +void KisToolPaint::update(KisCanvasSubject *subject) +{ + m_subject = subject; + updateCompositeOpComboBox(); +} + +void KisToolPaint::paint(KisCanvasPainter&) +{ +} + +void KisToolPaint::paint(KisCanvasPainter&, const TQRect&) +{ +} + +void KisToolPaint::deactivate() +{ +} + +void KisToolPaint::buttonPress(KisButtonPressEvent *) +{ +} + +void KisToolPaint::move(KisMoveEvent *) +{ +} + +void KisToolPaint::buttonRelease(KisButtonReleaseEvent * e) +{ + kdDebug() << "buttonRelease" << endl; + if(e->button() == Qt::MidButton) + { + kdDebug() << "switch" << endl; + KisColor bg = m_subject->bgColor(); + m_subject->setBGColor(m_subject->fgColor()); + m_subject->setFGColor(bg); + } +} + +void KisToolPaint::doubleClick(KisDoubleClickEvent *) +{ +} + +void KisToolPaint::keyPress(TQKeyEvent *) +{ +} + +void KisToolPaint::keyRelease(TQKeyEvent *) +{ +} + +TQWidget* KisToolPaint::createOptionWidget(TQWidget* tqparent) +{ + m_optionWidget = new TQWidget(tqparent); + m_optionWidget->setCaption(m_UIName); + + m_lbOpacity = new TQLabel(i18n("Opacity:"), m_optionWidget); + m_slOpacity = new KisIntSpinbox( m_optionWidget, "int_m_optionwidget"); + m_slOpacity->setRange( 0, 100); + m_slOpacity->setValue(m_opacity / OPACITY_OPAQUE * 100); + connect(m_slOpacity, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetOpacity(int))); + + m_lbComposite = new TQLabel(i18n("Mode:"), m_optionWidget); + m_cmbComposite = new KisCmbComposite(m_optionWidget); + connect(m_cmbComposite, TQT_SIGNAL(activated(const KisCompositeOp&)), this, TQT_SLOT(slotSetCompositeMode(const KisCompositeOp&))); + + TQVBoxLayout* verticalLayout = new TQVBoxLayout(m_optionWidget); + verticalLayout->setMargin(0); + verticalLayout->setSpacing(3); + + m_optionWidgetLayout = new TQGridLayout(verticalLayout, 2, 3, 6); + + m_optionWidgetLayout->addWidget(m_lbOpacity, 0, 0); + m_optionWidgetLayout->addWidget(m_slOpacity, 0, 1); + + m_optionWidgetLayout->addWidget(m_lbComposite, 1, 0); + m_optionWidgetLayout->addWidget(m_cmbComposite, 1, 1); + + verticalLayout->addItem(new TQSpacerItem(0,0,TQSizePolicy::Fixed,TQSizePolicy::Expanding)); + + if (!quickHelp().isEmpty()) { + TQPushButton* push = new TQPushButton(SmallIconSet( "help" ), "", m_optionWidget); + connect(push, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotPopupQuickHelp())); + + TQHBoxLayout* hLayout = new TQHBoxLayout(m_optionWidget); + hLayout->addWidget(push); + hLayout->addItem(new TQSpacerItem(0,0,TQSizePolicy::Expanding,TQSizePolicy::Fixed)); + verticalLayout->addLayout(hLayout); + } + return m_optionWidget; +} + +TQWidget* KisToolPaint::optionWidget() +{ + return m_optionWidget; +} + +void KisToolPaint::addOptionWidgetLayout(TQLayout *tqlayout) +{ + Q_ASSERT(m_optionWidget != 0); + Q_ASSERT(m_optionWidgetLayout != 0); + int rowCount = m_optionWidgetLayout->numRows(); + m_optionWidgetLayout->addMultiCellLayout(tqlayout, rowCount, rowCount, 0, 1); +} + +void KisToolPaint::addOptionWidgetOption(TQWidget *control, TQWidget *label) +{ + Q_ASSERT(m_optionWidget != 0); + Q_ASSERT(m_optionWidgetLayout != 0); + if(label) + { + m_optionWidgetLayout->addWidget(label, m_optionWidgetLayout->numRows(), 0); + m_optionWidgetLayout->addWidget(control, m_optionWidgetLayout->numRows()-1, 1); + } + else + m_optionWidgetLayout->addMultiCellWidget(control, m_optionWidgetLayout->numRows(), m_optionWidgetLayout->numRows(), 0, 1); +} + +void KisToolPaint::slotSetOpacity(int opacityPerCent) +{ + m_opacity = opacityPerCent * OPACITY_OPAQUE / 100; +} + +void KisToolPaint::slotSetCompositeMode(const KisCompositeOp& compositeOp) +{ + m_compositeOp = compositeOp; +} + +TQCursor KisToolPaint::cursor() +{ + return m_cursor; +} + +void KisToolPaint::setCursor(const TQCursor& cursor) +{ + m_cursor = cursor; + + if (m_subject) { + KisToolControllerInterface *controller = m_subject->toolController(); + + if (controller && controller->currentTool() == this) { + m_subject->canvasController()->setCanvasCursor(m_cursor); + } + } +} + +void KisToolPaint::activate() +{ + if (m_subject) { + KisToolControllerInterface *controller = m_subject->toolController(); + + if (controller) + controller->setCurrentTool(this); + + updateCompositeOpComboBox(); + + KisConfig cfg; + m_paintOutline = (cfg.cursorStyle() == CURSOR_STYLE_OUTLINE); + } +} + +void KisToolPaint::notifyModified() const +{ + if (m_subject && m_subject->currentImg()) { + m_subject->currentImg()->setModified(); + } +} + +void KisToolPaint::updateCompositeOpComboBox() +{ + if (m_optionWidget && m_subject) { + KisImageSP img = m_subject->currentImg(); + + if (img) { + KisPaintDeviceSP device = img->activeDevice(); + + if (device) { + KisCompositeOpList compositeOps = device->colorSpace()->userVisiblecompositeOps(); + m_cmbComposite->setCompositeOpList(compositeOps); + + if (compositeOps.tqfind(m_compositeOp) == compositeOps.end()) { + m_compositeOp = COMPOSITE_OVER; + } + m_cmbComposite->setCurrentItem(m_compositeOp); + } + } + } +} + +void KisToolPaint::slotPopupQuickHelp() { + TQWhatsThis::display(quickHelp()); +} + +#include "kis_tool_paint.moc" diff --git a/chalk/ui/kis_tool_paint.h b/chalk/ui/kis_tool_paint.h new file mode 100644 index 00000000..6e1406b5 --- /dev/null +++ b/chalk/ui/kis_tool_paint.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2003 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_PAINT_H_ +#define KIS_TOOL_PAINT_H_ + +#include +#include + +#include + +#include "kis_tool.h" +#include "kis_composite_op.h" + +class TQCheckBox; +class TQEvent; +class TQKeyEvent; +class TQComboBox; +class TQPaintEvent; +class TQRect; +class TQGridLayout; +class KDialog; +class KisCanvasSubject; +class TQLabel; +class KisCmbComposite; +class KisIntSpinbox; + +enum enumBrushMode { + PAINT, + PAINT_STYLUS, + ERASE, + ERASE_STYLUS, + HOVER +}; + +class KRITACORE_EXPORT KisToolPaint : public KisTool { + + Q_OBJECT + TQ_OBJECT + typedef KisTool super; + +public: + KisToolPaint(const TQString& UIName); + virtual ~KisToolPaint(); + +public: + virtual void update(KisCanvasSubject *subject); + + virtual void paint(KisCanvasPainter& gc); + virtual void paint(KisCanvasPainter& gc, const TQRect& rc); + + virtual void buttonPress(KisButtonPressEvent *e); + virtual void move(KisMoveEvent *e); + virtual void buttonRelease(KisButtonReleaseEvent *e); + virtual void doubleClick(KisDoubleClickEvent *e); + virtual void keyPress(TQKeyEvent *e); + virtual void keyRelease(TQKeyEvent *e); + + virtual TQCursor cursor(); + virtual void setCursor(const TQCursor& cursor); + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + virtual TQWidget* optionWidget(); + virtual void addOptionWidgetOption(TQWidget *control, TQWidget *label = 0); + +public slots: + virtual void activate(); + virtual void deactivate(); + + void slotSetOpacity(int opacityPerCent); + void slotSetCompositeMode(const KisCompositeOp& compositeOp); + void slotPopupQuickHelp(); + +protected: + void notifyModified() const; + + // Add the tool-specific tqlayout to the default option widget's tqlayout. + void addOptionWidgetLayout(TQLayout *tqlayout); + +private: + void updateCompositeOpComboBox(); + +protected: + KisCanvasSubject *m_subject; + TQRect m_dirtyRect; + TQ_UINT8 m_opacity; + KisCompositeOp m_compositeOp; + bool m_paintOutline; + +private: + TQString m_UIName; + + TQCursor m_cursor; + + TQWidget *m_optionWidget; + TQGridLayout *m_optionWidgetLayout; + + TQLabel *m_lbOpacity; + KisIntSpinbox *m_slOpacity; + TQLabel *m_lbComposite; + KisCmbComposite *m_cmbComposite; +}; + +#endif // KIS_TOOL_PAINT_H_ + diff --git a/chalk/ui/kis_tool_registry.cc b/chalk/ui/kis_tool_registry.cc new file mode 100644 index 00000000..e7696f0b --- /dev/null +++ b/chalk/ui/kis_tool_registry.cc @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kdebug.h" +#include +#include +#include +#include +#include + +#include "kis_generic_registry.h" +#include "kis_types.h" +#include "kis_tool_registry.h" +#include "kis_tool.h" +#include "kis_tool_factory.h" +#include "kis_canvas_subject.h" +#include "kis_id.h" +#include "kis_debug_areas.h" + +KisToolRegistry *KisToolRegistry::m_singleton = 0; + +KisToolRegistry::KisToolRegistry() +{ + // Load all modules: color models, paintops, filters + KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/Tool"), + TQString::tqfromLatin1("(Type == 'Service') and " + "([X-Chalk-Version] == 2)")); + + KTrader::OfferList::ConstIterator iter; + + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService ( service, this, 0, TQStringList(), &errCode); + if ( plugin ) + kdDebug(DBG_AREA_PLUGINS) << "found plugin " << service->property("Name").toString() << "\n"; + else { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n"; + if( errCode == KParts::ComponentFactory::ErrNoLibrary) + { + kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl; + } + } + + } + +} + +KisToolRegistry::~KisToolRegistry() +{ +} + +KisToolRegistry* KisToolRegistry::instance() +{ + if(KisToolRegistry::m_singleton == 0) + { + KisToolRegistry::m_singleton = new KisToolRegistry(); + } + return KisToolRegistry::m_singleton; +} + + + +vKisTool KisToolRegistry::createTools(KActionCollection * ac, KisCanvasSubject *subject) const +{ + Q_ASSERT(subject); + + vKisTool tools; + + KisIDList factories = listKeys(); + + for (KisIDList::Iterator it = factories.begin(); it != factories.end(); ++it ) + { + KisToolFactorySP f = get(*it); + + KisTool * tool = f->createTool(ac); + subject->attach(tool); + tools.push_back(tool); + } + + subject->notifyObservers(); + + return tools; +} + +KisTool * KisToolRegistry::createTool(KActionCollection * ac, KisCanvasSubject * subject, KisID & id) const +{ + KisToolFactorySP f = get(id); + KisTool * t = f->createTool(ac); + subject->attach(t); + return t; +} + +#include "kis_tool_registry.moc" diff --git a/chalk/ui/kis_tool_registry.h b/chalk/ui/kis_tool_registry.h new file mode 100644 index 00000000..5fd32b93 --- /dev/null +++ b/chalk/ui/kis_tool_registry.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_REGISTRY_H_ +#define KIS_TOOL_REGISTRY_H_ + +#include + +#include "kis_tool_types.h" +#include "kis_generic_registry.h" +#include + +class KActionCollection; +class KisCanvasSubject; +class TQStringList; + +/** + * A registry, similar to the tool and colormodel registry + * where new tool plugins can register themselves. KisToolRegistry + * in contrast to the paintop and colormodel registries, creates + * a vector containing instances of all registered tools. + */ +class KRITACORE_EXPORT KisToolRegistry : public TQObject, public KisGenericRegistry{ + + Q_OBJECT + TQ_OBJECT + +public: + virtual ~KisToolRegistry(); + + static KisToolRegistry* instance(); + + vKisTool createTools(KActionCollection * ac, KisCanvasSubject *subject) const; + KisTool * createTool(KActionCollection * ac, KisCanvasSubject * subject, KisID & id) const; + +private: + KisToolRegistry(); + KisToolRegistry(const KisToolRegistry&); + KisToolRegistry operator=(const KisToolRegistry&); + + static KisToolRegistry *m_singleton; +}; + +#endif // KIS_TOOL_REGISTRY_H_ + diff --git a/chalk/ui/kis_tool_shape.cc b/chalk/ui/kis_tool_shape.cc new file mode 100644 index 00000000..b919a578 --- /dev/null +++ b/chalk/ui/kis_tool_shape.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#include "kis_tool_shape.h" +#include "wdgshapeoptions.h" + +KisToolShape::KisToolShape(const TQString& UIName) : super(UIName) +{ + m_tqshapeOptionsWidget = 0; + m_optionLayout = 0; +} + +KisToolShape::~KisToolShape() +{ +} + +TQWidget* KisToolShape::createOptionWidget(TQWidget* tqparent) +{ + TQWidget *widget = super::createOptionWidget(tqparent); + + m_tqshapeOptionsWidget = new WdgGeometryOptions(0); + Q_CHECK_PTR(m_tqshapeOptionsWidget); + + m_optionLayout = new TQGridLayout(widget, 2, 1); + // super::addOptionWidgetLayout(m_optionLayout); + + m_tqshapeOptionsWidget->cmbFill->reparent(widget, TQPoint(0,0), true); + m_tqshapeOptionsWidget->textLabel3->reparent(widget, TQPoint(0,0), true); + addOptionWidgetOption(m_tqshapeOptionsWidget->cmbFill, m_tqshapeOptionsWidget->textLabel3); + + return widget; +} + +KisPainter::FillStyle KisToolShape::fillStyle(void) +{ + if (m_tqshapeOptionsWidget) { + return static_cast(m_tqshapeOptionsWidget->cmbFill->currentItem()); + } else { + return KisPainter::FillStyleNone; + } +} + +#include "kis_tool_shape.moc" + diff --git a/chalk/ui/kis_tool_shape.h b/chalk/ui/kis_tool_shape.h new file mode 100644 index 00000000..2c0a9500 --- /dev/null +++ b/chalk/ui/kis_tool_shape.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TOOL_SHAPE_H_ +#define KIS_TOOL_SHAPE_H_ + +#include + +#include "kis_tool_paint.h" +#include "kis_painter.h" + +class TQGridLayout; +class WdgGeometryOptions; + +class KRITACORE_EXPORT KisToolShape : public KisToolPaint { + + Q_OBJECT + TQ_OBJECT + typedef KisToolPaint super; + +public: + KisToolShape(const TQString& UIName); + virtual ~KisToolShape(); + + virtual enumToolType toolType() { return TOOL_SHAPE; } + +protected: + virtual TQWidget* createOptionWidget(TQWidget* tqparent); + + KisPainter::FillStyle fillStyle(); + +private: + TQGridLayout *m_optionLayout; + WdgGeometryOptions *m_tqshapeOptionsWidget; +}; + +#endif // KIS_TOOL_SHAPE_H_ + diff --git a/chalk/ui/kis_tool_types.h b/chalk/ui/kis_tool_types.h new file mode 100644 index 00000000..4811f75e --- /dev/null +++ b/chalk/ui/kis_tool_types.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_TOOL_TYPES_H_ +#define KIS_TOOL_TYPES_H_ + +#include +#include "kis_shared_ptr_vector.h" + + +class KisTool; +typedef KSharedPtr KisToolSP; +typedef KisSharedPtrVector vKisTool; +typedef vKisTool::iterator vKisTool_it; +typedef vKisTool::const_iterator vKisTool_cit; + +class KisToolFactory; +typedef KSharedPtr KisToolFactorySP; + +#endif // KIS_TOOL_TYPES_H_ diff --git a/chalk/ui/kis_view.cc b/chalk/ui/kis_view.cc new file mode 100644 index 00000000..a146ddcb --- /dev/null +++ b/chalk/ui/kis_view.cc @@ -0,0 +1,4018 @@ +/* This file is part of KimageShop^WKrayon^WChalk + * + * Copyright (c) 1999 Matthias Elter + * 1999 Michael Koch + * 1999 Carsten Pfeiffer + * 2002 Patrick Julien + * 2003-2005 Boudewijn Rempt + * 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +// TQt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// KOffice +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Local +#include "kis_brush.h" +#include "kis_button_press_event.h" +#include "kis_button_release_event.h" +#include "kis_canvas.h" +#include "kis_canvas_painter.h" +#include "kis_color.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_config.h" +#include "kis_controlframe.h" +#include "kis_cursor.h" +#include "kis_doc.h" +#include "kis_double_click_event.h" +#include "kis_factory.h" +#include "kis_filter_strategy.h" +#include "kis_gradient.h" +#include "kis_group_layer.h" +#include "kis_adjustment_layer.h" +#include "kis_paint_device.h" +#include "kis_tool_freehand.h" +//#include "kis_guide.h" +#include "kis_layerbox.h" +#include "kis_import_catcher.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_move_event.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_paintop_registry.h" +#include "kis_part_layer.h" +#include "kis_part_layer_handler.h" +#include "kis_pattern.h" +#include "kis_profile.h" +#include "kis_rect.h" +#include "kis_resource.h" +#include "kis_palette.h" +#include "kis_ruler.h" +#include "kis_selection.h" +#include "KoToolBox.h" +#include "kis_tool.h" +#include "kis_tool_manager.h" +#include "kis_transaction.h" +#include "kis_selected_transaction.h" +#include "kis_types.h" +#include "kis_undo_adapter.h" +#include "kis_view.h" +#include "kis_view_iface.h" +#include "kis_label_progress.h" +#include "kis_opengl_image_context.h" +#include "kis_background.h" +#include "kis_paint_device_action.h" +#include "kis_filter_configuration.h" +#include "kis_transform_worker.h" +#include "kis_shear_visitor.h" + +#include +#include + +#include "kis_icon_item.h" +#include "kis_palette_widget.h" +#include "kis_birdeye_box.h" +#include "kis_color.h" +#include "kis_factory.h" + +// Dialog boxes +#include "kis_dlg_new_layer.h" +#include "kis_dlg_layer_properties.h" +#include "kis_dlg_preferences.h" +#include "kis_dlg_image_properties.h" +#include "kis_dlg_adjustment_layer.h" +#include "kis_dlg_adj_layer_props.h" + +// Action managers +#include "kis_selection_manager.h" +#include "kis_filter_manager.h" +#include "kis_grid_manager.h" +#include "kis_perspective_grid_manager.h" + +#include "kis_custom_palette.h" +#include "wdgpalettechooser.h" + +#include + +// Time in ms that must pass after a tablet event before a mouse event is allowed to +// change the input device to the mouse. This is needed because mouse events are always +// sent to a receiver if it does not accept the tablet event. +#define MOUSE_CHANGE_EVENT_DELAY 100 + +KisView::KisView(KisDoc *doc, KisUndoAdapter *adapter, TQWidget *tqparent, const char *name) + : super(doc, tqparent, name) + , KXMLGUIBuilder( shell() ) + , m_panning( false ) + , m_oldTool( 0 ) + , m_doc( doc ) + , m_canvas( 0 ) + , m_partHandler( 0 ) + , m_gridManager( 0 ) + , m_perspectiveGridManager( 0 ) + , m_selectionManager( 0 ) + , m_filterManager( 0 ) + , m_paletteManager( 0 ) + , m_toolManager( 0 ) + , m_actLayerVis( false ) + , m_hRuler( 0 ) + , m_vRuler( 0 ) + , m_imgFlatten( 0 ) + , m_imgMergeLayer( 0 ) + , m_imgRename( 0 ) + , m_imgResizeToLayer( 0 ) + , m_imgScan( 0 ) + , m_actionPartLayer( 0 ) + , m_layerAdd( 0 ) + , m_layerBottom( 0 ) + , m_layerDup( 0 ) + , m_layerHide( 0 ) + , m_layerLower( 0 ) + , m_layerProperties( 0 ) + , m_layerRaise( 0 ) + , m_layerRm( 0 ) + , m_layerSaveAs( 0 ) + , m_layerTop( 0 ) + , m_zoomIn( 0 ) + , m_zoomOut( 0 ) + , m_actualPixels( 0 ) + , m_actualSize( 0 ) + , m_fitToCanvas( 0 ) + , m_fullScreen( 0 ) + , m_imgProperties( 0 ) + , m_RulerAction( 0 ) + , m_guideAction( 0 ) + , m_dcop( 0 ) + , m_hScroll( 0 ) + , m_vScroll( 0 ) + , m_scrollX( 0 ) + , m_scrollY( 0 ) + , m_canvasXOffset( 0) + , m_canvasYOffset( 0) + , m_paintViewEnabled( false ) + , m_guiActivateEventReceived( false ) + , m_showEventReceived( false ) + , m_imageLoaded( false ) +// , m_currentGuide( 0 ) + , m_adapter( adapter ) + , m_statusBarZoomLabel( 0 ) + , m_statusBarSelectionLabel( 0 ) + , m_statusBarProfileLabel( 0 ) + , m_progress( 0 ) + , m_layerBox( 0 ) + , m_toolBox( 0 ) + , m_brush( 0 ) + , m_pattern( 0 ) + , m_gradient( 0 ) + , m_toolIsPainting( false ) + , m_monitorProfile( 0 ) + , m_HDRExposure( 0 ) +{ + + Q_ASSERT(doc); + Q_ASSERT(adapter); + Q_ASSERT(tqparent); + + KisConfig cfg; + + m_currentColorChooserDisplay = KisID("BLA"); + setFocusPolicy( TQ_StrongFocus ); + + // Must come before input devices are referenced as this detects them. +#ifdef Q_WS_X11 + KisCanvasWidget::initX11Support(); +#endif + // Install event filter before we create any child widgets so they can see + // the tablet events. + tqApp->installEventFilter(this); + + m_tabletEventTimer.start(); + m_inputDevice = KisInputDevice::mouse(); + + connect(&m_initialZoomTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotInitialZoomTimeout())); + + m_paletteManager = new KoPaletteManager(this, actionCollection(), "Chalk palette manager"); + if (cfg.fixDockerWidth()) m_paletteManager->setFixedWidth( 360 ); + + m_paletteManager->createPalette( chalk::CONTROL_PALETTE, i18n("Control box")); + m_paletteManager->createPalette( chalk::COLORBOX, i18n("Colors")); + m_paletteManager->createPalette( chalk::LAYERBOX, i18n("Layers")); + + m_selectionManager = new KisSelectionManager(this, doc); + m_filterManager = new KisFilterManager(this, doc); + m_toolManager = new KisToolManager(canvasSubject(), getCanvasController()); + m_gridManager = new KisGridManager(this); + m_perspectiveGridManager = new KisPerspectiveGridManager(this); + + // This needs to be set before the dockers are created. + m_image = m_doc->currentImage(); + KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry()->getRGB8(); + m_fg = KisColor(TQt::black, cs); + m_bg = KisColor(TQt::white, cs); + + createDockers(); + + setInstance(KisFactory::instance(), false); + setClientBuilder( this ); + + if (!doc->isReadWrite()) + setXMLFile("chalk_readonly.rc"); + else + setXMLFile("chalk.rc"); + + KStdAction::keyBindings( mainWindow()->guiFactory(), TQT_SLOT( configureShortcuts() ), actionCollection() ); + + createLayerBox(); + + setupCanvas(); + m_canvas->hide(); + setupRulers(); + setupScrollBars(); + setupStatusBar(); + + setupActions(); + dcopObject(); + + + connect(TQT_TQOBJECT(this), TQT_SIGNAL(autoScroll(const TQPoint &)), TQT_SLOT(slotAutoScroll(const TQPoint &))); + + setMouseTracking(true); + + resetMonitorProfile(); + + layersUpdated(); + + m_brushesAndStuffToolBar = new KisControlFrame(mainWindow(), this); + + // Load all plugins + KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/ViewPlugin"), + TQString::tqfromLatin1("(Type == 'Service') and " + "([X-Chalk-Version] == 2)")); + KTrader::OfferList::ConstIterator iter; + for(iter = offers.begin(); iter != offers.end(); ++iter) + { + KService::Ptr service = *iter; + int errCode = 0; + KParts::Plugin* plugin = + KParts::ComponentFactory::createInstanceFromService ( service, TQT_TQOBJECT(this), 0, TQStringList(), &errCode); + if ( plugin ) { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << "\n"; + insertChildClient(plugin); + } + else { + kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n"; + if( errCode == KParts::ComponentFactory::ErrNoLibrary) + { + kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl; + } + } + } + + if(!doc->isLoading()) + { + slotLoadingFinished(); + } else { + connect(doc, TQT_SIGNAL(loadingFinished()), TQT_TQOBJECT(this), TQT_SLOT(slotLoadingFinished())); + } + + setFocus(); +} + +KisView::~KisView() +{ + KisConfig cfg; + cfg.setShowRulers( m_RulerAction->isChecked() ); + + delete m_dcop; + delete m_paletteManager; + delete m_selectionManager; + delete m_filterManager; + delete m_toolManager; + +} + + +static TQt::Dock stringToDock( const TQString& attrPosition ) +{ + KToolBar::Dock dock = KToolBar::DockTop; + if ( !attrPosition.isEmpty() ) { + if ( attrPosition == "top" ) + dock = TQt::DockTop; + else if ( attrPosition == "left" ) + dock = TQt::DockLeft; + else if ( attrPosition == "right" ) + dock = TQt::DockRight; + else if ( attrPosition == "bottom" ) + dock = TQt::DockBottom; + else if ( attrPosition == "floating" ) + dock = TQt::DockTornOff; + else if ( attrPosition == "flat" ) + dock = TQt::DockMinimized; + } + return dock; +} + +TQWidget * KisView::createContainer( TQWidget *tqparent, int index, const TQDomElement &element, int &id ) +{ + if( element.attribute( "name" ) == "ToolBox" ) + { + m_toolBox = new KoToolBox(mainWindow(), "ToolBox", KisFactory::instance(), NUMBER_OF_TOOLTYPES); + m_toolBox->setLabel(i18n("Chalk")); + m_toolManager->setUp(m_toolBox, m_paletteManager, actionCollection()); + + Dock dock = stringToDock( element.attribute( "position" ).lower() ); + + mainWindow()->addDockWindow( m_toolBox, dock, false); + mainWindow()->moveDockWindow( m_toolBox, dock, false, 0, 0 ); + } + + return KXMLGUIBuilder::createContainer( tqparent, index, element, id ); + +} + +void KisView::removeContainer( TQWidget *container, TQWidget *tqparent, TQDomElement &element, int id ) +{ + Q_ASSERT(container); + + if( shell() && container == m_toolBox ) + { + delete m_toolBox; + m_toolManager->youAintGotNoToolBox(); + } + else { + KXMLGUIBuilder::removeContainer( container, tqparent, element, id ); + } +} + +KoPaletteManager * KisView::paletteManager() +{ + if (!m_paletteManager) { + m_paletteManager = new KoPaletteManager(this, actionCollection(), "Chalk palette manager"); + Q_CHECK_PTR(m_paletteManager); + } + return m_paletteManager; +} + +void KisView::createLayerBox() +{ + m_layerBox = new KisLayerBox(this); + m_layerBox->setCaption(i18n("Layers")); + + connect(m_layerBox, TQT_SIGNAL(sigRequestLayer(KisGroupLayerSP, KisLayerSP)), + TQT_TQOBJECT(this), TQT_SLOT(addLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, TQT_SIGNAL(sigRequestGroupLayer(KisGroupLayerSP, KisLayerSP)), + TQT_TQOBJECT(this), TQT_SLOT(addGroupLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, TQT_SIGNAL(sigRequestAdjustmentLayer(KisGroupLayerSP, KisLayerSP)), + TQT_TQOBJECT(this), TQT_SLOT(addAdjustmentLayer(KisGroupLayerSP, KisLayerSP))); + connect(m_layerBox, TQT_SIGNAL(sigRequestPartLayer(KisGroupLayerSP, KisLayerSP, const KoDocumentEntry&)), + TQT_TQOBJECT(this), TQT_SLOT(addPartLayer(KisGroupLayerSP, KisLayerSP, const KoDocumentEntry&))); + connect(m_layerBox, TQT_SIGNAL(sigRequestLayerProperties(KisLayerSP)), + TQT_TQOBJECT(this), TQT_SLOT(showLayerProperties(KisLayerSP))); + connect(m_layerBox, TQT_SIGNAL(sigOpacityChanged(int, bool)), TQT_TQOBJECT(this), TQT_SLOT(layerOpacity(int, bool))); + connect(m_layerBox, TQT_SIGNAL(sigOpacityFinishedChanging(int, int)), + TQT_TQOBJECT(this), TQT_SLOT(layerOpacityFinishedChanging(int, int))); + connect(m_layerBox, TQT_SIGNAL(sigItemComposite(const KisCompositeOp&)), TQT_TQOBJECT(this), TQT_SLOT(layerCompositeOp(const KisCompositeOp&))); + + paletteManager()->addWidget(m_layerBox, "layerbox", chalk::LAYERBOX, 0); + +} + +DCOPObject* KisView::dcopObject() +{ + if (!m_dcop) { + m_dcop = new KisViewIface(this); + Q_CHECK_PTR(m_dcop); + } + return m_dcop; +} + +void KisView::setupScrollBars() +{ + m_scrollX = 0; + m_scrollY = 0; + m_vScroll = new TQScrollBar(Qt::Vertical, this); + Q_CHECK_PTR(m_vScroll); + + m_hScroll = new TQScrollBar(Qt::Horizontal, this); + Q_CHECK_PTR(m_hScroll); + + m_vScroll->setGeometry(width() - 16, 20, 16, height() - 36); + m_hScroll->setGeometry(20, height() - 16, width() - 36, 16); + m_hScroll->setValue(0); + m_vScroll->setValue(0); + TQObject::connect(m_vScroll, TQT_SIGNAL(valueChanged(int)), TQT_TQOBJECT(this), TQT_SLOT(scrollV(int))); + TQObject::connect(m_hScroll, TQT_SIGNAL(valueChanged(int)), TQT_TQOBJECT(this), TQT_SLOT(scrollH(int))); +} + +void KisView::setupRulers() +{ + m_hRuler = new KisRuler(Qt::Horizontal, this); + Q_CHECK_PTR(m_hRuler); + + m_vRuler = new KisRuler(Qt::Vertical, this); + Q_CHECK_PTR(m_vRuler); + + m_hRuler->setGeometry(20, 0, width() - 20, 20); + m_vRuler->setGeometry(0, 20, 20, height() - 20); + + if (statusBar()) { + m_hRuler->installEventFilter(this); + m_vRuler->installEventFilter(this); + } +} + +#define EPSILON 1e-6 + +void KisView::updateStatusBarZoomLabel () +{ + if (zoom() < 1 - EPSILON) { + m_statusBarZoomLabel->setText(i18n("Zoom %1%").tqarg(zoom() * 100, 0, 'g', 4)); + } else { + m_statusBarZoomLabel->setText(i18n("Zoom %1%").tqarg(zoom() * 100, 0, 'f', 0)); + } + m_statusBarZoomLabel->setMaximumWidth(m_statusBarZoomLabel->fontMetrics().width(i18n("Zoom %1%").tqarg("0.8888 "))); +} + +void KisView::updateStatusBarSelectionLabel() +{ + if (m_statusBarSelectionLabel == 0) { + return; + } + + KisImageSP img = currentImg(); + if (img) { + KisPaintDeviceSP dev = img->activeDevice(); + if (dev) { + if (dev->hasSelection()) { + TQRect r = dev->selection()->selectedExactRect(); + m_statusBarSelectionLabel->setText( i18n("Selection Active: x = %1 y = %2 width = %3 height = %4").tqarg(r.x()).tqarg(r.y()).tqarg( r.width()).tqarg( r.height())); + return; + } + } + } + + m_statusBarSelectionLabel->setText(i18n("No Selection")); +} + +void KisView::updateStatusBarProfileLabel() +{ + if (m_statusBarProfileLabel == 0) { + return; + } + + KisImageSP img = currentImg(); + if (!img) return; + + if (img->getProfile() == 0) { + m_statusBarProfileLabel->setText(i18n("No profile")); + } + else { + m_statusBarProfileLabel->setText(img->colorSpace()->id().name() + " " + img->getProfile()->productName()); + } +} + + +KisProfile * KisView::monitorProfile() +{ + if (m_monitorProfile == 0) { + resetMonitorProfile(); + } + return m_monitorProfile; +} + + +void KisView::resetMonitorProfile() +{ + m_monitorProfile = KisProfile::getScreenProfile(); + + if (m_monitorProfile == 0) { + KisConfig cfg; + TQString monitorProfileName = cfg.monitorProfile(); + m_monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + } + +} + +void KisView::setupStatusBar() +{ + KStatusBar *sb = statusBar(); + + if (sb) { + m_statusBarZoomLabel = new TQLabel(sb); + addStatusBarItem(m_statusBarZoomLabel,1); + updateStatusBarZoomLabel(); + + m_statusBarSelectionLabel = new KSqueezedTextLabel(sb); + addStatusBarItem(m_statusBarSelectionLabel,2); + updateStatusBarSelectionLabel(); + + m_statusBarProfileLabel = new KSqueezedTextLabel(sb); + addStatusBarItem(m_statusBarProfileLabel,3); + updateStatusBarProfileLabel(); + + //int height = m_statusBarProfileLabel->height(); + + m_progress = new KisLabelProgress(this); + m_progress->setMaximumWidth(225); + m_progress->setMinimumWidth(225); + m_progress->setMaximumHeight(fontMetrics().height() ); + addStatusBarItem(m_progress, 2, true); + + m_progress->hide(); + } +} + +void KisView::setupActions() +{ + KisConfig cfg; + + m_selectionManager->setup(actionCollection()); + m_filterManager->setup(actionCollection()); + m_gridManager->setup(actionCollection()); + m_perspectiveGridManager->setup(actionCollection()); + + + m_fullScreen = KStdAction::fullScreen( NULL, NULL, actionCollection(), this ); + connect( m_fullScreen, TQT_SIGNAL( toggled( bool )), TQT_TQOBJECT(this), TQT_SLOT( slotUpdateFullScreen( bool ))); + + m_imgProperties = new KAction(i18n("Image Properties"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotImageProperties()), actionCollection(), "img_properties"); + m_imgScan = 0; // How the hell do I get a KAction to the scan plug-in?!? + m_imgResizeToLayer = new KAction(i18n("Resize Image to Size of Current Layer"), 0, TQT_TQOBJECT(this), TQT_SLOT(imgResizeToActiveLayer()), actionCollection(), "resizeimgtolayer"); + + // view actions + m_zoomIn = KStdAction::zoomIn(TQT_TQOBJECT(this), TQT_SLOT(slotZoomIn()), actionCollection(), "zoom_in"); + m_zoomOut = KStdAction::zoomOut(TQT_TQOBJECT(this), TQT_SLOT(slotZoomOut()), actionCollection(), "zoom_out"); + m_actualPixels = new KAction(i18n("Actual Pixels"), "Ctrl+0", TQT_TQOBJECT(this), TQT_SLOT(slotActualPixels()), actionCollection(), "actual_pixels"); + m_actualSize = KStdAction::actualSize(TQT_TQOBJECT(this), TQT_SLOT(slotActualSize()), actionCollection(), "actual_size"); + m_actualSize->setEnabled(false); + m_fitToCanvas = KStdAction::fitToPage(TQT_TQOBJECT(this), TQT_SLOT(slotFitToCanvas()), actionCollection(), "fit_to_canvas"); + + // layer actions + m_layerAdd = new KAction(i18n("&Add..."), "Ctrl+Shift+N", TQT_TQOBJECT(this), TQT_SLOT(layerAdd()), actionCollection(), "insert_layer"); + + m_actionPartLayer = new KoPartSelectAction( i18n( "&Object Layer" ), "frame_query", + TQT_TQOBJECT(this), TQT_SLOT( addPartLayer() ), + actionCollection(), "insert_part_layer" ); + + + m_actionAdjustmentLayer = new KAction( i18n( "&Adjustment Layer" ), 0, + TQT_TQOBJECT(this), TQT_SLOT( addAdjustmentLayer() ), + actionCollection(), "insert_adjustment_layer" ); + + + m_layerRm = new KAction(i18n("&Remove"), 0, TQT_TQOBJECT(this), TQT_SLOT(layerRemove()), actionCollection(), "remove_layer"); + m_layerDup = new KAction(i18n("Duplicate"), 0, TQT_TQOBJECT(this), TQT_SLOT(layerDuplicate()), actionCollection(), "duplicate_layer"); + m_layerHide = new KToggleAction(i18n("&Hide"), 0, TQT_TQOBJECT(this), TQT_SLOT(layerToggleVisible()), actionCollection(), "hide_layer"); + m_layerHide->setCheckedState(KGuiItem(i18n("&Show"))); + m_layerHide->setChecked(false); + + m_layerRaise = new KAction(i18n("Raise"), "raise", "Ctrl+]", TQT_TQOBJECT(this), TQT_SLOT(layerRaise()), actionCollection(), "raiselayer"); + m_layerLower = new KAction(i18n("Lower"), "lower", "Ctrl+[", TQT_TQOBJECT(this), TQT_SLOT(layerLower()), actionCollection(), "lowerlayer"); + m_layerTop = new KAction(i18n("To Top"), "bring_forward", "Ctrl+Shift+]", TQT_TQOBJECT(this), TQT_SLOT(layerFront()), actionCollection(), "toplayer"); + m_layerBottom = new KAction(i18n("To Bottom"), "send_backward", "Ctrl+Shift+[", TQT_TQOBJECT(this), TQT_SLOT(layerBack()), actionCollection(), "bottomlayer"); + m_layerProperties = new KAction(i18n("Properties"), 0, TQT_TQOBJECT(this), TQT_SLOT(layerProperties()), actionCollection(), "layer_properties"); + (void)new KAction(i18n("I&nsert Image as Layer..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotInsertImageAsLayer()), actionCollection(), "insert_image_as_layer"); + m_layerSaveAs = new KAction(i18n("Save Layer as Image..."), "filesave", TQT_TQOBJECT(this), TQT_SLOT(saveLayerAsImage()), actionCollection(), "save_layer_as_image"); + (void)new KAction(i18n("Flip on &X Axis"), "view_left_right", 0, TQT_TQOBJECT(this), TQT_SLOT(mirrorLayerX()), actionCollection(), "mirrorLayerX"); + (void)new KAction(i18n("Flip on &Y Axis"), "view_top_bottom", 0, TQT_TQOBJECT(this), TQT_SLOT(mirrorLayerY()), actionCollection(), "mirrorLayerY"); + + m_createMask = new KAction(i18n("Create Mask"), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotCreateMask()), actionCollection(), "create_tqmask"); + m_tqmaskFromSelection = new KAction(i18n("Mask From Selection"), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotMaskFromSelection()), actionCollection(), + "tqmask_fromsel"); + m_tqmaskToSelection = new KAction(i18n("Mask to Selection"), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotMaskToSelection()), actionCollection(), "tqmask_tosel"); + m_applyMask = new KAction(i18n("Apply Mask"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotApplyMask()), + actionCollection(), "apply_tqmask"); + m_removeMask = new KAction(i18n("Remove Mask"), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotRemoveMask()), actionCollection(), "remove_tqmask"); + m_showMask = new KToggleAction(i18n( "Show Mask" ), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotShowMask()), actionCollection(), "show_tqmask"); + m_editMask = new KToggleAction(i18n( "Edit Mask" ), 0, TQT_TQOBJECT(this), + TQT_SLOT(slotEditMask()), actionCollection(), "edit_tqmask"); + + // image actions + m_imgFlatten = new KAction(i18n("&Flatten Image"), "Ctrl+Shift+E", TQT_TQOBJECT(this), TQT_SLOT(flattenImage()), actionCollection(), "flatten_image"); + m_imgMergeLayer = new KAction(i18n("&Merge with Layer Below"), "Ctrl+E", TQT_TQOBJECT(this), TQT_SLOT(mergeLayer()), actionCollection(), "merge_layer"); + + // setting actions + KStdAction::preferences(TQT_TQOBJECT(this), TQT_SLOT(preferences()), actionCollection(), "preferences"); + + m_RulerAction = new KToggleAction( i18n( "Show Rulers" ), "Ctrl+R", TQT_TQOBJECT(this), TQT_SLOT( showRuler() ), actionCollection(), "view_ruler" ); + m_RulerAction->setChecked(cfg.showRulers()); + m_RulerAction->setCheckedState(i18n("Hide Rulers")); + m_RulerAction->setWhatsThis( i18n("The rulers show the horizontal and vertical positions of the mouse on the image " + "and can be used to position your mouse at the right place on the canvas.

Uncheck this to disable " + "the rulers from being displayed." ) ); + + //m_guideAction = new KToggleAction( i18n( "Guide Lines" ), 0, TQT_TQOBJECT(this), TQT_SLOT( viewGuideLines() ), actionCollection(), "view_guidelines" ); + + // Add new palette + new KAction(i18n("Add New Palette..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotAddPalette()), + actionCollection(), "add_palette"); + new KAction(i18n("Edit Palette..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotEditPalette()), + actionCollection(), "edit_palette"); + + // XXX: This triggers a tqrepaint of the image, but way too early + //showRuler(); + +} + +void KisView::resizeEvent(TQResizeEvent *) +{ + if (!m_paintViewEnabled) { + startInitialZoomTimerIfReady(); + } + + KisImageSP img = currentImg(); + TQ_INT32 scrollBarExtent = tqstyle().tqpixelMetric(TQStyle::PM_ScrollBarExtent); + TQ_INT32 drawH; + TQ_INT32 drawW; + TQ_INT32 docW; + TQ_INT32 docH; + +// if (img) { +// KisGuideMgr *mgr = img->guides(); +// mgr->resize(size()); +// } + + docW = static_cast(ceil(docWidth() * zoom())); + docH = static_cast(ceil(docHeight() * zoom())); + + m_rulerThickness = m_RulerAction->isChecked() ? RULER_THICKNESS : 0; + drawH = height() - m_rulerThickness; + drawW = width() - m_rulerThickness; + + if (drawH < docH) { + // Will need vert scrollbar + drawW -= scrollBarExtent; + if (drawW < docW) + // Will need horiz scrollbar + drawH -= scrollBarExtent; + } else if (drawW < docW) { + // Will need horiz scrollbar + drawH -= scrollBarExtent; + if (drawH < docH) + // Will need vert scrollbar + drawW -= scrollBarExtent; + } + + m_vScroll->setEnabled(docH > drawH); + m_hScroll->setEnabled(docW > drawW); + + if (docH <= drawH && docW <= drawW) { + // we need no scrollbars + m_vScroll->hide(); + m_hScroll->hide(); + m_vScroll->setValue(0); + m_hScroll->setValue(0); + m_vScrollBarExtent = 0; + m_hScrollBarExtent = 0; + } else if (docH <= drawH) { + // we need a horizontal scrollbar only + m_vScroll->hide(); + m_vScroll->setValue(0); + m_hScroll->setRange(0, docW - drawW); + m_hScroll->setGeometry(m_rulerThickness, + height() - scrollBarExtent, + width() - m_rulerThickness, + scrollBarExtent); + m_hScroll->show(); + m_hScrollBarExtent = scrollBarExtent; + m_hScrollBarExtent = scrollBarExtent; + } else if(docW <= drawW) { + // we need a vertical scrollbar only + m_hScroll->hide(); + m_hScroll->setValue(0); + m_vScroll->setRange(0, docH - drawH); + m_vScroll->setGeometry(width() - scrollBarExtent, m_rulerThickness, scrollBarExtent, height() - m_rulerThickness); + m_vScroll->show(); + m_vScrollBarExtent = scrollBarExtent; + } else { + // we need both scrollbars + m_vScroll->setRange(0, docH - drawH); + m_vScroll->setGeometry(width() - scrollBarExtent, + m_rulerThickness, + scrollBarExtent, + height() -2* m_rulerThickness); + m_hScroll->setRange(0, docW - drawW); + m_hScroll->setGeometry(m_rulerThickness, + height() - scrollBarExtent, + width() - 2*m_rulerThickness, + scrollBarExtent); + m_vScroll->show(); + m_hScroll->show(); + m_vScrollBarExtent = scrollBarExtent; + m_hScrollBarExtent = scrollBarExtent; + } + + TQ_INT32 oldCanvasXOffset = m_canvasXOffset; + TQ_INT32 oldCanvasYOffset = m_canvasYOffset; + + if (docW < drawW) { + m_canvasXOffset = (drawW - docW) / 2; + } else { + m_canvasXOffset = 0; + } + + if (docH < drawH) { + m_canvasYOffset = (drawH - docH) / 2; + } else { + m_canvasYOffset = 0; + } + + //Check if rulers are visible + if( m_RulerAction->isChecked() ) + m_canvas->setGeometry(m_rulerThickness, m_rulerThickness, drawW, drawH); + else + m_canvas->setGeometry(0, 0, drawW, drawH); + m_canvas->show(); + + if (!m_canvas->isOpenGLCanvas()) { + + if (m_canvasPixmap.size() != TQSize(drawW, drawH)) { + + TQ_INT32 oldCanvasWidth = m_canvasPixmap.width(); + TQ_INT32 oldCanvasHeight = m_canvasPixmap.height(); + + TQ_INT32 newCanvasWidth = drawW; + TQ_INT32 newCanvasHeight = drawH; + + TQRegion exposedRegion = TQRect(0, 0, newCanvasWidth, newCanvasHeight); + + // Increase size first so that we can copy the old image area to the new one. + m_canvasPixmap.resize(TQMAX(oldCanvasWidth, newCanvasWidth), TQMAX(oldCanvasHeight, newCanvasHeight)); + + if (!m_canvasPixmap.isNull()) { + + if (oldCanvasXOffset != m_canvasXOffset || oldCanvasYOffset != m_canvasYOffset) { + + TQ_INT32 srcX; + TQ_INT32 srcY; + TQ_INT32 srcWidth; + TQ_INT32 srcHeight; + TQ_INT32 dstX; + TQ_INT32 dstY; + + if (oldCanvasXOffset <= m_canvasXOffset) { + // Move to the right + srcX = 0; + dstX = m_canvasXOffset - oldCanvasXOffset; + srcWidth = oldCanvasWidth; + } else { + // Move to the left + srcX = oldCanvasXOffset - m_canvasXOffset; + dstX = 0; + srcWidth = newCanvasWidth; + } + + if (oldCanvasYOffset <= m_canvasYOffset) { + // Move down + srcY = 0; + dstY = m_canvasYOffset - oldCanvasYOffset; + srcHeight = oldCanvasHeight; + } else { + // Move up + srcY = oldCanvasYOffset - m_canvasYOffset; + dstY = 0; + srcHeight = newCanvasHeight; + } + + bitBlt(&m_canvasPixmap, dstX, dstY, &m_canvasPixmap, srcX, srcY, srcWidth, srcHeight); + exposedRegion -= TQRegion(TQRect(dstX, dstY, srcWidth, srcHeight)); + } else { + exposedRegion -= TQRegion(TQRect(0, 0, oldCanvasWidth, oldCanvasHeight)); + } + } + + m_canvasPixmap.resize(newCanvasWidth, newCanvasHeight); + + if (!m_canvasPixmap.isNull() && !exposedRegion.isEmpty()) { + + TQMemArray rects = exposedRegion.tqrects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + TQRect r = rects[i]; + updateTQPaintDeviceCanvas(viewToWindow(r)); + } + } + } + } + + int fontheight = TQFontMetrics(KGlobalSettings::generalFont()).height() * 3; + m_vScroll->setPageStep(drawH); + m_vScroll->setLineStep(fontheight); + m_hScroll->setPageStep(drawW); + m_hScroll->setLineStep(fontheight); + + m_hRuler->setGeometry(m_rulerThickness + m_canvasXOffset, 0, TQMIN(docW, drawW), m_rulerThickness); + m_vRuler->setGeometry(0, m_rulerThickness + m_canvasYOffset, m_rulerThickness, TQMIN(docH, drawH)); + + if (m_vScroll->isVisible()) + m_vRuler->updateVisibleArea(0, m_vScroll->value()); + else + m_vRuler->updateVisibleArea(0, 0); + + if (m_hScroll->isVisible()) + m_hRuler->updateVisibleArea(m_hScroll->value(), 0); + else + m_hRuler->updateVisibleArea(0, 0); + + if( m_RulerAction->isChecked() ) + { + m_hRuler->show(); + m_vRuler->show(); + } + else { + m_hRuler->hide(); + m_vRuler->hide(); + } + + emit viewTransformationsChanged(); +} + +void KisView::styleChange(TQStyle& oldStyle) +{ + Q_UNUSED(oldStyle); + m_canvas->updateGeometry(); + refreshKisCanvas(); +} + +void KisView::paletteChange(const TQPalette& oldPalette) +{ + Q_UNUSED(oldPalette); + refreshKisCanvas(); +} + +void KisView::showEvent(TQShowEvent *) +{ + if (!m_showEventReceived) { + m_showEventReceived = true; + startInitialZoomTimerIfReady(); + } +} + +void KisView::updateReadWrite(bool readwrite) +{ + layerUpdateGUI(readwrite); +} + +TQ_INT32 KisView::horzValue() const +{ + return m_hScroll->value() - m_canvasXOffset; +} + +TQ_INT32 KisView::vertValue() const +{ + return m_vScroll->value() - m_canvasYOffset; +} + +void KisView::updateTQPaintDeviceCanvas(const TQRect& imageRect) +{ + TQRect vr = windowToView(imageRect); + vr &= TQRect(0, 0, m_canvas->width(), m_canvas->height()); + + if (!vr.isEmpty()) { + + TQPainter gc; + + if (gc.begin(&m_canvasPixmap)) { + + KisImageSP img = currentImg(); + + if (img && m_paintViewEnabled) { + + TQRect wr = viewToWindow(vr); + + if (wr.left() < 0 || wr.right() >= img->width() || wr.top() < 0 || wr.bottom() >= img->height()) { + // Erase areas outside document + TQRegion rg(vr); + rg -= TQRegion(windowToView(TQRect(0, 0, img->width(), img->height()))); + + TQMemArray rects = rg.tqrects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + TQRect er = rects[i]; + gc.fillRect(er, tqcolorGroup().mid()); + } + wr &= TQRect(0, 0, img->width(), img->height()); + } + + if (!wr.isEmpty()) { + + KisImage::PaintFlags paintFlags = (KisImage::PaintFlags)KisImage::PAINT_BACKGROUND; + + if (m_actLayerVis) { + paintFlags = (KisImage::PaintFlags)(paintFlags|KisImage::PAINT_MASKINACTIVELAYERS); + } + + if (m_selectionManager->displaySelection()) + { + paintFlags = (KisImage::PaintFlags)(paintFlags|KisImage::PAINT_SELECTION); + } + + if (zoom() > 1.0 - EPSILON) { + + gc.setWorldXForm(true); + gc.translate(-horzValue(), -vertValue()); + gc.scale(zoomFactor(), zoomFactor()); + + m_image->renderToPainter(wr.left(), wr.top(), + wr.right(), wr.bottom(), gc, monitorProfile(), + paintFlags, HDRExposure()); + } else { + + TQRect canvasRect = windowToView(wr); + TQRect scaledImageRect = canvasRect; + scaledImageRect.moveBy(horzValue(), vertValue()); + + TQSize scaledImageSize(static_cast(ceil(docWidth() * zoom())), + static_cast(ceil(docHeight() * zoom()))); + + TQImage image = m_image->convertToTQImage(scaledImageRect, scaledImageSize, + monitorProfile(), paintFlags, HDRExposure()); + + gc.drawImage(canvasRect.topLeft(), image, image.rect()); + + // Set up for the grid drawer. + gc.setWorldXForm(true); + gc.translate(-horzValue(), -vertValue()); + gc.scale(zoomFactor(), zoomFactor()); + } + + m_gridManager->drawGrid( wr, &gc ); + m_perspectiveGridManager->drawGrid( wr, &gc ); + } +// paintGuides(); + } else { + gc.fillRect(vr, tqcolorGroup().mid()); + } + } + } +} + +void KisView::paintTQPaintDeviceView(const TQRegion& canvasRegion) +{ + Q_ASSERT(m_canvas->TQPaintDeviceWidget() != 0); + + if (m_canvas->TQPaintDeviceWidget() != 0 && !m_canvasPixmap.isNull()) { + TQMemArray rects = canvasRegion.tqrects(); + + for (unsigned int i = 0; i < rects.count(); i++) { + TQRect r = rects[i]; + + bitBlt(m_canvas->TQPaintDeviceWidget(), r.x(), r.y(), &m_canvasPixmap, + r.x(), r.y(), r.width(), r.height()); + } + + paintToolOverlay(canvasRegion); + } +} + +void KisView::updateOpenGLCanvas(const TQRect& imageRect) +{ +#ifdef HAVE_GL + KisImageSP img = currentImg(); + + if (img && m_paintViewEnabled) { + Q_ASSERT(m_OpenGLImageContext != 0); + + if (m_OpenGLImageContext != 0) { + m_OpenGLImageContext->update(imageRect); + } + } +#else + Q_UNUSED(imageRect); +#endif +} + +void KisView::paintOpenGLView(const TQRect& canvasRect) +{ +#ifdef HAVE_GL + if (!m_canvas->isUpdatesEnabled()) { + return; + } + + m_canvas->OpenGLWidget()->makeCurrent(); + + glDrawBuffer(GL_BACK); + + TQColor widgetBackgroundColor = tqcolorGroup().mid(); + + glClearColor(widgetBackgroundColor.red() / 255.0, widgetBackgroundColor.green() / 255.0, widgetBackgroundColor.blue() / 255.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + KisImageSP img = currentImg(); + + if (img && m_paintViewEnabled) { + + TQRect vr = canvasRect; + vr &= TQRect(0, 0, m_canvas->width(), m_canvas->height()); + + if (!vr.isNull()) { + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, m_canvas->width(), m_canvas->height()); + glOrtho(0, m_canvas->width(), m_canvas->height(), 0, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, m_OpenGLImageContext->backgroundTexture()); + + glTranslatef(m_canvasXOffset, m_canvasYOffset, 0.0); + + glEnable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + + glTexCoord2f(0.0, 0.0); + glVertex2f(0.0, 0.0); + + glTexCoord2f((img->width() * zoom()) / KisOpenGLImageContext::BACKGROUND_TEXTURE_WIDTH, 0.0); + glVertex2f(img->width() * zoom(), 0.0); + + glTexCoord2f((img->width() * zoom()) / KisOpenGLImageContext::BACKGROUND_TEXTURE_WIDTH, + (img->height() * zoom()) / KisOpenGLImageContext::BACKGROUND_TEXTURE_HEIGHT); + glVertex2f(img->width() * zoom(), img->height() * zoom()); + + glTexCoord2f(0.0, (img->height() * zoom()) / KisOpenGLImageContext::BACKGROUND_TEXTURE_HEIGHT); + glVertex2f(0.0, img->height() * zoom()); + + glEnd(); + + glTranslatef(-m_canvasXOffset, -m_canvasYOffset, 0.0); + + glTranslatef(-horzValue(), -vertValue(), 0.0); + glScalef(zoomFactor(), zoomFactor(), 1.0); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + TQRect wr = viewToWindow(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + wr &= TQRect(0, 0, img->width(), img->height()); + + m_OpenGLImageContext->setHDRExposure(HDRExposure()); + + m_canvas->OpenGLWidget()->makeCurrent(); + + for (int x = (wr.left() / m_OpenGLImageContext->imageTextureTileWidth()) * m_OpenGLImageContext->imageTextureTileWidth(); + x <= wr.right(); + x += m_OpenGLImageContext->imageTextureTileWidth()) { + for (int y = (wr.top() / m_OpenGLImageContext->imageTextureTileHeight()) * m_OpenGLImageContext->imageTextureTileHeight(); + y <= wr.bottom(); + y += m_OpenGLImageContext->imageTextureTileHeight()) { + + glBindTexture(GL_TEXTURE_2D, m_OpenGLImageContext->imageTextureTile(x, y)); + + glBegin(GL_QUADS); + + glTexCoord2f(0.0, 0.0); + glVertex2f(x, y); + + glTexCoord2f(1.0, 0.0); + glVertex2f(x + m_OpenGLImageContext->imageTextureTileWidth(), y); + + glTexCoord2f(1.0, 1.0); + glVertex2f(x + m_OpenGLImageContext->imageTextureTileWidth(), y + m_OpenGLImageContext->imageTextureTileHeight()); + + glTexCoord2f(0.0, 1.0); + glVertex2f(x, y + m_OpenGLImageContext->imageTextureTileHeight()); + + glEnd(); + } + } + + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + + m_gridManager->drawGrid(wr, 0, true); + m_perspectiveGridManager->drawGrid( wr, 0, true ); + + // Unbind the texture otherwise the ATI driver crashes when the canvas context is + // made current after the textures are deleted following an image resize. + glBindTexture(GL_TEXTURE_2D, 0); + + //paintGuides(); + } + } + + m_canvas->OpenGLWidget()->swapBuffers(); + + paintToolOverlay(TQRegion(canvasRect)); + +#else + Q_UNUSED(canvasRect); +#endif +} + +void KisView::setInputDevice(KisInputDevice inputDevice) +{ + if (inputDevice != m_inputDevice) { + m_inputDevice = inputDevice; + + m_toolManager->setToolForInputDevice(m_inputDevice, inputDevice); + + if (m_toolManager->currentTool() == 0) { + m_toolManager->setCurrentTool(m_toolManager->findTool("tool_brush", m_inputDevice)); + } + else { + m_toolManager->setCurrentTool(m_toolManager->currentTool()); + } + m_toolManager->activateCurrentTool(); + + emit sigInputDeviceChanged(inputDevice); + } + +} + +KisInputDevice KisView::currentInputDevice() const +{ + return m_inputDevice; +} + + +KisCanvas *KisView::kiscanvas() const +{ + return m_canvas; +} + +void KisView::updateCanvas() +{ + if (m_image) { + updateCanvas(m_image->bounds()); + } +} + +void KisView::updateCanvas(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + updateCanvas(TQRect(x, y, w, h)); +} + +void KisView::updateCanvas(const TQRect& imageRect) +{ + if (m_canvas->isOpenGLCanvas()) { + updateOpenGLCanvas(imageRect); + paintOpenGLView(windowToView(imageRect)); + } else { + updateTQPaintDeviceCanvas(imageRect); + //m_canvas->update(windowToView(imageRect)); + m_canvas->tqrepaint(windowToView(imageRect)); + } +} + +void KisView::refreshKisCanvas() +{ + TQRect imageRect = viewToWindow(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + + if (m_image) { + imageRect |= m_image->bounds(); + } + + updateCanvas(imageRect); + + // Enable this if updateCanvas does an m_canvas->update() + //m_canvas->tqrepaint(); +} + +void KisView::selectionDisplayToggled(bool displaySelection) +{ +#ifdef HAVE_GL + if (m_canvas->isOpenGLCanvas()) { + if (m_OpenGLImageContext) { + m_OpenGLImageContext->setSelectionDisplayEnabled(displaySelection); + } + } +#else + Q_UNUSED(displaySelection); +#endif + updateCanvas(); +} + +void KisView::layerUpdateGUI(bool enable) +{ + KisImageSP img = currentImg(); + + KisLayerSP layer; + TQ_INT32 nlayers = 0; + TQ_INT32 nvisible = 0; + + + + if (img) { + layer = img->activeLayer(); + nlayers = img->nlayers(); + nvisible = nlayers - img->nHiddenLayers(); + } + + KisPaintLayer * pl = dynamic_cast(layer.data()); + + if (pl && ( m_currentColorChooserDisplay != KisID("BLA") || + pl->paintDevice()->colorSpace()->id() != m_currentColorChooserDisplay)) { + if (pl->paintDevice()->colorSpace()->id() == KisID("WET")) { + m_paletteManager->hideWidget( "hsvwidget" ); + m_paletteManager->hideWidget( "rgbwidget" ); + m_paletteManager->hideWidget( "graywidget" ); + m_paletteManager->hideWidget( "palettewidget" ); + m_paletteManager->showWidget( "watercolor docker" ); + } + else { + m_paletteManager->hideWidget( "watercolor docker" ); + m_paletteManager->showWidget( "palettewidget" ); + m_paletteManager->showWidget( "graywidget" ); + m_paletteManager->showWidget( "rgbwidget" ); + m_paletteManager->showWidget( "hsvwidget" ); + } + m_currentColorChooserDisplay = pl->paintDevice()->colorSpace()->id(); + } + + enable = enable && img && layer && layer->visible() && !layer->locked(); + m_layerDup->setEnabled(enable); + m_layerRm->setEnabled(enable); + m_layerHide->setEnabled(img && layer); + m_layerProperties->setEnabled(enable); + m_layerSaveAs->setEnabled(enable); + m_layerRaise->setEnabled(enable && layer->prevSibling()); + m_layerLower->setEnabled(enable && layer->nextSibling()); + m_layerTop->setEnabled(enable && nlayers > 1 && layer != img->rootLayer()->firstChild()); + m_layerBottom->setEnabled(enable && nlayers > 1 && layer != img->rootLayer()->lastChild()); + + // XXX these should be named layer instead of img + m_imgFlatten->setEnabled(nlayers > 1); + m_imgMergeLayer->setEnabled(nlayers > 1 && layer && layer->nextSibling()); + + + m_selectionManager->updateGUI(); + m_filterManager->updateGUI(); + m_toolManager->updateGUI(); + m_gridManager->updateGUI(); + m_perspectiveGridManager->updateGUI(); + + + KisPartLayer * partLayer = dynamic_cast(layer.data()); + if (partLayer) { + setCanvasCursor( KisCursor::arrowCursor() ); + } + + if (img && img->activeDevice()) + emit currentColorSpaceChanged(img->activeDevice()->colorSpace()); + + imgUpdateGUI(); +} + + +void KisView::imgUpdateGUI() +{ + KisImageSP img = currentImg(); + + m_imgResizeToLayer->setEnabled(img && img->activeLayer()); + + updateStatusBarProfileLabel(); +} + +static const double zoomLevels[] = { + 1.0 / 500, + 1.0 / 333.333333, + 1.0 / 250, + 1.0 / 200, + 1.0 / 150, + 1.0 / 100, + 1.0 / 66.666667, + 1.0 / 50, + 1.0 / 33.333333, + 1.0 / 25, + 1.0 / 20, + 1.0 / 16, + 1.0 / 12, + 1.0 / 8, + 1.0 / 6, + 1.0 / 4, + 1.0 / 3, + 1.0 / 2, + 1.0 / 1.5, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 12, + 16 +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define NUM_ZOOM_LEVELS ARRAY_SIZE(zoomLevels) + +#define FIRST_ZOOM_LEVEL_INDEX 0 +#define LAST_ZOOM_LEVEL_INDEX (NUM_ZOOM_LEVELS - 1) + +#define KISVIEW_MIN_ZOOM (zoomLevels[FIRST_ZOOM_LEVEL_INDEX]) +#define KISVIEW_MAX_ZOOM (zoomLevels[LAST_ZOOM_LEVEL_INDEX]) + +double KisView::nextZoomInLevel() const +{ + uint zoomLevelIndex = FIRST_ZOOM_LEVEL_INDEX; + + while (zoom() >= zoomLevels[zoomLevelIndex] && zoomLevelIndex < LAST_ZOOM_LEVEL_INDEX) { + zoomLevelIndex++; + } + + return zoomLevels[zoomLevelIndex]; +} + +double KisView::nextZoomOutLevel(double zoomLevel) const +{ + int zoomLevelIndex = LAST_ZOOM_LEVEL_INDEX; + + while (zoomLevel <= zoomLevels[zoomLevelIndex] && zoomLevelIndex > FIRST_ZOOM_LEVEL_INDEX) { + zoomLevelIndex--; + } + + return zoomLevels[zoomLevelIndex]; +} + +double KisView::nextZoomOutLevel() const +{ + return nextZoomOutLevel(zoom()); +} + +void KisView::zoomAroundPoint(double x, double y, double zf) +{ + // Disable updates while we change the scrollbar settings. + m_canvas->setUpdatesEnabled(false); + m_hScroll->setUpdatesEnabled(false); + m_vScroll->setUpdatesEnabled(false); + + if (x < 0 || y < 0) { + // Zoom about the centre of the current display + KisImageSP img = currentImg(); + + if (img) { + if (m_hScroll->isVisible()) { + KisPoint c = viewToWindow(KisPoint(m_canvas->width() / 2.0, m_canvas->height() / 2.0)); + x = c.x(); + } + else { + x = img->width() / 2.0; + } + + if (m_vScroll->isVisible()) { + KisPoint c = viewToWindow(KisPoint(m_canvas->width() / 2.0, m_canvas->height() / 2.0)); + y = c.y(); + } + else { + y = img->height() / 2.0; + } + } + else { + x = 0; + y = 0; + } + } + + setZoom(zf); + + Q_ASSERT(m_zoomIn); + Q_ASSERT(m_zoomOut); + + updateStatusBarZoomLabel (); + + m_zoomIn->setEnabled(zf < KISVIEW_MAX_ZOOM); + m_zoomOut->setEnabled(zf > KISVIEW_MIN_ZOOM); + resizeEvent(0); + + m_hRuler->setZoom(zf); + m_vRuler->setZoom(zf); + + if (m_hScroll->isVisible()) { + double vcx = m_canvas->width() / 2.0; + TQ_INT32 scrollX = tqRound(x * zoom() - vcx); + m_hScroll->setValue(scrollX); + } + + if (m_vScroll->isVisible()) { + double vcy = m_canvas->height() / 2.0; + TQ_INT32 scrollY = tqRound(y * zoom() - vcy); + m_vScroll->setValue(scrollY); + } + + // Now update everything. + m_canvas->setUpdatesEnabled(true); + m_hScroll->setUpdatesEnabled(true); + m_vScroll->setUpdatesEnabled(true); + m_hScroll->update(); + m_vScroll->update(); + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + refreshKisCanvas(); + } + + emit viewTransformationsChanged(); +} + +void KisView::zoomTo(const KisRect& r) +{ + if (!r.isNull()) { + + double wZoom = fabs(m_canvas->width() / r.width()); + double hZoom = fabs(m_canvas->height() / r.height()); + + double zf = kMin(wZoom, hZoom); + + if (zf < KISVIEW_MIN_ZOOM) { + zf = KISVIEW_MIN_ZOOM; + } + else + if (zf > KISVIEW_MAX_ZOOM) { + zf = KISVIEW_MAX_ZOOM; + } + + zoomAroundPoint(r.center().x(), r.center().y(), zf); + } +} + +void KisView::zoomTo(const TQRect& r) +{ + zoomTo(KisRect(r)); +} + +void KisView::zoomTo(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h) +{ + zoomTo(KisRect(x, y, w, h)); +} + +void KisView::zoomIn(TQ_INT32 x, TQ_INT32 y) +{ + zoomAroundPoint(x, y, nextZoomInLevel()); +} + +void KisView::zoomOut(TQ_INT32 x, TQ_INT32 y) +{ + zoomAroundPoint(x, y, nextZoomOutLevel()); +} + +void KisView::zoomIn() +{ + slotZoomIn(); +} + +void KisView::zoomOut() +{ + slotZoomOut(); +} + +void KisView::slotZoomIn() +{ + zoomIn(-1, -1); +} + +void KisView::slotZoomOut() +{ + zoomOut(-1, -1); +} + +void KisView::slotActualPixels() +{ + zoomAroundPoint(-1, -1, 1.0); +} + +void KisView::slotActualSize() +{ + //XXX later this should be update to take screen res and image res into consideration + zoomAroundPoint(-1, -1, 1.0); +} + +double KisView::fitToCanvasZoomLevel() const +{ + int fullCanvasWidth = width(); + + if (m_vRuler->isVisible()) { + fullCanvasWidth -= m_vRuler->width(); + } + + int fullCanvasHeight = height(); + + if (m_hRuler->isVisible()) { + fullCanvasHeight -= m_hRuler->height(); + } + + KisImageSP img = currentImg(); + if (img) { + double xZoomLevel = static_cast(fullCanvasWidth) / img->width(); + double yZoomLevel = static_cast(fullCanvasHeight) / img->height(); + + return TQMIN(xZoomLevel, yZoomLevel); + } + else { + return 1; + } +} + +void KisView::slotFitToCanvas() +{ + zoomAroundPoint(-1, -1, fitToCanvasZoomLevel()); +} + +void KisView::setInitialZoomLevel() +{ + double zoomLevel = fitToCanvasZoomLevel(); + + if (zoomLevel > 1) { + zoomLevel = 1; + } else { + zoomLevel = nextZoomOutLevel(zoomLevel); + } + + zoomAroundPoint(-1, -1, zoomLevel); +} + +void KisView::imgResizeToActiveLayer() +{ + KisImageSP img = currentImg(); + KisLayerSP layer; + + if (img && (layer = img->activeLayer())) { + + if (m_adapter && m_adapter->undo()) { + m_adapter->beginMacro(i18n("Resize Image to Size of Current Layer")); + } + + img->lock(); + + TQRect r = layer->exactBounds(); + img->resize(r.width(), r.height(), r.x(), r.y(), true); + + img->unlock(); + + if (m_adapter && m_adapter->undo()) { + m_adapter->endMacro(); + } + } +} + +void KisView::slotImageProperties() +{ + KisImageSP img = currentImg(); + + if (!img) return; + + KisDlgImageProperties dlg(img, this); + + if (dlg.exec() == TQDialog::Accepted) { + if (dlg.imageWidth() != img->width() || + dlg.imageHeight() != img->height()) { + + resizeCurrentImage(dlg.imageWidth(), + dlg.imageHeight()); + } + TQ_INT32 opacity = dlg.opacity(); + opacity = opacity * 255 / 100; + img->setName(dlg.imageName()); + img->setColorSpace(dlg.colorSpace()); + img->setResolution(dlg.resolution(), dlg.resolution()); + img->setDescription(dlg.description()); + img->setProfile(dlg.profile()); + } +} + +void KisView::slotInsertImageAsLayer() +{ + if (importImage() > 0) + m_doc->setModified(true); +} + +void KisView::slotAddPalette() +{ + KDialogBase* base = new KDialogBase(this, 0, true, i18n("Add Palette"), KDialogBase::Ok | KDialogBase::Cancel); + KisCustomPalette* p = new KisCustomPalette(base, "add palette", i18n("Add Palette"), this); + base->setMainWidget(p); + base->show(); +} + +void KisView::slotEditPalette() +{ + KisPaletteChooser chooser(this); + KisResourceServerBase* srv = KisResourceServerRegistry::instance()->get("PaletteServer"); + if (!srv) { + return; + } + TQValueList resources = srv->resources(); + TQValueList palettes; + + for(uint i = 0; i < resources.count(); i++) { + KisPalette* palette = dynamic_cast(*resources.at(i)); + + chooser.paletteList->insertItem(palette->name()); + palettes.append(palette); + } + + if (chooser.exec() != TQDialog::Accepted ) { + return; + } + + int index = chooser.paletteList->currentItem(); + if (index < 0) { + KMessageBox::error(this, i18n("No palette selected."), i18n("Palette")); + return; + } + + KDialogBase* base = new KDialogBase(this, 0, true, i18n("Edit Palette") , KDialogBase::Ok); + KisCustomPalette* cp = new KisCustomPalette(base, "edit palette", + i18n("Edit Palette"), this); + cp->setEditMode(true); + cp->setPalette(*palettes.at(index)); + base->setMainWidget(cp); + base->show(); +} + +void KisView::saveLayerAsImage() +{ + TQStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-chalk", KoFilterManager::Export); + TQString mimelist = listMimeFilter.join(" "); + + KFileDialog fd (TQString(), mimelist, this, "Export Layer", true); + fd.setCaption(i18n("Export Layer")); + fd.setMimeFilter(listMimeFilter); + fd.setOperationMode(KFileDialog::Saving); + + if (!fd.exec()) return; + + KURL url = fd.selectedURL(); + TQString mimefilter = fd.currentMimeFilter(); + + if (url.isEmpty()) + return; + + + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP l = img->activeLayer(); + if (!l) return; + + TQRect r = l->exactBounds(); + + KisDoc d; + d.prepareForImport(); + + KisImageSP dst = new KisImage(d.undoAdapter(), r.width(), r.height(), img->colorSpace(), l->name()); + d.setCurrentImage( dst ); + dst->addLayer(l->clone(),dst->rootLayer(),0); + + d.setOutputMimeType(mimefilter.latin1()); + d.exp0rt(url); +} + + + +TQ_INT32 KisView::importImage(const KURL& urlArg) +{ + KisImageSP currentImage = currentImg(); + + if (!currentImage) { + return 0; + } + + KURL::List urls; + TQ_INT32 rc = 0; + + if (urlArg.isEmpty()) { + TQString mimelist = KoFilterManager::mimeFilter("application/x-chalk", KoFilterManager::Import).join(" "); + urls = KFileDialog::getOpenURLs(TQString(), mimelist, 0, i18n("Import Image")); + } else { + urls.push_back(urlArg); + } + + if (urls.empty()) + return 0; + + for (KURL::List::iterator it = urls.begin(); it != urls.end(); ++it) { + new KisImportCatcher( *it, currentImage ); + } + + updateCanvas(); + + return rc; +} + +void KisView::rotateLayer180() +{ + rotateLayer( M_PI ); +} + +void KisView::rotateLayerLeft90() +{ + rotateLayer( M_PI/2 - 2*M_PI ); +} + +void KisView::rotateLayerRight90() +{ + rotateLayer( M_PI/2 ); +} + +void KisView::mirrorLayerX() +{ + if (!currentImg()) return; + KisPaintDeviceSP dev = currentImg()->activeDevice(); + if (!dev) return; + + KisTransaction * t = 0; + if (undoAdapter() && undoAdapter()->undo()) { + t = new KisTransaction(i18n("Mirror Layer X"), dev); + Q_CHECK_PTR(t); + } + + dev->mirrorX(); + + if (t) undoAdapter()->addCommand(t); + + m_doc->setModified(true); + layersUpdated(); + updateCanvas(); +} + +void KisView::mirrorLayerY() +{ + if (!currentImg()) return; + KisPaintDeviceSP dev = currentImg()->activeDevice(); + if (!dev) return; + + KisTransaction * t = 0; + if (undoAdapter() && undoAdapter()->undo()) { + t = new KisTransaction(i18n("Mirror Layer Y"), dev); + Q_CHECK_PTR(t); + } + + dev->mirrorY(); + + if (t) undoAdapter()->addCommand(t); + + m_doc->setModified(true); + layersUpdated(); + updateCanvas(); +} + +void KisView::scaleLayer(double sx, double sy, KisFilterStrategy *filterStrategy) +{ + if (!currentImg()) return; + + KisPaintDeviceSP dev = currentImg()->activeDevice(); + if (!dev) return; + + KisSelectedTransaction * t = 0; + if (undoAdapter() && undoAdapter()->undo()) { + t = new KisSelectedTransaction(i18n("Scale Layer"), dev); + Q_CHECK_PTR(t); + } + + KisTransformWorker worker(dev, sx, sy, 0, 0, 0.0, 0, 0, m_progress, filterStrategy); + worker.run(); + + if (t) undoAdapter()->addCommand(t); + currentImg()->rootLayer()->setDirty(false); + m_doc->setModified(true); + layersUpdated(); + updateCanvas(); +} + +void KisView::rotateLayer(double radians) +{ + if (!currentImg()) return; + + KisPaintDeviceSP dev = currentImg()->activeDevice(); + if (!dev) return; + + KisSelectedTransaction * t = 0; + if (undoAdapter() && undoAdapter()->undo()) { + t = new KisSelectedTransaction(i18n("Rotate Layer"), dev); + Q_CHECK_PTR(t); + } + + KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->get(KisID("Triangle")); + TQRect r; + if(dev->hasSelection()) + r = dev->selection()->selectedExactRect(); + else + r = dev->exactBounds(); + double cx = r.x()+r.width()/2.0; + double cy = r.y()+r.height()/2.0; + TQ_INT32 tx = TQ_INT32(cx*cos(radians) - cy*sin(radians) - cx + 0.5); + TQ_INT32 ty = TQ_INT32(cy*cos(radians) + cx*sin(radians) - cy + 0.5); + + KisTransformWorker tw(dev, 1.0, 1.0, 0, 0, radians, -tx, -ty, m_progress, filter); + tw.run(); + + if (t) undoAdapter()->addCommand(t); + + m_doc->setModified(true); + layersUpdated(); + updateCanvas(); +} + +void KisView::shearLayer(double angleX, double angleY) +{ + if (!currentImg()) return; + + KisLayerSP layer = currentImg()->activeLayer(); + if (!layer) return; + + KisUndoAdapter * undo = 0; + if ((undo = currentImg()->undoAdapter())) { + undo->beginMacro(i18n("Shear layer")); + } + + KisShearVisitor v(angleX, angleY, m_progress); + v.setUndoAdapter(undo); + layer->accept(v); + + if (undo) undo->endMacro(); + + m_doc->setModified(true); + layersUpdated(); + updateCanvas(); +} + +void KisView::flattenImage() +{ + KisImageSP img = currentImg(); + + if (img) { + bool doIt = true; + + if (img->nHiddenLayers() > 0) { + int answer = KMessageBox::warningYesNo(this, + i18n("The image contains hidden layers that will be lost."), + i18n("Flatten Image"), + i18n("&Flatten Image"), + KStdGuiItem::cancel()); + + if (answer != KMessageBox::Yes) { + doIt = false; + } + } + + if (doIt) { + img->flatten(); + } + } +} + +void KisView::mergeLayer() +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + img->mergeLayer(layer); +} + +void KisView::preferences() +{ +#ifdef HAVE_GL + bool canvasWasOpenGL = m_canvas->isOpenGLCanvas(); +#endif + + if (PreferencesDialog::editPreferences()) + { + KisConfig cfg; + m_paletteManager->slotResetFont(); + resetMonitorProfile(); + +#ifdef HAVE_GL + if (cfg.useOpenGL() != canvasWasOpenGL) { + + disconnectCurrentImg(); + + //XXX: Need to notify other views that this global setting has changed. + if (cfg.useOpenGL()) { + m_OpenGLImageContext = KisOpenGLImageContext::getImageContext(m_image, monitorProfile()); + m_canvas->createOpenGLCanvas(m_OpenGLImageContext->sharedContextWidget()); + } else + { + m_OpenGLImageContext = 0; + m_canvas->createTQPaintDeviceCanvas(); + } + + connectCurrentImg(); + + resizeEvent(0); + } + + if (cfg.useOpenGL()) { + m_OpenGLImageContext->setMonitorProfile(monitorProfile()); + } +#endif + + refreshKisCanvas(); + + if (m_toolManager->currentTool()) { + setCanvasCursor(m_toolManager->currentTool()->cursor()); + } + +#if defined(EXTENDED_X11_TABLET_SUPPORT) + m_canvas->selectTabletDeviceEvents(); +#endif + + } +} + +void KisView::layerCompositeOp(const KisCompositeOp& compositeOp) +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + if (img->undo()) { + KNamedCommand *cmd = layer->setCompositeOpCommand(compositeOp); + cmd->execute(); + undoAdapter()->addCommand(cmd); + } +} + +// range: 0 - 100 +void KisView::layerOpacity(int opacity, bool dontundo) +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + opacity = int(float(opacity * 255) / 100 + 0.5); + if (opacity > 255) + opacity = 255; + + if (opacity == layer->opacity()) return; + + if (dontundo) + layer->setOpacity( opacity ); + else + { + if (img->undo()) { + KNamedCommand *cmd = layer->setOpacityCommand(opacity); + cmd->execute(); + undoAdapter()->addCommand(cmd); + } + } +} + +void KisView::layerOpacityFinishedChanging( int previous, int opacity ) +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + opacity = int(float(opacity * 255) / 100 + 0.5); + if (opacity > 255) + opacity = 255; + + previous = int(float(previous * 255) / 100 + 0.5); + if (previous > 255) + previous = 255; + + if (previous == opacity) return; + + if (img->undo()) { + KNamedCommand *cmd = layer->setOpacityCommand(previous, opacity); + m_adapter->addCommand(cmd); + } +} + + +void KisView::showRuler() +{ + if( m_RulerAction->isChecked() ) + { + m_hRuler->show(); + m_vRuler->show(); + } + else + { + m_hRuler->hide(); + m_vRuler->hide(); + } + + resizeEvent(0); + refreshKisCanvas(); +} + +void KisView::slotUpdateFullScreen(bool toggle) +{ + if (KoView::shell()) { + + uint newState = KoView::shell()->windowState(); + + if (toggle) { + newState |= TQt::WindowFullScreen; + } else { + newState &= ~TQt::WindowFullScreen; + } + + KoView::shell()->setWindowState(newState); + } +} + +TQ_INT32 KisView::docWidth() const +{ + return currentImg() ? currentImg()->width() : 0; +} + +TQ_INT32 KisView::docHeight() const +{ + return currentImg() ? currentImg()->height() : 0; +} + +void KisView::scrollTo(TQ_INT32 x, TQ_INT32 y) +{ + if (m_hScroll->isVisible()) { + m_hScroll->setValue(x); + } + if (m_vScroll->isVisible()) { + m_vScroll->setValue(y); + } +} + +void KisView::brushActivated(KisResource *brush) +{ + + m_brush = dynamic_cast(brush); + + if (m_brush ) + { + emit brushChanged(m_brush); + notifyObservers(); + } +} + +void KisView::patternActivated(KisResource *pattern) +{ + m_pattern = dynamic_cast(pattern); + + if (m_pattern) { + emit patternChanged(m_pattern); + notifyObservers(); + } +} + +void KisView::gradientActivated(KisResource *gradient) +{ + + m_gradient = dynamic_cast(gradient); + + if (m_gradient) { + emit gradientChanged(m_gradient); + notifyObservers(); + } +} + +void KisView::paintopActivated(const KisID & paintop, const KisPaintOpSettings *paintopSettings) +{ + if (paintop.id().isNull() || paintop.id().isEmpty()) { + return; + } + + m_paintop = paintop; + m_paintopSettings = paintopSettings; + emit paintopChanged(m_paintop, paintopSettings); + notifyObservers(); +} + +void KisView::setBGColor(const KisColor& c) +{ + m_bg = c; + notifyObservers(); + emit sigBGQColorChanged( c.toTQColor() ); +} + +void KisView::setFGColor(const KisColor& c) +{ + m_fg = c; + notifyObservers(); + emit sigFGQColorChanged( c.toTQColor() ); +} + +void KisView::slotSetFGColor(const KisColor& c) +{ + + m_fg = c; + notifyObservers(); +} + +void KisView::slotSetBGColor(const KisColor& c) +{ + + m_bg = c; + notifyObservers(); +} + +void KisView::slotSetFGQColor(const TQColor& c) +{ + KisColorSpace * monitorSpace = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA"), m_monitorProfile); + setFGColor(KisColor(c, monitorSpace)); + emit sigFGQColorChanged(c); +} + +void KisView::slotSetBGQColor(const TQColor& c) +{ + KisColorSpace * monitorSpace = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA"), m_monitorProfile); + setBGColor(KisColor(c, monitorSpace)); + emit sigBGQColorChanged(c); +} + + +void KisView::setupPrinter(KPrinter& printer) +{ + KisImageSP img = currentImg(); + + if (img) { + printer.setPageSelection(KPrinter::ApplicationSide); + printer.setPageSize(KPrinter::A4); + printer.setOrientation(KPrinter::Portrait); + } +} + +void KisView::print(KPrinter& printer) +{ + TQPainter gc(&printer); + + KisImageSP img = currentImg(); + if (!img) return; + + printer.setFullPage(true); + gc.setClipping(false); + + KisConfig cfg; + TQString printerProfileName = cfg.printerProfile(); + KisProfile * printerProfile = KisMetaRegistry::instance()->csRegistry() ->getProfileByName(printerProfileName); + + TQRect r = img->bounds(); + img->renderToPainter(r.x(), r.y(), r.width(), r.height(), gc, printerProfile, KisImage::PAINT_IMAGE_ONLY, HDRExposure()); +} + +void KisView::paintToolOverlay(const TQRegion& region) +{ + if (!region.isEmpty() && m_toolManager->currentTool() && !m_toolIsPainting) { + KisCanvasPainter gc(m_canvas); + + gc.setClipRegion(region); + gc.setClipping(true); + + // Prevent endless loop if the tool needs to have the canvas tqrepainted + m_toolIsPainting = true; + m_toolManager->currentTool()->paint(gc, region.boundingRect()); + m_toolIsPainting = false; + } +} + +void KisView::canvasGotPaintEvent(TQPaintEvent *event) +{ + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(event->rect()); + } else { + paintTQPaintDeviceView(event->region()); + } +} + +void KisView::canvasGotButtonPressEvent(KisButtonPressEvent *e) +{ +#if defined(EXTENDED_X11_TABLET_SUPPORT) + // The event filter doesn't see tablet events going to the canvas. + if (e->device() != KisInputDevice::mouse()) { + m_tabletEventTimer.start(); + } +#endif // EXTENDED_X11_TABLET_SUPPORT + + if (e->device() != currentInputDevice()) { + if (e->device() == KisInputDevice::mouse()) { + if (m_tabletEventTimer.elapsed() > MOUSE_CHANGE_EVENT_DELAY) { + setInputDevice(KisInputDevice::mouse()); + } + } else { + setInputDevice(e->device()); + } + } + + KisImageSP img = currentImg(); + +// if (img) { +// TQPoint pt = mapToScreen(e->pos().floorTQPoint()); +// KisGuideMgr *mgr = img->guides(); +// +// m_lastGuidePoint = mapToScreen(e->pos().floorTQPoint()); +// m_currentGuide = 0; +// +// if ((e->state() & ~TQt::ShiftButton) == Qt::NoButton) { +// KisGuideSP gd = mgr->tqfind(static_cast(pt.x() / zoom()), static_cast(pt.y() / zoom()), TQMAX(2.0, 2.0 / zoom())); +// +// if (gd) { +// m_currentGuide = gd; +// +// if ((e->button() == Qt::RightButton) || ((e->button() & TQt::ShiftButton) == TQt::ShiftButton)) { +// if (gd->isSelected()) +// mgr->unselect(gd); +// else +// mgr->select(gd); +// } else { +// if (!gd->isSelected()) { +// mgr->unselectAll(); +// mgr->select(gd); +// } +// } +// +// updateGuides(); +// return; +// } +// } +// } + if (e->button() == Qt::RightButton) { + TQPopupMenu * m_popup = 0; + if (factory()) { + Q_ASSERT(factory()); + m_popup = (TQPopupMenu *)factory()->container("image_popup", this); + } + if (m_popup) { + m_popup->popup(e->globalPos().roundTQPoint()); + } + } + else if (e->device() == currentInputDevice() && m_toolManager->currentTool()) { + KisPoint p = viewToWindow(e->pos()); + // somewhat of a hack: we should actually test if we intersect with the scrollers, + // but the globalPos seems to be off by a few pixels + if (m_vScroll->draggingSlider() || m_hScroll->draggingSlider()) + return; + + if (m_toolManager->currentTool()->wantsAutoScroll()) { + enableAutoScroll(); + } + + KisButtonPressEvent ev(e->device(), p, e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->button(), e->state()); + m_toolManager->currentTool()->buttonPress(&ev); + } +} + +void KisView::canvasGotMoveEvent(KisMoveEvent *e) +{ +#if defined(EXTENDED_X11_TABLET_SUPPORT) + // The event filter doesn't see tablet events going to the canvas. + if (e->device() != KisInputDevice::mouse()) { + m_tabletEventTimer.start(); + } +#endif // EXTENDED_X11_TABLET_SUPPORT + + if (e->device() != currentInputDevice()) { + if (e->device() == KisInputDevice::mouse()) { + if (m_tabletEventTimer.elapsed() > MOUSE_CHANGE_EVENT_DELAY) { + setInputDevice(KisInputDevice::mouse()); + } + } else { + setInputDevice(e->device()); + } + } + + KisImageSP img = currentImg(); + + m_hRuler->updatePointer(e->pos().floorX() - m_canvasXOffset, e->pos().floorY() - m_canvasYOffset); + m_vRuler->updatePointer(e->pos().floorX() - m_canvasXOffset, e->pos().floorY() - m_canvasYOffset); + + KisPoint wp = viewToWindow(e->pos()); + +#if 0 + if (img && m_currentGuide) { + TQPoint p = mapToScreen(e->pos().floorTQPoint()); + KisGuideMgr *mgr = img->guides(); + + if (((e->state() & Qt::LeftButton) == Qt::LeftButton) && mgr->hasSelected()) { + eraseGuides(); + p -= m_lastGuidePoint; + + if (p.x()) + mgr->moveSelectedByX(p.x() / zoom()); + + if (p.y()) + mgr->moveSelectedByY(p.y() / zoom()); + + m_doc->setModified(true); + paintGuides(); + } + } else +#endif + if (e->device() == currentInputDevice() && m_toolManager->currentTool()) { + KisMoveEvent ev(e->device(), wp, e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->state()); + + m_toolManager->currentTool()->move(&ev); + } + +// m_lastGuidePoint = mapToScreen(e->pos().floorTQPoint()); + emit cursorPosition(wp.floorX(), wp.floorY()); +} + +int KisView::leftBorder() const +{ + return m_rulerThickness; +} + +int KisView::rightBorder() const +{ + return m_hScrollBarExtent; +} + +int KisView::topBorder() const +{ + return m_rulerThickness; +} + +int KisView::bottomBorder() const +{ + return m_vScrollBarExtent; +} + +void KisView::mouseMoveEvent(TQMouseEvent *e) +{ + KisMoveEvent ke(currentInputDevice(), KisPoint(e->pos()), KisPoint(e->globalPos()), PRESSURE_DEFAULT, 0, 0, e->state()); + canvasGotMoveEvent(&ke); +} + +void KisView::slotAutoScroll(const TQPoint &p) +{ + scrollTo(horzValue()+p.x(), vertValue()+p.y()); +} + +void KisView::canvasGotButtonReleaseEvent(KisButtonReleaseEvent *e) +{ +#if defined(EXTENDED_X11_TABLET_SUPPORT) + // The event filter doesn't see tablet events going to the canvas. + if (e->device() != KisInputDevice::mouse()) { + m_tabletEventTimer.start(); + } +#endif // EXTENDED_X11_TABLET_SUPPORT + + if (e->device() != currentInputDevice()) { + if (e->device() == KisInputDevice::mouse()) { + if (m_tabletEventTimer.elapsed() > MOUSE_CHANGE_EVENT_DELAY) { + setInputDevice(KisInputDevice::mouse()); + } + } else { + setInputDevice(e->device()); + } + } + + KisImageSP img = currentImg(); + +// if (img && m_currentGuide) { +// m_currentGuide = 0; +// } else + if (e->device() == currentInputDevice() && m_toolManager->currentTool()) { + KisPoint p = viewToWindow(e->pos()); + KisButtonReleaseEvent ev(e->device(), p, e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->button(), e->state()); + + disableAutoScroll(); + if (m_toolManager->currentTool()) { + m_toolManager->currentTool()->buttonRelease(&ev); + } + } +} + +void KisView::canvasGotDoubleClickEvent(KisDoubleClickEvent *e) +{ +#if defined(EXTENDED_X11_TABLET_SUPPORT) + // The event filter doesn't see tablet events going to the canvas. + if (e->device() != KisInputDevice::mouse()) { + m_tabletEventTimer.start(); + } +#endif // EXTENDED_X11_TABLET_SUPPORT + + if (e->device() != currentInputDevice()) { + if (e->device() == KisInputDevice::mouse()) { + if (m_tabletEventTimer.elapsed() > MOUSE_CHANGE_EVENT_DELAY) { + setInputDevice(KisInputDevice::mouse()); + } + } else { + setInputDevice(e->device()); + } + } + + if (e->device() == currentInputDevice() && m_toolManager->currentTool()) { + KisPoint p = viewToWindow(e->pos()); + KisDoubleClickEvent ev(e->device(), p, e->globalPos(), e->pressure(), e->xTilt(), e->yTilt(), e->button(), e->state()); + + if (m_toolManager->currentTool()) { + m_toolManager->currentTool()->doubleClick(&ev); + } + } +} + +void KisView::canvasGotEnterEvent(TQEvent *e) +{ + Q_UNUSED( e ); +} + +void KisView::canvasGotLeaveEvent (TQEvent *e) +{ + Q_UNUSED( e ); +} + +void KisView::canvasGotMouseWheelEvent(TQWheelEvent *event) +{ + //if(event->state() == ControlButton ) + //{ + if(event->delta() / 120 != 0) + { + if(event->delta() > 0) + { + zoomIn(); + } else { + zoomOut(); + } + if (m_oldTool) { + KisCanvasPainter gc(m_canvas); + m_oldTool->paint(gc); + } + } + //} else { + // TQApplication::sendEvent(m_vScroll, event); + //} +} + +void KisView::canvasGotKeyPressEvent(TQKeyEvent *event) +{ + if (!m_toolManager->currentTool()) { + event->ignore(); + return; + } + + if (event->key() == TQt::Key_Space) { + if (!m_panning) { + // Set tool temporarily to pan + m_panning = true; + m_oldTool = m_toolManager->currentTool(); + m_toolManager->setCurrentTool( "tool_pan" ); + } + else { + // Unset panning + m_panning = false; + m_toolManager->setCurrentTool( m_oldTool ); + m_oldTool = 0; + } + } + if (m_toolManager->currentTool()) + m_toolManager->currentTool()->keyPress(event); +} + +void KisView::canvasGotKeyReleaseEvent(TQKeyEvent *event) +{ + if (m_toolManager->currentTool()) + m_toolManager->currentTool()->keyRelease(event); +} + +void KisView::canvasGotDragEnterEvent(TQDragEnterEvent *event) +{ + bool accept = false; + + // Only accept drag if we're not busy, particularly as we may + // be showing a progress bar and calling tqApp->processEvents(). + if (KURLDrag::canDecode(event) && TQApplication::overrideCursor() == 0) { + accept = true; + } + + event->accept(accept); +} + +void KisView::canvasGotDropEvent(TQDropEvent *event) +{ + KURL::List urls; + + if (KURLDrag::decode(event, urls)) + { + if (urls.count() > 0) { + enum enumActionId { + addLayerId = 1, + addDocumentId = 2, + cancelId + }; + + KPopupMenu popup(this, "drop_popup"); + + if (urls.count() == 1) { + if (currentImg() != 0) { + popup.insertItem(i18n("Insert as New Layer"), addLayerId); + } + popup.insertItem(i18n("Open in New Document"), addDocumentId); + } + else { + if (currentImg() != 0) { + popup.insertItem(i18n("Insert as New Layers"), addLayerId); + } + popup.insertItem(i18n("Open in New Documents"), addDocumentId); + } + + popup.insertSeparator(); + popup.insertItem(i18n("Cancel"), cancelId); + + int actionId = popup.exec(TQCursor::pos()); + + if (actionId >= 0 && actionId != cancelId) { + for (KURL::List::ConstIterator it = urls.begin (); it != urls.end (); ++it) { + KURL url = *it; + + switch (actionId) { + case addLayerId: + importImage(url); + break; + case addDocumentId: + if (shell() != 0) { + shell()->openDocument(url); + } + break; + } + } + } + } + } +} + +void KisView::layerProperties() +{ + if (currentImg() && currentImg()->activeLayer()) + showLayerProperties(currentImg()->activeLayer()); +} + +namespace { + class KisChangeFilterCmd : public KNamedCommand { + typedef KNamedCommand super; + + public: + // The TQStrings are the _serialized_ configs + KisChangeFilterCmd(KisAdjustmentLayerSP layer, + KisFilterConfiguration* config, + const TQString& before, + const TQString& after) : super(i18n("Change Filter")) + { + m_layer = layer; + m_config = config; + m_before = before; + m_after = after; + } + public: + virtual void execute() + { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + m_config->fromXML(m_after); + //Q_ASSERT(m_after == m_config->toString()); + m_layer->setFilter(m_config); + m_layer->setDirty(); + TQApplication::restoreOverrideCursor(); + } + + virtual void unexecute() + { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + m_config->fromXML(m_before); + //Q_ASSERT(m_before == m_config->toString()); + m_layer->setFilter(m_config); + m_layer->setDirty(); + TQApplication::restoreOverrideCursor(); + } + private: + KisAdjustmentLayerSP m_layer; + KisFilterConfiguration* m_config; + TQString m_before; + TQString m_after; + }; +} + +void KisView::showLayerProperties(KisLayerSP layer) +{ + Q_ASSERT( layer ); + if ( !layer ) return; + + KisColorSpace * cs = 0; + KisPaintLayer * pl = dynamic_cast( layer.data() ); + if ( pl ) { + cs = pl->paintDevice()->colorSpace(); + } + else { + cs = layer->image()->colorSpace(); + } + + + if (KisAdjustmentLayerSP alayer = dynamic_cast(layer.data())) + { + KisDlgAdjLayerProps dlg(alayer, alayer->name(), i18n("Adjustment Layer Properties"), this, "dlgadjlayerprops"); + TQString before = dlg.filterConfiguration()->toString(); + if (dlg.exec() == TQDialog::Accepted) + { + KisChangeFilterCmd * cmd = new KisChangeFilterCmd(alayer, + dlg.filterConfiguration(), + before, + dlg.filterConfiguration()->toString()); + cmd->execute(); + m_adapter->addCommand(cmd); + m_doc->setModified( true ); + } + } + else + { + KisDlgLayerProperties dlg(layer->name(), + layer->opacity(), + layer->compositeOp(), + cs); + if (dlg.exec() == TQDialog::Accepted) + { + if (layer->name() != dlg.getName() || + layer->opacity() != dlg.getOpacity() || + layer->compositeOp() != dlg.getCompositeOp()) + { + TQApplication::setOverrideCursor(KisCursor::waitCursor()); + m_adapter->beginMacro(i18n("Property Changes")); + layer->image()->setLayerProperties(layer, dlg.getOpacity(), dlg.getCompositeOp(), dlg.getName()); + layer->setDirty(); + m_adapter->endMacro(); + TQApplication::restoreOverrideCursor(); + m_doc->setModified( true ); + } + } + } +} + +void KisView::layerAdd() +{ + KisImageSP img = currentImg(); + if (img && img->activeLayer()) { + addLayer(img->activeLayer()->tqparent(), img->activeLayer()); + } + else if (img) + addLayer(static_cast(img->rootLayer().data()), 0); +} + +void KisView::addLayer(KisGroupLayerSP tqparent, KisLayerSP above) +{ + KisImageSP img = currentImg(); + if (img) { + KisConfig cfg; + TQString profilename; + if(img->colorSpace()->getProfile()) + profilename = img->colorSpace()->getProfile()->productName(); + NewLayerDialog dlg(img->colorSpace()->id(), profilename, img->nextLayerName(), this); + + if (dlg.exec() == TQDialog::Accepted) { + KisColorSpace* cs = KisMetaRegistry::instance()-> csRegistry() -> + getColorSpace(dlg.colorSpaceID(),dlg.profileName()); + KisLayerSP layer = new KisPaintLayer(img, dlg.layerName(), dlg.opacity(), cs); + if (layer) { + layer->setCompositeOp(dlg.compositeOp()); + img->addLayer(layer, tqparent.data(), above); + updateCanvas(); + } else { + KMessageBox::error(this, i18n("Could not add layer to image."), i18n("Layer Error")); + } + } + else { + img->rollBackLayerName(); + } + } +} + +void KisView::addGroupLayer(KisGroupLayerSP tqparent, KisLayerSP above) +{ + KisImageSP img = currentImg(); + if (img) { + TQString profilename; + if(img->colorSpace()->getProfile()) + profilename = img->colorSpace()->getProfile()->productName(); + KisConfig cfg; + NewLayerDialog dlg(img->colorSpace()->id(), profilename, img->nextLayerName(), this); + dlg.setColorSpaceEnabled(false); + + if (dlg.exec() == TQDialog::Accepted) { + KisLayerSP layer = new KisGroupLayer(img, dlg.layerName(), dlg.opacity()); + if (layer) { + layer->setCompositeOp(dlg.compositeOp()); + img->addLayer(layer, tqparent.data(), above); + updateCanvas(); + } else { + KMessageBox::error(this, i18n("Could not add layer to image."), i18n("Layer Error")); + } + } + } +} + +void KisView::addPartLayer() +{ + KisImageSP img = currentImg(); + if (!img) return; + + addPartLayer(img->rootLayer(), img->rootLayer()->firstChild(), m_actionPartLayer->documentEntry()); +} + +void KisView::addPartLayer(KisGroupLayerSP tqparent, KisLayerSP above, const KoDocumentEntry& entry) +{ + delete m_partHandler; // Only one at a time + m_partHandler = new KisPartLayerHandler(this, entry, tqparent, above); + + disconnect(m_canvas, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), this, 0); + disconnect(m_canvas, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), this, 0); + disconnect(m_canvas, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent*)), this, 0); + disconnect(m_canvas, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), this, 0); + + connect(m_canvas, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), + m_partHandler, TQT_SLOT(gotButtonPressEvent(KisButtonPressEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), + m_partHandler, TQT_SLOT(gotButtonReleaseEvent(KisButtonReleaseEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + m_partHandler, TQT_SLOT(gotMoveEvent(KisMoveEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), + m_partHandler, TQT_SLOT(gotKeyPressEvent(TQKeyEvent*))); + + connect(m_partHandler, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotMoveEvent(KisMoveEvent*))); + connect(m_partHandler, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotKeyPressEvent(TQKeyEvent*))); + connect(m_partHandler, TQT_SIGNAL(handlerDone()), + TQT_TQOBJECT(this), TQT_SLOT(reconnectAfterPartInsert())); +} + +void KisView::insertPart(const TQRect& viewRect, const KoDocumentEntry& entry, + KisGroupLayerSP tqparent, KisLayerSP above) { + KisImageSP img = currentImg(); + if (!img) return; + + KoDocument* doc = entry.createDoc(m_doc); + if ( !doc ) + return; + + if ( !doc->showEmbedInitDialog(this) ) + return; + + TQRect rect = viewToWindow(viewRect); + + KisChildDoc * childDoc = m_doc->createChildDoc(rect, doc); + + KisPartLayerImpl* partLayer = new KisPartLayerImpl(img, childDoc); + partLayer->setDocType(entry.service()->genericName()); + img->addLayer(partLayer, tqparent, above); + m_doc->setModified(true); + + reconnectAfterPartInsert(); +} + +void KisView::reconnectAfterPartInsert() { + connect(m_canvas, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotButtonPressEvent(KisButtonPressEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotButtonReleaseEvent(KisButtonReleaseEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotMoveEvent(KisMoveEvent*))); + connect(m_canvas, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), + TQT_TQOBJECT(this), TQT_SLOT(canvasGotKeyPressEvent(TQKeyEvent*))); + + delete m_partHandler; + m_partHandler = 0; +} + +void KisView::addAdjustmentLayer() +{ + KisImageSP img = currentImg(); + if (!img) return; + + addAdjustmentLayer( img->activeLayer()->tqparent(), img->activeLayer() ); +} + +void KisView::addAdjustmentLayer(KisGroupLayerSP tqparent, KisLayerSP above) +{ + Q_ASSERT(tqparent); + Q_ASSERT(above); + + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP l = img->activeLayer(); + + KisPaintDeviceSP dev; + + // Argh! I hate having to cast, cast and cast again to see what kind of a layer I've got! + KisPaintLayer * pl = dynamic_cast(l.data()); + if (pl) { + dev = pl->paintDevice(); + } + else { + KisGroupLayer * gl = dynamic_cast(l.data()); + if (gl) { + dev = gl->projection(img->bounds()); + } + else { + KisAdjustmentLayer * al = dynamic_cast(l.data()); + if (al) { + dev = al->cachedPaintDevice(); + } + else { + return; + } + } + } + + KisDlgAdjustmentLayer dlg(img, img->nextLayerName(), i18n("New Adjustment Layer"), this, "dlgadjustmentlayer"); + if (dlg.exec() == TQDialog::Accepted) { + KisSelectionSP selection = 0; + if (dev->hasSelection()) { + selection = dev->selection(); + } + KisFilterConfiguration * filter = dlg.filterConfiguration(); + TQString name = dlg.layerName(); + + addAdjustmentLayer( tqparent, above, name, filter, selection); + + } +} + +void KisView::addAdjustmentLayer(KisGroupLayerSP tqparent, KisLayerSP above, const TQString & name, + KisFilterConfiguration * filter, KisSelectionSP selection) +{ + Q_ASSERT(tqparent); + Q_ASSERT(above); + Q_ASSERT(filter); + + KisImageSP img = currentImg(); + if (!img) return; + + KisAdjustmentLayer * l = new KisAdjustmentLayer(img, name, filter, selection); + img->addLayer(l, tqparent, above); +} + +void KisView::slotChildActivated(bool a) { + // It should be so that the only part (child) we can activate, is the current layer: + if (currentImg() && currentImg()->activeLayer()) + { + if (a) { + currentImg()->activeLayer()->activate(); + } else { + currentImg()->activeLayer()->deactivate(); + } + } + + super::slotChildActivated(a); +} + +void KisView::layerRemove() +{ + KisImageSP img = currentImg(); + + if (img) { + KisLayerSP layer = img->activeLayer(); + + if (layer) { + + + img->removeLayer(layer); + + if (layer->tqparent()) + layer->tqparent()->setDirty(layer->extent()); + + updateCanvas(); + layerUpdateGUI(img->activeLayer() != 0); + } + } +} + +void KisView::layerDuplicate() +{ + KisImageSP img = currentImg(); + + if (!img) + return; + + KisLayerSP active = img->activeLayer(); + + if (!active) + return; + + KisLayerSP dup = active->clone(); + dup->setName(i18n("Duplicate of '%1'").tqarg(active->name())); + img->addLayer(dup, active->tqparent().data(), active); + if (dup) { + img->activate( dup ); + updateCanvas(); + } else { + KMessageBox::error(this, i18n("Could not add layer to image."), i18n("Layer Error")); + } +} + +void KisView::layerRaise() +{ + KisImageSP img = currentImg(); + KisLayerSP layer; + + if (!img) + return; + + layer = img->activeLayer(); + + img->raiseLayer(layer); +} + +void KisView::layerLower() +{ + KisImageSP img = currentImg(); + KisLayerSP layer; + + if (!img) + return; + + layer = img->activeLayer(); + + img->lowerLayer(layer); +} + +void KisView::layerFront() +{ + KisImageSP img = currentImg(); + KisLayerSP layer; + + if (!img) + return; + + layer = img->activeLayer(); + img->toTop(layer); +} + +void KisView::layerBack() +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer; + + layer = img->activeLayer(); + img->toBottom(layer); +} + +void KisView::layersUpdated() +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + + layerUpdateGUI(img && layer); + + notifyObservers(); +} + +void KisView::layerToggleVisible() +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + layer->setVisible(!layer->visible()); +} + +void KisView::layerToggleLocked() +{ + KisImageSP img = currentImg(); + if (!img) return; + + KisLayerSP layer = img->activeLayer(); + if (!layer) return; + + layer->setLocked(!layer->locked()); +} + +void KisView::actLayerVisChanged(int show) +{ + m_actLayerVis = (show != 0); +} + +bool KisView::activeLayerHasSelection() +{ + return m_image && m_image->activeDevice() && m_image->activeDevice()->hasSelection(); +} + +void KisView::scrollH(int value) +{ + m_hRuler->updateVisibleArea(value, 0); + + int xShift = m_scrollX - value; + m_scrollX = value; + + if (m_canvas->isUpdatesEnabled()) { + if (xShift > 0) { + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + TQRect drawRect(0, 0, xShift, m_canvasPixmap.height()); + + bitBlt(&m_canvasPixmap, xShift, 0, &m_canvasPixmap, 0, 0, m_canvasPixmap.width() - xShift, m_canvasPixmap.height()); + + updateTQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->tqrepaint(); + } + } else if (xShift < 0) { + + TQRect drawRect(m_canvasPixmap.width() + xShift, 0, -xShift, m_canvasPixmap.height()); + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + bitBlt(&m_canvasPixmap, 0, 0, &m_canvasPixmap, -xShift, 0, m_canvasPixmap.width() + xShift, m_canvasPixmap.height()); + + updateTQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->tqrepaint(); + } + } + if (m_oldTool) { + KisCanvasPainter gc(m_canvas); + m_oldTool->paint(gc); + } + } + + if (xShift != 0) { + // XXX do sth with the childframe or so + } + emit viewTransformationsChanged(); +} + +void KisView::scrollV(int value) +{ + m_vRuler->updateVisibleArea(0, value); + + int yShift = m_scrollY - value; + m_scrollY = value; + + if (m_canvas->isUpdatesEnabled()) { + if (yShift > 0) { + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + TQRect drawRect(0, 0, m_canvasPixmap.width(), yShift); + + bitBlt(&m_canvasPixmap, 0, yShift, &m_canvasPixmap, 0, 0, m_canvasPixmap.width(), m_canvasPixmap.height() - yShift); + + updateTQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->tqrepaint(); + } + } else if (yShift < 0) { + + if (m_canvas->isOpenGLCanvas()) { + paintOpenGLView(TQRect(0, 0, m_canvas->width(), m_canvas->height())); + } else { + TQRect drawRect(0, m_canvasPixmap.height() + yShift, m_canvasPixmap.width(), -yShift); + + bitBlt(&m_canvasPixmap, 0, 0, &m_canvasPixmap, 0, -yShift, m_canvasPixmap.width(), m_canvasPixmap.height() + yShift); + + updateTQPaintDeviceCanvas(viewToWindow(drawRect)); + m_canvas->tqrepaint(); + } + } + if (m_oldTool) { + KisCanvasPainter gc(m_canvas); + m_oldTool->paint(gc); + } + } + + if (yShift != 0) { + // XXX do sth with the childframe or so + } + emit viewTransformationsChanged(); +} + +void KisView::setupCanvas() +{ + m_canvas = new KisCanvas(this, "kis_canvas"); + m_canvas->setFocusPolicy( TQ_StrongFocus ); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotButtonPressEvent(KisButtonPressEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotButtonPressEvent(KisButtonPressEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotButtonReleaseEvent(KisButtonReleaseEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotButtonReleaseEvent(KisButtonReleaseEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotDoubleClickEvent(KisDoubleClickEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotDoubleClickEvent(KisDoubleClickEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotMoveEvent(KisMoveEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotMoveEvent(KisMoveEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotPaintEvent(TQPaintEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotPaintEvent(TQPaintEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotEnterEvent(TQEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotEnterEvent(TQEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotLeaveEvent(TQEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotLeaveEvent(TQEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotMouseWheelEvent(TQWheelEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotMouseWheelEvent(TQWheelEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotKeyPressEvent(TQKeyEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotKeyPressEvent(TQKeyEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotKeyReleaseEvent(TQKeyEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotKeyReleaseEvent(TQKeyEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotDragEnterEvent(TQDragEnterEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotDragEnterEvent(TQDragEnterEvent*))); + TQObject::connect(m_canvas, TQT_SIGNAL(sigGotDropEvent(TQDropEvent*)), TQT_TQOBJECT(this), TQT_SLOT(canvasGotDropEvent(TQDropEvent*))); +} + +void KisView::connectCurrentImg() +{ + if (m_image) { + connect(m_image, TQT_SIGNAL(sigActiveSelectionChanged(KisImageSP)), m_selectionManager, TQT_SLOT(imgSelectionChanged(KisImageSP))); + connect(m_image, TQT_SIGNAL(sigActiveSelectionChanged(KisImageSP)), TQT_TQOBJECT(this), TQT_SLOT(updateCanvas())); + connect(m_image, TQT_SIGNAL(sigColorSpaceChanged(KisColorSpace *)), TQT_TQOBJECT(this), TQT_SLOT(updateStatusBarProfileLabel())); + connect(m_image, TQT_SIGNAL(sigProfileChanged(KisProfile * )), TQT_SLOT(profileChanged(KisProfile * ))); + + connect(m_image, TQT_SIGNAL(sigLayersChanged(KisGroupLayerSP)), TQT_SLOT(layersUpdated())); + connect(m_image, TQT_SIGNAL(sigMaskInfoChanged()), TQT_SLOT(tqmaskUpdated())); + connect(m_image, TQT_SIGNAL(sigLayerAdded(KisLayerSP)), TQT_SLOT(layersUpdated())); + connect(m_image, TQT_SIGNAL(sigLayerRemoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), TQT_SLOT(layersUpdated())); + connect(m_image, TQT_SIGNAL(sigLayerMoved(KisLayerSP, KisGroupLayerSP, KisLayerSP)), TQT_SLOT(layersUpdated())); + connect(m_image, TQT_SIGNAL(sigLayerActivated(KisLayerSP)), TQT_SLOT(layersUpdated())); + connect(m_image, TQT_SIGNAL(sigLayerActivated(KisLayerSP)), TQT_SLOT(updateCanvas())); + connect(m_image, TQT_SIGNAL(sigLayerPropertiesChanged(KisLayerSP)), TQT_SLOT(layersUpdated())); + + KisConnectPartLayerVisitor v(m_image, this, true); + m_image->rootLayer()->accept(v); + connect(m_image, TQT_SIGNAL(sigLayerAdded(KisLayerSP)), + TQT_SLOT(handlePartLayerAdded(KisLayerSP))); + + tqmaskUpdated(); +#ifdef HAVE_GL + if (m_OpenGLImageContext != 0) { + connect(m_OpenGLImageContext, TQT_SIGNAL(sigImageUpdated(TQRect)), TQT_SLOT(slotOpenGLImageUpdated(TQRect))); + connect(m_OpenGLImageContext, TQT_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)), TQT_SLOT(slotImageSizeChanged(TQ_INT32, TQ_INT32))); + } else +#endif + { + connect(m_image, TQT_SIGNAL(sigImageUpdated(TQRect)), TQT_SLOT(imgUpdated(TQRect))); + connect(m_image, TQT_SIGNAL(sigSizeChanged(TQ_INT32, TQ_INT32)), TQT_SLOT(slotImageSizeChanged(TQ_INT32, TQ_INT32))); + } + } + + m_layerBox->setImage(m_image); + m_birdEyeBox->setImage(m_image); +} + +void KisView::disconnectCurrentImg() +{ + if (m_image) { + m_image->disconnect(this); + m_layerBox->setImage(0); + m_birdEyeBox->setImage(0); + + KisConnectPartLayerVisitor v(m_image, this, false); + m_image->rootLayer()->accept(v); + } + +#ifdef HAVE_GL + if (m_OpenGLImageContext != 0) { + m_OpenGLImageContext->disconnect(this); + } +#endif +} + +void KisView::handlePartLayerAdded(KisLayerSP layer) +{ + KisPartLayer* l = dynamic_cast(layer.data()); + if (!l) + return; + + connect(TQT_TQOBJECT(this), TQT_SIGNAL(childActivated(KoDocumentChild*)), + layer, TQT_SLOT(childActivated(KoDocumentChild*))); +} + +void KisView::imgUpdated(TQRect rc) +{ + updateCanvas(rc); +} + +void KisView::slotOpenGLImageUpdated(TQRect rc) +{ + paintOpenGLView(windowToView(rc)); +} + +void KisView::profileChanged(KisProfile * /*profile*/) +{ + updateStatusBarProfileLabel(); +} + +void KisView::slotImageSizeChanged(TQ_INT32 /*w*/, TQ_INT32 /*h*/) +{ + resizeEvent(0); + refreshKisCanvas(); +} + +void KisView::resizeCurrentImage(TQ_INT32 w, TQ_INT32 h, bool cropLayers) +{ + if (!currentImg()) return; + + currentImg()->resize(w, h, cropLayers); + m_doc->setModified(true); + layersUpdated(); +} + +void KisView::scaleCurrentImage(double sx, double sy, KisFilterStrategy *filterStrategy) +{ + if (!currentImg()) return; + currentImg()->scale(sx, sy, m_progress, filterStrategy); + m_doc->setModified(true); + layersUpdated(); +} + +void KisView::rotateCurrentImage(double radians) +{ + if (!currentImg()) return; + currentImg()->rotate(radians, m_progress); + m_doc->setModified(true); + layersUpdated(); +} + +void KisView::shearCurrentImage(double angleX, double angleY) +{ + if (!currentImg()) return; + currentImg()->shear(angleX, angleY, m_progress); + m_doc->setModified(true); + layersUpdated(); +} + + +TQPoint KisView::viewToWindow(const TQPoint& pt) +{ + TQPoint converted; + + converted.rx() = static_cast((pt.x() + horzValue()) / zoom()); + converted.ry() = static_cast((pt.y() + vertValue()) / zoom()); + + return converted; +} + +TQPoint KisView::viewToWindow(const TQPoint& pt) const +{ + TQPoint converted; + + converted.rx() = static_cast((pt.x() + horzValue()) / zoom()); + converted.ry() = static_cast((pt.y() + vertValue()) / zoom()); + + return converted; +} + +KisPoint KisView::viewToWindow(const KisPoint& pt) +{ + KisPoint converted; + + converted.setX((pt.x() + horzValue()) / zoom()); + converted.setY((pt.y() + vertValue()) / zoom()); + + return converted; +} + +TQRect KisView::viewToWindow(const TQRect& rc) +{ + TQRect r; + + r.setTopLeft(viewToWindow(rc.topLeft())); + r.setRight((int)(ceil((rc.right() + 1.0 + horzValue()) / zoom()) - 1)); + r.setBottom((int)(ceil((rc.bottom() + 1.0 + vertValue()) / zoom()) - 1)); + + return r; +} + +KisRect KisView::viewToWindow(const KisRect& rc) +{ + KisRect r; + KisPoint p = viewToWindow(KisPoint(rc.x(), rc.y())); + r.setX(p.x()); + r.setY(p.y()); + r.setWidth(rc.width() / zoom()); + r.setHeight(rc.height() / zoom()); + + return r; +} + +void KisView::viewToWindow(TQ_INT32 *x, TQ_INT32 *y) +{ + if (x && y) { + TQPoint p = viewToWindow(TQPoint(*x, *y)); + *x = p.x(); + *y = p.y(); + } +} + +TQPoint KisView::windowToView(const TQPoint& pt) +{ + TQPoint p; + p.setX(static_cast(pt.x() * zoom() - horzValue())); + p.setY(static_cast(pt.y() * zoom() - vertValue())); + + return p; +} + +TQPoint KisView::windowToView(const TQPoint& pt) const +{ + TQPoint p; + p.setX(static_cast(pt.x() * zoom() - horzValue())); + p.setY(static_cast(pt.y() * zoom() - vertValue())); + + return p; +} + +KisPoint KisView::windowToView(const KisPoint& pt) +{ + KisPoint p; + p.setX(pt.x() * zoom() - horzValue()); + p.setY(pt.y() * zoom() - vertValue()); + + return p; +} + +TQRect KisView::windowToView(const TQRect& rc) +{ + TQRect r; + + r.setTopLeft(windowToView(rc.topLeft())); + r.setRight((int)(ceil((rc.right() + 1.0) * zoom()) - horzValue() - 1)); + r.setBottom((int)(ceil((rc.bottom() + 1.0) * zoom()) - vertValue() - 1)); + + return r; +} + +KisRect KisView::windowToView(const KisRect& rc) +{ + KisRect r; + KisPoint p = windowToView(KisPoint(rc.x(), rc.y())); + r.setX(p.x()); + r.setY(p.y()); + r.setWidth(rc.width() * zoom()); + r.setHeight(rc.height() * zoom()); + + return r; +} + +void KisView::windowToView(TQ_INT32 *x, TQ_INT32 *y) +{ + if (x && y) { + TQPoint p = windowToView(TQPoint(*x, *y)); + *x = p.x(); + *y = p.y(); + } +} + +void KisView::guiActivateEvent(KParts::GUIActivateEvent *event) +{ + Q_ASSERT(event); + + if (event->activated()) { + + KStatusBar *sb = statusBar(); + if (sb) { + sb->show(); + } + + if (!m_guiActivateEventReceived) { + m_guiActivateEventReceived = true; + startInitialZoomTimerIfReady(); + } + } + + super::guiActivateEvent(event); +} + +bool KisView::eventFilter(TQObject *o, TQEvent *e) +{ + Q_ASSERT(o); + Q_ASSERT(e); + + switch (e->type()) { + case TQEvent::TabletMove: + case TQEvent::TabletPress: + case TQEvent::TabletRelease: + { + TQTabletEvent *te = TQT_TQTABLETEVENT(e); + KisInputDevice device; + + switch (te->device()) { + default: + case TQTabletEvent::Stylus: + case TQTabletEvent::NoDevice: + device = KisInputDevice::stylus(); + break; + case TQTabletEvent::Puck: + device = KisInputDevice::puck(); + break; + case TQTabletEvent::Eraser: + device = KisInputDevice::eraser(); + break; + } + + setInputDevice(device); + + // We ignore device change due to mouse events for a short duration + // after a tablet event, since these are almost certainly mouse events + // sent to tqreceivers that don't accept the tablet event. + m_tabletEventTimer.start(); + break; + } + case TQEvent::MouseButtonPress: + case TQEvent::MouseMove: + case TQEvent::MouseButtonRelease: + { +#ifdef EXTENDED_X11_TABLET_SUPPORT + KisInputDevice device = KisCanvasWidget::findActiveInputDevice(); + + if (device != KisInputDevice::mouse()) { + setInputDevice(device); + m_tabletEventTimer.start(); + } else +#endif + { + if (currentInputDevice() != KisInputDevice::mouse() && m_tabletEventTimer.elapsed() > MOUSE_CHANGE_EVENT_DELAY) { + setInputDevice(KisInputDevice::mouse()); + } + } + break; + } + case TQEvent::KeyPress: + case TQEvent::KeyRelease: + { + if (m_canvas->cursorIsOverCanvas()) { + m_canvas->handleKeyEvent(e); + return true; + } + break; + } +#if 0 + // This code is unnecessary now that there's an application event filter + // This eventFilter is called for all widgets already, no need to install event filters multiple times + // Even worse: with multiple views, they would all install event filters on each other's widgets, + // due to the qapp event filter triggering in all views! + case TQEvent::ChildInserted: + { + TQChildEvent *childEvent = static_cast(e); + TQObject *child = childEvent->child(); + if ( child->isWidgetType() ) { + + child->installEventFilter(this); + + TQObjectList *objectList = child->queryList(TQWIDGET_OBJECT_NAME_STRING); + TQObjectListIt it(*objectList); + TQObject *obj; + while ((obj = it.current()) != 0) { + obj->installEventFilter(this); + ++it; + } + delete objectList; + } + } +#endif + default: + // Ignore + break; + } + +#if 0 + if ((o == m_hRuler || o == m_vRuler) && (e->type() == TQEvent::MouseMove || e->type() == TQEvent::MouseButtonRelease)) { + TQMouseEvent *me = dynamic_cast(e); + TQPoint pt = mapFromGlobal(me->globalPos()); + KisImageSP img = currentImg(); + KisGuideMgr *mgr; + + if (!img) + return super::eventFilter(o, e); + + mgr = img->guides(); + + if (e->type() == TQEvent::MouseMove && (me->state() & Qt::LeftButton)) { + bool flag = tqgeometry().tqcontains(pt); + KisGuideSP gd; + + if (m_currentGuide == 0 && flag) { + // No guide is being edited and moving mouse over the canvas. + // Create a new guide. + enterEvent(0); + eraseGuides(); + mgr->unselectAll(); + + if (o == m_vRuler) + gd = mgr->add((pt.x() - m_vRuler->width() + horzValue()) / zoom(), Qt::Vertical); + else + gd = mgr->add((pt.y() - m_hRuler->height() + vertValue()) / zoom(), Qt::Horizontal); + + m_currentGuide = gd; + mgr->select(gd); + m_lastGuidePoint = mapToScreen(pt); + } else if (m_currentGuide) { + if (flag) { + // moved an existing guide. + KisMoveEvent kme(currentInputDevice(), pt, me->globalPos(), PRESSURE_DEFAULT, 0, 0, me->state()); + canvasGotMoveEvent(&kme); + } else { + // moved a guide out of the frame, destroy it + leaveEvent(0); + eraseGuides(); + mgr->remove(m_currentGuide); + paintGuides(); + m_currentGuide = 0; + } + } + } else if (e->type() == TQEvent::MouseButtonRelease && m_currentGuide) { + eraseGuides(); + mgr->unselect(m_currentGuide); + paintGuides(); + m_currentGuide = 0; + enterEvent(0); + KisMoveEvent kme(currentInputDevice(), pt, me->globalPos(), PRESSURE_DEFAULT, 0, 0, Qt::NoButton); + canvasGotMoveEvent(&kme); + } + } +#endif + + return super::eventFilter(o, e); +} + +#if 0 +void KisView::eraseGuides() +{ + KisImageSP img = currentImg(); + + if (img) { + KisGuideMgr *mgr = img->guides(); + + if (mgr) + mgr->erase(&m_canvasPixmap, this, horzValue(), vertValue(), zoom()); + } +} + +void KisView::paintGuides() +{ + KisImageSP img = currentImg(); + + if (img) { + KisGuideMgr *mgr = img->guides(); + + if (mgr) + mgr->paint(&m_canvasPixmap, this, horzValue(), vertValue(), zoom()); + } +} + +void KisView::updateGuides() +{ + eraseGuides(); + paintGuides(); +} +#endif + +//void KisView::viewGuideLines() +//{ +//} + +TQPoint KisView::mapToScreen(const TQPoint& pt) +{ + TQPoint converted; + + converted.rx() = pt.x() + horzValue(); + converted.ry() = pt.y() + vertValue(); + return converted; +} + +void KisView::attach(KisCanvasObserver *observer) +{ + Q_ASSERT(observer); + if (observer) + m_observers.push_back(observer); +} + +void KisView::detach(KisCanvasObserver *observer) +{ + Q_ASSERT(observer); + if (observer) { + vKisCanvasObserver_it it = std::find(m_observers.begin(), m_observers.end(), observer); + + if (it != m_observers.end()) + m_observers.erase(it); + } +} + +void KisView::notifyObservers() +{ + for (vKisCanvasObserver_it it = m_observers.begin(); it != m_observers.end(); ++it) { + (*it)->update(this); + } +} + +KisImageSP KisView::currentImg() const +{ + return m_image; +} + +void KisView::setCurrentImage(KisImageSP image) +{ + if(!image) return; + + disconnectCurrentImg(); + m_image = image; + + KisConfig cfg; + +#ifdef HAVE_GL + if (cfg.useOpenGL()) { + m_OpenGLImageContext = KisOpenGLImageContext::getImageContext(image, monitorProfile()); + m_canvas->createOpenGLCanvas(m_OpenGLImageContext->sharedContextWidget()); + } +#endif + connectCurrentImg(); + m_layerBox->setImage(currentImg()); + + zoomAroundPoint(0, 0, 1.0); + + if (!currentImg()) + layersUpdated(); + + imgUpdateGUI(); + + image->blockSignals(false); +} + +KisColor KisView::bgColor() const +{ + return m_bg; +} + +KisColor KisView::fgColor() const +{ + return m_fg; +} + +KisBrush *KisView::currentBrush() const +{ + return m_brush; +} + +KisPattern *KisView::currentPattern() const +{ + return m_pattern; +} + +KisGradient *KisView::currentGradient() const +{ + return m_gradient; +} + +KisID KisView::currentPaintop() const +{ + return m_paintop; +} + +const KisPaintOpSettings *KisView::currentPaintopSettings() const +{ + return m_paintopSettings; +} + +double KisView::zoomFactor() const +{ + return zoom(); +} + +KisUndoAdapter *KisView::undoAdapter() const +{ + return m_adapter; +} + +KisCanvasController *KisView::canvasController() const +{ + return const_cast(static_cast(this)); +} + +KisToolControllerInterface *KisView::toolController() const +{ + return const_cast(static_cast(m_toolManager)); +} + +KisDoc *KisView::document() const +{ + return m_doc; +} + +KisProgressDisplayInterface *KisView::progressDisplay() const +{ + return m_progress; +} + +TQCursor KisView::setCanvasCursor(const TQCursor & cursor) +{ + TQCursor oldCursor = m_canvas->cursor(); + TQCursor newCursor; + + KisConfig cfg; + + switch (cfg.cursorStyle()) { + case CURSOR_STYLE_TOOLICON: + newCursor = cursor; + break; + case CURSOR_STYLE_CROSSHAIR: + newCursor = KisCursor::crossCursor(); + break; + case CURSOR_STYLE_POINTER: + newCursor = KisCursor::arrowCursor(); + break; + case CURSOR_STYLE_OUTLINE: + newCursor = cursor; + break; + default: + newCursor = cursor; + } + + m_canvas->setCursor(newCursor); + return oldCursor; +} + +float KisView::HDRExposure() const +{ + return m_HDRExposure; +} + +void KisView::setHDRExposure(float exposure) +{ + if (exposure != m_HDRExposure) { + m_HDRExposure = exposure; + notifyObservers(); + updateCanvas(); + } +} + +void KisView::createDockers() +{ + + m_birdEyeBox = new KisBirdEyeBox(this); + m_birdEyeBox->setCaption(i18n("Overview")); + m_paletteManager->addWidget( m_birdEyeBox, "birdeyebox", chalk::CONTROL_PALETTE); + + m_hsvwidget = new KoHSVWidget(this, "hsv"); + m_hsvwidget->setCaption(i18n("HSV")); + + connect(m_hsvwidget, TQT_SIGNAL(sigFgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetFGQColor(const TQColor &))); + connect(m_hsvwidget, TQT_SIGNAL(sigBgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetBGQColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigFGQColorChanged(const TQColor &)), m_hsvwidget, TQT_SLOT(setFgColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigBGQColorChanged(const TQColor &)), m_hsvwidget, TQT_SLOT(setBgColor(const TQColor &))); + m_paletteManager->addWidget( m_hsvwidget, "hsvwidget", chalk::COLORBOX, 0, PALETTE_DOCKER, true); + + m_rgbwidget = new KoRGBWidget(this, "rgb"); + m_rgbwidget->setCaption(i18n("RGB")); + connect(m_rgbwidget, TQT_SIGNAL(sigFgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetFGQColor(const TQColor &))); + connect(m_rgbwidget, TQT_SIGNAL(sigBgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetBGQColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigFGQColorChanged(const TQColor &)), m_rgbwidget, TQT_SLOT(setFgColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigBGQColorChanged(const TQColor &)), m_rgbwidget, TQT_SLOT(setBgColor(const TQColor &))); + m_paletteManager->addWidget( m_rgbwidget, "rgbwidget", chalk::COLORBOX); + + m_graywidget = new KoGrayWidget(this, "gray"); + m_graywidget->setCaption(i18n("Gray")); + connect(m_graywidget, TQT_SIGNAL(sigFgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetFGQColor(const TQColor &))); + connect(m_graywidget, TQT_SIGNAL(sigBgColorChanged(const TQColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetBGQColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigFGQColorChanged(const TQColor &)), m_graywidget, TQT_SLOT(setFgColor(const TQColor &))); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(sigBGQColorChanged(const TQColor &)), m_graywidget, TQT_SLOT(setBgColor(const TQColor &))); + m_paletteManager->addWidget( m_graywidget, "graywidget", chalk::COLORBOX); + + //make sure the color chooser get right default values + emit sigFGQColorChanged(m_fg.toTQColor()); + emit sigBGQColorChanged(m_bg.toTQColor()); + + m_palettewidget = new KisPaletteWidget(this); + m_palettewidget->setCaption(i18n("Palettes")); + connect(m_palettewidget, TQT_SIGNAL(colorSelected(const TQColor &)), + TQT_TQOBJECT(this), TQT_SLOT(slotSetFGQColor(const TQColor &))); + // No BGColor or reverse slotFGChanged->palette connections, since that's not useful here + + KisResourceServerBase* rServer; + rServer = KisResourceServerRegistry::instance()->get("PaletteServer"); + TQValueList resources = rServer->resources(); + TQValueList::iterator it; + for ( it = resources.begin(); it != resources.end(); ++it ) { + m_palettewidget->slotAddPalette( *it ); + } + connect(m_palettewidget, TQT_SIGNAL(colorSelected(const KisColor &)), TQT_TQOBJECT(this), TQT_SLOT(slotSetFGColor(const KisColor &))); + m_paletteManager->addWidget( m_palettewidget, "palettewidget", chalk::COLORBOX, 10, PALETTE_DOCKER, true); +} + +TQPoint KisView::applyViewTransformations(const TQPoint& p) const { + TQPoint point(windowToView(p)); + + if (m_hRuler->isShown()) + point.ry() += m_hRuler->height(); + if (m_vRuler -> isShown()) + point.rx() += m_vRuler->width(); + + return point; +} + +TQPoint KisView::reverseViewTransformations(const TQPoint& p) const { + // Since we now zoom ourselves, the only thing super::~ does is nothing anymore. + // Hence, zoom ourselves, like super would + // viewToWindow doesn't take the rulers into account, do that ourselves + TQPoint point(p); + if (m_hRuler -> isShown()) + point.ry() -= m_hRuler -> height(); + if (m_vRuler -> isShown()) + point.rx() -= m_vRuler -> width(); + + return viewToWindow(point); +} + +void KisView::canvasAddChild(KoViewChild *child) { + super::canvasAddChild(child); + connect(TQT_TQOBJECT(this), TQT_SIGNAL(viewTransformationsChanged()), child, TQT_SLOT(reposition())); + m_vScroll->raise(); + m_hScroll->raise(); + m_vScroll->raise(); + m_hRuler->raise(); + m_vRuler->raise(); +} + +void KisView::slotLoadingFinished() +{ + // Set the current image for real now everything is ready to go. + setCurrentImage(document()->currentImage()); + m_paletteManager->showWidget( "layerbox" ); + m_canvas->show(); + disconnect(document(), TQT_SIGNAL(loadingFinished()), TQT_TQOBJECT(this), TQT_SLOT(slotLoadingFinished())); + + m_imageLoaded = true; + startInitialZoomTimerIfReady(); +} + +void KisView::startInitialZoomTimerIfReady() +{ + if (m_imageLoaded && m_showEventReceived && m_guiActivateEventReceived) { + m_initialZoomTimer.start(250, true); + } +} + +void KisView::slotInitialZoomTimeout() +{ + Q_ASSERT(!m_paintViewEnabled); + + m_paintViewEnabled = true; + setInitialZoomLevel(); +} + + +void KisView::slotCreateMask() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + KNamedCommand *cmd = layer->createMaskCommand(); + cmd->execute(); + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(cmd); + } +} + +void KisView::slotMaskFromSelection() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + KNamedCommand *cmd = layer->tqmaskFromSelectionCommand(); + cmd->execute(); + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(cmd); + } +} + +void KisView::slotMaskToSelection() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + KNamedCommand *cmd = layer->tqmaskToSelectionCommand(); + cmd->execute(); + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(cmd); + } +} + +void KisView::slotApplyMask() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + KNamedCommand *cmd = layer->applyMaskCommand(); + cmd->execute(); + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(cmd); + } +} + +void KisView::slotRemoveMask() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + KNamedCommand *cmd = layer->removeMaskCommand(); + cmd->execute(); + if (undoAdapter() && undoAdapter()->undo()) { + undoAdapter()->addCommand(cmd); + } +} + +void KisView::slotEditMask() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + layer->setEditMask(m_editMask->isChecked()); +} + +void KisView::slotShowMask() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) + return; + + layer->setRenderMask(m_showMask->isChecked()); +} + +void KisView::tqmaskUpdated() { + KisPaintLayer* layer = dynamic_cast(currentImg()->activeLayer().data()); + if (!layer) { + m_createMask->setEnabled(false); + m_applyMask->setEnabled(false); + m_removeMask->setEnabled(false); + m_editMask->setEnabled(false); + m_showMask->setEnabled(false); + return; + } + m_createMask->setEnabled(!layer->hasMask()); + m_tqmaskFromSelection->setEnabled(true); // Perhaps also update this to false when no selection? + m_tqmaskToSelection->setEnabled(layer->hasMask()); + m_applyMask->setEnabled(layer->hasMask()); + m_removeMask->setEnabled(layer->hasMask()); + + m_editMask->setEnabled(layer->hasMask()); + m_editMask->setChecked(layer->editMask()); + m_showMask->setEnabled(layer->hasMask()); + m_showMask->setChecked(layer->renderMask()); +} + +#include "kis_view.moc" + diff --git a/chalk/ui/kis_view.h b/chalk/ui/kis_view.h new file mode 100644 index 00000000..1f197f87 --- /dev/null +++ b/chalk/ui/kis_view.h @@ -0,0 +1,664 @@ +/* + * Copyright (c) 1999 Matthias Elter + * 1999 Michael Koch + * 1999 Carsten Pfeiffer + * 2002 Patrick Julien + * 2004 Clarence Dang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_VIEW_H_ +#define KIS_VIEW_H_ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "kis_canvas_controller.h" +#include "kis_canvas_subject.h" +#include "kis_global.h" +// #include "kis_debug_areas.h" +#include "kis_types.h" +#include "kis_profile.h" +#include "kis_opengl_image_context.h" +#include "kis_id.h" +#include "koffice_export.h" +#include "kis_color.h" +#include "kis_input_device.h" + +class TQButton; +class TQLabel; +class TQPaintEvent; +class TQScrollBar; +class TQWidget; +class TQPopup; +class TQPopupMenu; + +class DCOPObject; +class KAction; +class KActionMenu; +class KPrinter; +class KToggleAction; +class KToolBar; + +class KoPartSelectAction; +class KoDocumentEntry; +class KoIconItem; +class KoTabBar; +class KoPaletteManager; +class KoGrayWidget; +class KoHSVWidget; +class KoRGBWidget; + +class KisBirdEyeBox; +class KisBrush; +class KisButtonPressEvent; +class KisButtonReleaseEvent; +class KisCanvas; +class KisCanvasObserver; +class KisCompositeOp; +class KisControlFrame; +class KisDoc; +class KisDoubleClickEvent; +class KisFilterManager; +class KisFilterStrategy; +class KisGradient; +class KisGridManager; +class KisPerspectiveGridManager; +class KisLabelProgress; +class KisLayerBox; +class KisMoveEvent; +class KisPaletteWidget; +class KisPattern; +class KisPoint; +class KisRect; +class KisResource; +class KisResourceMediator; +class KisRuler; +class KisSelectionManager; +class KoToolBox; +class KisToolControllerInterface; +class KisToolManager; +class KisUndoAdapter; +class KisFilterConfiguration; +class KisPartLayerHandler; +class KisPaintOpSettings; + +class KRITA_EXPORT KisView + : public KoView, + public KisCanvasSubject, + public KXMLGUIBuilder, + private KisCanvasController +{ + + Q_OBJECT + TQ_OBJECT + + typedef KoView super; + + typedef std::list vKisCanvasObserver; + typedef vKisCanvasObserver::iterator vKisCanvasObserver_it; + typedef vKisCanvasObserver::const_iterator vKisCanvasObserver_cit; + +public: + KisView(KisDoc *doc, KisUndoAdapter *adapter, TQWidget *tqparent = 0, const char *name = 0); + virtual ~KisView(); + +public: // KXMLGUIBuilder implementation + + virtual TQWidget *createContainer( TQWidget *tqparent, int index, const TQDomElement &element, int &id ); + virtual void removeContainer( TQWidget *container, TQWidget *tqparent, TQDomElement &element, int id ); + +public: // KoView implementation + virtual bool eventFilter(TQObject *o, TQEvent *e); + + virtual DCOPObject* dcopObject(); + + virtual void print(KPrinter &printer); + virtual void setupPrinter(KPrinter &printer); + + virtual void updateReadWrite(bool readwrite); + virtual void guiActivateEvent(KParts::GUIActivateEvent *event); + + virtual int leftBorder() const; + virtual int rightBorder() const; + virtual int topBorder() const; + virtual int bottomBorder() const; + + TQ_INT32 docWidth() const; + TQ_INT32 docHeight() const; + + void updateStatusBarSelectionLabel(); + + virtual TQPoint applyViewTransformations(const TQPoint& p) const; + virtual TQPoint reverseViewTransformations( const TQPoint& p) const; + virtual void canvasAddChild(KoViewChild *child); + +signals: + + void brushChanged(KisBrush * brush); + void gradientChanged(KisGradient * gradient); + void patternChanged(KisPattern * pattern); + void paintopChanged(KisID paintop, const KisPaintOpSettings *paintopSettings); + /** + * Indicates when the current layer changed so that the current colorspace could have + * changed. + **/ + void currentColorSpaceChanged(KisColorSpace* cs); + void cursorPosition(TQ_INT32 xpos, TQ_INT32 ypos); + + void sigFGQColorChanged(const TQColor &); + void sigBGQColorChanged(const TQColor &); + + void sigInputDeviceChanged(const KisInputDevice& inputDevice); + + /* + * Emitted whenever the zoom or scroll values change. + */ + void viewTransformationsChanged(); + +public slots: + + void slotSetFGColor(const KisColor& c); + void slotSetBGColor(const KisColor& c); + + void rotateLayer180(); + void rotateLayerLeft90(); + void rotateLayerRight90(); + void mirrorLayerX(); + void mirrorLayerY(); + void scaleLayer(double sx, double sy, KisFilterStrategy *filterStrategy); + void rotateLayer(double radians); + void shearLayer(double angleX, double angleY); + + void slotCreateMask(); + void slotMaskFromSelection(); + void slotMaskToSelection(); + void slotApplyMask(); + void slotRemoveMask(); + void slotEditMask(); + void slotShowMask(); + + void brushActivated(KisResource *brush); + void patternActivated(KisResource *pattern); + void gradientActivated(KisResource *gradient); + void paintopActivated(const KisID & paintop, const KisPaintOpSettings *paintopSettings); + + +public: + virtual void mouseMoveEvent(TQMouseEvent *e); + + void resizeCurrentImage(TQ_INT32 w, TQ_INT32 h, bool cropLayers = false); + void scaleCurrentImage(double sx, double sy, KisFilterStrategy *filterStrategy); + void rotateCurrentImage(double radians); + void shearCurrentImage(double angleX, double angleY); + + void insertPart(const TQRect& viewRect, const KoDocumentEntry& entry, + KisGroupLayerSP tqparent, KisLayerSP above); + + /** + * Import an image as a layer. If there is more than + * one layer in the image, import all of them as separate + * layers. + * + * @param url the url to the image file + * @return the number of layers added + */ + TQ_INT32 importImage(const KURL& url = KURL()); +protected: + + virtual void resizeEvent(TQResizeEvent*); // From TQWidget + virtual void styleChange(TQStyle& oldStyle); // From TQWidget + virtual void paletteChange(const TQPalette& oldPalette); // From TQWidget + virtual void showEvent(TQShowEvent *); + +protected slots: + virtual void slotChildActivated(bool a); // from KoView + +// -------------------------------------------------------------------------// +// KisCanvasSubject implementation +// -------------------------------------------------------------------------// +public: + + KisCanvasSubject * canvasSubject() { return this; }; + +private: + + virtual KisImageSP currentImg() const; + + virtual void attach(KisCanvasObserver *observer); + virtual void detach(KisCanvasObserver *observer); + virtual void notifyObservers(); + + virtual KisColor bgColor() const; + virtual void setBGColor(const KisColor& c); + + virtual KisColor fgColor() const; + virtual void setFGColor(const KisColor& c); + + float HDRExposure() const; + void setHDRExposure(float exposure); + + virtual KisBrush *currentBrush() const; + virtual KisPattern *currentPattern() const; + virtual KisGradient *currentGradient() const; + virtual KisID currentPaintop() const; + virtual const KisPaintOpSettings *currentPaintopSettings() const; + + virtual double zoomFactor() const; + + virtual KisUndoAdapter *undoAdapter() const; + + virtual KisCanvasController *canvasController() const; + virtual KisToolControllerInterface *toolController() const; + + virtual KisProgressDisplayInterface *progressDisplay() const; + + virtual KisDoc * document() const; + + inline KisGridManager * gridManager() { return m_gridManager; } + inline KisPerspectiveGridManager* perspectiveGridManager() { return m_perspectiveGridManager; } + + inline KisSelectionManager * selectionManager() { return m_selectionManager; } + + KoPaletteManager * paletteManager(); + + KisProfile * monitorProfile(); + + +// -------------------------------------------------------------------------// +// KisCanvasController implementation +// -------------------------------------------------------------------------// + +public: + + KisCanvasController * getCanvasController() { return this; }; + + +private slots: + virtual void updateCanvas(); + + void updateStatusBarZoomLabel(); + void updateStatusBarProfileLabel(); + +private: + virtual KisCanvas *kiscanvas() const; + + virtual TQ_INT32 horzValue() const; + virtual TQ_INT32 vertValue() const; + + virtual void scrollTo(TQ_INT32 x, TQ_INT32 y); + + virtual void updateCanvas(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + virtual void updateCanvas(const TQRect& imageRect); + + virtual void zoomIn(); + virtual void zoomIn(TQ_INT32 x, TQ_INT32 y); + + virtual void zoomOut(); + virtual void zoomOut(TQ_INT32 x, TQ_INT32 y); + + virtual void zoomTo(TQ_INT32 x, TQ_INT32 y, TQ_INT32 w, TQ_INT32 h); + virtual void zoomTo(const TQRect& r); + virtual void zoomTo(const KisRect& r); + virtual void zoomAroundPoint(double x, double y, double zf); + + virtual TQPoint viewToWindow(const TQPoint& pt); + virtual TQPoint viewToWindow(const TQPoint& pt) const; + virtual KisPoint viewToWindow(const KisPoint& pt); + virtual TQRect viewToWindow(const TQRect& rc); + virtual KisRect viewToWindow(const KisRect& rc); + virtual void viewToWindow(TQ_INT32 *x, TQ_INT32 *y); + + virtual TQPoint windowToView(const TQPoint& pt); + virtual TQPoint windowToView(const TQPoint& pt) const; + virtual KisPoint windowToView(const KisPoint& pt); + virtual TQRect windowToView(const TQRect& rc); + virtual KisRect windowToView(const KisRect& rc); + virtual void windowToView(TQ_INT32 *x, TQ_INT32 *y); + + virtual TQCursor setCanvasCursor(const TQCursor & cursor); + + void setInputDevice(KisInputDevice inputDevice); + KisInputDevice currentInputDevice() const; + +// -------------------------------------------------------------------------// +// KisView internals +// -------------------------------------------------------------------------// + +private: + + void connectCurrentImg(); + void disconnectCurrentImg(); +// void eraseGuides(); +// void paintGuides(); +// void updateGuides(); +// void viewGuideLines(); + + void imgUpdateGUI(); + + void layerUpdateGUI(bool enable); + void createLayerBox(); + void createDockers(); + + void paintToolOverlay(const TQRegion& region); + + void paintTQPaintDeviceView(const TQRegion& canvasRegion); + void paintOpenGLView(const TQRect& canvasRect); + + void updateTQPaintDeviceCanvas(const TQRect& imageRect); + void updateOpenGLCanvas(const TQRect& imageRect); + + /** + * Update the whole of the KisCanvas, including areas outside the image. + */ + void refreshKisCanvas(); + + void selectionDisplayToggled(bool displaySelection); + + bool activeLayerHasSelection(); + + /** + * Reset the monitor profile to the new settings. + */ + void resetMonitorProfile(); + + void setupActions(); + void setupCanvas(); + void setupRulers(); + void setupScrollBars(); + void setupStatusBar(); + + + KisFilterManager * filterManager() { return m_filterManager; } + void setCurrentImage(KisImageSP image); + + /** + * Returns the next zoom level when zooming in from the current level. + */ + double nextZoomInLevel() const; + + /** + * Returns the next zoom level when zooming out from the current level. + */ + double nextZoomOutLevel() const; + + /** + * Returns the next zoom level when zooming out from the given level. + */ + double nextZoomOutLevel(double zoomLevel) const; + + /** + * Returns the zoom level that fits the image to the canvas. + */ + double fitToCanvasZoomLevel() const; + + /** + * Set the zoom level on first creating the view. + */ + void setInitialZoomLevel(); + + void startInitialZoomTimerIfReady(); + +private slots: + void layersUpdated(); // Used in the channel separation to notify the view that we have added a few layers. + void tqmaskUpdated(); // To update the enabled or disabled status of the tqmask entries + + void slotSetFGQColor(const TQColor & c); + void slotSetBGQColor(const TQColor & c); + + void imgUpdated(TQRect rc); + void slotOpenGLImageUpdated(TQRect rc); + + void imgResizeToActiveLayer(); + + void canvasGotMoveEvent(KisMoveEvent *e); + void canvasGotButtonPressEvent(KisButtonPressEvent *e); + void canvasGotButtonReleaseEvent(KisButtonReleaseEvent *e); + void canvasGotDoubleClickEvent(KisDoubleClickEvent *e); + void canvasGotPaintEvent(TQPaintEvent *e); + void canvasGotEnterEvent(TQEvent *e); + void canvasGotLeaveEvent(TQEvent *e); + void canvasGotMouseWheelEvent(TQWheelEvent *e); + void canvasGotKeyPressEvent(TQKeyEvent*); + void canvasGotKeyReleaseEvent(TQKeyEvent*); + void canvasGotDragEnterEvent(TQDragEnterEvent*); + void canvasGotDropEvent(TQDropEvent*); + + void reconnectAfterPartInsert(); + + TQPoint mapToScreen(const TQPoint& pt); + void slotImageProperties(); + + void layerCompositeOp(const KisCompositeOp& compositeOp); + void layerOpacity(int opacity, bool dontundo); + void layerOpacityFinishedChanging(int previous, int opacity); + + void layerToggleVisible(); + void layerToggleLocked(); + void actLayerVisChanged(int show); + void layerProperties(); + void showLayerProperties(KisLayerSP layer); + void layerAdd(); + void addLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void addGroupLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void addPartLayer(); + void addPartLayer(KisGroupLayerSP tqparent, KisLayerSP above, const KoDocumentEntry& entry); + void addAdjustmentLayer(); + void addAdjustmentLayer(KisGroupLayerSP tqparent, KisLayerSP above); + void addAdjustmentLayer(KisGroupLayerSP tqparent, KisLayerSP above, const TQString & name, KisFilterConfiguration * filter, KisSelectionSP selection = 0); + void layerRemove(); + void layerDuplicate(); + void layerRaise(); + void layerLower(); + void layerFront(); + void layerBack(); + void flattenImage(); + void mergeLayer(); + void saveLayerAsImage(); + + void slotUpdateFullScreen(bool toggle); + void showRuler(); + + void slotZoomIn(); + void slotZoomOut(); + void slotActualPixels(); + void slotActualSize(); + void slotFitToCanvas(); + + void slotImageSizeChanged(TQ_INT32 w, TQ_INT32 h); + + void scrollH(int value); + void scrollV(int value); + + void slotInsertImageAsLayer(); + void profileChanged(KisProfile * profile); + + void slotAddPalette(); + void slotEditPalette(); + + void preferences(); + + void slotAutoScroll(const TQPoint &p); + + void handlePartLayerAdded(KisLayerSP layer); + + /// Is called when the file is loaded + void slotLoadingFinished(); + + void slotInitialZoomTimeout(); + +private: + + bool m_panning; + + KisTool * m_oldTool; + + KisDoc *m_doc; + KisCanvas *m_canvas; + KisPartLayerHandler* m_partHandler; + + KisGridManager * m_gridManager; + KisPerspectiveGridManager * m_perspectiveGridManager; + KisSelectionManager * m_selectionManager; + KisFilterManager * m_filterManager; + KoPaletteManager * m_paletteManager; + KisToolManager * m_toolManager; + bool m_actLayerVis; + + // Fringe benefits + KisRuler *m_hRuler; + KisRuler *m_vRuler; + TQ_INT32 m_rulerThickness; + TQ_INT32 m_vScrollBarExtent; + TQ_INT32 m_hScrollBarExtent; + + // Actions + KAction *m_imgFlatten; + KAction *m_imgMergeLayer; + KAction *m_imgRename; + KAction *m_imgResizeToLayer; + KAction *m_imgScan; + + KoPartSelectAction * m_actionPartLayer; + KAction * m_actionAdjustmentLayer; + KAction *m_layerAdd; + KAction *m_layerBottom; + KAction *m_layerDup; + KToggleAction *m_layerHide; + KAction *m_layerLower; + KAction *m_layerProperties; + KAction *m_layerRaise; + KAction *m_layerRm; + KAction *m_layerSaveAs; + KAction *m_layerTop; + + KAction *m_createMask; + KAction *m_tqmaskFromSelection; + KAction *m_tqmaskToSelection; + KAction *m_applyMask; + KAction *m_removeMask; + KToggleAction *m_editMask; + KToggleAction *m_showMask; + + KAction *m_zoomIn; + KAction *m_zoomOut; + KAction *m_actualPixels; + KAction *m_actualSize; + KAction *m_fitToCanvas; + + KAction *m_fullScreen; + KAction *m_imgProperties; + + KToggleAction *m_RulerAction; + KToggleAction *m_guideAction; + + DCOPObject *m_dcop; + + // Widgets + TQScrollBar *m_hScroll; // XXX: the sizing of the scrollthumbs + TQScrollBar *m_vScroll; // is not right yet. + int m_scrollX; + int m_scrollY; + int m_canvasXOffset; + int m_canvasYOffset; + + bool m_paintViewEnabled; + bool m_guiActivateEventReceived; + bool m_showEventReceived; + bool m_imageLoaded; + + TQTimer m_initialZoomTimer; + + +// KisGuideSP m_currentGuide; +// TQPoint m_lastGuidePoint; + KisUndoAdapter *m_adapter; + vKisCanvasObserver m_observers; + TQLabel *m_statusBarZoomLabel; + KSqueezedTextLabel *m_statusBarSelectionLabel; + KSqueezedTextLabel *m_statusBarProfileLabel; + KisLabelProgress *m_progress; + + + KisLayerBox *m_layerBox; + KoToolBox * m_toolBox; + KisControlFrame * m_brushesAndStuffToolBar; + + // Current colours, brushes, patterns etc. + + KisColor m_fg; + KisColor m_bg; + + KisBrush *m_brush; + KisPattern *m_pattern; + KisGradient *m_gradient; + + KisID m_paintop; + const KisPaintOpSettings *m_paintopSettings; + + TQTime m_tabletEventTimer; + TQTabletEvent::TabletDevice m_lastTabletEventDevice; + + TQPixmap m_canvasPixmap; + bool m_toolIsPainting; + +#ifdef HAVE_GL + // OpenGL context for the current image, containing textures + // shared between multiple views. + KisOpenGLImageContextSP m_OpenGLImageContext; +#endif + + // Monitorprofile for this view + KisProfile * m_monitorProfile; + + float m_HDRExposure; + + // Currently active input device (mouse, stylus, eraser...) + KisInputDevice m_inputDevice; + + KisBirdEyeBox * m_birdEyeBox; + KoHSVWidget *m_hsvwidget; + KoRGBWidget *m_rgbwidget; + KoGrayWidget *m_graywidget; + KisPaletteWidget *m_palettewidget; + KisID m_currentColorChooserDisplay; + +private: + KisImageSP m_image; + +protected: + + friend class KisSelectionManager; + friend class KisFilterManager; + friend class KisGridManager; + friend class KisPerspectiveGridManager; +}; + +#endif // KIS_VIEW_H_ diff --git a/chalk/ui/kis_view_iface.cc b/chalk/ui/kis_view_iface.cc new file mode 100644 index 00000000..7de36c48 --- /dev/null +++ b/chalk/ui/kis_view_iface.cc @@ -0,0 +1,98 @@ +/* + * This file is part of the KDE project + * + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "kis_view_iface.h" + +#include "kis_view.h" + +#include + +KisViewIface::KisViewIface( KisView *view_ ) + : KoViewIface( view_ ) +{ + m_view = view_; +} + +void KisViewIface::copy() +{ +// m_view->copy(); +} + +void KisViewIface::cut() +{ +// m_view->cut(); +} + +void KisViewIface::removeSelection() +{ +// m_view->removeSelection(); +} + +void KisViewIface::paste() +{ +// m_view->paste(); +} + +void KisViewIface::copySelectionToNewLayer() +{ +// m_view->copySelectionToNewLayer(); +} + +void KisViewIface::selectAll() +{ +// m_view->selectAll(); +} + +void KisViewIface::unSelectAll() +{ +// m_view->unSelectAll(); +} + + + +void KisViewIface::slotImportImage() +{ +} + + +void KisViewIface::rotateLayer180() +{ + m_view->rotateLayer180(); +} + +void KisViewIface::rotateLayerLeft90() +{ + m_view->rotateLayerLeft90(); +} + +void KisViewIface::rotateLayerRight90() +{ + m_view->rotateLayerRight90(); +} + +void KisViewIface::mirrorLayerX() +{ + m_view->mirrorLayerX(); +} + +void KisViewIface::mirrorLayerY() +{ + m_view->mirrorLayerY(); +} diff --git a/chalk/ui/kis_view_iface.h b/chalk/ui/kis_view_iface.h new file mode 100644 index 00000000..34701c4c --- /dev/null +++ b/chalk/ui/kis_view_iface.h @@ -0,0 +1,58 @@ +/* This file is part of the KDE project + * Copyright (C) 2002 Laurent Montel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef KRAYON_VIEW_IFACE_H +#define KRAYON_VIEW_IFACE_H + +#include + +#include + +class KisView; + +/** + * This is the definition of the interface Chalk presents to + * dcop. + */ +class KisViewIface : public KoViewIface +{ + K_DCOP +public: + KisViewIface( KisView *view_ ); +k_dcop: + void copy(); + void cut(); + void removeSelection(); + void paste(); + void copySelectionToNewLayer(); + void selectAll(); + void unSelectAll(); + + void slotImportImage(); + + void rotateLayer180(); + void rotateLayerLeft90(); + void rotateLayerRight90(); + void mirrorLayerX(); + void mirrorLayerY(); + +private: + KisView *m_view; +}; + +#endif diff --git a/chalk/ui/kobirdeyepanel.cpp b/chalk/ui/kobirdeyepanel.cpp new file mode 100644 index 00000000..0cd835b1 --- /dev/null +++ b/chalk/ui/kobirdeyepanel.cpp @@ -0,0 +1,619 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "wdgbirdeye.h" +#include "kobirdeyepanel.h" +#include "kis_int_spinbox.h" + +KoCanvasAdapter::KoCanvasAdapter() {} +KoCanvasAdapter::~KoCanvasAdapter() {} + +KoZoomAdapter::KoZoomAdapter() {} +KoZoomAdapter::~KoZoomAdapter() {} + +KoThumbnailAdapter::KoThumbnailAdapter() {} +KoThumbnailAdapter::~KoThumbnailAdapter() {} + +KoBirdEyePanel::KoBirdEyePanel( KoZoomAdapter * zoomListener, + KoThumbnailAdapter * thumbnailProvider, + KoCanvasAdapter * canvas, + TQWidget * tqparent, + const char * name, + WFlags f) + : TQWidget(tqparent, name, f) + , m_zoomListener(zoomListener) + , m_thumbnailProvider(thumbnailProvider) + , m_canvas(canvas) + , m_dragging(false) +{ + TQHBoxLayout * l = new TQHBoxLayout(this); + m_page = new WdgBirdEye(this); + m_page->zoom->setRange((int) (TQMAX(1, 100 * zoomListener->getMinZoom())), (int) (100 * zoomListener->getMaxZoom())); + m_page->zoom->setValue(100); + m_page->zoom->setSuffix("%"); + + m_page->toolbar->setIconSize(16); + m_page->view->installEventFilter(this); + m_page->view->setBackgroundMode(TQt::NoBackground); + + m_zoomIn = new KAction( i18n("Zoom In"), "birdeye_zoom_plus", 0, TQT_TQOBJECT(this), TQT_SLOT(zoomPlus()), TQT_TQOBJECT(this), "zoomIn" ); + m_zoomOut = new KAction( i18n("Zoom Out"), "birdeye_zoom_minus", 0, TQT_TQOBJECT(this), TQT_SLOT(zoomMinus()), TQT_TQOBJECT(this), "zoomOut" ); + + l->addWidget(m_page); + + connect(m_page->zoom, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(zoomValueChanged(int))); + connect(m_page->bn100, TQT_SIGNAL(clicked()), TQT_SLOT(zoom100())); + connect(m_page->slZoom, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(sliderChanged( int ))); +} + +KoBirdEyePanel::~KoBirdEyePanel() +{ + delete m_canvas; + delete m_thumbnailProvider; + delete m_zoomListener; +} + +void KoBirdEyePanel::setZoom(int zoom) +{ + m_page->zoom->blockSignals(true); + m_page->slZoom->blockSignals(true); + + m_page->zoom->setValue(zoom); + + if (zoom < 10) { + m_page->slZoom->setValue(0); + } + else if (zoom > 10 && zoom < 100) { + m_page->slZoom->setValue(zoom / 10); + } + else if (zoom >= 100 && zoom < 150) { + m_page->slZoom->setValue(10); + } + else if (zoom >= 150 && zoom < 250) { + m_page->slZoom->setValue(11); + } + else if (zoom >= 250 && zoom < 350) { + m_page->slZoom->setValue(12); + } + else if (zoom >= 350 && zoom < 450) { + m_page->slZoom->setValue(13); + } + else if (zoom >= 450 && zoom < 550) { + m_page->slZoom->setValue(14); + } + else if (zoom >= 550 && zoom < 650) { + m_page->slZoom->setValue(15); + } + else if (zoom >= 650 && zoom < 875) { + m_page->slZoom->setValue(16); + } + else if (zoom >= 875 && zoom < 1150) { + m_page->slZoom->setValue(17); + } + else if (zoom >= 1150 && zoom < 1450) { + m_page->slZoom->setValue(18); + } + else if (zoom >= 1450) { + m_page->slZoom->setValue(19); + } + + + m_page->zoom->blockSignals(false); + m_page->slZoom->blockSignals(false); + + +} + +void KoBirdEyePanel::zoomValueChanged(int zoom) +{ + KoPoint center; + center = m_canvas->visibleArea().center(); + m_zoomListener->zoomTo(center.x(), center.y(), zoom / 100.0); + setZoom(zoom); +} + +void KoBirdEyePanel::zoom100() +{ + zoomValueChanged( 100 ); +} + +void KoBirdEyePanel::sliderChanged( int v ) +{ + if (v < 10) { + zoomValueChanged((v + 1) * 10); + } + else { + switch(v) { + case 10: + zoomValueChanged(100); + break; + case 11: + zoomValueChanged(200); + break; + case 12: + zoomValueChanged(300); + case 13: + zoomValueChanged(400); + break; + case 14: + zoomValueChanged(500); + break; + case 15: + zoomValueChanged(600); + break; + case 16: + zoomValueChanged(750); + break; + case 17: + zoomValueChanged(1000); + break; + case 18: + zoomValueChanged(1300); + break; + case 19: + zoomValueChanged(1600); + break; + } + } +} + +void KoBirdEyePanel::cursorPosChanged(TQ_INT32 xpos, TQ_INT32 ypos) +{ + m_page->txtX->setText(TQString("%L1").tqarg(xpos, 5)); + m_page->txtY->setText(TQString("%L1").tqarg(ypos, 5)); +} + +void KoBirdEyePanel::setThumbnailProvider(KoThumbnailAdapter * thumbnailProvider) +{ + delete m_thumbnailProvider; + m_thumbnailProvider = thumbnailProvider; +} + +void KoBirdEyePanel::slotViewTransformationChanged() +{ + updateVisibleArea(); + renderView(); + m_page->view->update(); + setZoom(tqRound(m_canvas->zoomFactor() * 100)); +} + +void KoBirdEyePanel::slotUpdate(const TQRect & r) +{ + TQRect updateRect = r; + + if (m_thumbnailProvider->pixelSize() != m_documentSize) { + m_documentSize = m_thumbnailProvider->pixelSize(); + fitThumbnailToView(); + updateRect = TQRect(0, 0, m_documentSize.width(), m_documentSize.height()); + } + + updateRect &= TQRect(0, 0, m_documentSize.width(), m_documentSize.height()); + + if (!updateRect.isEmpty() && !m_documentSize.isEmpty()) { + + TQRect thumbnailRect = documentToThumbnail(KoRect::fromTQRect(updateRect)); + + if (!thumbnailRect.isEmpty()) { + + TQImage thumbnailImage = m_thumbnailProvider->image(thumbnailRect, m_thumbnail.size()); + + if (!thumbnailImage.isNull()) { + + Q_ASSERT(thumbnailImage.size() == thumbnailRect.size()); + + TQPainter painter(&m_thumbnail); + + painter.fillRect(thumbnailRect, tqcolorGroup().mid()); + painter.drawImage(thumbnailRect.x(), thumbnailRect.y(), thumbnailImage); + } + } + } + + renderView(); + m_page->view->update(); +} + +TQRect KoBirdEyePanel::documentToThumbnail(const KoRect& docRect) +{ + if (docRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { + return TQRect(); + } + + TQ_INT32 thumbnailLeft = static_cast((docRect.left() * m_thumbnail.width()) / m_documentSize.width()); + TQ_INT32 thumbnailRight = static_cast(((docRect.right() + 1) * m_thumbnail.width()) / m_documentSize.width()); + TQ_INT32 thumbnailTop = static_cast((docRect.top() * m_thumbnail.height()) / m_documentSize.height()); + TQ_INT32 thumbnailBottom = static_cast(((docRect.bottom() + 1) * m_thumbnail.height()) / m_documentSize.height()); + + TQRect thumbnailRect(thumbnailLeft, thumbnailTop, thumbnailRight - thumbnailLeft + 1, thumbnailBottom - thumbnailTop + 1); + thumbnailRect &= m_thumbnail.rect(); + + return thumbnailRect; +} + +KoRect KoBirdEyePanel::thumbnailToDocument(const TQRect& thumbnailRect) +{ + if (thumbnailRect.isEmpty() || m_documentSize.isEmpty() || m_thumbnail.isNull()) { + return KoRect(); + } + + double docLeft = (static_cast(thumbnailRect.left()) * m_documentSize.width()) / m_thumbnail.width(); + double docRight = (static_cast(thumbnailRect.right() + 1) * m_documentSize.width()) / m_thumbnail.width(); + double docTop = (static_cast(thumbnailRect.top()) * m_documentSize.height()) / m_thumbnail.height(); + double docBottom = (static_cast(thumbnailRect.bottom() + 1) * m_documentSize.height()) / m_thumbnail.height(); + + KoRect docRect(docLeft, docTop, docRight - docLeft + 1, docBottom - docTop + 1); + docRect &= KoRect(0, 0, m_documentSize.width(), m_documentSize.height()); + + return docRect; +} + +TQPoint KoBirdEyePanel::viewToThumbnail(const TQPoint& viewPoint) +{ + int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; + int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; + + return TQPoint(viewPoint.x() - thumbnailX, viewPoint.y() - thumbnailY); +} + + +void KoBirdEyePanel::zoomMinus() +{ +} + +void KoBirdEyePanel::zoomPlus() +{ +} + +void KoBirdEyePanel::updateVisibleArea() +{ + m_visibleAreaInThumbnail = documentToThumbnail(m_canvas->visibleArea()); +} + + +bool KoBirdEyePanel::eventFilter(TQObject* o, TQEvent* ev) +{ + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::Resize) { + resizeViewEvent(TQT_TQRESIZEEVENT(ev)->size()); + } + + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::Paint) { + paintViewEvent(TQT_TQPAINTEVENT(ev)); + } + + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseMove) { + + TQMouseEvent* me = (TQMouseEvent*)ev; + TQPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (m_dragging) { + handleMouseMoveAction(thumbnailPos); + } else { + handleMouseMove(thumbnailPos); + } + + return true; + } + + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseButtonPress) { + + TQMouseEvent* me = (TQMouseEvent*)ev; + TQPoint thumbnailPos = viewToThumbnail(me->pos()); + + if (me->button() == Qt::LeftButton) { + handleMousePress(thumbnailPos); + } + + return true; + } + + if (TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_page->view) && ev->type() == TQEvent::MouseButtonRelease) { + + TQMouseEvent* me = (TQMouseEvent*)ev; + + if (me->button() == Qt::LeftButton) { + m_dragging = false; + } + + return true; + } + + return m_page->eventFilter(o, ev); +} + +KoBirdEyePanel::enumDragHandle KoBirdEyePanel::dragHandleAt(TQPoint p) +{ + TQRect left = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + TQRect right = TQRect(m_visibleAreaInThumbnail.right()-1, m_visibleAreaInThumbnail.top()-1, 3, m_visibleAreaInThumbnail.height()+2); + TQRect top = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.top()-1, m_visibleAreaInThumbnail.width()+2, 3); + TQRect bottom = TQRect(m_visibleAreaInThumbnail.left()-1, m_visibleAreaInThumbnail.bottom()-1, m_visibleAreaInThumbnail.width()+2, 3); + + if (left.tqcontains(p)) { + return DragHandleLeft; + } + + if (right.tqcontains(p)) { + return DragHandleRight; + } + + if (top.tqcontains(p)) { + return DragHandleTop; + } + + if (bottom.tqcontains(p)) { + return DragHandleBottom; + } + + if (m_visibleAreaInThumbnail.tqcontains(p)) { + return DragHandleCentre; + } + + return DragHandleNone; +} + +void KoBirdEyePanel::handleMouseMove(TQPoint p) +{ + TQCursor cursor; + + switch (dragHandleAt(p)) { + case DragHandleLeft: + case DragHandleRight: + cursor = TQt::sizeHorCursor; + break; + case DragHandleTop: + case DragHandleBottom: + cursor = TQt::sizeVerCursor; + break; + case DragHandleCentre: + cursor = TQt::sizeAllCursor; + break; + default: + case DragHandleNone: + if (TQT_TQRECT_OBJECT(m_thumbnail.rect()).tqcontains(p)) { + cursor = TQt::PointingHandCursor; + } else { + cursor = TQt::arrowCursor; + } + break; + } + + m_page->view->setCursor(cursor); +} + +void KoBirdEyePanel::handleMouseMoveAction(TQPoint p) +{ + if (m_dragging) { + + TQ_INT32 dx = p.x() - m_lastDragPos.x(); + TQ_INT32 dy = p.y() - m_lastDragPos.y(); + + m_lastDragPos = p; + + TQRect thumbnailRect = m_visibleAreaInThumbnail; + + switch (m_dragHandle) { + case DragHandleLeft: { + thumbnailRect.setLeft(thumbnailRect.left()+dx); + break; + } + case DragHandleRight: { + thumbnailRect.setRight(thumbnailRect.right()+dx); + break; + } + case DragHandleTop: { + thumbnailRect.setTop(thumbnailRect.top()+dy); + break; + } + case DragHandleBottom: { + thumbnailRect.setBottom(thumbnailRect.bottom()+dy); + break; + } + case DragHandleCentre: { + thumbnailRect.moveBy(dx, dy); + break; + } + default: + case DragHandleNone: + break; + } + + makeThumbnailRectVisible(thumbnailRect); + } +} + +void KoBirdEyePanel::handleMousePress(TQPoint p) +{ + if (!m_dragging) { + + enumDragHandle dragHandle = dragHandleAt(p); + + if (dragHandle == DragHandleNone) { + if (TQT_TQRECT_OBJECT(m_thumbnail.rect()).tqcontains(p)) { + + // Snap visible area centre to p and begin a centre drag. + + TQRect thumbnailRect = m_visibleAreaInThumbnail; + thumbnailRect.moveCenter(p); + makeThumbnailRectVisible(thumbnailRect); + + m_dragHandle = DragHandleCentre; + m_page->view->setCursor(TQt::sizeAllCursor); + m_dragging = true; + } + } else { + m_dragHandle = dragHandle; + m_dragging = true; + } + m_lastDragPos = p; + } +} + +void KoBirdEyePanel::makeThumbnailRectVisible(const TQRect& r) +{ + if (r.isEmpty()) { + return; + } + + TQRect thumbnailRect = r; + + if (thumbnailRect.left() < m_thumbnail.rect().left()) { + thumbnailRect.moveLeft(m_thumbnail.rect().left()); + } + if (thumbnailRect.right() > m_thumbnail.rect().right()) { + thumbnailRect.moveRight(m_thumbnail.rect().right()); + } + if (thumbnailRect.top() < m_thumbnail.rect().top()) { + thumbnailRect.moveTop(m_thumbnail.rect().top()); + } + if (thumbnailRect.bottom() > m_thumbnail.rect().bottom()) { + thumbnailRect.moveBottom(m_thumbnail.rect().bottom()); + } + + if (thumbnailRect.width() > m_thumbnail.rect().width()) { + thumbnailRect.setLeft(m_thumbnail.rect().left()); + thumbnailRect.setRight(m_thumbnail.rect().right()); + } + if (thumbnailRect.height() > m_thumbnail.rect().height()) { + thumbnailRect.setTop(m_thumbnail.rect().top()); + thumbnailRect.setBottom(m_thumbnail.rect().bottom()); + } + + double zoomFactor = m_canvas->zoomFactor(); + + if (thumbnailRect.size() == m_visibleAreaInThumbnail.size()) { + // No change to zoom + } else if (thumbnailRect.width() != m_visibleAreaInThumbnail.width()) { + + Q_ASSERT(thumbnailRect.height() == m_visibleAreaInThumbnail.height()); + + zoomFactor *= static_cast(m_visibleAreaInThumbnail.width()) / thumbnailRect.width(); + } else { + + Q_ASSERT(thumbnailRect.width() == m_visibleAreaInThumbnail.width()); + + zoomFactor *= static_cast(m_visibleAreaInThumbnail.height()) / thumbnailRect.height(); + } + + if (zoomFactor < m_zoomListener->getMinZoom()) { + zoomFactor = m_zoomListener->getMinZoom(); + } else if (zoomFactor > m_zoomListener->getMaxZoom()) { + zoomFactor = m_zoomListener->getMaxZoom(); + } + + KoRect docRect = thumbnailToDocument(thumbnailRect); + m_zoomListener->zoomTo(docRect.center().x(), docRect.center().y(), zoomFactor); +} + +void KoBirdEyePanel::resizeViewEvent(TQSize size) +{ + m_viewBuffer.resize(size); + fitThumbnailToView(); + slotUpdate(TQRect(0, 0, m_documentSize.width(), m_documentSize.height())); +} + +void KoBirdEyePanel::fitThumbnailToView() +{ + TQRect docRect = TQRect(0, 0, m_thumbnailProvider->pixelSize().width(), m_thumbnailProvider->pixelSize().height()); + TQ_INT32 thumbnailWidth; + TQ_INT32 thumbnailHeight; + + if (docRect.isEmpty()) { + thumbnailWidth = 0; + thumbnailHeight = 0; + } else { + const int thumbnailBorderPixels = 4; + + double xScale = double(m_page->view->contentsRect().width() - thumbnailBorderPixels) / docRect.width(); + double yScale = double(m_page->view->contentsRect().height() - thumbnailBorderPixels) / docRect.height(); + + if (xScale < yScale) { + thumbnailWidth = m_page->view->contentsRect().width() - thumbnailBorderPixels; + thumbnailHeight = TQ_INT32(ceil(docRect.height() * xScale)); + } else { + thumbnailWidth = TQ_INT32(ceil(docRect.width() * yScale)); + thumbnailHeight = m_page->view->contentsRect().height() - thumbnailBorderPixels; + } + } + + m_thumbnail.resize(thumbnailWidth, thumbnailHeight); + updateVisibleArea(); +} + +void KoBirdEyePanel::renderView() +{ + Q_ASSERT(!m_viewBuffer.isNull()); + + if (!m_viewBuffer.isNull()) { + + updateVisibleArea(); + + TQPainter painter(&m_viewBuffer); + + painter.fillRect(0, 0, m_viewBuffer.width(), m_viewBuffer.height(), tqcolorGroup().mid()); + + if (!m_thumbnail.isNull()) { + + int thumbnailX = (m_viewBuffer.width() - m_thumbnail.width()) / 2; + int thumbnailY = (m_viewBuffer.height() - m_thumbnail.height()) / 2; + + painter.drawPixmap(thumbnailX, thumbnailY, m_thumbnail); + + painter.setPen(TQt::red); + painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 1, + thumbnailY + m_visibleAreaInThumbnail.y() - 1, + m_visibleAreaInThumbnail.width() + 2, + m_visibleAreaInThumbnail.height() + 2); + painter.setPen(TQt::red.light()); + painter.drawRect(thumbnailX + m_visibleAreaInThumbnail.x() - 2, + thumbnailY + m_visibleAreaInThumbnail.y() - 2, + m_visibleAreaInThumbnail.width() + 4, + m_visibleAreaInThumbnail.height() + 4); + } + } +} + +void KoBirdEyePanel::paintViewEvent(TQPaintEvent *e) +{ + Q_ASSERT(!m_viewBuffer.isNull()); + + if (!m_viewBuffer.isNull()) { + bitBlt(m_page->view, e->rect().x(), e->rect().y(), &m_viewBuffer, + e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); + } +} + +#include "kobirdeyepanel.moc" diff --git a/chalk/ui/kobirdeyepanel.h b/chalk/ui/kobirdeyepanel.h new file mode 100644 index 00000000..24770b18 --- /dev/null +++ b/chalk/ui/kobirdeyepanel.h @@ -0,0 +1,263 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KO_BIRD_EYE_PANEL +#define KO_BIRD_EYE_PANEL + +#include +#include + +#include +#include + +class TQPixmap; +class KAction; +class KoDocument; +class WdgBirdEye; + + +class KoCanvasAdapter { + +public: + + KoCanvasAdapter(); + virtual ~KoCanvasAdapter(); + + /** + * Returns the area of the document that is visible, in pixels + */ + virtual KoRect visibleArea() = 0; + + /** + * Returns the total area of the document in pixels. Use KoPageLayout and KoZoomhandler + * to take care of zoom, points and whatnot when computing this. + */ + virtual TQRect size() = 0; + + /** + * Return the current canvas zoom factor. + */ + virtual double zoomFactor() = 0; + + /** + * Show pt in the center of the view + */ + virtual void setViewCenterPoint(double x, double y) = 0; +}; + +/** + * The zoom listener interface defines methods that the bird eye + * panel will call whenever the zoomlevel is changed through one + * of the panel actions. + */ +class KoZoomAdapter { + +public: + + KoZoomAdapter(); + virtual ~KoZoomAdapter(); + + /** + * Zoom to the specified factor around the point x and y + */ + virtual void zoomTo(double x, double y, double factor ) = 0; + + /** + * Zoom one step in. + */ + virtual void zoomIn() = 0; + + /** + * Zoom one step out. + */ + virtual void zoomOut() = 0; + + /** + * Get the minimum zoom factor that this listener supports. + */ + virtual double getMinZoom() = 0; + + /** + * Get the maximum zoom factor that this listener supports. + */ + virtual double getMaxZoom() = 0; + +}; + + +class KoThumbnailAdapter +{ + public: + + KoThumbnailAdapter(); + ~KoThumbnailAdapter(); + + /** + * Returns the size of the document in pixels. + * If the document is a KoDocument that uses a KoPageLayout, the same + * formula as in the generatePreview() method should be used to go from points + * to pixels. + * + * @returns the size in pixels. + */ + virtual TQSize pixelSize() = 0; + + /** + * Returns the specified rectangle of the thumbnail as a TQImage. thumbnailSize + * gives the dimensions of the whole document thumbnail, and r specifies a rectangle + * within that. + * + * @param r the rectangle in the thumbnail to be rendered + * @param thumbnailSize the size in pixels of the full thumbnail + */ + virtual TQImage image(TQRect r, TQSize thumbnailSize) = 0; +}; + +/** + * A complex widget that provides an overview of a document + * with a red panning rectangle to and a zoom slider and a toolbar + * with a couple of useful functions. + */ +class KoBirdEyePanel : public TQWidget { + + Q_OBJECT + TQ_OBJECT + +public: + + /** + * Create a new bird eye panel. + * + * @param zoomListener the object that listens to the zoom instructions we give + * @param thumbnailProvider the class that creates the small image at the right + * zoomlevel + * @param canvas the place the document is painted. + * @param tqparent the tqparent widget + * @param name the TQObject name of this bird eye widget + * @param f the widget flags (@see TQWidget) + */ + KoBirdEyePanel( KoZoomAdapter * zoomListener, + KoThumbnailAdapter * thumbnailProvider, + KoCanvasAdapter * canvas, + TQWidget * tqparent, + const char * name = 0, + WFlags f = 0 ); + + virtual ~KoBirdEyePanel(); + + bool eventFilter(TQObject*, TQEvent*); + +public slots: + + void setZoomListener( KoZoomAdapter * zoomListener) { m_zoomListener = zoomListener; } + + /** + * Set a new thumbnail provider. This will first delete the existing provider. + **/ + void setThumbnailProvider( KoThumbnailAdapter * thumbnailProvider ); + + /** + * Connect to this slot to inform the bird's eye view of changes in + * the view transformation, i.e. zoom level or scroll changes. + */ + void slotViewTransformationChanged(); + + void cursorPosChanged(TQ_INT32 xpos, TQ_INT32 ypos); + + void zoomMinus(); + void zoomPlus(); + + /** + * Connect to this slot if a (rectangular) area of your document is changed. + * + * @param r The rect that has been changed: this is unzoomed. + */ + void slotUpdate(const TQRect & r); + +protected slots: + + void updateVisibleArea(); + void zoomValueChanged(int zoom); + void zoom100(); + void sliderChanged(int); + +protected: + void setZoom(int zoom); + + void handleMouseMove(TQPoint); + void handleMouseMoveAction(TQPoint); + void handleMousePress(TQPoint); + void fitThumbnailToView(); + void renderView(); + void resizeViewEvent(TQSize size); + void paintViewEvent(TQPaintEvent *e); + void makeThumbnailRectVisible(const TQRect& r); + + enum enumDragHandle { + DragHandleNone, + DragHandleLeft, + DragHandleCentre, + DragHandleRight, + DragHandleTop, + DragHandleBottom + }; + + /* + * Returns the drag handle type at point p in thumbnail coordinates. + */ + enumDragHandle dragHandleAt(TQPoint p); + + /** + * Returns the rectangle in the thumbnail covered by the given document rectangle. + */ + TQRect documentToThumbnail(const KoRect& docRect); + + /** + * Returns the rectangle in the document covered by the given thumbnail rectangle. + */ + KoRect thumbnailToDocument(const TQRect& thumbnailRect); + + /** + * Converts a point in the view to a point in the thumbnail. + */ + TQPoint viewToThumbnail(const TQPoint& viewPoint); + +private: + + WdgBirdEye * m_page; + + KoZoomAdapter * m_zoomListener; + KoThumbnailAdapter * m_thumbnailProvider; + KoCanvasAdapter * m_canvas; + + KAction* m_zoomIn; + KAction* m_zoomOut; + TQPixmap m_viewBuffer; + TQPixmap m_thumbnail; + + TQSize m_documentSize; + TQRect m_visibleAreaInThumbnail; + bool m_dragging; + enumDragHandle m_dragHandle; + TQPoint m_lastDragPos; + +}; + +#endif diff --git a/chalk/ui/layerlist.cpp b/chalk/ui/layerlist.cpp new file mode 100644 index 00000000..976ec84d --- /dev/null +++ b/chalk/ui/layerlist.cpp @@ -0,0 +1,1325 @@ +/* + Copyright (c) 2005 Gábor Lehel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#include "layerlist.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LayerItemIterator: public TQListViewItemIterator +{ +public: + LayerItemIterator( LayerList *list ): TQListViewItemIterator( list ) { } + LayerItemIterator( LayerList *list, IteratorFlag flags ): TQListViewItemIterator( list, flags ) { } + LayerItemIterator( LayerItem *item ): TQListViewItemIterator( item ) { } + LayerItemIterator( LayerItem *item, IteratorFlag flags ): TQListViewItemIterator( item, flags ) { } + LayerItem *operator*() { return static_cast( TQListViewItemIterator::operator*() ); } +}; + +struct LayerProperty +{ + TQString name; + TQString displayName; + TQPixmap enabledIcon; + TQPixmap disabledIcon; + bool defaultValue; + bool validForFolders; + + LayerProperty(): defaultValue( false ), validForFolders( true ) { } + LayerProperty( const TQString &pname, const TQString &pdisplayName, const TQPixmap &enabled, const TQPixmap &disabled, + bool pdefaultValue, bool pvalidForFolders ) + : name( pname ), + displayName( pdisplayName ), + enabledIcon( enabled ), + disabledIcon( disabled ), + defaultValue( pdefaultValue ), + validForFolders( pvalidForFolders ) + { } +}; + +class LayerToolTip; +class LayerList::Private +{ +public: + LayerItem *activeLayer; + bool foldersCanBeActive; + bool previewsShown; + int itemHeight; + TQValueList properties; + KPopupMenu contextMenu; + LayerToolTip *tooltip; + + Private( TQWidget *tqparent, LayerList *list ); + ~Private(); +}; + +class LayerItem::Private +{ +public: + bool isFolder; + int id; + TQValueList properties; + TQImage *previewImage; + bool previewChanged; + TQPixmap scaledPreview; + TQSize previewSize; + TQPoint previewOffset; + + Private( int pid ): isFolder( false ), id( pid ), previewImage( 0 ), previewChanged( false ) + { } +}; + +static const int MAX_SIZE = 256; +class LayerToolTip: public TQToolTip, public TQFrame +{ + LayerList *m_list; + LayerItem *m_item; + TQPoint m_pos; + TQTimer m_timer; + TQImage m_img; + +public: + LayerToolTip( TQWidget *tqparent, LayerList *list ) + : TQToolTip( tqparent ), + TQFrame( 0, 0, WStyle_Customize | WStyle_NoBorder | WStyle_Tool | WStyle_StaysOnTop | WX11BypassWM | WNoAutoErase ), + m_list( list ) + { + TQFrame::setPalette( TQToolTip::palette() ); + connect( &m_timer, TQT_SIGNAL( timeout() ), m_list, TQT_SLOT( hideTip() ) ); + tqApp->installEventFilter( this ); + } + + virtual void maybeTip( const TQPoint &pos ) + { + m_pos = pos; + LayerItem *prev = m_item; + m_item = static_cast(m_list->itemAt( m_pos )); + if( TQToolTip::tqparentWidget() && m_list->showToolTips() && m_item ) + { + if( m_item != prev ) + hideTip(); + showTip(); + } + else + hideTip(); + } + + void showTip() + { + m_img = m_item->tooltipPreview(); + m_timer.start( 15000, true ); + if( !isVisible() || tqsizeHint() != size() ) + { + resize( tqsizeHint() ); + position(); + } + if( !isVisible() ) + show(); + else + update(); + } + + void hideTip() + { + if( !isVisible() ) + return; + TQFrame::hide(); + TQToolTip::hide(); + m_timer.stop(); + m_img.reset(); + m_list->triggerUpdate(); + } + + virtual void drawContents( TQPainter *painter ) + { + TQPixmap buf( width(), height() ); + TQPainter p( &buf ); + buf.fill( tqcolorGroup().background() ); + p.setPen( tqcolorGroup().foreground() ); + p.drawRect( buf.rect() ); + + TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() ); + text.setWidth( TQCOORD_MAX ); + + p.translate( 5, 5 ); + if( !m_img.isNull() ) + { + if( m_img.width() > MAX_SIZE || m_img.height() > MAX_SIZE ) + m_img = m_img.scale( MAX_SIZE, MAX_SIZE, TQ_ScaleMin ); + int y = 0; + if( m_img.height() < text.height() ) + y = text.height()/2 - m_img.height()/2; + p.drawImage( 0, y, m_img ); + p.drawRect( -1, y-1, m_img.width()+2, m_img.height()+2 ); + p.translate( m_img.width() + 10, 0 ); + } + + text.draw( &p, 0, 0, rect(), tqcolorGroup() ); + + painter->drawPixmap( 0, 0, buf ); + } + + virtual TQSize tqsizeHint() const + { + if( !m_item ) + return TQSize( 0, 0 ); + + TQSimpleRichText text( m_item->tooltip(), TQToolTip::font() ); + text.setWidth( TQCOORD_MAX ); + + int width = text.widthUsed(); + if( !m_img.isNull() ) + width += kMin( m_img.width(), MAX_SIZE ) + 10; + width += 10; + + int height = text.height(); + if( !m_img.isNull() && kMin( m_img.height(), MAX_SIZE ) > height ) + height = kMin( m_img.height(), MAX_SIZE ); + height += 10; + + return TQSize( width, height ); + } + + void position() + { + const TQRect drect = TQApplication::desktop()->availableGeometry( TQToolTip::tqparentWidget() ); + const TQSize size = tqsizeHint(); + const int width = size.width(), height = size.height(); + const TQRect tmp = m_item->rect(); + const TQRect irect( m_list->viewport()->mapToGlobal( m_list->contentsToViewport(tmp.topLeft()) ), tmp.size() ); + + int y; + if( irect.bottom() + height < drect.bottom() ) + y = irect.bottom(); + else + y = kMax( drect.top(), irect.top() - height ); + + int x = kMax( drect.x(), TQToolTip::tqparentWidget()->mapToGlobal( m_pos ).x() - width/2 ); + if( x + width > drect.right() ) + x = drect.right() - width; + + move( x, y ); + } + + virtual bool eventFilter( TQObject *, TQEvent *e ) + { + if( isVisible() ) + switch ( e->type() ) + { + case TQEvent::KeyPress: + case TQEvent::KeyRelease: + case TQEvent::MouseButtonPress: + case TQEvent::MouseButtonRelease: + //case TQEvent::MouseMove: + case TQEvent::FocusIn: + case TQEvent::FocusOut: + case TQEvent::Wheel: + case TQEvent::Leave: + hideTip(); + default: break; + } + + return false; + } +}; + +LayerList::Private::Private( TQWidget *tqparent, LayerList *list ) + : activeLayer( 0 ), foldersCanBeActive( false ), previewsShown( false ), itemHeight( 32 ), + tooltip( new LayerToolTip( tqparent, list ) ) { } + +LayerList::Private::~Private() +{ + delete tooltip; + tooltip = 0; +} + +static int getID() +{ + static int id = -2; + return id--; +} + +static TQSize iconSize() { return TQIconSet::iconSize( TQIconSet::Small ); } + + +/////////////// +// LayerList // +/////////////// + +LayerList::LayerList( TQWidget *tqparent, const char *name ) + : super( tqparent, name ), d( new Private( viewport(), this ) ) +{ + setSelectionMode( TQListView::Extended ); + setRootIsDecorated( true ); + setSorting( -1 ); + setSortColumn( -1 ); + setAllColumnsShowFocus( true ); + setFullWidth( true ); + setItemsRenameable( false ); + setDropHighlighter( true ); + setDefaultRenameAction( TQListView::Accept ); + setDragEnabled( true ); + setAcceptDrops( true ); + setItemsMovable( true ); + addColumn( TQString() ); + header()->hide(); + + TQToolTip::add(this, i18n("Right-click to create folders. Click on the layername to change the layer's name. Click and drag to move layers.")); + + setNumRows( 2 ); + + connect( this, TQT_SIGNAL( itemRenamed( TQListViewItem*, const TQString&, int ) ), + TQT_SLOT( slotItemRenamed( TQListViewItem*, const TQString&, int ) ) ); + connect( this, TQT_SIGNAL( moved( TQPtrList&, TQPtrList&, TQPtrList& ) ), + TQT_SLOT( slotItemMoved( TQPtrList&, TQPtrList&, TQPtrList& ) ) ); + connect( this, TQT_SIGNAL( onItem( TQListViewItem* ) ), TQT_SLOT( hideTip() ) ); + connect( this, TQT_SIGNAL( onViewport() ), TQT_SLOT( hideTip() ) ); +} + +LayerList::~LayerList() +{ + delete d; +} + +void LayerList::addProperty( const TQString &name, const TQString &displayName, const TQIconSet &icon, + bool defaultValue, bool validForFolders ) +{ + addProperty( name, displayName, icon.pixmap( TQIconSet::Small, TQIconSet::Normal ), icon.pixmap( TQIconSet::Small, TQIconSet::Disabled ), defaultValue, validForFolders ); +} + +void LayerList::addProperty( const TQString &name, const TQString &displayName, TQPixmap enabled, TQPixmap disabled, + bool defaultValue, bool validForFolders ) +{ + d->properties.append( LayerProperty( name, displayName, enabled, disabled, defaultValue, validForFolders ) ); + + for( LayerItemIterator it( this ); *it; ++it ) + (*it)->d->properties.append( defaultValue ); + + //we do this only afterwards in case someone wants to access the other items in a connected slot... + for( LayerItemIterator it( this ); *it; ++it ) + if( validForFolders || !(*it)->isFolder() ) + { + emit propertyChanged( *it, name, defaultValue ); + emit propertyChanged( (*it)->id(), name, defaultValue ); + } + + triggerUpdate(); +} + +LayerItem *LayerList::layer( int id ) const +{ + if( !firstChild() || id == -1 ) + return 0; + + for( LayerItemIterator it( firstChild() ); *it; ++it ) + if( (*it)->id() == id ) + return (*it); + + return 0; +} + +LayerItem *LayerList::folder( int id ) const +{ + if( !firstChild() || id == -1 ) + return 0; + + for( LayerItemIterator it( firstChild() ); *it; ++it ) + if( (*it)->id() == id && (*it)->isFolder() ) + return (*it); + + return 0; +} + +LayerItem *LayerList::activeLayer() const +{ + return d->activeLayer; +} + +int LayerList::activeLayerID() const +{ + if( activeLayer() ) + return activeLayer()->id(); + return -1; +} + +TQValueList LayerList::selectedLayers() const +{ + if( !firstChild() ) + return TQValueList(); + + TQValueList layers; + for( LayerItemIterator it( firstChild() ); *it; ++it ) + if( (*it)->isSelected() ) + layers.append( *it ); + + return layers; +} + +TQValueList LayerList::selectedLayerIDs() const +{ + const TQValueList layers = selectedLayers(); + TQValueList ids; + for( int i = 0, n = layers.count(); i < n; ++i ) + ids.append( layers[i]->id() ); + + return ids; +} + +bool LayerList::foldersCanBeActive() const +{ + return d->foldersCanBeActive; +} + +bool LayerList::previewsShown() const +{ + return d->previewsShown; +} + +int LayerList::itemHeight() const +{ + return d->itemHeight; +} + +int LayerList::numRows() const +{ + if( itemHeight() < kMax( fontMetrics().height(), iconSize().height() ) ) + return 0; + + return ( itemHeight() - fontMetrics().height() ) / iconSize().height() + 1; +} + +void LayerList::makeFolder( int id ) +{ + LayerItem* const l = layer( id ); + if( l ) + l->makeFolder(); +} + +bool LayerList::isFolder( int id ) const +{ + LayerItem* const l = layer( id ); + if( !l ) + return false; + + return l->isFolder(); +} + +TQString LayerList::displayName( int id ) const +{ + LayerItem* const l = layer( id ); + if( !l ) + return TQString(); //should be more severe... + + return l->displayName(); +} + +bool LayerList::property( int id, const TQString &name ) const +{ + LayerItem* const l = layer( id ); + if( !l ) + return false; //should be more severe... + + return l->property( name ); +} + +KPopupMenu *LayerList::contextMenu() const +{ + return &( d->contextMenu ); +} + +void LayerList::setFoldersCanBeActive( bool can ) //SLOT +{ + d->foldersCanBeActive = can; + if( !can && activeLayer() && activeLayer()->isFolder() ) + { + d->activeLayer = 0; + emit activated( static_cast( 0 ) ); + emit activated( -1 ); + } +} + +void LayerList::setPreviewsShown( bool show ) //SLOT +{ + d->previewsShown = show; + triggerUpdate(); +} + +void LayerList::setItemHeight( int height ) //SLOT +{ + d->itemHeight = height; + for( LayerItemIterator it( this ); *it; ++it ) + (*it)->setup(); + triggerUpdate(); +} + +void LayerList::setNumRows( int rows ) +{ + if( rows < 1 ) + return; + + if( rows == 1 ) + setItemHeight( kMax( fontMetrics().height(), iconSize().height() ) ); + else + setItemHeight( fontMetrics().height() + ( rows - 1 ) * iconSize().height() ); +} + +void LayerList::setActiveLayer( LayerItem *layer ) //SLOT +{ + if( !foldersCanBeActive() && layer && layer->isFolder() ) + return; + + ensureItemVisible( layer ); + + if( d->activeLayer == layer ) + return; + + d->activeLayer = layer; + + if( currentItem() != layer ) + setCurrentItem( layer ); + else + { + int n = 0; + for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; } + if( n == 1 ) + (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false ); + if( layer ) + layer->setSelected( true ); + } + + emit activated( layer ); + if( layer ) + emit activated( layer->id() ); + else + emit activated( -1 ); +} + +void LayerList::setActiveLayer( int id ) //SLOT +{ + setActiveLayer( layer( id ) ); +} + +void LayerList::setLayerDisplayName( LayerItem *layer, const TQString &displayName ) +{ + if( !layer ) + return; + + layer->setDisplayName( displayName ); +} + +void LayerList::setLayerDisplayName( int id, const TQString &displayName ) +{ + setLayerDisplayName( layer( id ), displayName ); +} + +void LayerList::setLayerProperty( LayerItem *layer, const TQString &name, bool on ) //SLOT +{ + if( !layer ) + return; + + layer->setProperty( name, on ); +} + +void LayerList::setLayerProperty( int id, const TQString &name, bool on ) //SLOT +{ + setLayerProperty( layer( id ), name, on ); +} + +void LayerList::toggleLayerProperty( LayerItem *layer, const TQString &name ) //SLOT +{ + if( !layer ) + return; + + layer->toggleProperty( name ); +} + +void LayerList::toggleLayerProperty( int id, const TQString &name ) //SLOT +{ + toggleLayerProperty( layer( id ), name ); +} + +void LayerList::setLayerPreviewImage( LayerItem *layer, TQImage *image ) +{ + if( !layer ) + return; + + layer->setPreviewImage( image ); +} + +void LayerList::setLayerPreviewImage( int id, TQImage *image ) +{ + setLayerPreviewImage( layer( id ), image ); +} + +void LayerList::layerPreviewChanged( LayerItem *layer ) +{ + if( !layer ) + return; + + layer->previewChanged(); +} + +void LayerList::layerPreviewChanged( int id ) +{ + layerPreviewChanged( layer( id ) ); +} + +LayerItem *LayerList::addLayer( const TQString &displayName, LayerItem *after, int id ) //SLOT +{ + return new LayerItem( displayName, this, after, id ); +} + +LayerItem *LayerList::addLayer( const TQString &displayName, int afterID, int id ) //SLOT +{ + return new LayerItem( displayName, this, layer( afterID ), id ); +} + +//SLOT +LayerItem *LayerList::addLayerToParent( const TQString &displayName, LayerItem *tqparent, LayerItem *after, int id ) +{ + if( tqparent && tqparent->isFolder() ) + return tqparent->addLayer( displayName, after, id ); + else + return 0; +} + +LayerItem *LayerList::addLayerToParent( const TQString &displayName, int tqparentID, int afterID, int id ) //SLOT +{ + return addLayerToParent( displayName, folder( tqparentID ), layer( afterID ), id ); +} + +void LayerList::moveLayer( LayerItem *layer, LayerItem *tqparent, LayerItem *after ) //SLOT +{ + if( !layer ) + return; + + if( tqparent && !tqparent->isFolder() ) + tqparent = 0; + + if( layer->tqparent() == tqparent && layer->prevSibling() == after ) + return; + + TQListViewItem *current = currentItem(); + + moveItem( layer, tqparent, after ); + + emit layerMoved( layer, tqparent, after ); + emit layerMoved( layer->id(), tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + + setCurrentItem( current ); //HACK, sometimes TQt changes this under us +} + +void LayerList::moveLayer( int id, int tqparentID, int afterID ) //SLOT +{ + moveLayer( layer( id ), folder( tqparentID ), layer( afterID ) ); +} + +void LayerList::removeLayer( LayerItem *layer ) //SLOT +{ + delete layer; +} + +void LayerList::removeLayer( int id ) //SLOT +{ + delete layer( id ); +} + +void LayerList::contentsMousePressEvent( TQMouseEvent *e ) +{ + LayerItem *item = static_cast( itemAt( contentsToViewport( e->pos() ) ) ); + + if( item ) + { + TQMouseEvent m( TQEvent::MouseButtonPress, item->mapFromListView( e->pos() ), e->button(), e->state() ); + if( !item->mousePressEvent( &m ) ) + super::contentsMousePressEvent( e ); + } + else + { + super::contentsMousePressEvent( e ); + if( e->button() == Qt::RightButton ) + showContextMenu(); + } +} + +void LayerList::contentsMouseDoubleClickEvent( TQMouseEvent *e ) +{ + super::contentsMouseDoubleClickEvent( e ); + if( LayerItem *layer = static_cast( itemAt( contentsToViewport( e->pos() ) ) ) ) + { + if( !layer->iconsRect().tqcontains( layer->mapFromListView( e->pos() ) ) ) + { + emit requestLayerProperties( layer ); + emit requestLayerProperties( layer->id() ); + } + } + else + { + emit requestNewLayer( static_cast( 0 ), static_cast( 0 ) ); + emit requestNewLayer( -1, -1 ); + } +} + +void LayerList::findDrop( const TQPoint &pos, TQListViewItem *&tqparent, TQListViewItem *&after ) +{ + LayerItem *item = static_cast( itemAt( contentsToViewport( pos ) ) ); + if( item && item->isFolder() ) + { + tqparent = item; + after = 0; + } + else + super::findDrop( pos, tqparent, after ); +} + +void LayerList::showContextMenu() +{ + LayerItem *layer = static_cast( itemAt( viewport()->mapFromGlobal( TQCursor::pos() ) ) ); + if( layer ) + setCurrentItem( layer ); + d->contextMenu.clear(); + constructMenu( layer ); + menuActivated( d->contextMenu.exec( TQCursor::pos() ), layer ); +} + +void LayerList::hideTip() +{ + d->tooltip->hideTip(); +} + +void LayerList::maybeTip() +{ + d->tooltip->maybeTip( d->tooltip->TQToolTip::tqparentWidget()->mapFromGlobal( TQCursor::pos() ) ); +} + +void LayerList::constructMenu( LayerItem *layer ) +{ + if( layer ) + { + for( int i = 0, n = d->properties.count(); i < n; ++i ) + if( !layer->isFolder() || d->properties[i].validForFolders ) + d->contextMenu.insertItem( layer->d->properties[i] ? d->properties[i].enabledIcon : d->properties[i].disabledIcon, d->properties[i].displayName, MenuItems::COUNT + i ); + d->contextMenu.insertItem( SmallIconSet( "info" ), i18n( "&Properties" ), MenuItems::LayerProperties ); + d->contextMenu.insertSeparator(); + d->contextMenu.insertItem( SmallIconSet( "editdelete" ), + selectedLayers().count() > 1 ? i18n( "Remove Layers" ) + : layer->isFolder() ? i18n( "&Remove Folder" ) + : i18n( "&Remove Layer" ), MenuItems::RemoveLayer ); + } + d->contextMenu.insertItem( SmallIconSet( "filenew" ), i18n( "&New Layer" ), MenuItems::NewLayer ); + d->contextMenu.insertItem( SmallIconSet( "folder" ), i18n( "New &Folder" ), MenuItems::NewFolder ); +} + +void LayerList::menuActivated( int id, LayerItem *layer ) +{ + const TQValueList selected = selectedLayers(); + + LayerItem *tqparent = ( layer && layer->isFolder() ) ? layer : 0; + LayerItem *after = 0; + if( layer && !tqparent ) + { + tqparent = layer->tqparent(); + after = layer->prevSibling(); + } + switch( id ) + { + case MenuItems::NewLayer: + emit requestNewLayer( tqparent, after ); + emit requestNewLayer( tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::NewFolder: + emit requestNewFolder( tqparent, after ); + emit requestNewFolder( tqparent ? tqparent->id() : -1, after ? after->id() : -1 ); + break; + case MenuItems::RemoveLayer: + { + TQValueList ids; + for( int i = 0, n = selected.count(); i < n; ++i ) + { + ids.append( selected[i]->id() ); + emit requestRemoveLayer( selected[i]->id() ); + } + emit requestRemoveLayers( ids ); + } + for( int i = 0, n = selected.count(); i < n; ++i ) + emit requestRemoveLayer( selected[i] ); + emit requestRemoveLayers( selected ); + break; + case MenuItems::LayerProperties: + if( layer ) + { + emit requestLayerProperties( layer ); + emit requestLayerProperties( layer->id() ); + } + break; + default: + if( id >= MenuItems::COUNT && layer ) + for( int i = 0, n = selected.count(); i < n; ++i ) + selected[i]->toggleProperty( d->properties[ id - MenuItems::COUNT ].name ); + } +} + +void LayerList::slotItemRenamed( TQListViewItem *item, const TQString &text, int col ) +{ + if( !item || col != 0 ) + return; + + emit displayNameChanged( static_cast( item ), text ); + emit displayNameChanged( static_cast( item )->id(), text ); +} + +void LayerList::slotItemMoved( TQPtrList &items, TQPtrList &/*afterBefore*/, TQPtrList &afterNow ) +{ + for( int i = 0, n = items.count(); i < n; ++i ) + { + LayerItem *l = static_cast( items.at(i) ), *a = static_cast( afterNow.at(i) ); + if( !l ) + continue; + + if( l->tqparent() ) + l->tqparent()->setOpen( true ); + + emit layerMoved( l, l->tqparent(), a ); + emit layerMoved( l->id(), l->tqparent() ? l->tqparent()->id() : -1, a ? a->id() : -1 ); + } +} + +void LayerList::setCurrentItem( TQListViewItem *item ) +{ + if( !item ) + return; + + super::setCurrentItem( item ); + ensureItemVisible( item ); + int n = 0; + for( LayerItemIterator it( this, LayerItemIterator::Selected ); n < 2 && (*it); ++it ) { n++; } + if( n == 1 ) + (*LayerItemIterator( this, LayerItemIterator::Selected ))->setSelected( false ); + item->setSelected( true ); + if( activeLayer() != item ) + setActiveLayer( static_cast(item) ); +} + + +/////////////// +// LayerItem // +/////////////// + +LayerItem::LayerItem( const TQString &displayName, LayerList *p, LayerItem *after, int id ) + : super( p, after ), d( new Private( id ) ) +{ + init(); + setDisplayName( displayName ); +} + +LayerItem::LayerItem( const TQString &displayName, LayerItem *p, LayerItem *after, int id ) + : super( ( p && p->isFolder() ) ? p : 0, after ), d( new Private( id ) ) +{ + init(); + setDisplayName( displayName ); +} + +void LayerItem::init() +{ + if( d->id < 0 ) + d->id = getID(); + + for( int i = 0, n = listView()->d->properties.count(); i < n; ++i ) + d->properties.append( listView()->d->properties[i].defaultValue ); + + if( tqparent()) + tqparent()->setOpen( true ); +} + +LayerItem::~LayerItem() +{ + if (listView() && (listView()->activeLayer() == this || tqcontains(listView()->activeLayer()))) + listView()->setActiveLayer( static_cast( 0 ) ); + delete d; +} + +void LayerItem::makeFolder() +{ + d->isFolder = true; + setPixmap( 0, SmallIcon( "folder", 16 ) ); + if( isActive() && !listView()->foldersCanBeActive() ) + listView()->setActiveLayer( static_cast( 0 ) ); +} + +bool LayerItem::isFolder() const +{ + return d->isFolder; +} + +bool LayerItem::tqcontains(const LayerItem *item) +{ + TQListViewItemIterator it(this); + + while (it.current()) { + if (static_cast(it.current()) == item) { + return true; + } + ++it; + } + return false; +} + +int LayerItem::id() const +{ + return d->id; +} + +TQString LayerItem::displayName() const +{ + return text( 0 ); +} + +void LayerItem::setDisplayName( const TQString &s ) +{ + if( displayName() == s ) + return; + setText( 0, s ); + emit listView()->displayNameChanged( this, s ); + emit listView()->displayNameChanged( id(), s ); +} + +bool LayerItem::isActive() const +{ + return listView()->activeLayer() == this; +} + +void LayerItem::setActive() +{ + listView()->setActiveLayer( this ); +} + +bool LayerItem::property( const TQString &name ) const +{ + int i = listView()->d->properties.count() - 1; + while( i && listView()->d->properties[i].name != name ) + --i; + + if( i < 0 ) + return false; //should do something more severe... but what? + + return d->properties[i]; +} + +void LayerItem::setProperty( const TQString &name, bool on ) +{ + int i = listView()->d->properties.count() - 1; + while( i && listView()->d->properties[i].name != name ) + --i; + + if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) ) + return; + + const bool notify = ( on != d->properties[i] ); + d->properties[i] = on; + if( notify ) + { + emit listView()->propertyChanged( this, name, on ); + emit listView()->propertyChanged( id(), name, on ); + } + + update(); +} + +void LayerItem::toggleProperty( const TQString &name ) +{ + int i = listView()->d->properties.count() - 1; + while( i && listView()->d->properties[i].name != name ) + --i; + + if( i < 0 || ( isFolder() && !listView()->d->properties[i].validForFolders ) ) + return; + + d->properties[i] = !(d->properties[i]); + emit listView()->propertyChanged( this, name, d->properties[i] ); + emit listView()->propertyChanged( id(), name, d->properties[i] ); + + update(); +} + +void LayerItem::setPreviewImage( TQImage *image ) +{ + d->previewImage = image; + previewChanged(); +} + +void LayerItem::previewChanged() +{ + d->previewChanged = true; + update(); +} + +LayerItem *LayerItem::addLayer( const TQString &displayName, LayerItem *after, int id ) +{ + if( !isFolder() ) + return 0; + return new LayerItem( displayName, this, after, id ); +} + +LayerItem *LayerItem::prevSibling() const +{ + LayerItem *item = tqparent() ? tqparent()->firstChild() : listView()->firstChild(); + if( !item || this == item ) + return 0; + for(; item && this != item->nextSibling(); item = item->nextSibling() ); + return item; +} + +int LayerItem::mapXFromListView( int x ) const +{ + return x - rect().left(); +} + +int LayerItem::mapYFromListView( int y ) const +{ + return y - rect().top(); +} + +TQPoint LayerItem::mapFromListView( const TQPoint &point ) const +{ + return TQPoint( mapXFromListView( point.x() ), mapYFromListView( point.y() ) ); +} + +TQRect LayerItem::mapFromListView( const TQRect &rect ) const +{ + return TQRect( mapFromListView( rect.topLeft() ), rect.size() ); +} + +int LayerItem::mapXToListView( int x ) const +{ + return x + rect().left(); +} + +int LayerItem::mapYToListView( int y ) const +{ + return y + rect().top(); +} + +TQPoint LayerItem::mapToListView( const TQPoint &point ) const +{ + return TQPoint( mapXToListView( point.x() ), mapYToListView( point.y() ) ); +} + +TQRect LayerItem::mapToListView( const TQRect &rect ) const +{ + return TQRect( mapToListView( rect.topLeft() ), rect.size() ); +} + +TQRect LayerItem::rect() const +{ + const int indent = listView()->treeStepSize() * ( depth() + 1 ); + return TQRect( listView()->header()->sectionPos( 0 ) + indent, itemPos(), + listView()->header()->sectionSize( 0 ) - indent, height() ); +} + +TQRect LayerItem::textRect() const +{ + static TQFont f; + static int minbearing = 1337 + 666; //can be 0 or negative, 2003 is less likely + if( minbearing == 2003 || f != font() ) + { + f = font(); //getting your bearings can be expensive, so we cache them + minbearing = fontMetrics().minLeftBearing() + fontMetrics().minRightBearing(); + } + + const int margin = listView()->itemMargin(); + int indent = previewRect().right() + margin; + if( pixmap( 0 ) ) + indent += pixmap( 0 )->width() + margin; + + const int width = ( multiline() ? rect().right() : iconsRect().left() ) - indent - margin + minbearing; + + return TQRect( indent, 0, width, fontMetrics().height() ); +} + +TQRect LayerItem::iconsRect() const +{ + const TQValueList &lp = listView()->d->properties; + int propscount = 0; + for( int i = 0, n = lp.count(); i < n; ++i ) + if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) ) + propscount++; + + const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin(); + + const int x = multiline() ? previewRect().right() + listView()->itemMargin() : rect().width() - iconswidth; + const int y = multiline() ? fontMetrics().height() : 0; + + return TQRect( x, y, iconswidth, iconSize().height() ); +} + +TQRect LayerItem::previewRect() const +{ + return TQRect( 0, 0, listView()->previewsShown() ? height() : 0, height() ); +} + +void LayerItem::drawText( TQPainter *p, const TQColorGroup &cg, const TQRect &r ) +{ + p->translate( r.left(), r.top() ); + + p->setPen( isSelected() ? cg.highlightedText() : cg.text() ); + + const TQString text = KStringHandler::rPixelSqueeze( displayName(), p->fontMetrics(), r.width() ); + p->drawText( listView()->itemMargin(), 0, r.width(), r.height(), TQt::AlignAuto | TQt::AlignTop, text ); + + p->translate( -r.left(), -r.top() ); +} + +void LayerItem::drawIcons( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r ) +{ + p->translate( r.left(), r.top() ); + + int x = 0; + const TQValueList &lp = listView()->d->properties; + for( int i = 0, n = lp.count(); i < n; ++i ) + if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) ) + { + if( !isFolder() || lp[i].validForFolders ) + p->drawPixmap( x, 0, d->properties[i] ? lp[i].enabledIcon : lp[i].disabledIcon ); + x += iconSize().width() + listView()->itemMargin(); + } + + p->translate( -r.left(), -r.top() ); +} + +void LayerItem::drawPreview( TQPainter *p, const TQColorGroup &/*cg*/, const TQRect &r ) +{ + if( !showPreview() ) + return; + + if( d->previewChanged || r.size() != d->previewSize ) + { //TODO handle width() != height() + const int size = kMin( r.width(), kMax( previewImage()->width(), previewImage()->height() ) ); + const TQImage i = previewImage()->smoothScale( size, size, TQ_ScaleMin ); + d->scaledPreview.convertFromImage( i ); + d->previewOffset.setX( r.width()/2 - i.width()/2 ); + d->previewOffset.setY( r.height()/2 - i.height()/2 ); + + d->previewChanged = false; + d->previewSize = r.size(); + } + + p->drawPixmap( r.topLeft() + d->previewOffset, d->scaledPreview ); +} + +bool LayerItem::showPreview() const +{ + return listView()->previewsShown() && previewImage() && !previewImage()->isNull(); +} + +bool LayerItem::multiline() const +{ + return height() >= fontMetrics().height() + iconSize().height(); +} + +TQFont LayerItem::font() const +{ + if( isActive() ) + { + TQFont f = listView()->font(); + f.setBold( !f.bold() ); + f.setItalic( !f.italic() ); + return f; + } + else + return listView()->font(); +} + +TQFontMetrics LayerItem::fontMetrics() const +{ + return TQFontMetrics( font() ); +} + +bool LayerItem::mousePressEvent( TQMouseEvent *e ) +{ + if( e->button() == Qt::RightButton ) + { + if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) ) + setActive(); + TQTimer::singleShot( 0, listView(), TQT_SLOT( showContextMenu() ) ); + return false; + } + + const TQRect ir = iconsRect(), tr = textRect(); + + if( ir.tqcontains( e->pos() ) ) + { + const int iconWidth = iconSize().width(); + int x = e->pos().x() - ir.left(); + if( x % ( iconWidth + listView()->itemMargin() ) < iconWidth ) //it's on an icon, not a margin + { + const TQValueList &lp = listView()->d->properties; + int p = -1; + for( int i = 0, n = lp.count(); i < n; ++i ) + { + if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) ) + x -= iconWidth + listView()->itemMargin(); + p += 1; + if( x < 0 ) + break; + } + toggleProperty( lp[p].name ); + } + return true; + } + + else if( tr.tqcontains( e->pos() ) && isSelected() && !listView()->renameLineEdit()->isVisible() ) + { + listView()->rename( this, 0 ); + TQRect r( listView()->contentsToViewport( mapToListView( tr.topLeft() ) ), tr.size() ); + listView()->renameLineEdit()->setGeometry( r ); + return true; + } + + if ( !(e->state() & TQt::ControlButton) && !(e->state() & TQt::ShiftButton) ) + setActive(); + + return false; +} + +TQString LayerItem::tooltip() const +{ + TQString tip; + tip += ""; + tip += TQString("").tqarg( displayName() ); + TQString row = ""; + for( int i = 0, n = listView()->d->properties.count(); i < n; ++i ) + if( !isFolder() || listView()->d->properties[i].validForFolders ) + { + if( d->properties[i] ) + tip += row.tqarg( i18n( "%1:" ).tqarg( listView()->d->properties[i].displayName ) ).tqarg( i18n( "Yes" ) ); + else + tip += row.tqarg( i18n( "%1:" ).tqarg( listView()->d->properties[i].displayName ) ).tqarg( i18n( "No" ) ); + } + tip += "
%1
%1%2
"; + return tip; +} + +TQImage *LayerItem::previewImage() const +{ + return d->previewImage; +} + +TQImage LayerItem::tooltipPreview() const +{ + if( previewImage() ) + return *previewImage(); + return TQImage(); +} + +int LayerItem::width( const TQFontMetrics &fm, const TQListView *lv, int c ) const +{ + if( c != 0 ) + return super::width( fm, lv, c ); + + const TQValueList &lp = listView()->d->properties; + int propscount = 0; + for( int i = 0, n = d->properties.count(); i < n; ++i ) + if( !lp[i].enabledIcon.isNull() && ( !multiline() || !isFolder() || lp[i].validForFolders ) ) + propscount++; + + const int iconswidth = propscount * iconSize().width() + (propscount - 1) * listView()->itemMargin(); + + if( multiline() ) + return kMax( super::width( fm, lv, 0 ), iconswidth ); + else + return super::width( fm, lv, 0 ) + iconswidth; +} + +void LayerItem::paintCell( TQPainter *painter, const TQColorGroup &cg, int column, int width, int align ) +{ + if( column != 0 ) + { + super::paintCell( painter, cg, column, width, align ); + return; + } + + TQPixmap buf( width, height() ); + TQPainter p( &buf ); + + p.setFont( font() ); + + const TQColorGroup cg_ = isEnabled() ? listView()->tqpalette().active() : listView()->tqpalette().disabled(); + + const TQColor bg = isSelected() ? cg_.highlight() + : isAlternate() ? listView()->alternateBackground() + : listView()->viewport()->backgroundColor(); + + buf.fill( bg ); + + if( pixmap( 0 ) ) + p.drawPixmap( previewRect().right() + listView()->itemMargin(), 0, *pixmap( 0 ) ); + + drawText( &p, cg_, textRect() ); + drawIcons( &p, cg_, iconsRect() ); + drawPreview( &p, cg_, previewRect() ); + + painter->drawPixmap( 0, 0, buf ); +} + +void LayerItem::setup() +{ + super::setup(); + setHeight( listView()->d->itemHeight ); +} + +void LayerItem::setSelected( bool selected ) +{ + if( !selected && ( isActive() || this == listView()->currentItem() ) ) + return; + super::setSelected( selected ); +} + + +///////////////////////// +// Convenience Methods // +///////////////////////// + +LayerItem *LayerList::firstChild() const { return static_cast( super::firstChild() ); } +LayerItem *LayerList::lastChild() const { return static_cast( super::lastChild() ); } +LayerList *LayerItem::listView() const { return static_cast( super::listView() ); } +void LayerItem::update() const { listView()->tqrepaintItem( this ); } +LayerItem *LayerItem::firstChild() const { return static_cast( super::firstChild() ); } +LayerItem *LayerItem::nextSibling() const { return static_cast( super::nextSibling() ); } +LayerItem *LayerItem::tqparent() const { return static_cast( super::tqparent() ); } + + +#include "layerlist.moc" diff --git a/chalk/ui/layerlist.h b/chalk/ui/layerlist.h new file mode 100644 index 00000000..129baa7c --- /dev/null +++ b/chalk/ui/layerlist.h @@ -0,0 +1,269 @@ +/* + Copyright (c) 2005 Gábor Lehel + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef LAYERLIST_H +#define LAYERLIST_H + +#include +#include + +class TQMouseEvent; +class TQString; +class KPopupMenu; +class LayerItem; +class LayerFolder; +template class TQPtrList; + +class LayerList: public KListView +{ + Q_OBJECT + TQ_OBJECT + +public: + LayerList( TQWidget *tqparent = 0, const char *name = 0 ); + virtual ~LayerList(); + + void addProperty( const TQString &name, const TQString &displayName, const TQIconSet &icon = TQIconSet(), + bool defaultValue = false, bool validForFolders = true ); + void addProperty( const TQString &name, const TQString &displayName, TQPixmap enabled, TQPixmap disabled, + bool defaultValue = false, bool validForFolders = true ); + + bool foldersCanBeActive() const; + bool previewsShown() const; + int itemHeight() const; + int numRows() const; + + LayerItem *layer( int id ) const; + LayerItem *folder( int id ) const; //returns 0 if not a folder + + LayerItem *activeLayer() const; + int activeLayerID() const; + + TQValueList selectedLayers() const; + TQValueList selectedLayerIDs() const; + + void makeFolder( int id ); + bool isFolder( int id ) const; + TQString displayName( int id ) const; + bool property( int id, const TQString &name ) const; + + struct MenuItems + { + enum { NewLayer = 0, NewFolder, RemoveLayer, LayerProperties, COUNT }; + }; + KPopupMenu *contextMenu() const; + +public slots: + void setFoldersCanBeActive( bool can ); + void setPreviewsShown( bool show ); + void setItemHeight( int height ); + void setNumRows( int rows ); //how many rows of property icons can fit + + void setActiveLayer( LayerItem *layer ); + void setActiveLayer( int id ); + + void setLayerDisplayName( LayerItem *layer, const TQString &displayName ); + void setLayerDisplayName( int id, const TQString &displayName ); + + void setLayerProperty( LayerItem *layer, const TQString &name, bool on ); + void setLayerProperty( int id, const TQString &name, bool on ); + + void toggleLayerProperty( LayerItem *layer, const TQString &name ); + void toggleLayerProperty( int id, const TQString &name ); + + void setLayerPreviewImage( LayerItem *layer, TQImage *image ); + void setLayerPreviewImage( int id, TQImage *image ); + + void layerPreviewChanged( LayerItem *layer ); + void layerPreviewChanged( int id ); + + LayerItem *addLayer( const TQString &displayName, LayerItem *after = 0, int id = -1 ); + LayerItem *addLayer( const TQString &displayName, int afterID, int id = -1 ); + + LayerItem *addLayerToParent( const TQString &displayName, LayerItem *tqparent, LayerItem *after = 0, int id = -1 ); + LayerItem *addLayerToParent( const TQString &displayName, int tqparentID, int afterID = -1, int id = -1 ); + + void moveLayer( LayerItem *layer, LayerItem *tqparent, LayerItem *after ); + void moveLayer( int id, int tqparentID, int afterID ); + + void removeLayer( LayerItem *layer ); + void removeLayer( int id ); + +signals: + void activated( LayerItem *layer ); + void activated( int id ); + + void displayNameChanged( LayerItem *layer, const TQString &displayName ); + void displayNameChanged( int id, const TQString &displayName ); + + void propertyChanged( LayerItem *layer, const TQString &name, bool on ); + void propertyChanged( int id, const TQString &name, bool on ); + + void layerMoved( LayerItem *layer, LayerItem *tqparent, LayerItem *after ); + void layerMoved( int id, int tqparentID, int afterID ); + + void requestNewLayer( LayerItem *tqparent, LayerItem *after ); + void requestNewLayer( int tqparentID, int afterID ); + + void requestNewFolder( LayerItem *tqparent, LayerItem *after ); + void requestNewFolder( int tqparentID, int afterID ); + + void requestRemoveLayer( LayerItem *layer ); + void requestRemoveLayer( int id ); + + void requestRemoveLayers( TQValueList layers ); + void requestRemoveLayers( TQValueList ids ); + + void requestLayerProperties( LayerItem *layer ); + void requestLayerProperties( int id ); + +public: //convenience + LayerItem *firstChild() const; + LayerItem *lastChild() const; + +protected slots: + virtual void constructMenu( LayerItem *layer ); + virtual void menuActivated( int id, LayerItem *layer ); + +private: + typedef KListView super; + friend class LayerItem; + friend class LayerToolTIp; + + class Private; + Private* const d; + +private slots: + void slotItemRenamed( TQListViewItem *item, const TQString &text, int col ); + void slotItemMoved( TQPtrList&, TQPtrList&, TQPtrList& ); + void showContextMenu(); + void hideTip(); + void maybeTip(); + +public: //reimplemented for internal reasons + virtual void setCurrentItem( TQListViewItem *i ); + +protected: + virtual void contentsMousePressEvent( TQMouseEvent *e ); + virtual void contentsMouseDoubleClickEvent ( TQMouseEvent *e ); + virtual void findDrop( const TQPoint &pos, TQListViewItem *&tqparent, TQListViewItem *&after ); +}; + +class LayerItem: public KListViewItem +{ +public: + LayerItem( const TQString &displayName, LayerList *tqparent, LayerItem *after = 0, int id = -1 ); + LayerItem( const TQString &displayName, LayerItem *tqparent, LayerItem *after = 0, int id = -1 ); + virtual ~LayerItem(); + + void makeFolder(); + bool isFolder() const; + + // Returns true if this item is the given item or the tree rooted at + // this item contains the given item. + bool tqcontains(const LayerItem *item); + + int id() const; + + TQString displayName() const; + void setDisplayName( const TQString &displayName ); + + bool isActive() const; + void setActive(); + + bool property( const TQString &name ) const; + void setProperty( const TQString &name, bool on ); + void toggleProperty( const TQString &name ); + + void setPreviewImage( TQImage *image ); + void previewChanged(); + + LayerItem *addLayer( const TQString &displayName, LayerItem *after = 0, int id = -1 ); + + LayerItem *prevSibling() const; + +public: //convenience + LayerItem *nextSibling() const; + LayerList *listView() const; + LayerItem *firstChild() const; + LayerItem *tqparent() const; + void update() const; //like TQWidget::update() + +protected: + virtual TQRect rect() const; + + int mapXFromListView( int x ) const; + int mapYFromListView( int y ) const; + TQPoint mapFromListView( const TQPoint &point ) const; + TQRect mapFromListView( const TQRect &rect ) const; + + int mapXToListView( int x ) const; + int mapYToListView( int y ) const; + TQPoint mapToListView( const TQPoint &point ) const; + TQRect mapToListView( const TQRect &rect ) const; + + virtual TQRect textRect() const; + virtual TQRect iconsRect() const; + virtual TQRect previewRect() const; + + virtual void drawText( TQPainter *p, const TQColorGroup &cg, const TQRect &r ); + virtual void drawIcons( TQPainter *p, const TQColorGroup &cg, const TQRect &r ); + virtual void drawPreview( TQPainter *p, const TQColorGroup &cg, const TQRect &r ); + + bool multiline() const; + bool showPreview() const; + virtual TQFont font() const; + TQFontMetrics fontMetrics() const; + + virtual bool mousePressEvent( TQMouseEvent *e ); + + virtual TQString tooltip() const; + + virtual TQImage *previewImage() const; + virtual TQImage tooltipPreview() const; + +private: + typedef KListViewItem super; + friend class LayerList; + friend class LayerToolTip; + + class Private; + Private* const d; + + void init(); + +public: //reimplemented for internal reasons + virtual int width( const TQFontMetrics &fm, const TQListView *lv, int c ) const; + virtual void paintCell( TQPainter *p, const TQColorGroup &cg, int column, int width, int align ); + virtual void setup(); + virtual void setSelected( bool selected ); +}; + +class LayerFolder: public LayerItem +{ +public: + LayerFolder( const TQString &displayName, LayerList *tqparent, LayerItem *after = 0, int id = -1 ) + : LayerItem( displayName, tqparent, after, id ) { makeFolder(); } + LayerFolder( const TQString &displayName, LayerItem *tqparent, LayerItem *after = 0, int id = -1 ) + : LayerItem( displayName, tqparent, after, id ) { makeFolder(); } +}; + + +#endif diff --git a/chalk/ui/squeezedcombobox.cpp b/chalk/ui/squeezedcombobox.cpp new file mode 100644 index 00000000..96929450 --- /dev/null +++ b/chalk/ui/squeezedcombobox.cpp @@ -0,0 +1,167 @@ +/* ============================================================ + * Author: Tom Albers + * Date : 2005-01-01 + * Description : + * + * Copyright 2005 by Tom Albers + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +/** @file squeezedcombobox.cpp */ + +// TQt includes. + +#include +#include +#include +#include +#include +#include +#include +#include + +// Local includes. + +#include "squeezedcombobox.h" + +SqueezedComboBoxTip::SqueezedComboBoxTip( TQWidget * tqparent, SqueezedComboBox* name ) + : TQToolTip( tqparent ) +{ + m_originalWidget = name; +} + +void SqueezedComboBoxTip::maybeTip( const TQPoint &pos ) +{ + TQListBox* listBox = m_originalWidget->listBox(); + if (!listBox) + return; + + TQListBoxItem* selectedItem = listBox->itemAt( pos ); + if (selectedItem) + { + TQRect positionToolTip = listBox->tqitemRect( selectedItem ); + TQString toolTipText = m_originalWidget->itemHighlighted(); + if (!toolTipText.isNull()) + tip(positionToolTip, toolTipText); + } +} + +SqueezedComboBox::SqueezedComboBox( TQWidget *tqparent, const char *name ) + : TQComboBox( tqparent, name ) +{ + setMinimumWidth(100); + m_timer = new TQTimer(this); + m_tooltip = new SqueezedComboBoxTip( listBox()->viewport(), this ); + + connect(m_timer, TQT_SIGNAL(timeout()), + TQT_SLOT(slotTimeOut())); + connect(this, TQT_SIGNAL(activated( int )), + TQT_SLOT(slotUpdateToolTip( int ))); +} + +SqueezedComboBox::~SqueezedComboBox() +{ + delete m_tooltip; + delete m_timer; +} + +bool SqueezedComboBox::tqcontains( const TQString& _text ) const +{ + if ( _text.isEmpty() ) + return false; + + const int itemCount = count(); + for (int i = 0; i < itemCount; ++i ) + { + if ( text(i) == _text ) + return true; + } + return false; +} + +TQSize SqueezedComboBox::tqsizeHint() const +{ + constPolish(); + TQFontMetrics fm = fontMetrics(); + + int maxW = count() ? 18 : 7 * fm.width(TQChar('x')) + 18; + int maxH = TQMAX( fm.lineSpacing(), 14 ) + 2; + + return tqstyle().tqsizeFromContents(TQStyle::CT_ComboBox, this, + TQSize(maxW, maxH)). + expandedTo(TQApplication::globalStrut()); +} + +void SqueezedComboBox::insertSqueezedItem(const TQString& newItem, int index) +{ + m_originalItems[index] = newItem; + insertItem( squeezeText(newItem), index ); + + // if this is the first item, set the tooltip. + if (index == 0) + slotUpdateToolTip(0); +} + +void SqueezedComboBox::resizeEvent ( TQResizeEvent * ) +{ + m_timer->start(200, true); +} + +void SqueezedComboBox::slotTimeOut() +{ + TQMapIterator it; + for (it = m_originalItems.begin() ; it != m_originalItems.end(); + ++it) + { + changeItem( squeezeText( it.data() ), it.key() ); + } +} + +TQString SqueezedComboBox::squeezeText( const TQString& original) +{ + // not the complete widgetSize is usable. Need to compensate for that. + int widgetSize = width()-30; + TQFontMetrics fm( fontMetrics() ); + + // If we can fit the full text, return that. + if (fm.width(original) < widgetSize) + return(original); + + // We need to squeeze. + TQString sqItem = original; // prevent empty return value; + widgetSize = widgetSize-fm.width("..."); + for (uint i = 0 ; i != original.length(); ++i) + { + if ( (int)fm.width(original.right(i)) > widgetSize) + { + sqItem = TQString("..." + original.right(--i)); + break; + } + } + return sqItem; +} + +void SqueezedComboBox::slotUpdateToolTip( int index ) +{ + TQToolTip::remove(this); + TQToolTip::add(this, m_originalItems[index]); +} + +TQString SqueezedComboBox::itemHighlighted() +{ + int curItem = this->listBox()->currentItem(); + return m_originalItems[curItem]; +} + +#include "squeezedcombobox.moc" diff --git a/chalk/ui/squeezedcombobox.h b/chalk/ui/squeezedcombobox.h new file mode 100644 index 00000000..66758335 --- /dev/null +++ b/chalk/ui/squeezedcombobox.h @@ -0,0 +1,137 @@ +/* ============================================================ + * Author: Tom Albers + * Date : 2005-01-01 + * Description : + * + * Copyright 2005 by Tom Albers + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software Foundation; + * either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * ============================================================ */ + +/** @file squeezedcombobox.h */ + +#ifndef STQUEEZEDCOMBOBOX_H +#define STQUEEZEDCOMBOBOX_H + +class TQTimer; + +// TQt includes. + +#include +#include + +class SqueezedComboBox; + +/** @class SqueezedComboBoxTip + * This class shows a tooltip for a SqueezedComboBox + * the tooltip will contain the full text and helps + * the user find the correct entry. It is automatically + * activated when starting a SqueezedComboBox. This is + * inherited from TQToolTip + * + * @author Tom Albers + */ +class SqueezedComboBoxTip : public TQToolTip +{ +public: + /** + * Constructor. An example call (as done in + * SqueezedComboBox::SqueezedComboBox): + * @code + * t = new SqueezedComboBoxTip( this->listBox()->viewport(), this ); + * @endcode + * + * @param tqparent tqparent widget (viewport) + * @param name tqparent widget + */ + SqueezedComboBoxTip( TQWidget *tqparent, SqueezedComboBox *name ); + +protected: + /** + * Reimplemented version from TQToolTip which shows the + * tooltip when needed. + * @param pos the point where the mouse currently is + */ + void maybeTip( const TQPoint& pos ); + +private: + SqueezedComboBox* m_originalWidget; +}; + +/** @class SqueezedComboBox + * + * This widget is a TQComboBox, but then a little bit + * different. It only shows the right part of the items + * depending on de size of the widget. When it is not + * possible to show the complete item, it will be shortened + * and "..." will be prepended. + * + * @image html squeezedcombobox.png "This is how it looks" + * @author Tom Albers + */ +class SqueezedComboBox : public TQComboBox +{ + Q_OBJECT + TQ_OBJECT + +public: + /** + * Constructor + * @param tqparent tqparent widget + * @param name name to give to the widget + */ + SqueezedComboBox(TQWidget *tqparent = 0, const char *name = 0 ); + + /** + * destructor + */ + virtual ~SqueezedComboBox(); + + bool tqcontains(const TQString & text) const; + + /** + * This inserts a item to the list. See TQComboBox::insertItem() + * for detaills. Please do not use TQComboBox::insertItem() to this + * widget, as that will fail. + * @param newItem the original (long version) of the item which needs + * to be added to the combobox + * @param index the position in the widget. + */ + void insertSqueezedItem(const TQString& newItem, int index); + + /** + * This method returns the full text (not squeezed) of the currently + * highlighted item. + * @return full text of the highlighted item + */ + TQString itemHighlighted( ); + + /** + * Sets the tqsizeHint() of this widget. + */ + virtual TQSize tqsizeHint() const; + +private slots: + void slotTimeOut(); + void slotUpdateToolTip( int index ); + +private: + void resizeEvent ( TQResizeEvent * ); + TQString squeezeText( const TQString& original); + + TQMap m_originalItems; + TQTimer* m_timer; + SqueezedComboBoxTip* m_tooltip; +}; + +#endif // STQUEEZEDCOMBOBOX_H diff --git a/chalk/ui/wdgapplyprofile.ui b/chalk/ui/wdgapplyprofile.ui new file mode 100644 index 00000000..35674162 --- /dev/null +++ b/chalk/ui/wdgapplyprofile.ui @@ -0,0 +1,172 @@ + +WdgApplyProfile + + + WdgApplyProfile + + + + 0 + 0 + 538 + 312 + + + + + 3 + 3 + 0 + 0 + + + + + unnamed + + + + groupBox1 + + + Apply Profile + + + + unnamed + + + + lblProfile + + + &Profiles: + + + cmbProfile + + + + + + None + + + + cmbProfile + + + + 7 + 0 + 0 + 0 + + + + + + textLabel1 + + + The image data you want to paste does not have an ICM profile associated with it. If you do not select a profile, Chalk will assume that the image data is encoded in the import profile defined in the Settings dialog. + + + WordBreak|AlignVCenter + + + + + grpRenderIntent + + + &Rendering Intent + + + + + + Rendering intent determines the bias in the color conversion. + + + + unnamed + + + + radioRelativeColorimetric + + + Relative colorimetric + + + Within and outside gamut; same as Absolute Colorimetric. White point changed to result in neutral grays. + + + + + radioSaturation + + + Saturation + + + Hue and saturation maintained with lightness sacrificed to maintain saturation. White point changed to result in neutral grays. Intended for business graphics (make it colorful charts, graphs, overheads, ...) + + + + + radioButton4 + + + Absolute colorimetric + + + Within the destination device gamut; hue, lightness and saturation are maintained. Outside the gamut; hue and lightness are maintained, saturation is sacrificed. White point for source and destination; unchanged. Intended for spot colors (Pantone, TruMatch, logo colors, ...) + + + + + radioPerceptual + + + Perceptual + + + Hue hopefully maintained (but not required), lightness and saturation sacrificed to maintain the perceived color. White point changed to result in neutral grays. Intended for images. + + + + + + + + + + + SqueezedComboBox +

squeezedcombobox.h
+ + -1 + i24 + + 0 + + 3 + 0 + 0 + 0 + + image0 + + + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + + cmbProfile + + + diff --git a/chalk/ui/wdgautobrush.ui b/chalk/ui/wdgautobrush.ui new file mode 100644 index 00000000..a8aa02e0 --- /dev/null +++ b/chalk/ui/wdgautobrush.ui @@ -0,0 +1,355 @@ + +KisWdgAutobrush + + + KisWdgAutobrush + + + + 0 + 0 + 373 + 200 + + + + + 1 + 1 + 0 + 0 + + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + grpSize + + + &Size + + + + unnamed + + + 0 + + + + tqlayout21 + + + + unnamed + + + 0 + + + + textLabel2 + + + + 1 + 1 + 0 + 0 + + + + + + + image0 + + + + + spinBoxWidth + + + ClickFocus + + + 9999 + + + 5 + + + + + textLabel2_2 + + + + + + image1 + + + + + spinBoxHeigth + + + ClickFocus + + + 9999 + + + 5 + + + + + + + bnLinkSize + + + + 1 + 0 + 0 + 0 + + + + + 16 + 0 + + + + + 16 + 32767 + + + + + + + true + + + true + + + + + + + grpFade + + + &Fade + + + + unnamed + + + 0 + + + + tqlayout23 + + + + unnamed + + + 0 + + + + textLabelHorizontal + + + + + + image0 + + + + + spinBoxHorizontal + + + ClickFocus + + + 9999 + + + 1 + + + + + textLabel2_2_2 + + + + + + image1 + + + + + spinBoxVertical + + + ClickFocus + + + 9999 + + + 1 + + + + + + + bnLinkFade + + + + 1 + 0 + 0 + 0 + + + + + 16 + 0 + + + + + 16 + 32767 + + + + NoBackground + + + + + + true + + + true + + + + + + + + + tqlayout6 + + + + unnamed + + + + brushPreview + + + + 7 + 7 + 0 + 0 + + + + + 95 + 95 + + + + + + + true + + + + + + Circle + + + + + Square + + + + comboBoxShape + + + ClickFocus + + + + + spacer4 + + + Vertical + + + Expanding + + + + 20 + 0 + + + + + + + + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b3494441544889dd963112c420084581d97acdfd4f29b9005b3913135050d722bf54f0018223e6ccf06f7db4c594be4d27e63304a190f525885e20154433f646ea050d6512d516887af10075c922f5d7e4ca24da4d439059f803721c4946a1962f798c6641d4da5c05421101445c06b82a6746804d73822202cc67956289a0c89a937b77596790b638abfb59d4da5c017840664196aff97679deab62d39bfcf73cf5ef8160ef4bb4e2e7627657e4909eb694eb071e3b4da9ba4f1ddb0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b9494441544889dd95410ec4200845b1e9ba78ff538a176056260c5181569bccfca590ff2a204da510ecd601008078ed8778953372cec8db20d23c0a72417aa611900999997941a795500a256d2acf7a434354bf212d4927ebc488a417518d4dd75d0dcbb5f2ed983d59f101af94eb7f20d39e3c1963136299f7e2b361f89d9e8c6ed16efc4ee3892a205ecb9adc24fdcc176ffd4b9839e9b896592eb9d623b1106464e605b821da340200086e61afb91ea2a377e89577e57f00357f504513c00b590000000049454e44ae426082 + + + + diff --git a/chalk/ui/wdgautogradient.ui b/chalk/ui/wdgautogradient.ui new file mode 100644 index 00000000..59875f87 --- /dev/null +++ b/chalk/ui/wdgautogradient.ui @@ -0,0 +1,399 @@ + +KisWdgAutogradient + + + KisWdgAutogradient + + + + 0 + 0 + 174 + 180 + + + + + unnamed + + + 0 + + + 0 + + + + groupBox1 + + + Custom Gradient + + + + unnamed + + + + gradientSlider + + + + 7 + 0 + 0 + 0 + + + + + 32767 + 30 + + + + ClickFocus + + + + + tqlayout11 + + + + Arial Unicode MS + 6 + + + + + unnamed + + + + tqlayout10 + + + + + + + + unnamed + + + + textLabel1 + + + + + + + Segment Color + + + + + tqlayout8 + + + + + + + + unnamed + + + + labelLeftColor + + + + + + + Left: + + + + + leftColorButton + + + + 0 + 0 + 0 + 0 + + + + + 30 + 30 + + + + + + + + ClickFocus + + + + + + + + + + tqlayout9 + + + + + + + + unnamed + + + + labelRightColor + + + + + + + Right: + + + + + rightColorButton + + + + 0 + 0 + 0 + 0 + + + + + 30 + 30 + + + + + + + + ClickFocus + + + + + + + + + + + + tqlayout5 + + + + + + + + unnamed + + + + textLabel2 + + + + + + + Opacity: + + + + + intNumInputLeftOpacity + + + + 5 + 0 + 0 + 0 + + + + + + + + ClickFocus + + + % + + + 100 + + + + + intNumInputRightOpacity + + + + 5 + 0 + 0 + 0 + + + + + + + + ClickFocus + + + % + + + 100 + + + + + + + + + tqlayout11_2 + + + + Arial Unicode MS + 6 + + + + + unnamed + + + + + Linear + + + + + Curved + + + + + Sine + + + + + Sphere Inc. + + + + + Sphere Dec. + + + + comboBoxInterpolationType + + + + + + + ClickFocus + + + + + + RGB + + + + + HSV CW + + + + + HSV CCW + + + + comboBoxColorInterpolationType + + + + + + + ClickFocus + + + + + + + + + + + KisGradientSliderWidget +
kis_gradient_slider_widget.h
+ + 40 + 40 + + 0 + + 1 + 1 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + + + kcolorbutton.h + +
diff --git a/chalk/ui/wdgbirdeye.ui b/chalk/ui/wdgbirdeye.ui new file mode 100644 index 00000000..77f03131 --- /dev/null +++ b/chalk/ui/wdgbirdeye.ui @@ -0,0 +1,304 @@ + +WdgBirdEye + + + WdgBirdEye + + + + 0 + 0 + 188 + 126 + + + + + 1 + 1 + 0 + 0 + + + + Overview + + + + + + + + unnamed + + + 0 + + + 0 + + + + tqlayout4 + + + + unnamed + + + 1 + + + 1 + + + + tqlayout10 + + + + unnamed + + + + lblX + + + X: + + + + + txtX + + + + 50 + 0 + + + + + 50 + 32767 + + + + NoFrame + + + Plain + + + 00000 + + + + + lblY + + + Y: + + + + + txtY + + + + 50 + 0 + + + + + 50 + 32767 + + + + NoFrame + + + Plain + + + 00000 + + + + + spacer6 + + + Vertical + + + Expanding + + + + 20 + 20 + + + + + + + + view + + + + 7 + 0 + 2 + 0 + + + + + 75 + 75 + + + + + 200 + 75 + + + + true + + + Box + + + Raised + + + + + + + toolbar + + + + 32767 + 32 + + + + + + tqlayout4 + + + + unnamed + + + 1 + + + 1 + + + + zoom + + + + + + 1600 + + + 10 + + + 10 + + + + + slZoom + + + + 1 + 0 + 1 + 0 + + + + 19 + + + 1 + + + 10 + + + Horizontal + + + + + bn100 + + + 1:1 + + + Zoom to 100% + + + + + + + + + KToolBar +
ktoolbar.h
+ + 20 + 100 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000002a149444154388db595df4b536118c73f3bdbecf8036c4e41f2c6695022045e486e90b721e4ba126f1a0966627f4108512004a197fd0586588220980a9a068be63abaa884cc1f6d30a7e29cfb216dceb39d9d2e2cf3c74997e417de97972fbc9fe77d1e789e57e772b9384d369b4d3deab95c2edd497784b3404ff20f460650fff732fc0ee0f5bc241298252dc710f4174e4be4908cb9661439cefa7c0fb71eee79fbe0486096b5af3d644e4e50537a3de880b4f2c7db07a7e51819156e77fe3b1860b4bb1095d871f0c1f4239108068381f84e9cc58545c6c7c78946a3d45dafa3b4b414511411f34456d756e9eded65706090924a076bdf9e1f071fd4c0c000c15010f7b49bc93793b4de6ba5abab0bd3451300bbbbbb783e7a08ac04d858dfd0cc4013dcdedebe7f368a462449a2ff553fcd4dcdf87c3eba7bba71bbdcf8fd7e8a8a8ab20703d4d6d6d2f1a00383d180b9c84c85a58282fc027c3e1ff537ea71dc71303a36caf6f6367d2ffab203773eeaa4e1660336ab8db49226c798839c9211f402b22c53535383cd6ac35261c1eff76b82353b4fafd7a3a80a899d048220904aa588842324779278bd5e9cef9cc41371ca2e9511de0a675f8ae1a161cc2633e5e5e5980a4d0882c06678133157243f2f9f85a50526a62698fb32c78c674613acf962dfb28fd05688443c41329944de95997e3fcdc8e8088b4b8bb85d6e42c110f6463b5557aab207c77ec458febe8c3fe067657585542a85d566c5bbecc5fdc18de5b285603088925168b9db927d294451c4e9745275b50a7ba39dc44e8292e212daeeb7517dad9aa9b7534833129224d1d4d4a409de9f6e9fc61eabaf9f9d7d9a7d1e7ba20e3dd5986e8a1c47c75ecf97543ab45ff117e5e416138f7af790474bb13edf435a0195d8a19ecf46eaaf2d9339609ed7a03ff56b3aabce0dfc13238259bff00a6d890000000049454e44ae426082 + + + + kiconloader.h + + + zoomChanged(int) + zoomMinus() + zoomPlus() + +BarIcon + + + ktoolbar.h + knuminput.h + +
diff --git a/chalk/ui/wdgcolorsettings.ui b/chalk/ui/wdgcolorsettings.ui new file mode 100644 index 00000000..3d2def86 --- /dev/null +++ b/chalk/ui/wdgcolorsettings.ui @@ -0,0 +1,357 @@ + +WdgColorSettings + + + WdgColorSettings + + + + 0 + 0 + 586 + 457 + + + + Color Settings + + + + unnamed + + + + tqlayout8 + + + + unnamed + + + + textLabel1_2 + + + Default color model for new images: + + + + + cmbWorkingColorSpace + + + + 7 + 0 + 0 + 0 + + + + + 0 + 20 + + + + + + + + grpDisplay + + + Display + + + + unnamed + + + + textLabel1 + + + &Monitor profile: + + + cmbPrintProfile + + + The icm profile for your calibrated monitor. + + + + + textLabel1_4 + + + &Rendering intent: + + + cmbMonitorIntent + + + In converting the image data to be shown on screen you can select different ways in which to handle colors that can not be displayed on a monitor (out of gamut). +The different rendering intent methods will affect only what is shown on screen, and exporting or printing the image will not be affected. +<li>Perceptual, shows full gamut. Recommended for photographic images.</li> +<li>Relative Colorimetric, also called Proof or Preserve Identical Color and White Point. Reproduces in-gamut colors and clips out-of-gamut colors to the nearest reproducible color.</li> +<li>Absolute Colorimetric, much like Relative Colorimetric but it sacrificing saturation and possibly lightness for out-of-gamut colors. Rarely of use for photographic images.</li><li>Saturation, Preserves saturation. Convert from the saturated primary colors in the image to saturated primary colors on screen.</li> + + + + + + Perceptual + + + + + Relative Colorimetric + + + + + Saturation + + + + + Absolute Colorimetric + + + + cmbMonitorIntent + + + + 7 + 0 + 0 + 0 + + + + In converting the image data to be shown on screen you can select different ways in which to handle colors that can not be displayed on a monitor (out of gamut). +The different rendering intent methods will affect only what is shown on screen, and exporting or printing the image will not be affected. +<li>Perceptual, shows full gamut. Recommended for photographic images.</li> +<li>Relative Colorimetric, also called Proof or Preserve Identical Color and White Point. Reproduces in-gamut colors and clips out-of-gamut colors to the nearest reproducible color.</li> +<li>Absolute Colorimetric, much like Relative Colorimetric but it sacrificing saturation and possibly lightness for out-of-gamut colors. Rarely of use for photographic images.</li><li>Saturation, Preserves saturation. Convert from the saturated primary colors in the image to saturated primary colors on screen.</li> + + + + + cmbMonitorProfile + + + + 7 + 0 + 0 + 0 + + + + + + + + groupBox2 + + + true + + + Printing + + + + unnamed + + + + cmbPrintingColorSpace + + + + 7 + 5 + 0 + 0 + + + + + + cmbPrintProfile + + + + + lbldefaultprinterspace + + + Color model: + + + + + textLabel4 + + + Profile: + + + cmbPrintProfile + + + The icm profile for your calibrated printer + + + + + + + grpPasteBehaviour + + + Profile on Paste + + + + unnamed + + + + textLabel1_2_2 + + + <p>Select what color profile to add when pasting from external applications that do not use a color profile.</p> + + + WordBreak|AlignVCenter + + + + + radioPasteWeb + + + Use sRGB + + + sRGB are like images from the web are supposed to be seen. + + + + + radioPasteMonitor + + + Use monitor profile + + + This is like you see it in the other application + + + + + radioPasteAsk + + + Ask + + + + + + + tqlayout6 + + + + unnamed + + + + chkBlackpoint + + + Use Blackpoint compensation + + + true + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+ + SqueezedComboBox +
squeezedcombobox.h
+ + -1 + 0 + + 0 + + 3 + 0 + 0 + 0 + + image1 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082 + + + + + kis_cmb_idlist.h + kcombobox.h + squeezedcombobox.h + kis_cmb_idlist.h + kcombobox.h + +
diff --git a/chalk/ui/wdgcustombrush.ui b/chalk/ui/wdgcustombrush.ui new file mode 100644 index 00000000..78c77be3 --- /dev/null +++ b/chalk/ui/wdgcustombrush.ui @@ -0,0 +1,199 @@ + +KisWdgCustomBrush + + + KisWdgCustomBrush + + + + 0 + 0 + 267 + 265 + + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + textLabel2 + + + Style: + + + + + + Constant + + + + + Random + + + + + Incremental + + + + + Pressure + + + + + Angular + + + + comboBox2 + + + true + + + 2 + + + + + textLabel3 + + + Selection mode: + + + + + + Regular + + + + + Animated + + + + style + + + + + + + colorAsMask + + + Use color as tqmask + + + + + tqlayout6 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + preview + + + + 0 + 0 + 0 + 0 + + + + + 50 + 50 + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + tqlayout7 + + + + unnamed + + + + brushButton + + + Use as Brush + + + + + addButton + + + Add to Predefined Brushes + + + + + + + + diff --git a/chalk/ui/wdgcustompalette.ui b/chalk/ui/wdgcustompalette.ui new file mode 100644 index 00000000..c5cbe9dc --- /dev/null +++ b/chalk/ui/wdgcustompalette.ui @@ -0,0 +1,88 @@ + +KisWdgCustomPalette + + + KisWdgCustomPalette + + + + 0 + 0 + 282 + 384 + + + + + unnamed + + + + palettename + + + Unnamed + + + + + view + + + + + addColor + + + Add New Color... + + + + + removeColor + + + true + + + Remove Selected Color + + + + + addPalette + + + Add to Predefined Palettes + + + + + + + KisPaletteView +
kis_palette_view.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082 + + + + + kis_palette_view.h + +
diff --git a/chalk/ui/wdgcustompattern.ui b/chalk/ui/wdgcustompattern.ui new file mode 100644 index 00000000..d195f670 --- /dev/null +++ b/chalk/ui/wdgcustompattern.ui @@ -0,0 +1,156 @@ + +KisWdgCustomPattern + + + KisWdgCustomPattern + + + + 0 + 0 + 255 + 232 + + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + textLabel1 + + + Source: + + + + + + Entire Image + + + + comboBox1 + + + false + + + + + + + tqlayout6 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + preview + + + + 0 + 0 + 0 + 0 + + + + + 50 + 50 + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + tqlayout7 + + + + unnamed + + + + patternButton + + + Use as Pattern + + + + + exportButton + + + false + + + Export + + + + + addButton + + + Add to Predefined Patterns + + + + + + + + diff --git a/chalk/ui/wdgdisplaysettings.ui b/chalk/ui/wdgdisplaysettings.ui new file mode 100644 index 00000000..990f316b --- /dev/null +++ b/chalk/ui/wdgdisplaysettings.ui @@ -0,0 +1,90 @@ + +WdgDisplaySettings + + + WdgDisplaySettings + + + + 0 + 0 + 374 + 154 + + + + Display + + + + unnamed + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 50 + + + + + + buttonGroup1 + + + OpenGL + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + cbUseOpenGL + + + Enable OpenGL + + + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 121 + 31 + + + + + + + + + diff --git a/chalk/ui/wdggeneralsettings.ui b/chalk/ui/wdggeneralsettings.ui new file mode 100644 index 00000000..051cf795 --- /dev/null +++ b/chalk/ui/wdggeneralsettings.ui @@ -0,0 +1,183 @@ + +WdgGeneralSettings + + + WdgGeneralSettings + + + + 0 + 0 + 335 + 209 + + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + tqlayout1 + + + + unnamed + + + + textLabel1 + + + &Cursor tqshape: + + + m_cmbtqCursorShape + + + + + + Tool Icon + + + + + Crosshair + + + + + Arrow + + + + + Brush Outline + + + + m_cmbtqCursorShape + + + + + + + grpDockability + + + Palette Behavior + + + true + + + + unnamed + + + + radioAllowDocking + + + Allow &docking + + + + + radioDisallowDocking + + + Allow only &floating + + + + + radioSmartDocking + + + Allow docking only on &large screens + + + + + + + tqlayout2 + + + + unnamed + + + + textLabel1_2 + + + &Palette font size: + + + numDockerFontSize + + + + + numDockerFontSize + + + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 41 + 20 + + + + + + spacer2 + + + Vertical + + + Expanding + + + + 20 + 41 + + + + + + + + + + knuminput.h + + diff --git a/chalk/ui/wdggridsettings.ui b/chalk/ui/wdggridsettings.ui new file mode 100644 index 00000000..a89574d1 --- /dev/null +++ b/chalk/ui/wdggridsettings.ui @@ -0,0 +1,468 @@ + +WdgGridSettingsBase + + + WdgGridSettingsBase + + + + 0 + 0 + 422 + 233 + + + + + unnamed + + + 0 + + + + spacer14 + + + Vertical + + + Expanding + + + + 20 + 31 + + + + + + groupBox9 + + + Colors + + + + unnamed + + + + spacer12_2 + + + Horizontal + + + Expanding + + + + 16 + 20 + + + + + + colorMain + + + + + + + 99 + 99 + 99 + + + + + + textLabel3 + + + Subdivision: + + + + + textLabel2_4 + + + Main: + + + + + colorSubdivision + + + + + + + 200 + 200 + 200 + + + + + + + + groupBox5 + + + Styles + + + + unnamed + + + + textLabel4 + + + Main: + + + + + + Lines + + + + + Dashed Lines + + + + + Dots + + + + selectMainStyle + + + 0 + + + + + + Lines + + + + + Dashed Lines + + + + + Dots + + + + selectSubdivisionStyle + + + + + textLabel5 + + + Subdivision: + + + + + spacer15 + + + Horizontal + + + Expanding + + + + 34 + 20 + + + + + + + + groupBox3 + + + Spacing + + + + unnamed + + + + tqlayout8 + + + + unnamed + + + + tqlayout6 + + + + unnamed + + + + textLabel2 + + + + 1 + 1 + 0 + 0 + + + + + + + image0 + + + + + textLabel2_2 + + + + + + image1 + + + + + intVSpacing + + + 10 + + + 0 + + + + + intHSpacing + + + 10 + + + 0 + + + + + + + bnLinkSpacing + + + + 1 + 0 + 0 + 0 + + + + + 16 + 0 + + + + + 16 + 32767 + + + + + + + true + + + true + + + + + + + tqlayout9 + + + + unnamed + + + + textLabel1 + + + Subdivision: + + + + + intSubdivision + + + 2 + + + 1 + + + + + + + spacer12 + + + Horizontal + + + Expanding + + + + 41 + 20 + + + + + + + + groupBox3_2 + + + Offset + + + + unnamed + + + + textLabel2_3 + + + + 1 + 1 + 0 + 0 + + + + X: + + + + + textLabel2_2_2 + + + Y: + + + + + intOffsetY + + + 0 + + + + + intOffsetX + + + 0 + + + + + spacer11 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + + + + + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b3494441544889dd963112c420084581d97acdfd4f29b9005b3913135050d722bf54f0018223e6ccf06f7db4c594be4d27e63304a190f525885e20154433f646ea050d6512d516887af10075c922f5d7e4ca24da4d439059f803721c4946a1962f798c6641d4da5c05421101445c06b82a6746804d73822202cc67956289a0c89a937b77596790b638abfb59d4da5c017840664196aff97679deab62d39bfcf73cf5ef8160ef4bb4e2e7627657e4909eb694eb071e3b4da9ba4f1ddb0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000190000001a0806000000427df7cd000000b9494441544889dd95410ec4200845b1e9ba78ff538a176056260c5181569bccfca590ff2a204da510ecd601008078ed8778953372cec8db20d23c0a72417aa611900999997941a795500a256d2acf7a434354bf212d4927ebc488a417518d4dd75d0dcbb5f2ed983d59f101af94eb7f20d39e3c1963136299f7e2b361f89d9e8c6ed16efc4ee3892a205ecb9adc24fdcc176ffd4b9839e9b896592eb9d623b1106464e605b821da340200086e61afb91ea2a377e89577e57f00357f504513c00b590000000049454e44ae426082 + + + + + kcolorbutton.h + kcolorbutton.h + kcombobox.h + kcombobox.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + + diff --git a/chalk/ui/wdglayerbox.ui b/chalk/ui/wdglayerbox.ui new file mode 100644 index 00000000..9bfe5760 --- /dev/null +++ b/chalk/ui/wdglayerbox.ui @@ -0,0 +1,299 @@ + +WdgLayerBox + + + WdgLayerBox + + + + 0 + 0 + 352 + 542 + + + + + unnamed + + + 0 + + + 0 + + + + tqlayout3 + + + + unnamed + + + + cmbComposite + + + + 3 + 0 + 0 + 0 + + + + + 0 + 10 + + + + Blending mode + + + + + intOpacity + + + + 0 + 5 + 0 + 0 + + + + + + + + listLayers + + + + + tqlayout6 + + + + unnamed + + + + bnAdd + + + + 22 + 22 + + + + + 18 + 18 + + + + + + + image0 + + + Create a new layer + + + + + bnLower + + + + 22 + 22 + + + + + 18 + 18 + + + + + + + image1 + + + Move layer down + + + + + bnRaise + + + + 22 + 22 + + + + + 18 + 18 + + + + + + + image2 + + + Move layer up + + + + + bnProperties + + + + 22 + 22 + + + + + 18 + 18 + + + + ... + + + View or change the layer properties + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 20 + 20 + + + + + + bnDelete + + + + 22 + 22 + + + + + 18 + 18 + + + + + + + image3 + + + Delete the layer + + + + + + + + + KisCmbComposite +
kis_cmb_composite.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image4 +
+ + KisLayerList +
kis_layerlist.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image4 +
+ + KisIntSpinbox +
kis_int_spinbox.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image4 +
+
+ + + 89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff610000015c49444154388d8592c1aec22010450f94561bbfcda53f60d77e927fe0ca4d5dfb3126d59586b44271780b539eedab7924041866eebd7341c51801381c0e1160384fc7e97462bfdfab69dc0c9b18239bcd265d586b71ced1340dc6bcd3aaaa8a53103d4b071445419ee7e4799e62ebf59aaaaa4612bf02006459465114a985e3f108c076bb4d2066bef45decbdc71883738edd6ec7e572e17abd723e9fff57a094a2280ab4d6e479ceed76e37ebf638c41a95f1bbe2ad05aa7b5ef7b9c732c160b5eafd7286f164044e8ba8ee7f349d334586b59ad56946549dff7a3a7fe0320228808de7b1e8f072242599600841092b2af005a6bdab6c55a0bc072b924840080730e111979f0c7c410026ddba2b54e7330eef34f7c55e0bd9ffdce5a6b628c6459368e4f13bbae1b154d59638c2382d91606234524f52f222967d603a514defbc43cb83db04ddd1f46f2a0ae6beaba26c638621840945209ecf3fe07b32fb7352555170c0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000160000001208060000005f252e2d000000d949444154388ded94210e84301045ffdfecb5b0582c24681a2c1a8e00b24d3900774063d11c0314d8594543a06cd6ace39b9974326f7e3a4d2922f8875e7fa13ee0a3debec33ccf050048625f2e49008088b87c97d69a27841f4c124551b8fc0c3b0e8ba2e877c722a29aa6b1699a5e404765590692ca6bcef78e876140d77519491b86a1d751599600a08c316d100497faedf292246901a8beef31cf33966571b1aa2a07bdebbf0593441cc72d49358e23d675c5b66da8eb1a22a2b4d6b7d0afe0235c44d4344db0d682a432c6b4e7fbbef43e7fc503bee8030549631e4f2cf51e0000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000000da49444154388dcd92310e83300c45bfab5e872b709ca0b03022b13130b123251720e21830700060820db18623b84b5dd1a22eedd0fe29b6e2e76f27c4ccf84697afaaff02709543dbb62022c84e9c738a994dd77520a2a8aa2a2b7799196118be77e09c53004c5996e8fb1e008cd65a4931119d4790a474cef31cebba62db36344df3801c8b4f0eeaba56004c966598e719de7b78efb1ef3bacb50060e23856c7a72709ee749324099665395995384d531051340c837d05b0d61ad334bdddb8a8280a8ce3484f802008583a1d252e5ef327c0a7fafd4ffc3de006c2bf7b9f44bff3680000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d49484452000000100000001008060000001ff3ff61000000ff49444154388da592318e84300c459f4773072e0105b7a1e10020eeb0ecd57205e8e9902221100851e2a9321b3261a5d5ba89127f3ddbdf1155e53ff1bc4b6459a621bcef7b0975e244755d7fa96a0b20f2a103c0694504634cdbf7fdf7d34bb64551902409499260adc55acbbaae8808aacab22cecfbce711c18635ae0072022344d43cc13077067740480aaaab42c4bf23c679a26b66d631806c671e4380ee679669a268c316f3f1e612557c581fd02eeddf7e802f0c54e749e671414058433fa77d75db8a10b20acaeaaef0eee220ab8081ebf4ba21ef86d3be37c636f4d0c2336bf0ffa008406f926c63604c1470248d354fd5dc736d3759ddc02fe1a2f646fb86fb4737d520000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + +
diff --git a/chalk/ui/wdglayerproperties.ui b/chalk/ui/wdglayerproperties.ui new file mode 100644 index 00000000..35eb01ad --- /dev/null +++ b/chalk/ui/wdglayerproperties.ui @@ -0,0 +1,170 @@ + +WdgLayerProperties + + + WdgLayerProperties + + + + 0 + 0 + 362 + 210 + + + + + unnamed + + + + editName + + + + + textLabel3 + + + &Opacity: + + + intOpacity + + + + + cmbProfile + + + + + textLabel4 + + + Composite mode: + + + + + textLabel1_2 + + + Profile: + + + + + textLabel2 + + + Colorspace: + + + + + textLabel1 + + + &Name: + + + editName + + + + + cmbColorSpaces + + + + + cmbComposite + + + + + intOpacity + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+ + KisCmbComposite +
kis_cmb_composite.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image1 +
+ + KisIntSpinbox +
kis_int_spinbox.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image1 +
+ + SqueezedComboBox +
squeezedcombobox.h
+ + -1 + i24 + + 0 + + 3 + 0 + 0 + 0 + + image2 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082 + + + +
diff --git a/chalk/ui/wdgnewimage.ui b/chalk/ui/wdgnewimage.ui new file mode 100644 index 00000000..5e3b89a6 --- /dev/null +++ b/chalk/ui/wdgnewimage.ui @@ -0,0 +1,435 @@ + +WdgNewImage + + + WdgNewImage + + + + 0 + 0 + 572 + 595 + + + + New Image + + + + unnamed + + + 0 + + + + lblName + + + &Name: + + + txtName + + + + + txtName + + + untitled-1 + + + + + grpImage + + + &Image Size + + + + unnamed + + + + lblHeight + + + &Height: + + + intHeight + + + + + lblWidth + + + &Width: + + + intWidth + + + + + intWidth + + + 1600 + + + 0 + + + + + intHeight + + + 1200 + + + 0 + + + + + lblResolution + + + &Resolution: + + + doubleResolution + + + + + doubleResolution + + + dpi + + + 500 + + + 1 + + + 10 + + + 100 + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 131 + 61 + + + + + + + + grpMode + + + Mode + + + + unnamed + + + + lblColorSpaces + + + Color space: + + + cmbColorSpaces + + + + + cmbColorSpaces + + + + + cmbProfile + + + + + lblProfiles + + + Profile: + + + cmbProfile + + + + + + + grpContents + + + Contents + + + + unnamed + + + + txtDescription + + + + + lblColor + + + Canvas color: + + + cmbColor + + + + + cmbColor + + + + + lblDescription + + + Description: + + + AlignTop + + + txtDescription + + + + + lblOpacity + + + Opacity: + + + sliderOpacity + + + + + opacityPanel + + + NoFrame + + + Plain + + + + unnamed + + + 0 + + + + textLabel1 + + + Transparent + + + + + sliderOpacity + + + 100 + + + 10 + + + 100 + + + Horizontal + + + Below + + + 20 + + + Opacity of the background color. + + + Opacity of the background color. + + + + + textLabel2 + + + Opaque + + + + + + + + + tqlayout1 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Expanding + + + + 480 + 21 + + + + + + m_createButton + + + Create + + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 21 + 0 + + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+ + SqueezedComboBox +
squeezedcombobox.h
+ + -1 + 32 + + 0 + + 3 + 0 + 0 + 0 + + image1 +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000032d49444154388db59531681c4714863f892dde8004b320c32e3870020b74458a6b0f5458e581c016a809a8496b42208454098604d2c4904a6954a410511ae752085b858c1208dc35221244b00119f60ac12ee860062c980719708a95a248f129459cd7cceeccf0edb76fff61a706830197d5ed765ff3166a30184c4d5d829fed3c7bdd5e6ce3bda71a5738ef301802e1d6d179477152303c1842bc822797a64fbf7b4a9a43be00ada817cb0e12011c2611205ccd73755f9c087c6b19bef0d7c100f5b8267d07caf10fe8ab9210156320fc01be16aa5a11043307f30b20a21041019985f48ef2f7fa0becc68e80475fd584e831b396f210f67795c3831a4940a3228925bb27f4d652ba4b01a199b73342f3981be0ca57745042ac30c632d853b6373d44b056c8ef0922508d94d14be59b2f4aeaf58cd5751069e06f3436890114332b9487d0bf80f61e64dc5f813c3790045453f67703fd4d4f7f6b4496b5597e689044af194f5f5e841800210478bee3d1a8f41e64acbe0f69ae6852e1cf0ccf7f74f4d652defbc042226c6f55e8f89f91bb6e9c387c9d521c9558db988a3416fe3c67e32b4779ec7167f0e8939ce19ea7fc5d298a80c875f03563930855ed2081bc05e91d5014ef53363eaf288e3d6285ee520a338e76c7a251a94e41e30470d3631004a262672e3eca59cec6978ef2b889979d11f2bb904af3be92081a416e28dfe831983920b1142345d5b0ff2234a6334276d7321ad53c795c511ca654a5a251996f19b83d158ef602b45a423d52f67703abeb29ee4ce9de4fc93378f218462f6b3efdb042cf3d59666977a0aa6fe9310888d25b13342afd4dcffeaee3d147399da540ab13f8f8b39c2cb3f8710d11ba2b96f9c57fcd7180287497a03ecde86f8dd8fe1a867b9ef6bb1612a84a871f6bd35b94e217a53832589970f2dcd85d9c7d4580d57521cbdaf4bfaf288e95e268d4ec8e60e72ccb0f2dbffea454e71e8d29f57882717152509482a48d8924b0bc12e82ee51445a03a6da079cbd0eec0fc22142b06620e89a3fc8d3783870743d814d2bc8994aa6ff286472e764902e5a96f72bbd3b4c37b280e95aa9e604c84e1cf978b37c74935797d7ae2ca7fac6968fe51ff0bf86dc30783c1d49f0baa9bb819e612310000000049454e44ae426082 + + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b249444154388db5944d4c5c5518869f73ce9db9cc40f929cc30300e18129a50685268a28291982e1a2175212eaab1c49d3f8971e7aec6aedb54a32b435dd8685cb8c0c4b8b0feb421b7bd8186a069d23209144b18cb0c02f3732ff3c3ccbdd705a571941213f1dd9d93739ef37e6fbeef08d334d9d5d0d090c701c8344d2176c1a6697a5d5d5dd8b64d2a95c2b2ac7f05b12c8b783c8e6118d8b6fd685fdb753a39394928e2a7c55724d693a7e214104220242805520a84d8b9e4790f0b1302c7751958f1e30534be9fa41a0c60db362dbe227f64af91b6e7719c2dfc0117a71c603da591de2882a7d3d4ec27122b10acad50aeb88044d542b84de3af7ab44aa55274f4e449dbf354bc347aa096fbf37e7efa2ecbad1b36907d78b289de8120232f37726250c3f52cf0a026a0f6065b9645d929e038167aa096d91b307171059034b5f8e9e9eb44fa052b4b25eeccd9dc99cb71f6ad082fbea2e351c075bdbdc13b9109fc01b83fef63e2e232e03076b68393231a0dcd024daf502c1e66e67a89cb971ef0e5a74bb4b61e6378248094b92ab0ac024b70ca017ef8360394187b2dc6d8b89ffa500e4d4f93d9083275d5e6f9913ade3dd70ee87c7d25c95646a25415aadab152b09ed4f8c5cc130a853839eac3951b684a61e70ef3f9c739668c24eba912afbfddc6d4d506e6a6d7b8b7d082aa8eb8dab19482cdcd220e36dd3dc19df23545de0a71f952861923493456cfd3cf36123c54a0b7bf0e8064621b21f7712c040857071ca4eea0f40a99f510573ec971cb48030e811a1faded3e94be85f2fb00703d1ff26f96ab9f011a5b04d0c4f26fdb948a754c1b25668c2491483d5d5d611617d6b8f0fe32cb779b492ce65168b4c774a4701eefd8f3a02d56e6e8f13aeefe9a63fa5a89d1970e91d908f3d46003e1480d173e28b37827c9b977348ab92ce16890237d1ec907ee3e8e3d8f60d0e1f4583d009f7d9860662acff89bad1c1faad0717493f7ce7713ed8cb0995c255f2a317a26427b67198f6a70f51c0a41b902279ed1187f23cc17130b7c74de65eac77a7a8f05517e41e2deefa4930576db60fa7a8ee1535134df3e93e7b82e0817476439fd6a9070a49f6fbe4a3077739db99b15c001146dd13a46cf1cc1f83943c62e51de76b0738fc9381e8f3390f0236b252e124999e11724fd833196164bacadb87848224fe874f779b43fe9f2dca928956d505a96dbb3f9bdc18661e00534c26d1a7a40e13912a11c9454280da41048a9915c75585df500074d53d816dc9edd229528ef0db66dbbea3ffdaffa471f1f28d8344df1bf800f1a6e9aa6f813c39885bc050f269c0000000049454e44ae426082 + + + + txtName + intWidth + intHeight + doubleResolution + cmbColorSpaces + cmbProfile + cmbColor + sliderOpacity + txtDescription + + + + knuminput.h + knuminput.h + knuminput.h + knuminput.h + knuminput.h + kis_cmb_idlist.h + squeezedcombobox.h + kcolorcombo.h + +
diff --git a/chalk/ui/wdgpalettechooser.ui b/chalk/ui/wdgpalettechooser.ui new file mode 100644 index 00000000..553cd62b --- /dev/null +++ b/chalk/ui/wdgpalettechooser.ui @@ -0,0 +1,105 @@ + +KisPaletteChooser + + + KisPaletteChooser + + + + 0 + 0 + 289 + 163 + + + + Choose Palette + + + true + + + + unnamed + + + + paletteList + + + + + tqlayout2 + + + + unnamed + + + + Horizontal Spacing2 + + + Horizontal + + + Expanding + + + + 255 + 20 + + + + + + buttonOk + + + &OK + + + + + + true + + + true + + + + + buttonCancel + + + &Cancel + + + + + + true + + + + + + + + + buttonOk + clicked() + KisPaletteChooser + accept() + + + buttonCancel + clicked() + KisPaletteChooser + reject() + + + + diff --git a/chalk/ui/wdgperformancesettings.ui b/chalk/ui/wdgperformancesettings.ui new file mode 100644 index 00000000..0bce88e9 --- /dev/null +++ b/chalk/ui/wdgperformancesettings.ui @@ -0,0 +1,146 @@ + +WdgPerformanceSettings + + + WdgPerformanceSettings + + + + 0 + 0 + 495 + 220 + + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + textLabel1 + + + Maximum number of tiles kept in memory: + + + The maximum number of "tiles" that are kept in memory. For regular RGBA8 images, each tile is about 16 kB in size. Thus, for a value of 500 tiles this usually means about 8 megabytes are used for image data. If you regularly handle large images, a greater value here might be useful. +Note that this number is only a guideline for Chalk, and is not guaranteed to be the actual number of tiles in memory. + + + + + m_maxTiles + + + 500 + + + 0 + + + The maximum number of "tiles" that are kept in memory. For regular RGBA8 images, each tile is about 16 kB in size. Thus, for a value of 500 tiles this usually means about 8 megabytes are used for image data. If you regularly handle large images, a greater value here might be useful. +Note that this number is only a guideline for Chalk, and is not guaranteed to be the actual number of tiles in memory. + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 81 + 20 + + + + + + + + tqlayout5 + + + + unnamed + + + + textLabel2 + + + Swappiness: + + + This configures how much Chalk will use the swap file. If you move the slider all the way to the left, Chalk will not use the swap file at all. If you move it all the way to the right, Chalk will make maximum use of the swap file. + + + + + m_swappiness + + + + 600 + 32767 + + + + 6 + + + 3 + + + Horizontal + + + Below + + + This configures how much Chalk likes to swap. Move the slider to the left, and there is no swapping at all. Move it to the right there is a lot of swapping going on. + + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 139 + + + + + + + + + + knuminput.h + knuminput.h + + diff --git a/chalk/ui/wdgpressuresettings.ui b/chalk/ui/wdgpressuresettings.ui new file mode 100644 index 00000000..41ead6a9 --- /dev/null +++ b/chalk/ui/wdgpressuresettings.ui @@ -0,0 +1,66 @@ + +WdgPressureSettings + + + WdgPressureSettings + + + + 0 + 0 + 510 + 87 + + + + + unnamed + + + + spacer1 + + + Vertical + + + Expanding + + + + 21 + 89 + + + + + + textLabel3 + + + Softer + + + + + textLabel2 + + + Firmer + + + + + slPressure + + + Horizontal + + + NoMarks + + + + + + diff --git a/chalk/ui/wdgselectionoptions.ui b/chalk/ui/wdgselectionoptions.ui new file mode 100644 index 00000000..39846fa3 --- /dev/null +++ b/chalk/ui/wdgselectionoptions.ui @@ -0,0 +1,64 @@ + +WdgSelectionOptions + + + WdgSelectionOptions + + + + 0 + 0 + 180 + 34 + + + + + unnamed + + + 0 + + + 0 + + + + tqlayout1 + + + + unnamed + + + 6 + + + + lblAction + + + Action: + + + + + + Add + + + + + Subtract + + + + cmbAction + + + + + + + + diff --git a/chalk/ui/wdgshapeoptions.ui b/chalk/ui/wdgshapeoptions.ui new file mode 100644 index 00000000..c0e6338b --- /dev/null +++ b/chalk/ui/wdgshapeoptions.ui @@ -0,0 +1,98 @@ + +WdgGeometryOptions + + + WdgGeometryOptions + + + + 0 + 0 + 275 + 31 + + + + Geometry Options + + + + unnamed + + + 2 + + + 2 + + + + spacer9 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + textLabel3 + + + Fill: + + + + + + Not Filled + + + + + Foreground Color + + + + + Background Color + + + + + Pattern + + + + cmbFill + + + + + spacer2 + + + Horizontal + + + Expanding + + + + 21 + 20 + + + + + + + diff --git a/chalk/ui/wdgtabletdevicesettings.ui b/chalk/ui/wdgtabletdevicesettings.ui new file mode 100644 index 00000000..59cad307 --- /dev/null +++ b/chalk/ui/wdgtabletdevicesettings.ui @@ -0,0 +1,193 @@ + +WdgTabletDeviceSettings + + + WdgTabletDeviceSettings + + + + 0 + 0 + 363 + 386 + + + + Configure Tablet Device + + + + unnamed + + + + spacer1 + + + Vertical + + + Expanding + + + + 21 + 90 + + + + + + groupBox3 + + + Axes + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + textLabel1_2 + + + X: + + + + + cbX + + + + + + + tqlayout4_4 + + + + unnamed + + + + textLabel1_2_4 + + + Y: + + + + + cbY + + + + + + + tqlayout4_2 + + + + unnamed + + + + textLabel1_2_2 + + + Pressure: + + + + + cbPressure + + + + + + + tqlayout4_3 + + + + unnamed + + + + textLabel1_2_3 + + + X tilt: + + + + + cbXTilt + + + + + + + tqlayout4_6 + + + + unnamed + + + + textLabel1_2_6 + + + Y tilt: + + + + + cbYTilt + + + + + + + tqlayout4_5 + + + + unnamed + + + + textLabel1_2_5 + + + Wheel: + + + + + cbWheel + + + + + + + + + + diff --git a/chalk/ui/wdgtabletsettings.ui b/chalk/ui/wdgtabletsettings.ui new file mode 100644 index 00000000..ad4dc7bf --- /dev/null +++ b/chalk/ui/wdgtabletsettings.ui @@ -0,0 +1,104 @@ + +WdgTabletSettings + + + WdgTabletSettings + + + + 0 + 0 + 510 + 268 + + + + Tablet + + + + unnamed + + + + grpTabletDevices + + + Tablet Devices + + + + unnamed + + + + tqlayout4 + + + + unnamed + + + + textLabel1 + + + Device: + + + + + cbTabletDevice + + + + + + + tqlayout5 + + + + unnamed + + + + chkEnableTabletDevice + + + Enable + + + + + btnConfigureTabletDevice + + + Configure... + + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 21 + 90 + + + + + + + diff --git a/chalk/ui/wdgtextbrush.ui b/chalk/ui/wdgtextbrush.ui new file mode 100644 index 00000000..562a62f9 --- /dev/null +++ b/chalk/ui/wdgtextbrush.ui @@ -0,0 +1,158 @@ + +KisWdgTextBrush + + + KisWdgTextBrush + + + + 0 + 0 + 317 + 89 + + + + Text + + + + unnamed + + + + tqlayout3 + + + + unnamed + + + + tqlayout9 + + + + unnamed + + + + labelText + + + Text: + + + + + lineEdit + + + + 120 + 0 + + + + + + + + The Quick Brown Fox Jumps Over The Lazy Dog + + + + + + + tqlayout10 + + + + unnamed + + + + lblFont + + + + 5 + 5 + 0 + 0 + + + + Font: + + + + + bnFont + + + + 0 + 0 + 0 + 0 + + + + ... + + + + + + + + + + + + spacer1 + + + Horizontal + + + Minimum + + + + 121 + 20 + + + + + + spacer2 + + + Vertical + + + Minimum + + + + 20 + 31 + + + + + + + + + boldButtonClicked() + + + + klineedit.h + + diff --git a/changes-1.4 b/changes-1.4 index f3b4666c..95ae5bcb 100644 --- a/changes-1.4 +++ b/changes-1.4 @@ -1,18 +1,18 @@ -New applications: krita, kexi +New applications: chalk, kexi -Krita +Chalk ===== -Krita is an image editor and paint application with a wide range of +Chalk is an image editor and paint application with a wide range of applications, from photo editing to the creation of original artwork. Sporting a clear and uncluttered interface (for a paint app...) it makes the features it delivers accessible and intuitive to use. -This is the first public release of Krita and while it provides a coherent set +This is the first public release of Chalk and while it provides a coherent set of features, it is only the first stepping stone towards a flexible paint application for artists and image editors. -Krita offers: +Chalk offers: * Layers (without fixed boundaries). * A familiar set of tools -- brushes, selection tools and shape tools. diff --git a/changes-1.5 b/changes-1.5 index 30af9693..9ece0340 100644 --- a/changes-1.5 +++ b/changes-1.5 @@ -1,7 +1,7 @@ * General: - Paragraph background color can now be set (in addition to text background color) - - Palettes now remember their position between sessions (Krita, Kivio, Karbon) + - Palettes now remember their position between sessions (Chalk, Kivio, Karbon) - Palettes now have a smart mode where they start floating on small screens and docked on larger screens - ToolBox is no longer duplicated for every view @@ -18,8 +18,8 @@ - Fix RMB in table-cell should not unselect text -** Krita: - - Krita now compiles on NetBSD +** Chalk: + - Chalk now compiles on NetBSD - Fix rotation bugs - When "Select Similar Colors" a transparant area, add only transparant areas instead of the entire image to the selection. @@ -64,11 +64,11 @@ - 111717 How to bring back the overview window if you close it? - 111618 Rename plugins menu to "Effects" - 109520 Change Align Center (Vertical) to Align Middle and add some extra separators -- 108789 Keybindings like krita, and other tweaks +- 108789 Keybindings like chalk, and other tweaks - 108755 Always use this document at startup, Karbon has no way to stop doing this. Add a basic karbon template. - 91376, 111207, 60844 Dockers now use the KoPalette library. This means a huge improvement when it comes to docker management - 112691 Usability: The tools should be grouped -- 114429 The color picker is bad: Karbon now uses the Krita color choosers. +- 114429 The color picker is bad: Karbon now uses the Chalk color choosers. - 99927 karbon prints empty page the same in preview - 119452 Printing scales the entire drawing down - 116494 [usability] polyline interaction suggestions @@ -90,7 +90,7 @@ * Features: -** Krita: +** Chalk: - Add histograms - Histograms for images with more than 8-bit to the channel can be zoomed - Add histogram docker @@ -103,7 +103,7 @@ painting style (eraser, brush, pen, airbrush...) - Create better and more modern selection visualisation - Put brush, gradient, pattern and paint style in popups in a toolbar, reducing the amount - of space Krita needs for its dockers + of space Chalk needs for its dockers - Make hardness of tablet pressure curve configurable - Many performance improvements to the backend (allocation cache, transform cache) - Use color profiles everywhere @@ -111,7 +111,7 @@ - Add feather selection feature - Pasted clipboard contents are placed in the middle of the image initially - Brush shape is shown as an outline cursor when painting freehand - - Krita now adds itself to the Open With menu in Konqueror + - Chalk now adds itself to the Open With menu in Konqueror - support more modes from GImp image hose brushes - Much work on documentation - Allow the user to choose between contiguous fill behaviour in combination with selections. diff --git a/configure.files b/configure.files index dc5dd4b8..635634e0 100644 --- a/configure.files +++ b/configure.files @@ -2,15 +2,15 @@ configure.in.in ./example/configure.in.in ./filters/configure.in.mid -./filters/krita/configure.in.in -./filters/krita/gmagick/configure.in.bot -./filters/krita/jpeg/configure.in.bot -./filters/krita/magick/configure.in.bot -./filters/krita/openexr/configure.in.bot -./filters/krita/pdf/configure.in.bot -./filters/krita/pdf/configure.in.in -./filters/krita/png/configure.in.bot -./filters/krita/tiff/configure.in.bot +./filters/chalk/configure.in.in +./filters/chalk/gmagick/configure.in.bot +./filters/chalk/jpeg/configure.in.bot +./filters/chalk/magick/configure.in.bot +./filters/chalk/openexr/configure.in.bot +./filters/chalk/pdf/configure.in.bot +./filters/chalk/pdf/configure.in.in +./filters/chalk/png/configure.in.bot +./filters/chalk/tiff/configure.in.bot ./filters/kword/msword/configure.in.bot ./filters/kword/msword/configure.in.in ./filters/kword/pdf/xpdf/configure.in.in @@ -31,10 +31,10 @@ configure.in.in ./kexi/plugins/macros/configure.in.in ./kivio/configure.in.in ./kpresenter/configure.in.in -./krita/configure.in.bot -./krita/configure.in.in -./krita/plugins/configure.in.in -./krita/plugins/viewplugins/imagesize/configure.in.in +./chalk/configure.in.bot +./chalk/configure.in.in +./chalk/plugins/configure.in.in +./chalk/plugins/viewplugins/imagesize/configure.in.in ./kspread/plugins/calculator/configure.in.in ./kword/mailmerge/configure.in.in ./lib/configure.in.in diff --git a/configure.in b/configure.in index 699ee395..2203528e 100644 --- a/configure.in +++ b/configure.in @@ -373,7 +373,7 @@ dnl Do NOT put this file in your application, if you want it compiled ! DO_NOT_COMPILE="$DO_NOT_COMPILE example" dnl ======================================================= -dnl FILE: ./filters/krita/configure.in.in +dnl FILE: ./filters/chalk/configure.in.in dnl ======================================================= # Check if the tiff lib is available @@ -443,7 +443,7 @@ AM_CONDITIONAL(have_exif, test -n "$LIBEXIF") AM_CONDITIONAL(include_jpeg_filter, test -n "$LIBJPEG" -a -n "$LIBEXIF") AM_CONDITIONAL(include_tiff_filter, test -n "$LIBTIFF" -a -n "$LIBEXIF") dnl ======================================================= -dnl FILE: ./filters/krita/pdf/configure.in.in +dnl FILE: ./filters/chalk/pdf/configure.in.in dnl ======================================================= # Compile the pdf import filter only if Poppler is available @@ -1248,7 +1248,7 @@ dnl ======================================================= AC_HAVE_DPMS() dnl ======================================================= -dnl FILE: ./krita/configure.in.in +dnl FILE: ./chalk/configure.in.in dnl ======================================================= KDE_CHECK_LIB(Xi, XOpenDisplay, [ @@ -1354,13 +1354,13 @@ if test "$have_powf" = 'yes'; then AC_DEFINE([HAVE_POWF], 1, [Define to 1 if your system has powf in ]) fi\ dnl ======================================================= -dnl FILE: ./krita/plugins/configure.in.in +dnl FILE: ./chalk/plugins/configure.in.in dnl ======================================================= KDE_CHECK_HEADER(kjsembed/jsproxy_imp.h, have_kjsembed=yes, have_kjsembed=no) AM_CONDITIONAL(use_kjsembed, test x$have_kjsembed = xyes) dnl ======================================================= -dnl FILE: ./krita/plugins/viewplugins/imagesize/configure.in.in +dnl FILE: ./chalk/plugins/viewplugins/imagesize/configure.in.in dnl ======================================================= AC_CHECK_DECLS([round], [], [], [#include ]) @@ -1638,7 +1638,7 @@ AM_CONDITIONAL(kivio_SUBDIR_included, test "x$kivio_SUBDIR_included" = xyes) AM_CONDITIONAL(koshell_SUBDIR_included, test "x$koshell_SUBDIR_included" = xyes) AM_CONDITIONAL(kounavail_SUBDIR_included, test "x$kounavail_SUBDIR_included" = xyes) AM_CONDITIONAL(kpresenter_SUBDIR_included, test "x$kpresenter_SUBDIR_included" = xyes) -AM_CONDITIONAL(krita_SUBDIR_included, test "x$krita_SUBDIR_included" = xyes) +AM_CONDITIONAL(chalk_SUBDIR_included, test "x$chalk_SUBDIR_included" = xyes) AM_CONDITIONAL(kspread_SUBDIR_included, test "x$kspread_SUBDIR_included" = xyes) AM_CONDITIONAL(kugar_SUBDIR_included, test "x$kugar_SUBDIR_included" = xyes) AM_CONDITIONAL(mimetypes_SUBDIR_included, test "x$mimetypes_SUBDIR_included" = xyes) @@ -1663,7 +1663,7 @@ AC_CONFIG_FILES([ doc/koffice/Makefile ]) AC_CONFIG_FILES([ doc/koshell/Makefile ]) AC_CONFIG_FILES([ doc/kplato/Makefile ]) AC_CONFIG_FILES([ doc/kpresenter/Makefile ]) -AC_CONFIG_FILES([ doc/krita/Makefile ]) +AC_CONFIG_FILES([ doc/chalk/Makefile ]) AC_CONFIG_FILES([ doc/kspread/Makefile ]) AC_CONFIG_FILES([ doc/kugar/Makefile ]) AC_CONFIG_FILES([ doc/kword/Makefile ]) @@ -1714,17 +1714,17 @@ AC_CONFIG_FILES([ filters/kpresenter/powerpoint/libppt/Makefile ]) AC_CONFIG_FILES([ filters/kpresenter/svg/Makefile ]) AC_CONFIG_FILES([ filters/kpresenter/xbm/Makefile ]) AC_CONFIG_FILES([ filters/kpresenter/xpm/Makefile ]) -AC_CONFIG_FILES([ filters/krita/Makefile ]) -AC_CONFIG_FILES([ filters/krita/gmagick/Makefile ]) -AC_CONFIG_FILES([ filters/krita/jpeg/Makefile ]) -AC_CONFIG_FILES([ filters/krita/libkisexif/Makefile ]) -AC_CONFIG_FILES([ filters/krita/magick/Makefile ]) -AC_CONFIG_FILES([ filters/krita/openexr/Makefile ]) -AC_CONFIG_FILES([ filters/krita/pdf/Makefile ]) -AC_CONFIG_FILES([ filters/krita/png/Makefile ]) -AC_CONFIG_FILES([ filters/krita/raw/Makefile ]) -AC_CONFIG_FILES([ filters/krita/tiff/Makefile ]) -AC_CONFIG_FILES([ filters/krita/xcf/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/gmagick/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/jpeg/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/libkisexif/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/magick/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/openexr/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/pdf/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/png/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/raw/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/tiff/Makefile ]) +AC_CONFIG_FILES([ filters/chalk/xcf/Makefile ]) AC_CONFIG_FILES([ filters/kspread/Makefile ]) AC_CONFIG_FILES([ filters/kspread/applixspread/Makefile ]) AC_CONFIG_FILES([ filters/kspread/csv/Makefile ]) @@ -1980,114 +1980,114 @@ AC_CONFIG_FILES([ kpresenter/templates/common_icon/Makefile ]) AC_CONFIG_FILES([ kpresenter/templates/legal/Makefile ]) AC_CONFIG_FILES([ kpresenter/templates/letter/Makefile ]) AC_CONFIG_FILES([ kpresenter/toolbar/Makefile ]) -AC_CONFIG_FILES([ krita/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/cmyk_u16/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/cmyk_u8/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/cmyk_u8/templates/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/gray_u16/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/gray_u8/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/gray_u8/templates/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/gray_u8/tests/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/lms_f32/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_f16half/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_f16half/tests/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_f32/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_f32/tests/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_u16/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_u16/tests/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_u8/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_u8/templates/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/rgb_u8/tests/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/wet/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/wetsticky/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/wetsticky/brushop/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/ycbcr_u16/Makefile ]) -AC_CONFIG_FILES([ krita/colorspaces/ycbcr_u8/Makefile ]) -AC_CONFIG_FILES([ krita/core/Makefile ]) -AC_CONFIG_FILES([ krita/core/tests/Makefile ]) -AC_CONFIG_FILES([ krita/core/tiles/Makefile ]) -AC_CONFIG_FILES([ krita/core/tiles/tests/Makefile ]) -AC_CONFIG_FILES([ krita/data/Makefile ]) -AC_CONFIG_FILES([ krita/data/brushes/Makefile ]) -AC_CONFIG_FILES([ krita/data/gradients/Makefile ]) -AC_CONFIG_FILES([ krita/data/images/Makefile ]) -AC_CONFIG_FILES([ krita/data/palettes/Makefile ]) -AC_CONFIG_FILES([ krita/data/patterns/Makefile ]) -AC_CONFIG_FILES([ krita/data/profiles/Makefile ]) -AC_CONFIG_FILES([ krita/dtd/Makefile ]) -AC_CONFIG_FILES([ krita/kritacolor/Makefile ]) -AC_CONFIG_FILES([ krita/kritacolor/colorspaces/Makefile ]) -AC_CONFIG_FILES([ krita/kritacolor/tests/Makefile ]) -AC_CONFIG_FILES([ krita/pics/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/blur/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/bumpmap/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/cimg/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/colorify/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/colors/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/colorsfilters/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/convolutionfilters/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/cubismfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/embossfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/example/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/fastcolortransfer/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/imageenhancement/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/lenscorrectionfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/levelfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/noisefilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/oilpaintfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/pixelizefilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/raindropsfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/randompickfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/roundcorners/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/smalltilesfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/sobelfilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/threadtest/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/unsharp/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/filters/wavefilter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/paintops/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/paintops/defaultpaintops/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/defaulttools/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/selectiontools/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_crop/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_curves/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_filter/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_perspectivegrid/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_perspectivetransform/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_polygon/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_polyline/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_selectsimilar/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_star/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/tools/tool_transform/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/colorrange/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/colorspaceconversion/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/dropshadow/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/filtersgallery/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/histogram/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/histogram_docker/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/history_docker/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/imagesize/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/modify_selection/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/performancetest/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/rotateimage/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/screenshot/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/kritacore/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/kritascripting/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/samples/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/samples/python/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/scripting/samples/ruby/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/selectopaque/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/separate_channels/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/shearimage/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/substrate/Makefile ]) -AC_CONFIG_FILES([ krita/plugins/viewplugins/variations/Makefile ]) -AC_CONFIG_FILES([ krita/sdk/Makefile ]) -AC_CONFIG_FILES([ krita/ui/Makefile ]) +AC_CONFIG_FILES([ chalk/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/cmyk_u16/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/cmyk_u8/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/cmyk_u8/templates/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/gray_u16/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/gray_u8/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/gray_u8/templates/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/gray_u8/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/lms_f32/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_f16half/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_f16half/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_f32/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_f32/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_u16/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_u16/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_u8/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_u8/templates/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/rgb_u8/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/wet/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/wetsticky/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/wetsticky/brushop/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/ycbcr_u16/Makefile ]) +AC_CONFIG_FILES([ chalk/colorspaces/ycbcr_u8/Makefile ]) +AC_CONFIG_FILES([ chalk/core/Makefile ]) +AC_CONFIG_FILES([ chalk/core/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/core/tiles/Makefile ]) +AC_CONFIG_FILES([ chalk/core/tiles/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/data/Makefile ]) +AC_CONFIG_FILES([ chalk/data/brushes/Makefile ]) +AC_CONFIG_FILES([ chalk/data/gradients/Makefile ]) +AC_CONFIG_FILES([ chalk/data/images/Makefile ]) +AC_CONFIG_FILES([ chalk/data/palettes/Makefile ]) +AC_CONFIG_FILES([ chalk/data/patterns/Makefile ]) +AC_CONFIG_FILES([ chalk/data/profiles/Makefile ]) +AC_CONFIG_FILES([ chalk/dtd/Makefile ]) +AC_CONFIG_FILES([ chalk/chalkcolor/Makefile ]) +AC_CONFIG_FILES([ chalk/chalkcolor/colorspaces/Makefile ]) +AC_CONFIG_FILES([ chalk/chalkcolor/tests/Makefile ]) +AC_CONFIG_FILES([ chalk/pics/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/blur/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/bumpmap/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/cimg/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/colorify/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/colors/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/colorsfilters/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/convolutionfilters/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/cubismfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/embossfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/example/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/fastcolortransfer/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/imageenhancement/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/lenscorrectionfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/levelfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/noisefilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/oilpaintfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/pixelizefilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/raindropsfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/randompickfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/roundcorners/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/smalltilesfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/sobelfilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/threadtest/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/unsharp/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/filters/wavefilter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/paintops/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/paintops/defaultpaintops/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/defaulttools/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/selectiontools/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_crop/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_curves/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_filter/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_perspectivegrid/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_perspectivetransform/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_polygon/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_polyline/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_selectsimilar/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_star/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/tools/tool_transform/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/colorrange/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/colorspaceconversion/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/dropshadow/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/filtersgallery/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/histogram/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/histogram_docker/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/history_docker/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/imagesize/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/modify_selection/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/performancetest/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/rotateimage/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/screenshot/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/chalkcore/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/chalkscripting/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/samples/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/samples/python/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/scripting/samples/ruby/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/selectopaque/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/separate_channels/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/shearimage/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/substrate/Makefile ]) +AC_CONFIG_FILES([ chalk/plugins/viewplugins/variations/Makefile ]) +AC_CONFIG_FILES([ chalk/sdk/Makefile ]) +AC_CONFIG_FILES([ chalk/ui/Makefile ]) AC_CONFIG_FILES([ kspread/Makefile ]) AC_CONFIG_FILES([ kspread/dialogs/Makefile ]) AC_CONFIG_FILES([ kspread/dtd/Makefile ]) @@ -2214,7 +2214,7 @@ for args in $SUBDIRLIST ; do kpresenter) COMPILE_FILTER_KPRESENTER="$args " ;; kformula) COMPILE_FILTER_KFORMULA="$args " ;; kugar) COMPILE_FILTER_KUGAR="$args " ;; - krita) COMPILE_FILTER_KRITA="$args " ;; + chalk) COMPILE_FILTER_KRITA="$args " ;; kivio) COMPILE_FILTER_KIVIO="$args " ;; kexi) COMPILE_FILTER_KEXI="$args " ;; esac @@ -2230,7 +2230,7 @@ for args in $DO_NOT_COMPILE ; do kpresenter) COMPILE_FILTER_KPRESENTER= ;; kformula) COMPILE_FILTER_KFORMULA= ;; kugar) COMPILE_FILTER_KUGAR= ;; - krita) COMPILE_FILTER_KRITA= ;; + chalk) COMPILE_FILTER_KRITA= ;; kivio) COMPILE_FILTER_KIVIO= ;; kexi) COMPILE_FILTER_KEXI= ;; esac @@ -2306,7 +2306,7 @@ AC_MSG_CHECKING([whether kopainter should be compiled]) # first check which main application we could compile for args in $SUBDIRLIST ; do case $args in - krita) COMPILE_LIB_FOR_KRITA="$args " ;; + chalk) COMPILE_LIB_FOR_KRITA="$args " ;; karbon) COMPILE_LIB_FOR_KARBON="$args " ;; kivio) COMPILE_LIB_FOR_KIVIO="$args " ;; esac @@ -2316,7 +2316,7 @@ done COMPILE_LIB_FOR_KPRESENTER="#" for args in $DO_NOT_COMPILE ; do case $args in - krita) COMPILE_LIB_FOR_KRITA= ;; + chalk) COMPILE_LIB_FOR_KRITA= ;; karbon) COMPILE_LIB_FOR_KARBON= ;; kivio) COMPILE_LIB_FOR_KIVIO= ;; kpresenter) COMPILE_LIB_FOR_KPRESENTER= ;; @@ -2336,13 +2336,13 @@ AM_CONDITIONAL(compile_lib_KOPAINTER, test "$USERFEEDBACKCOMPILELIB" = "yes" ) AC_OUTPUT if test -z "$LIBGMAGICK_LIBS" -a -z "$LIBMAGICK_LIBS"; then echo "" - echo "You're missing GraphicsMagick (>=1.1.7). krita's GraphicsMagick import/export" + echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export" echo "filter will not be compiled. You can download GraphicsMagick from" - echo "http://www.graphicsmagick.org/. The GraphicsMagick filter allows krita to" + echo "http://www.graphicsmagick.org/. The GraphicsMagick filter allows chalk to" echo "read and write XCF, PSD, GIF, BMP, and many other image formats." echo "" echo "If you have problems compiling GraphicsMagick, please try configuring it using" - echo "the --without-magick-plus-plus flag, the C++ API isn't needed for krita." + echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk." echo "" all_tests=bad AC_DEFINE([include_imagemagick_filter],"",[don't use magick filter]) @@ -2351,8 +2351,8 @@ fi if test -z "$LIBGMAGICK_LIBS" -a ! -z "$LIBMAGICK_LIBS"; then echo "" - echo "You're missing GraphicsMagick (>=1.1.7). krita's GraphicsMagick import/export" - echo "filter will not be compiled. But ImageMagick was found, which mean that krita" + echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export" + echo "filter will not be compiled. But ImageMagick was found, which mean that chalk" echo "will be able to read and write XCF, PSD, GIF, BMP, and many other image formats." echo "But the ImageMagick filter is deprecated and we strongly advise you to install" echo "GraphicsMagick either from your distribution or from http://www.graphicsmagick.org/" @@ -2360,7 +2360,7 @@ fi if test -z "$LIBJPEG" -o -z "$LIBEXIF"; then echo "" echo "You're missing libjpeg or libexif 0.6.12 or later (binaries and/or headers)." - echo "krita won't be able to import/export jpeg" + echo "chalk won't be able to import/export jpeg" echo "" all_tests=bad fi @@ -2368,20 +2368,20 @@ fi # #if test -z "$LIBMAGICK_LIBS"; then # echo "" -# echo "You're missing ImageMagick (>=6.1.0). krita's ImageMagick import/export" +# echo "You're missing ImageMagick (>=6.1.0). chalk's ImageMagick import/export" # echo "filter will not be compiled. You can download ImageMagick from" -# echo "http://www.imagemagick.org/. The ImageMagick filter allows krita to" +# echo "http://www.imagemagick.org/. The ImageMagick filter allows chalk to" # echo "read and write XCF, PSD, GIF, BMP, and many other image formats." # echo "" # echo "If you have problems compiling ImageMagick, please try configuring it using" -# echo "the --without-magick-plus-plus flag, the C++ API isn't needed for krita." +# echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk." # echo "" # all_tests=bad #fi if test -z "$OPENEXR_LIBS"; then echo "" - echo "You're missing the OpenEXR library. Krita's OpenEXR import/export filter will " + echo "You're missing the OpenEXR library. Chalk's OpenEXR import/export filter will " echo "not be compiled. You can download OpenEXR from http://www.openexr.com or " echo "install it from an appropriate binary package." echo "" @@ -2391,13 +2391,13 @@ fi if test -z "$POPPLER_LIBS"; then echo "" echo "You're missing libpoppler 0.5.1 or later (binaries and/or headers)." - echo "krita won't be able to import pdf" + echo "chalk won't be able to import pdf" echo "note that the qt-binding of libpoppler is required" echo "" fi if test -z "$LIBPNG"; then echo "" - echo "You're missing libpng (binaries and/or headers), krita won't be able" + echo "You're missing libpng (binaries and/or headers), chalk won't be able" echo "to import/export png" echo "" all_tests=bad @@ -2405,7 +2405,7 @@ fi if test -z "$LIBTIFF"; then echo "" - echo "You're missing libtiff (binaries and/or headers), krita won't be able" + echo "You're missing libtiff (binaries and/or headers), chalk won't be able" echo "to import/export tiff" echo "" all_tests=bad @@ -2572,16 +2572,16 @@ EOS fi if test -z "$LCMS_LIBS"; then echo "" - echo "LittleCMS is missing, Krita will not be built." + echo "LittleCMS is missing, Chalk will not be built." echo "" - echo "If you want to compile Krita you should install:" + echo "If you want to compile Chalk you should install:" echo " * lcms 1.15 or newer (http://www.littlecms.com/)" echo "" all_tests=bad else if test -z "$GLLIB"; then echo "" - echo "You're missing OpenGL libraries. krita will" + echo "You're missing OpenGL libraries. chalk will" echo "not be able to use OpenGL for hardware" echo "accelerated rendering." echo "" diff --git a/doc/chalk/Makefile.am b/doc/chalk/Makefile.am new file mode 100644 index 00000000..085981d9 --- /dev/null +++ b/doc/chalk/Makefile.am @@ -0,0 +1,4 @@ + +KDE_LANG = en +KDE_DOCS = AUTO + diff --git a/doc/chalk/README.SCREENSHOTS b/doc/chalk/README.SCREENSHOTS new file mode 100644 index 00000000..bc1d55bd --- /dev/null +++ b/doc/chalk/README.SCREENSHOTS @@ -0,0 +1,7 @@ +Note for translators: + +The file "mountains.png" is the original photo used for creating the screenshots +in the Dialogs section. + + +- ASK \ No newline at end of file diff --git a/doc/chalk/commands-dialogs.docbook b/doc/chalk/commands-dialogs.docbook new file mode 100644 index 00000000..86ef91d1 --- /dev/null +++ b/doc/chalk/commands-dialogs.docbook @@ -0,0 +1,1411 @@ + +Dialogs + + +This section describes &chalk;'s dialog windows. + + + +Dialogs for working with images + + +The <guilabel>Color Range</guilabel> dialog + + + +The Color Range dialog + + + + + +The Color Range dialog + +The Color Range dialog + + + + + +You can create a selection based on the color values of pixels here. In the +dropdown box, choose which color range you want to select. Pixels will be +selected according to their color value on this scale (⪚ a fully yellow +pixel would score maximally on the yellow scale and on the red and green scales). +If you check the Invert box, the selection becomes inverted: +pixels will become selected if they have a lower value in the specified range instead. +You can choose whether the current selection should be +added to or subtracted from the color range selection by clicking the +respective option: Add to current selection or +Subtract from current selection. Choose +Select to actually perform the selection or +Deselect to remove these pixels from the selection. + + + + + +The <guilabel>Convert Image Type</guilabel> dialog + + + +The Convert Image Type dialog + + + + + +The Convert Image Type dialog + +The Convert Image Type dialog + + + + + +This dialog allows you to convert your image from one color space to another. +The Target color space and Destination ICM +profile are used to set to which colorspace and profile the image +will be converted. You can influence how this conversion is done with the +Rendering Intent option. + + +With Perceptual conversion, the source color space is +mapped linearly to the destination color space. If the destination color space +accepts a lesser color range than the source, shifts may occur +because the range is compressed. Relative colorimetric +conversion converts every color to the closest color in the destination color +space. This may mean that a certain color range is mapped to one color in the +destination color space. Saturation means that fully +saturated colors will remain fully saturated, even if this means that the +actual color is changed. With Absolute colorimetric +conversion, the same approach is used as with Relative +colorimetric, but the white point of the color space (the value +designating the color white) is not changed to match the new color space, +which may result in unwanted changes to near colors. + + + + + +The <guilabel>Image Properties</guilabel> dialog + + + +The Image Properties dialog + + + + + +The Image Properties dialog + +The Image Properties dialog + + + + + +In this dialog you can change a couple of image properties. First of all, the +Name of the image. If you did not set a name earlier +(that can also be done when creating the image), it will have a default name +like Image1. Then, you can set its size (determined by the +Width and Height in pixels and +the Resolution in dots per inch) and the color profile to +be used (Profile). Finally, you can fill in the +Description field with any information you want to add to +the image. + + + + + +The <guilabel>Image Size</guilabel> dialog + + + +The Image Size dialog + + + + + +The Image Size dialog + +The Image Size dialog + + + + + +This dialog lets you resize your image. In the top part, you can choose the +way the image is resized. If you choose Resize, the size +of the image is changed, but its layers (which contain the actual contents) +will not be modified. So, when you double the height and width of the image, +your original image will occupy the top-left quarter part of your new image. +On decreasing the size of your image, the image layers will stretch out over +the image borders, unless you choose Crop layers on image +resize, which will crop all layers to the new image size. + +With Scale, the image layers will be resized with the +image. So increasing the image size will actually enlarge the contents, and +similar for decreasing. + +Under Pixel dimensions, you can set which new size you +want the image to have. The original size is given as a reference. The new +size can be set both as pixels or as a percentage, with 100% being the +original size. If you select Constrain proportions, the +new width and height will always be set to the same percentage. For example, +if you have an image of 200 x 100 pixels, and set the width to 20 pixels, the +height will automatically be changed to 10. With this checkbox unselected, you +can also resize the image non-proportionally. + +The Filter: dropdown box can be used to select a +different algorithm for determining the colors of the pixels in the newly +resized image that did not correspond to a pixel in the old image (the +calculated corresponding location in the old image was located in between +pixels). BSpline uses a 4 x 4 pixel grid and results into a quite high +blurring. Bell is quite fast while resulting in a reasonably smooth image. +Box is the fastest method, but yields the least appealing result. Hermite +keeps the image quite sharp, while smoothing it as well, and is reasonably +fast. Lanczos3 results in sharp images, but is very slow. Mitchell (the +default) is not very fast, but often yields a good intermediate result. +Triangle/Bilinear uses the 2 x 2 pixel grid around the calculated location +resulting in relatively sharp lines. + + + + + +The <guilabel>Rotate Image</guilabel> dialog + + + +The Rotate Image dialog + + + + + +The Rotate Image dialog + +The Rotate Image dialog + + + + + +With this dialog, you can rotate the image. The top part of the dialog shows +the result of the rotation in the form of a change in dimension (if any). +Under Direction you can choose between +rotating clockwise and counter-clockwise. Under Angle, +you can set the amount of rotation. 90, 180 and 270 degrees can be selected +using the respective option button, other amounts need to be specified with +the Custom spin box. + + + + + +The <guilabel>Separate Image</guilabel> dialog + + + +The Separate Image dialog + + + + + +The Separate Image dialog + +The Separate Image dialog + + + + + +With this dialog, you can separate (part of) your image. Every color component +(channel) will be put into a separate layer or image. At the top of the +dialog, the current color model is shown. Below that, a couple of options can +be set. + + +Under Source, you can choose what part of the image to +separate. The two options are Current layer, which +(obviously) only uses the currently selected layer and Flatten all +layers before separation, which uses the entire image. + + +Under Output, you can choose where the result of the +separation should be written to: either to a couple of layers, or to a couple +of images. + + +Under Alpha Options, you can choose what should be done +with the alpha channel of the selected layer(s). It can be copied to each new +channel, be discarded, or separated on its own. + + +The two options at the bottom of the dialog, finally, determine whether the +source should be downscaled to 8 bit colors (if it contains more), and whether +the output should be in color (default is to separate the channels to grayscale +values). + + + + +The <guilabel>Shear Image</guilabel> dialog + + + +The Shear Image dialog + + + + + +The Shear Image dialog + +The Shear Image dialog + + + + + +This dialog allows you to shear your image. By shearing, the bounding +rectangle of your image is transformed into a parallellogram. One pixel +row/column is kept in place, the next one is shifted by a certain amount, the +next one by the same amount relative to the previous one, etcetera. +The X and Y shearing angles can be set using the two spin boxes. + + + + + +The <guilabel>Substrate</guilabel> dialog + + + +The Substrate dialog + + + + + +The Substrate dialog + +The Substrate dialog + + + + + +(This dialog is still to be described.) + + + + + + + +Dialogs for working with layers + + +The <guilabel>Convert Layer Type</guilabel> dialog + + + +The Convert Layer Type dialog + + + + + +The Convert Layer Type dialog + +The Convert Layer Type dialog + + + + + +This dialog is exactly the same as the Convert Image +Type dialog, which converts an entire image instead of a +single layer. See the description there for details. + + + + + +The <guilabel>Drop Shadow</guilabel> dialog + + + +The Drop Shadow dialog + + + + + +The Drop Shadow dialog + +The Drop Shadow dialog + + + + + +With this dialog, you can add a drop shadow effect to the current layer. +Select the X and Y offsets (displacements) of the shadow relative to the +original layer with the two topmost spin boxes. The Blur +radius spinbox determines the radius in which the shadow will be +blurred (to achieve a smooth transition at the shadow border). If you want +a special color for the shadow, you can choose one with the +Color field. The Opacity slider and +spinbox can be used to make the shadow more or less transparent. Disable the +Allow resizing checkbox if you don't want the layer to be +resized in order to give it a shadow. + + + + + +The <guilabel>Histogram</guilabel> dialog + + + +The Histogram dialog + + + + + +The Histogram dialog + +The Histogram dialog + + + + + +This dialog shows a histogram for the current layer. With the +Method: settings, you can choose what kind of histogram +to show. You can change the channel(s) to show with the +Channels: listbox, and the scale on which it should be +drawn with the Linear and +Logarithmic radio buttons. Under the preview, there are +buttons available to zoom in to, and move over, the histogram. These are +activated for 16-bit colorspace layers. + + + + + +The <guilabel>Layer Properties</guilabel> dialog + + + +The Layer Properties dialog + + + + + +The Layer Properties dialog + +The Layer Properties dialog + + + + + +This dialog is in essence the same as the New Layer dialog, with the difference that +you cannot change its colorspace or profile anymore. These properties are +shown, though, to keep the information complete. + + + + +The <guilabel>Layer Size</guilabel> dialog + + + +The Layer Size dialog + + + + + +The Layer Size dialog + +The Layer Size dialog + + + + + +This dialog allows you to resize the current layer. +Under Pixel dimensions, you can set which new size you +want the layer to have. The original size is given as a reference. The new +size can be set both as pixels or as a percentage, with 100% being the +original size. If you select Constrain proportions, the +new width and height will always be set to the same percentage. For example, +if you have a layer of 200 x 100 pixels, and set the width to 20 pixels, the +height will automatically be changed to 10. With this checkbox unselected, you +can also resize the layer non-proportionally. The Filter: +dropdown list can be used to select a different algorithm for resizing the +layer. + + + + + +The <guilabel>New Adjustment Layer</guilabel> dialog + + + +The New Adjustment Layer dialog + + + + + +The New Adjustment Layer dialog + +The New Adjustment Layer dialog + + + + + +In this dialog, you can select the type of adjustment layer to add to the +image. In the left-hand list, you can see the available adjustment layers, +each with a preview. When you select one, the Preview +will change to show a correctly scaled preview of what the result of the +adjustment layer is going to be. + +You can then choose to show either the original image or the preview of the +adjustment layer with the radio buttons below the preview window. The buttons +next to these allow you to zoom in, zoom out, and refresh the preview, +respectively. The Autoupdate checkbox determines if the +preview window should update automatically after you made a change. + +The various options available for the filter that is used to create the +adjustment layer, are shown at the bottom of the dialog. See the section on +filters of this chapter for +descriptions. + + + + + +The <guilabel>New Layer</guilabel> dialog + + + +The New Layer dialog + + + + + +The New Layer dialog + +The New Layer dialog + + + + + +You can add a new layer to your image with this dialog. If you want a +descriptive name for your layer, you can fill one in at +Name:. You can select the desired colorspace for the new +layer from the Colorspace: list, and the specific +color profile for that colorspace at Profile:. +You can preset the layer's Opacity (you can change it later with the slider in +the Layer box), and choose the mode with which the layer should be composited +onto the final image. + + + + + +The <guilabel>Rotate Layer</guilabel> dialog + + + +The Rotate Layer dialog + + + + + +The Rotate Layer dialog + +The Rotate Layer dialog + + + + + +This dialog, similar to the Rotate Image +dialog, allows you to rotate the current layer. You can choose the +direction in which to rotate and the amount to rotate the layer by. + + + + + +The <guilabel>Shear Layer</guilabel> dialog + + + +The Shear Layer dialog + + + + + +The Shear Layer dialog + +The Shear Layer dialog + + + + + +This dialog works the same as the Shear Image +dialog, except that it operates on the current layer instead of on the +entire image. + + + + + + + +Dialogs for working with filters + + +All filter dialogs consist of a filter-specific part, at the left, and a +generic part, at the right. The generic part contains a preview window, which +you can configure using the controls below it. Choose +Preview or Original depending on +whether you want the preview window to show the preview of the filter effect +or the original image. The four buttons at the bottom right allow you to zoom +in and zoom out, set the zooming factor to 100% (this shows the image at its +original size), and refresh the preview, respectively. Furthermore, the option +Autoupdate determines if the preview window is updated +automatically. If you uncheck this checkbox, you will have to refresh the +preview yourself. + + + +The <guilabel>Blur</guilabel> dialog + + + +The Blur dialog + + + + + +The Blur dialog + +The Blur dialog + + + + + +This dialog allows you to customize the way your image is blurred. The +Half-width and Half-height spinboxes +determine the size of the areas of your image that are consecutively blurred. +With the Strength spinbox you can set the strength with which the +blurring should be applied, and with the Angle spinbox +you can add a rotation to the area. The Shape setting, +finally, allows you to choose between circular and rectangular areas + + + + + + +The <guilabel>Brightness / Contrast</guilabel> dialog + + + +The Brightness / Contrast dialog + + + + + +The Brightness / Contrast dialog + +The Brightness / Contrast dialog + + + + + +With this dialog, you can customize the brightness and contrast of your image. + +The curve diagram has a histogram-like background that shows you the abundance +of various brightness levels. The curve itself (initially a diagonal line from +bottom left to top right) determines to which new brightness level (on the +vertical axis) pixels with a certain original level (on the horizontal axis) are +to be mapped. For example, the default diagonal line from bottom left to top +right sets every original pixel to its own brightness value, meaning no +change. A horizontal line means that all pixels will get the same brightness. +This means minimal contrast, the brightness itself is indicated by the height +at which the line is placed. + +You can click on a handle (red circle) to select it (a selected handle is +indicated by a filled circle) and drag it around to change the shape of the +curve. The curve will be drawn smoothly through the handles (always +strictly from left to right). If you click on the curve, a handle is added to +it at that position. Clicking somewhere else in the image will also add a +handle at that point. You can press Delete to delete the +currently selected handle. + + + + + +The <guilabel>Bumpmap</guilabel> dialog + + + +The Bumpmap dialog + + + + + +The Bumpmap dialog + +The Bumpmap dialog + + + + + +You can apply a bumpmap effect and customize it using this dialog. One layer +is used as bumpmap layer: it is read as grayscale image and the gray values of +its pixels are used to to distort the other layer for creating the depth +illusion. High grey values, &ie; more white, mean a larger height, small +values, &ie; near black, mean a smaller height — or a larger depth, the +height can get below sealevel. A light source, shining +from above on the image that lies on the ground, +is simulated to determine the depth and direction of the shadows. + +The first option in this dialog offers you the selection of the +Bumpmap layer. + +Under Type, you can select what kind of bumpmap to be +applied. There are three types, Linear (a normal +application of the bumpmap), Spherical (focusing on the +extremes, that is, the shadow and highlight values) and +Sinusoidal (focusing on the midtone values). + +Then, there are three options to modify the bumpmap apart from its +algorithmical application. With Compensate for darkening, +the image is restored to about its original average lightness if using the +bumpmap filter would make it darker. The Invert bumpmap +option creates an inverted bumpmap (high and low are reversed). With +Tile bumpmap, a bumpmap layer that is smaller than the +layer it is applied to, will be tiled (repeatedly) to cover the entire layer. + +Under Settings, you can select the mathematical +parameters for the bumpmap. First of all, Azimuth (the +angle of the light source in the X-Y plane), Elevation +(the height of the simulated light source above the surface in degrees, with 0 +degrees being on the ground and 90 degrees being vertically above the image), +and Depth (the maximal vertical distortion of the image). + +Then, there are the X offset and Y +offset, with which you can displace the bumpmap layer relative to +the destination layer, Water level (the depth seen as +neutral), and Ambient light, which determines the +relative amount of ambient (environmental) light. + + + + + +The <guilabel>Color Adjustment</guilabel> dialog + + + +The Color Adjustment dialog + + + + + +The Color Adjustment dialog + +The Color Adjustment dialog + + + + + +This dialog allows you to customize the Color Adjustment filter. You can use +the curve (see the section on Brightness / +Contrast for a description on the curve) to determine the mapping +from old to new color levels, for each of the channels separately. + + + + + +The <guilabel>Color to Alpha</guilabel> dialog + + + +The Color to Alpha dialog + + + + + +The Color to Alpha dialog + +The Color to Alpha dialog + + + + + +With this dialog, you can make parts of the image having a certain color +transparent (officially alpha-transparent). You can select the +color you want to remove from the image (replacing it with transparency) with +the Color swatch, and how much a color may differ from +the selected one before it is considered not to match, with the +Threshold spinbox. Setting a threshold of zero (0) +ensures that only pixels with the exact matching color will be made +transparent, higher thresholds will make other colors match as well. + + + + +The <guilabel>Color Transfer</guilabel> dialog + + + +The Color Transfer dialog + + + + + +The Color Transfer dialog + +The Color Transfer dialog + + + + + +This dialog lets you copy the colors from one image (the Reference +Image) to the current one. The colors in both images are compared +and each color in the one you are working with, will be replaced by the +nearest one in the reference image. + + + + + + + +The <guilabel>Custom Convolution</guilabel> dialog + + + +The Custom Convolution dialog + + + + + +The Custom Convolution dialog + +The Custom Convolution dialog + + + + + +With this filter, you can apply a customized distortion effect to your image. +The nine spinboxes at the top left determine the distortion. Each pixel is +assigned a new value based on these values: the old color values of the pixel +inself and the eight surrounding pixels are each multiplied by the values in +the respective spinboxes, these results are added, and the final result is the +new color value for the pixel. Before being applied, this final result can be +multiplied with a certain Factor: or a certain +Offset: can be added to it. + +In the example screenshot, each pixel is assigned a new value based on its +own (the 1 in the center), to which are added the values of the pixels to its +top right and directly below it (each with a factor of 1, &ie; the actual +value, since multiplying by one has no effect), and from which are subtracted +the values of the pixels to its bottom right and directly above it (added with +a factor of -1, so subtracted by a factor of 1). + + + + + +The <guilabel>Emboss</guilabel> dialog + + + +The Emboss dialog + + + + + +The Emboss dialog + +The Emboss dialog + + + + + +This dialog contains just one option, the Depth: slider +and spinbox which determines the depth of the embossing effect. + + + + + +The <guilabel>Filters Gallery</guilabel> dialog + + + +The Filters Gallery dialog + + + + + +The Filters Gallery dialog + +The Filters Gallery dialog + + + + + +This dialog can be used to get a quick overview of what the various available +filters do. The filters are in turn applied to the current image and the +results are put in the left list box as thumbnails. If you select one, its +options become available in the Configuration section. +See the description of the respective filter for details. + + + + + +The <guilabel>Gaussian Noise Reduction</guilabel> dialog + + + +The Gaussian Noise Reduction dialog + + + + + +The Gaussian Noise Reduction dialog + +The Gaussian Noise Reduction dialog + + + + + +This dialog allows you to customize a Gaussian noise reduction. The +Threshold setting is a measure for how much noise should +be removed (&ie; how quickly a lonely pixel should be made +equal to its surroundings), while the Window Size setting +determines the radius of the area considered when changing pixels. + + + + + +The <guilabel>Lens Correction</guilabel> dialog + + + +The Lens Correction dialog + + + + + +The Lens Correction dialog + +The Lens Correction dialog + + + + + +With this dialog, you can fix an image which is distorted due to common lens +anomalies. You can specify a Distortion correction, +indicating how much the image should be corrected if its +concaveness / convexness is not right, for areas near the center and areas +near the edges. If you want an asymmetrical correction, you can specify +different X and Y coordinates for +the center (in percentages of the total width and height, measured from the +top left). + +You can also correct a too light or too dark image with the +Brightness correction spinbox. + + + + + +The <guilabel>Image Restoration</guilabel> dialog + + + +The Image Restoration dialog + + + + + +The Image Restoration dialog + +The Image Restoration dialog + + + + + +Using this dialog, you can specify exactly how the image restoration should +be done. This filter tries to increase the quality of an image, for instance +by removing scratches. Various options are available to customize its +behaviour. + +(Unfortunately, these are not described as of yet.) + + + + + +The <guilabel>Oilpaint</guilabel> dialog + + + +The Oilpaint dialog + + + + + +The Oilpaint dialog + +The Oilpaint dialog + + + + + +This dialog can configure two parameters for the associated filter. The +Brush size: setting determines the size of the brush that +is used to simulate the oilpaint effect, the Smooth: +setting specifies if the difference in colors between adjacent +swatches may be large (low smoothness) or should be small (high +smoothness). + + + + + +The <guilabel>Pixelize</guilabel> dialog + + + +The Pixelize dialog + + + + + +The Pixelize dialog + +The Pixelize dialog + + + + + +On this dialog, you can adjust two settings. Pixel width: +and Pixel height: indicate the width and height of the +area that should be taken together and averaged to form one new, large +pixel. + + + + + +The <guilabel>Raindrops</guilabel> dialog + + + +The Raindrops dialog + + + + + +The Raindrops dialog + +The Raindrops dialog + + + + + +This filter can be configured using the settings Drop +size: (the average diameter of the raindrops), +Number: (the number of raindrop effects that should be +added to the image), and Fish eyes: (the percentage of +raindrops that should be rendered as fisheye lens effects instead of plain +raindrop effects). + + + + +The <guilabel>Random Noise</guilabel> dialog + + + +The Random Noise dialog + + + + + +The Random Noise dialog + +The Random Noise dialog + + + + + +This filter adds random noise (speckles, or something similar) to your image. +There are two customizable settings: the amount of noise +(Level, as a percentage) and the +Opacity of the noise (should the original color still be +a bit visible or not). + + + + +The <guilabel>Random Pick</guilabel> dialog + + + +The Random Pick dialog + + + + + +The Random Pick dialog + +The Random Pick dialog + + + + + +In this dialog, you can specify parameters for the Random Pick +filter. The Level setting determines how much pixels will +be affected (measured as a percentage), the area which is looked in to take a +new color for a pixel is set with the Size of the window +setting, and the Opacity of the modifications can be set as +well. + + + + + + +The <guilabel>Round Corners</guilabel> dialog + + + +The Round Corners dialog + + + + + +The Round Corners dialog + +The Round Corners dialog + + + + + +This dialog has one setting: the radius of the rounded corners. + + + + + +The <guilabel>Small Tiles</guilabel> dialog + + + +The Small Tiles dialog + + + + + +The Small Tiles dialog + +The Small Tiles dialog + + + + + +In this dialog, you can set the amount of subdivisions with the +Number of tiles settings. + + + + + +The <guilabel>Sobel</guilabel> dialog + + + +The Sobel dialog + + + + + +The Sobel dialog + +The Sobel dialog + + + + + +Here, you can set the parameters for the Sobel edge +detection filter. First of all you can determine which directions to sobel in: +horizontally, vertically, or both. The Keep sign of +result setting does not affect regular images. +Make image opaque determines whether the resulting image +is opaque or transparent. + + + + + +The <guilabel>Unsharp Mask</guilabel> dialog + + + +The Unsharp Mask dialog + + + + + +The Unsharp Mask dialog + +The Unsharp Mask dialog + + + + + +This dialog offers three options for the sharpening filter +Unsharp Mask: the radius (Half-size) +of the mask, the Amount of sharpening that should be +done, and the Threshold level. + + + + + +The <guilabel>Wave</guilabel> dialog + + + +The Wave dialog + + + + + +The Wave dialog + +The Wave dialog + + + + + +For both the horizontal and the vertical components of the wave distortion +(note: a vertical wave means that the vertical position is dependent on the +horizontal one, and hence looks like a W), +you can determine four settings here. The Wavelength (a +shorter wavelength means a more erratical wave), the +Shift (which point of the wave should be started at), the +Amplitude (the amount of distortion), and the +Shape (Sinusoidal or rounded, +versus Triangle or pointy). + + + + + +The <guilabel>Wavelet Noise Reduction</guilabel> dialog + + + +The Wavelet Noise Reduction dialog + + + + + +The Wavelet Noise Reduction dialog + +The Wavelet Noise Reduction dialog + + + + + +The only setting here, Threshold, indicates how easily pixels +are seen as noise that should be removed and made equal to the surrounding area. + + + + + + + +Miscellaneous dialogs + + +The <guilabel>Add Palette</guilabel> dialog + + + +The Add Palette dialog + + + + + +The Add Palette dialog + +The Add Palette dialog + + + + + +With this dialog, you can add a custom color palette to &chalk;. Fill in the +name for your palette in the text field at the top. Then make the palette: use +the button Add New Color... to add a color to the palette +and Remove Selected Color to remove the currently +selected color. Click the button Add to Predefined +Palettes to add your newly created palette to the palette list, or +just choose OK when you're done. + + + + + +The <guilabel>Document Information</guilabel> dialog + + + +The Document Information dialog + + + + + +The Document Information dialog + +The Document Information dialog + + + + + +This dialog is the same as in other &koffice; programs. You can enter various +information about your document here, which will be saved with the document so +that you can retrieve it later to review or edit. + + + +On the General tab, you can enter the title, subject and +keywords, as well as an abstract. On the bottom of this tab, some statistical +information is displayed. On the Author tab, you can +store information about yourself. The third tab, User-defined +Metadata, allows you to store any other information. + + + + + + + diff --git a/doc/chalk/commands-menus.docbook b/doc/chalk/commands-menus.docbook new file mode 100644 index 00000000..e0a58131 --- /dev/null +++ b/doc/chalk/commands-menus.docbook @@ -0,0 +1,2158 @@ + +Menus + + +Some of &chalk;'s menus are standard in &kde; or &koffice;, while others are +particular to &chalk;. The File menu contains commands for +manipluating files. In the Edit menu, you can find commands +that do things with the current selection. With the commands from the +View menu, you can change the way you look at the image. +The Image menu contains commands that change the entire +image, like converting all layers to another color model or resizing or +scaling the image. The Layer menu is like the +Image menu, but the commands only work on the current +layer. The Select menu contains commands to create and +manipulate selections. The Filter menu contains all the +filters you have installed. These work on the current layer. The +Scripts menu contains entries for working with scripts. +The Settings menu is again common to &koffice; and allows +you to manipulate the toolbars, shortcuts and configuration of &chalk;. +Finally, the Help menu gives you access to various +(hopefully helpful) information, such as this handbook. + + + + + +The <guimenu>File</guimenu> Menu + + + + + +&Ctrl;N +File +New + +Creates a new document. This displays the +New document dialog, standard across &koffice;, in which +you can choose to start with a blank document of a certain type, or to open a +recently opened document. + + + + +&Ctrl;O +File +Open... + +Opens an existing document. +Because this uses the usual &kde; Open Document +dialog to let you select a file, you can open files via various protocols +(ftp, fish, etcetera). + + + + + +File +Open Recent + +Opens a recently +opened document. Clicking this menu item will show a +submenu with the ten most recently opened documents in which +you can quickly open an image you have been working on lately. + + + + +&Ctrl;S +File +Save + +Saves the document. If you +haven't saved the document before, you will get the Save +Document As dialog, otherwise the document will be saved under +its current name. + + + + +File +Save As... + +Saves the document under a different name. +The default &kde; dialog is used, so saving remotely via ftp +or ssh (fish) is perfectly possible. + + + + +File +Reload + +Reloads the current document +from disk. All changes since you last saved the document +will be lost. + + + + +File +Import... + +Opens an existing document. Unlike +FileOpen, +this does not load the actual document, but only its contents: you receive a +copy of the chosen file as a new document. + + + + + +File +Export... + +Saves the document under a different name. (For +the moment, this is the same as +FileSave +As....) + + + + + +File +Mail... + +Sends the document via email. The default &kde; +mail compose window will be used. + + + + +&Ctrl;P +File +Print... + +Prints the document. You will see the usual +&kde; print dialog appear. + + + + +File +Print Preview... + +Shows a preview of what the printed document +will look like. + + + + +File +Document Information + +Opens the Document +Information dialog. This dialog can be used to add +various information to the image, like title, subject, keywords, author +information, and any other information you want to save with the +image. + + + + +&Ctrl;W +File +Close + +Closes the document. + + + + +&Ctrl;Q +File +Quit + +Quits &chalk;. + + + + + + + + + + + +The <guimenu>Edit</guimenu> Menu + + + + + +&Ctrl;Z +Edit +Undo + +Undoes the last action carried out. Actions +(like painting a stroke, filling an area, etcetera) are stored on +a stack. The last action you did will be undone, and the image is +restored to the state before that. Immediately choosing +Undo again will undo the action that was carried +out before the one just undone, etcetera. + + + + +&Ctrl;&Shift;Z +Edit +Redo + +Redoes the last action undone. As described at +Undo, a series of actions can be undone. With +Redo, an action undone is carried out again, and if +more actions have been undone before that, you can redo these in +turn. + + + + +&Ctrl;X +Edit +Cut + +Cuts the selection to the +clipboard. The current selection is put on the &kde; +clipboard, and the selection is cleared. + + + + +&Ctrl;C +Edit +Copy + +Copies the selection to the +clipboard. + + + + +&Ctrl;V +Edit +Paste + +Pastes the contents of the +clipboard. + + + + +Edit +Paste into New Image + +Pastes the contents of the +clipboard as a new image. + + + + +Edit +Clear + +Clears the selection. + + + + +&Alt;&Backspace; +Edit +Fill with Foreground Color + +Fills the selection with the current foreground +color. The current foreground color is shown in the top left color +square of the Colors palette. + + + + +&Backspace; +Edit +Fill with Background Color + +Fills the selection with the current background +color. The current background color is shown in the bottom right color +square in the top left corner of the Colors +palette. + + + + +Edit +Fill with Pattern + +Fills the selection with the current pattern. +The current pattern is shown on the Brush Shapes toolbar, +usually at the top right of the &chalk; window. + + + + +Edit +Resources + +Contains options for working with color +palettes. + + + + +Edit +Resources +Add New Palette... + +Opens the Add Palette +dialog. You can create a custom color palette +here. + + + + +Edit +Resources +Edit Palette... + +Opens the Edit Palette +dialog. Choose a color palette to edit from this list. You will then be +given the same dialog as with Add Palette, with the +difference that you edit the chosen color palette instead of adding a new +one. + + + + + + + + + + + +The <guimenu>View</guimenu> Menu + + + + + +&Ctrl;&Shift;F +View +Full Screen Mode + +Switches between normal view +and full screen view. In full screen view, the title +bar is hidden and the actual application window is resized to the entire +screen. + + + + +View +New View + +Opens a new view for the +current document. A new application window is opened +so that you can have two different views of the same document, for example +to work on different areas at the same time, or to look at an area at different +zoom levels simultaneously. Changes you make to the document in one view are +immediately visible in other views. + + + + +&Ctrl;&Shift;W +View +Close All Views + +Closes all views. + + + + +View +Split View + +Splits the current view. The +drawing area will be split into two parts, which can be used +just like two views in different windows. + + + + +View +Remove View + +Unsplits the view. The second +view (the bottom or right one) will be closed and the first one will remain +visible. + + + + +View +Splitter Orientation + +Changes the way the split +view is displayed. + + + + +View +Splitter Orientation +Vertical + +Changes the orientation of +the splitter to vertical. The two split +views will be positioned side by side. + + + + +View +Splitter Orientation +Horizontal + +Changes the orientation of +the splitter to horizontal. The two split views will +be positioned above each other. + + + + +&Ctrl;+ +View +Zoom In + +Zooms in on the view. The view +will be more detailed, but a smaller area will be visible at the +same time. + + + + +&Ctrl;- +View +Zoom Out + +Zooms out of the view. A larger +area will be visible at the same time, but it will be less +detailed. + + + + +&Ctrl;0 +View +Actual Pixels + +Zooms the view to actual pixel +level. (1:1 scale) + + + + +View +Actual Size + +Zooms the view to the actual image +size. + + + + +View +Fit to Page + +Zooms the view so that the image fills the available +workspace. + + + + +&Ctrl;R +View +Show Rulers + +Toggles display of the +rulers on and off. + + + + +View +Show Grid + +Toggles display of the +grid lines on and off. + + + + +View +Grid Spacing + +Contains various options to set the distance between +grid lines. The available spacing options are +1x1, 2x2, +5x5, 10x10, +20x20, and 40x40. + + + + + +View +Show Perspective Grid + +Toggles display of the perspective grid on and off. + + + + + + +View +Clear Perspective Grid + +Clears the perspective grid. (All grid lines +that were created, are deleted.) + + + + + +View +Palettes + +Allows you to toggle the +display of the various palettes on and off. The +default view of &chalk; shows all palettes, and the items are listed as Hide +palette therefore. When a certain palette is hidden, +the corresponding menu item changes to Show +palette. + + + + +&Ctrl;&Shift;H +View +Palettes +Hide All Palette Windows + +Hides all palettes. + + + + +View +Palettes +Hide Overview + +Hides the +Overview palette. + + + + +View +Palettes +Hide HSV + +Hides the +HSV palette. + + + + +View +Palettes +Hide RGB + +Hides the +RGB palette. + + + + +View +Palettes +Hide Gray + +Hides the +Gray palette. + + + + +View +Palettes +Hide Palettes + +Hides the +Palettes palette. + + + + +View +Palettes +Hide Layers + +Hides the Layers +palette. + + + + +View +Palettes +Hide Scripts Manager + +Hides the Scripts Manager. + + + + + +View +Palettes +Hide Histogram + +Hides the +Histogram palette. + + + + +View +Palettes +Hide Watercolors + +Hides the Watercolors +palette. + + + + +View +Palettes +Hide Brush, Ellipse, Filter tool, Line, Polygon &etc; + +Hides the palette of the selected +Tool. + + + + +View +Wetness Visualisation + +Toggles indication of the wetness of watercolor paint +on and off. + + + + + + + + + + + +The <guimenu>Image</guimenu> Menu + + + + + +Image +Image Properties + +Opens the Image +Properties dialog, +in which you can change the image name, size, +profile and description. + + + + +Image +Resize Image to Size of Current Layer + +Resizes the image to the +size of the currently active layer. + + + + +Image +Substrate... + +Opens the Substrate dialog. + + + +Image +Rotate + +Rotates the image. + + + + +Image +Rotate +Rotate Image... + +Opens the Rotate Image +dialog. + + + + +Image +Rotate +Rotate Image CW + +Rotates the image 90 degrees +clockwise. + + + + +Image +Rotate +Rotate Image CCW + +Rotates the image 90 degrees counterclockwise +(270 degrees clockwise). + + + + +Image +Rotate +Rotate 180 + +Rotates the image 180 degrees. + + + + +Image +Convert Image Type... + +Opens the Convert All +Layers dialog. This allows you to convert the image +to a different color space. Apart from the color space, the profile and +rendering intent can be specified as well. + + + + +Image +Separate Image... + +Opens the +Separate Image +dialog. You can separate the image into layers for each +individual colorspace component there. + + + + +Image +Change Image Size... + +Opens the +Image Size +dialog . You can resize or scale the image using various +algorithms here. + + + + +Image +Shear Image... + +Opens the Shear Image +dialog. You can shear the image in X or Y directions, +or both. + + + + + + + + + + +The <guimenu>Layer</guimenu> Menu + + + + + + +Layer +New + +Creates a new layer. + + + + +&Ctrl;&Shift;N +Layer +New +Add... + +Opens the +New Layer +dialog. This will create a new empty +layer. You can set the name, opacity, composite mode and +layer type. + + + + +Layer +New +Object Layer + +Creates a new layer for a +given &koffice; object type. + + + + +Layer +New +Object Layer +Scalable Graphics + +Creates a new layer for an +embedded &karbon14; object. + + + + +Layer +New +Object Layer +Text Documents + +Creates a new layer for an +embedded &kword; document. + + + + +Layer +New +Object Layer +Flowchart & Diagram + +Creates a new layer for an embedded +&kivio; object. + + + + +Layer +New +Object Layer +Slide Presentations + +Creates a new layer for an embedded +&kpresenter; object. + + + + +Layer +New +Object Layer +Image Object + +Creates a new layer for an +embedded &chalk; object. + + + + +Layer +New +Object Layer +Report Template + +Creates a new layer for an embedded +&kugar; Designer object. + + + + +Layer +New +Object Layer +Chart + +Creates a new layer for an +embedded &kchart; object. + + + + +Layer +New +Object Layer +Formula Editor + +Creates a new layer for an +embedded &kformula; object. + + + + +Layer +New +Object Layer +Report Generator + +Creates a new layer for an +embedded &kugar; object. + + + + +Layer +New +Object Layer +Project Management + +Creates a new layer for an +embedded KPlato object. + + + + +Layer +New +Object Layer +Spreadsheets + +Creates a new layer for an +embedded &kspread; document. + + + + +Layer +New +Adjustment Layer + +Opens the New Adjustment +Layerdialog. + + + + +Layer +New +Insert Image as Layer... + +Opens the Import Image +dialog. You can browse and select an image file, +which will be inserted in a new layer. + + + + +&Ctrl;&Shift;J +Layer +New +Cut Selection to New Layer + +Cuts the current selection +and inserts it as a new layer. + + + + +&Ctrl;J +Layer +New +Copy Selection to New Layer + +Copies the current selection +and inserts it as a new layer. + + + + +Layer +Remove + +Removes the current layer +and its contents. + + + + +Layer +Duplicate + +Duplicates the current +layer. + + + + +Layer +Hide/Show + +Toggles the visibility of +the current layer in the image editing window. + + + + +Layer +Mask + +Contains actions for working with layer masks. + + + + +Layer +Mask +Create Mask + + + + + + +Layer +Mask +Mask From Selection + + + + + + +Layer +Mask +Mask To Selection + + + + + + +Layer +Mask +Apply Mask + + + + + + +Layer +Mask +Remove Mask + + + + + + +Layer +Mask +Edit Mask + + + + + + +Layer +Mask +Show Mask + + + + + + +&Ctrl;] +Layer +Raise + +Moves the current layer one +level upward. + + + + +&Ctrl;[ +Layer +Lower + +Moves the current layer one +level downward. + + + + +&Ctrl;&Shift;] +Layer +To Top + +Moves the current layer to the +top. + + + + +&Ctrl;&Shift;[ +Layer +To Bottom + +Moves the current layer to +the bottom. + + + + +Layer +Save Layer as Image... + +Opens the Export Layer +dialog. The current layer will be saved to the +chosen file. + + + + +Layer +Flip on X Axis + +Flips the current layer +horizontally. + + + + +Layer +Flip on Y Axis + +Flips the current layer +vertically. + + + + +Layer +Properties + +Opens the Layer +Properties dialog. You can change the name, +colorspace, opacity, composite mode and position of the current layer +here. + + + + +&Ctrl;E +Layer +Merge with Layer Below + +Merges the current layer +with the one below it. + + + + +&Ctrl;&Shift;E +Layer +Flatten Image + +Merges all visible layers. + + + + +Layer +Rotate + +Rotates the current layer. + + + + +Layer +Rotate +Rotate Layer... + +Opens the Rotate Layer +dialog. + + + + +Layer +Rotate +Rotate CW + +Rotates the current layer 90 degrees +clockwise. + + + + +Layer +Rotate +Rotate CCW + +Rotates the current layer 90 degrees counterclockwise +(270 degrees clockwise). + + + + +Layer +Rotate +Rotate 180 + +Rotates the current layer by +180 degrees. + + + + +Layer +Histogram... + +Opens the Histogram +dialog, in which you can see histograms for the current +layer. + + + + +Layer +Convert Layer Type... + +Opens the +Convert +Current Layer dialog. You can +set various options with respect to the colorspace and +rendering intent. + + + + +Layer +Scale Layer... + +Opens the Layer +Size dialog. You can choose the new +dimensions and the resize filter to use. + + + + +Layer +Layer Effects + +Contains commands to add effects to the current layer. + + + + + +Layer +Layer Effects +Add Drop Shadow... + +Opens the Drop Shadow +dialog. This dialog can be used to add a drop shadow beneath +the current layer. + + + + +Layer +Shear Layer... + +Opens the Shear Layer +dialog. You can select the X and Y angles to shear +by. + + + + + + + + + + + +The <guimenu>Select</guimenu> Menu + + + + + +&Ctrl;A +Select +Select All + +Selects the entire +current layer. + + + + +&Ctrl;&Shift;A +Select +Deselect + +Unselects everything. + + + + +&Ctrl;&Shift;D +Select +Reselect + +Reselects the previous +unselected areas. + + + + +&Ctrl;I +Select +Invert + +Inverts the selection. +(Everything that is selected will be unselected and vice +versa.) + + + + +&Alt;&Ctrl;D +Select +Feather... + +Feathers the selection. (Adds +a soft border around it.) + + + + +Select +Similar + + + + + + +&Ctrl;H +Select +Hide Selection + +Hides the selection. The selection is still +active, but it is not made visible anymore. + + + + +Select +Grow Selection... + +Grows the selection. + + + + +Select +Shrink Selection... + +Shrinks the selection. + + + + +Select +Border Selection... + +Borders the selection. + + + + +Select +Color Range... + +Opens the Color Range +dialog. + + + + + + + + + + + +The <guimenu>Filter</guimenu> Menu + +See the Filters chapter for more +information on filters. + + + + +&Ctrl;&Shift;J +Filter +Apply Filter Again + +Repeats the last filter +action. + + + + +Filter +Adjust + +Contains various options for changing the +colors in your image. + + + + +Filter +Adjust +Auto Contrast + +Automatically changes the image to obtain as much +contrast as possible. + + + + +Filter +Adjust +Brightness/Contrast... + +Opens the +Brightness/Contrast +dialog. You can set the +brightness and contrast ratio of your image here. + + + + +Filter +Adjust +Desaturate + +Desaturates the image. This +will effectively convert the current image to grayscale, but all subsequent +painting is done with usual colors. + + + + +Filter +Adjust +Invert + +Inverts the image or +selection. (Black becomes white, blue becomes yellow, +etcetera.) + + + + +Filter +Adjust +Color Adjustment... + +Opens the Color Adjustment +dialog. You can adjust the colorspace components +of the current image there (for example, in an RGB image, you can change the +contribution of red, green, and blue to the total image). + + + + +Filter +Artistic + +Contains various filters for +artistic actions. + + + + + + +Filter +Artistic +Oilpaint... + +Opens the Oilpaint +dialog to add +an oilpaint effect to the selection or image. + + + + +Filter +Artistic +Pixelize... + +Opens the Pixelize +dialog to pixelize the image. (A block of pixels is +changed so that they all become the same, averaged color.) + + + + +Filter +Artistic +Raindrops... + +Opens the Raindrops +dialog to add a raindrops effect to the selection or +image. + + + + +Filter +Artistic +Dry the Paint + +Dries wet paint. + + + + +Filter +Blur + +Contains various blur filters. + + + + +Filter +Blur +Gaussian Blur + +Performs a slight blur on the image or +selection. + + + + +Filter +Colors + +Contains filters that change the image colors. + + + + +Filter +Colors +Color to Alpha + + + + + + +Filter +Colors +Color Transfer + +Opens the Color Transfer dialog +to give the image a new look. + + + + +Filter +Colors +Maximize Channel + +Adjusts the colors of each pixel by removing color +channels that are less abundant. + + + + +Filter +Colors +Minimize Channel + +Adjusts the colors of each pixel by removing color +channels that are abundant. + + + + +Filter +Edge Detection + +Contains edge detecting filters. + + + + +Filter +Edge Detection +Bottom Edge Detection + +Performs edge detection with the bottom sides of image +parts as references. + + + + +Filter +Edge Detection +Left Edge Detection + +Performs edge detection with the left sides of image +parts as references. + + + + +Filter +Edge Detection +Right Edge Detection + +Performs edge detection with the right sides of image +parts as references. + + + + +Filter +Edge Detection +Sobel... + +Opens the Sobel +dialog. + + + + +Filter +Edge Detection +Top Edge Detection + +Performs edge detection with the top sides of image +parts as references. + + + + +Filter +Enhance + +Contains image enhancing +filters. + + + + +Filter +Enhance +CImg Image Restoration... + +Opens the Image +Restoration dialog. + + + + +Filter +Enhance +Custom Convolution... + +Opens the Custom +Convolution dialog. + + + + +Filter +Enhance +Gaussian Noise Reduction... + + + + + + +Filter +Enhance +Mean Removal + +Sharpens the image or selection by aggravating color +borders. + + + + +Filter +Enhance +Sharpen + +Sharpens the image or selection. + + + + +Filter +Enhance +Unsharp Mask + +Applies an unsharp mask to the image or +selection. + + + + +Filter +Enhance +Wavelet Noise Reducer + +Reduces noise in the image or +selection. + + + + +Filter +Emboss + +Contains emboss filters. + + + + +Filter +Emboss +Emboss Horizontal & Vertical + +Embosses the image or selection on the two main +directions. + + + + +Filter +Emboss +Emboss with Variable Depth... + +Opens the Emboss +dialog. + + + + +Filter +Emboss +Emboss in All Directions + +Embosses the image or +selection. + + + + +Filter +Emboss +Emboss Horizontal Only + +Embosses the image or selection on the horizontal axis +only. + + + + +Filter +Emboss +Emboss Laplascian + +Embosses the image or selection using the Laplace +technique. + + + + +Filter +Emboss +Emboss Vertical Only + +Embosses the image or selection on the vertical axis +only. + + + + +Filter +Map + +Contains map filters. + + + + +Filter +Map +Bumpmap... + +Opens the Bumpmap +dialog. + + + + +Filter +Map +Round Corners... + +Opens the Round +Corners dialog to round off the corners of the image or +selection. + + + + +Filter +Map +Small Tiles... + +Shrinks the image or selection and then tiles +it. + + + + +Filter +Other + +Contains miscellaneous filters. + + + + +Filter +Other +Lens Correction... + +Opens the Lens Correction +dialog to correct for lens anomalies. + + + + +Filter +Other +Random Noise... + +Opens the Random Noise dialog to add +random noise to the image. + + + + +Filter +Other +Random Pick... + +Opens the Random Pick dialog to +distort the image. + + + + +Filter +Other +Wave... + +Opens the Wave dialog to distort the +image + + + + + +Filter +Filters Gallery + +Opens the +Filters +Gallery dialog. This +shows previews of the various filters and allows for easy +comparison. + + + + + + + + + + + +The <guimenu>Scripts</guimenu> Menu + + + + + +Scripts +Execute Script File + +Executes a script file. + + + + +Scripts +Script Manager + +Opens the Script Manager dialog. + + + + + + + + + + + +The <guimenu>Settings</guimenu> Menu + + + + + +Settings +Toolbars + +Contains options to display or hide the various +toolbars. + + + + +Settings +Toolbars +File + +Displays or hides the File +toolbar. + + + + +Settings +Toolbars +Edit + +Displays or hides the Edit +toolbar. + + + + +Settings +Toolbars +Navigation + +Displays or hides the Navigation +toolbar. + + + + +Settings +Toolbars +&chalk; + +Displays or hides the +&chalk; toolbar. + + + + +Settings +Toolbars +Brushes and Stuff + +Displays or hides the +Brushes and Stuff toolbar. + + + + +Settings +Configure Shortcuts... + +Opens the Configure Shortcuts + dialog. This dialog is common to most &kde; applications +and allows you to configure shortcuts for all actions &chalk; has to +offer. + + + + +Settings +Configure Toolbars... + +Opens the Configure Toolbars +dialog. This dialog is common to most &kde; applications +and allows you to configure &chalk;'s toolbars. + + + + +Settings +Configure &chalk;... + +Opens the +Preferences +dialog. You can configure &chalk; here to match your personal +preferences. + + + + + + + + + + + +The <guimenu>Help</guimenu> Menu +&help.menu.documentation; + + + diff --git a/doc/chalk/commands-palettes.docbook b/doc/chalk/commands-palettes.docbook new file mode 100644 index 00000000..f71be732 --- /dev/null +++ b/doc/chalk/commands-palettes.docbook @@ -0,0 +1,769 @@ + +Palettes + + +This section describes &chalk;'s palettes. The palettes are usually found at +the right hand side of &chalk;'s main window. There are three palettes which +help you in customizing your images: + + + +The <guilabel>Control box</guilabel> palette +The Control box contains three tabs. You can get an +overview of the image, view a color histogram, and modify options for the +current tool. + + +<guilabel>Overview</guilabel> + + + +The Overview tab + + + + + +The Overview tab + +The Overview tab + + + +This tab offers you two settings. With the spinbox, slider, and +1:1 button at the bottom, you can set the zoom level +for the document. The Exposure slider and textbox can be +used to choose the exposure level for OpenEXR images. Furthermore, the +X and Y labels indicate the current +pointer position, with (0,0) being the top left corner of the canvas. + + + +<guilabel>Histogram</guilabel> + + + +The Histogram tab + + + + + +The Histogram tab + +The Histogram tab + + + +This tab displays a color histogram showing the distribution of +colors over the image. The histogram is split up in red, green and blue +levels. + + + +<guilabel>Tool</guilabel> + +Actually, there is no tab named like this, since the tab name changes to +reflect the name of the currently selected tool. This tab shows the +customization options available for the tools that have them. + + +<guilabel>Brush</guilabel> + + +The Tool tab for Brush + + + + + +The Tool tab for Brush + +The Tool tab for Brush + + + +There are three options available on this tab. + +The Opacity slider and spin box are used to set the +opacity when drawing (opacity is the opposite of transparency, i.e. 100% +opaque is 0% transparent, and vice versa). + +In the Mode drop down box, you can choose a drawing +mode. This changes the actual effect that results from drawing on the image +(for example, only changing the saturation or lightness). + +With the Paint direct option, you can determine whether +you want to paint directly on the current layer, or on a temporary layer which +is then composited onto the actual layer. This makes a difference especially +when using relative low opacity values. + + + +<guilabel>Line</guilabel> + + +The Tool tab for Line + + + + + +The Tool tab for Line + +The Tool tab for Line + + + +See Brush +for the description of Opacity and +Mode. The ? button shows a tip about +the usage of modifier keys. + + + +<guilabel>Rectangle</guilabel> + + +The Tool tab for Rectangle + + + + + +The Tool tab for Rectangle + +The Tool tab for Rectangle + + + +See Brush for a description of Opacity and +Mode. + +The Fill drop down box is used to specify whether the +inside of the rectangle should be filled. You can choose between three fill +options: the current foreground color, background color or pattern is +used. + + + +<guilabel>Bezier</guilabel> +See Brush for the +description of Mode and Opacity. + + + + +<guilabel>Ellipse</guilabel> +The same options as for Rectangle are +available here. + + + +<guilabel>Polygon</guilabel> +The same options as for Rectangle are +available here. + + + +<guilabel>Polyline</guilabel> +The same options as for Line +are available here. + + + +<guilabel>Star</guilabel> + + +The Tool tab for Star + + + + + +The Tool tab for Star + +The Tool tab for Star + + + +The options for Rectangle are +available here, as well as two options specific to this tool. + +The Vertices drop down box is used to set the amount +of vertices (points) in the star. + +The Ratio setting defines the shape of the +star. A ratio of 0% will create a star with no inner area (when drawing the +star, the two lines that make up a star point, overlap). Increasing the ratio +will slowly make the star more outlined (the two lines are pulled +apart). A star with a ratio of 100% is a regular polygon. + + + + +<guilabel>Duplicate</guilabel> + + +The Tool tab for Duplicate + + + + + +The Tool tab for Duplicate + +The Tool tab for Duplicate + + + +The same options as for Line +are available here. In addition, there are three other options. + +With the Healing and +Healing radius options, you can specify that the +duplication should not copy the colors, but only the structure +of the source area. + +If you enable the Correct the perspective option, the +duplicate tool will follow your perspective grid. + + + + +<guilabel>Paint with Filters</guilabel> + + +The Tool tab for Paint with Filters + + + + + +The Tool tab for Paint with Filters + +The Tool tab for Paint with Filters + + + +Depending on the filter, you can set different options here. The +options you can set are the same as those available in the +normal settings dialog for the chosen filter. See the +Filters section in the Dialogs +chapter for more information. + + +<guilabel>Transform</guilabel> + + +The Tool tab for Transform + + + + + +The Tool tab for Transform + +The Tool tab for Transform + + + + +You can choose which transformation algorithm to use in the +Filter drop down box. + + + +<guilabel>Crop</guilabel> + + +The Tool tab for Crop + + + + + +The Tool tab for Crop + +The Tool tab for Crop + + + +Set the corner coordinates of the area that should remain with the +four spin boxes X, Y, +Width and Height. You can also +fill in Ratio to determine the Y/X ratio. Check one of +the checkboxes to have the respective value remain constant while changing the +size of the area. The drop down box can be used to select whether the entire +image or only the current layer should be cropped. Clicking the +Crop button has the same effect as double-clicking +outside the area in the image. + + + +<guilabel>Contiguous Fill</guilabel> + + +The Tool tab for Contiguous Fill + + + + + +The Tool tab for Contiguous Fill + +The Tool tab for Contiguous Fill + + + +The same options as for Brush +are available here, as are a couple of other options. + +The setting in the Threshold slider and spin box +determines how near the color of a point should be to the color of the +starting point of the fill, in order for the fill to spread out over the +former point. A higher threshold will therefore fill areas that have less +similar colors, a lower threshold limits the spread. + +If you check the Fill entire selection checkbox, the +entire selection will be filled instead of only the neighboring area. + +Checking the Limit to current layer checkbox changes the +behavior of the fill: the extent to which the fill is done, is determined from +the current layer only instead of the entire image. + +By checking the Use pattern checkbox you can choose to +fill with the currently selected pattern instead of with the foreground color. + + + + +<guilabel>Gradient</guilabel> + + +The Tool tab for Gradient + + + + + +The Tool tab for Gradient + +The Tool tab for Gradient + + + +The same options as for Brush +are available here, as are a couple of other options. + +The Shape drop down box can be used to select the gradient +type: Linear, Bi-Linear, Radial, +Square, Conical and Conical Symmetric. + +The Repeat option determines whether the gradient is +repeated if it does not fill the entire image. With None, the colors on the +ends of the gradient are used to fill the remaining space. With Forwards, the +gradient is normally repeated (connecting the back end of one occurrence with +the front end of the next). With Alternating, the gradient is repeated with +every second occurrence being drawn from back to front (linking front to front +and back to back). + +Check the Reverse checkbox to have the gradient drawn +reversed (from back to front). + +The final setting is Anti-alias threshold, which +determines how smooth the gradient will become. + + + + +<guilabel>Text</guilabel> + + +The Tool tab for Text + + + + + +The Tool tab for Text + +The Tool tab for Text + + + +The same options as for Brush +are available here. Furthermore there is an option Font, +which shows the font that will be used for the text. Click the +... button to change the font. + + + + +<guilabel>Color Picker</guilabel> + + +The Tool tab for Color Picker + + + + + +The Tool tab for Color Picker + +The Tool tab for Color Picker + + + +The first option is a dropdown box in which you can choose which +layer to pick the color from. If you choose a specific layer, +the color of the point in that layer will be retrieved. With Sample +All Visible Layers, the topmost visible layer which is not +transparent at that point is used. + +If the Update current color checkbox is checked, then the +current foreground color (when clicking with the &LMB;) or background color +(when clicking with the &RMB;) is set to the picked color. + +The checkbox Add to palette and the accompanying +dropdown box determine whether the picked color should be added to an existing +palette. Check the checkbox, and choose the desired palette from the list, if +you want to do so. + +The checkbox Show colors as percentages switches the +range of color values displayed from the normal range (e.g. 0 to +255) to a scaled value between 0% and 100%. + +With the Sample radius option, you can choose the area +size to use when picking the color. A radius of one just picks one pixel, +larger radii will make the picker average over the colors of the circle-shaped +area with the chosen radius that is centered around the chosen pixel. + + + + +<guilabel>Select</guilabel> tools + + +The Tool tab for Select tools + + + + + +The Tool tab for Select tools + +The Tool tab for Select tools + + + +The Paint Selection, Erase Selection, +Select Rectangular, Select Elliptical, Select Polygonal and Select Outline tools have one option: +the Action to perform. You can choose between Add to, or +Subtract from the selection. + + + +<guilabel>Select Contiguous Area</guilabel> + + +The Tool tab for Select Contiguous + + + + + +The Tool tab for Select Contiguous + +The Tool tab for Select Contiguous + + + +The Action is the same as discussed with the +Select +operations. + +The slider and spin box at Fuzziness determine how near +colors must be to the color at the clicked point to be added to the selection. + +When the Sample merged checkbox is checked, the +bounds of the selection are determined by looking at the entire image instead +of at the current layer. + + + + +<guilabel>Similar Select</guilabel> +The Action and Fuzziness +options are the same as with Select +contiguous. + + + +<guilabel>Select Magnetic</guilabel> + + +The Tool tab for Select Magnetic + + + + + +The Tool tab for Select Magnetic + +The Tool tab for Select Magnetic + + + +The Action option is the same as with the other +Select tools. + + +The Distance option determines the maximal distance at +which boundaries to attach to, are searched for. The To +Selection button has the same effect as double-clicking the &LMB;: +the selection is finished. + + + + + + + + +The <guilabel>Colors</guilabel> palette +In this palette you can choose the foreground and background colors +that should be used for painting. You can choose these in five different +ways. Each of these has its own tab on this palette. + +You can choose which color to set by clicking the corresponding +buttons at the top left. The topmost color is the foreground color, the +bottom one is the background color. You can click the double-headed arrow +to swap the colors: foreground color becomes background color and vice +versa. You can reset the colors to the default (foreground black, background +white) by clicking the small black/white icon. + + + +<guilabel>HSV</guilabel> + + +The HSV tab + + + + + +The HSV tab + +The HSV tab + + + +On this tab, you can select a color via the Hue / Saturation / Value +system. + +The hue determines the major color and starts at red with 0, then increases +along the color spectrum (that is, along the line yellow, green, +blue, violet) to a maximum of 359. This is represented in the circle on the tab +as the angle component (starting at the top, rotate along the circle +in clockwise direction to increase the hue). + +The saturation determines the pureness of the color. A saturation of 255 +yields the pure color, while a saturation of 0 yields a gray. This is the +radius component of the color circle on the tab: the center corresponds to +no saturation, the circle boundary corresponds to fully saturated. + +The value determines the lightness of the color. This darkens or lightens the +color, as can be set using the vertical slider on the tab. A value of 0 gives +black, a value of 255 gives the pure color. + + + + +<guilabel>RGB</guilabel> + + +The RGB tab + + + + + +The RGB tab + +The RGB tab + + + +On this tab, colors can be selected using their Red / Green / Blue +components. + +You can set red, green and blue components on a scale of 0 to 255. At 0 that +color component is absent, at 255 it is used at maximum intensity. The sliders +will change color to give you a hint about which color you will produce by +altering the corresponding value. + + + + +<guilabel>Gray</guilabel> + + +The Gray tab + + + + + +The Gray tab + +The Gray tab + + + +On this tab, you can choose a gray value (indicated with a K for Key, +the usual designation for black). +The gray value can be chosen on a scale from 0 (pure white) to 255 +(pure black). + + + +<guilabel>Palettes</guilabel> + + +The Palettes tab + + + + + +The Palettes tab + +The Palettes tab + + + +On this tab, you can select a color from one of several predefined +color palettes. +You can choose which color palette to pick from in the drop down +box at the top. + + + +<guilabel>Watercolors</guilabel> + + +The Watercolors tab + + + + + +The Watercolors tab + +The Watercolors tab + + + +This tab offers you a selection of watercolors for painting with wet +paint. + +You can set two options to modify the painting behaviour: Paint +strength influences how much paint you will apply to the canvas, +and Wetness determines how wet the paint is when it is +applied. You can dry the paint later. + + + + + + +The <guilabel>Layers</guilabel> palette +This palette offers two tabs. + + +<guilabel>Layers</guilabel> + + +The Layers tab + + + + + +The Layers tab + +The Layers tab + + + +This tab offers you access to various operations on layers. + +On the top left, you can select what blending mode should be used for the +selected layer. These are the same possibilities as you can choose from for +drawing modes. + +The slider/textbox at the top right determines the opacity of the selected +layer. 0% opacity corresponds to 100% transparency, and vice versa. + +The list shows all layers and their names, and offers various controls for each +layer. The eye icon toggles whether the layer is visible or not. The link icon +is used to link layers together. The lock icon determines if the layer is +locked or not. Locked layers cannot be edited. + +Below the layer list, there are some other controls. You can create a new +layer, move the current layer up or down, show the layer's properties and +delete it. + + +There are some more handy tricks you can do with the mouse within the list. +Right-click on the layer list and select New Folder to +create a new layer folder, which you can use to group layers in. You can also +drag and drop layers to change their order. To do so, click on the bottom part +of the list item representing the layer, drag the mouse, and release the mouse +button at the desired position. If you click at the top part of the list item +instead, you will get a text field so that you can rename the layer. + + + + +<guilabel>Scripts Manager</guilabel> + + +The Script Manager tab + + + + + +The Script Manager tab + +The Script Manager tab + + + +This tab is a smaller version of the Script +Manager dialog. See the description over there for more +information. + + + + + + diff --git a/doc/chalk/commands-toolbars.docbook b/doc/chalk/commands-toolbars.docbook new file mode 100644 index 00000000..b99457f1 --- /dev/null +++ b/doc/chalk/commands-toolbars.docbook @@ -0,0 +1,752 @@ + +Toolbars + +This section describes &chalk;'s toolbars. By default, the +Chalk toolbar is located to the left of the drawing area, +while the others can be found at the top, below the menu bar. + +You can customize your toolbars by choosing +SettingsConfigure +Toolbars... or by clicking with the &RMB; on a +toolbar and choosing Configure Toolbars.... + + +The <guilabel>File</guilabel> Toolbar + + + +The File toolbar + + + + + +The File toolbar + +The File toolbar + + + + +This toolbar contains actions for working with files. In &chalk;'s +default, there are five buttons on this toolbar: New, +Open, Save, Print +Preview, and Print. + +These actions all correspond to entries in the File menu. + + + + +The <guilabel>Edit</guilabel> Toolbar + + + +The Edit toolbar + + + + + +The Edit toolbar + +The Edit toolbar + + + + +This toolbar contains editing actions. With default settings this +toolbar offers four buttons: Undo, +Redo, Cut, and +Copy. + +These actions all correspond to entries in the Edit menu. + + + +The <guilabel>Navigation</guilabel> Toolbar + + + +The Navigation toolbar + + + + + +The Navigation toolbar + +The Navigation toolbar + + + + +This toolbar offers easy access to navigation actions. The two +default actions available are Zoom In and +Zoom Out. With Zoom In, the zoom +level is increased. You will see less, but in higher detail. With +Zoom Out, the zoom level is decreased, so that you see +more at less detail. + + + + +The <guilabel>Chalk</guilabel> Toolbar + + + +The Chalk toolbar + + + + + +The Chalk toolbar + +The Chalk toolbar + + + + + +This toolbar contains painting operations and tools, as well as editing and +selecting tools. The available actions and some controls are listed below. You +can change the behaviour of most tools (and with that, usually the resulting +effect) by setting their options. + + + + + + Brush + +With this tool you can paint freely. Click the &LMB; to paint a +single instance of the currently selected brush, or hold the &LMB; and drag +your mouse around to paint. The mouse movements you make are directly used for +painting. + + + + Line + +This tool is used to draw lines. Click the &LMB; to indicate the first +endpoint, keep the button pressed, drag to the second endpoint and release the +button. + +Use &Shift; while holding the mouse button to restrict drawing to only +horizontal or vertical lines. You can press &Alt; while still keeping the &LMB; +down to move the line to a different location. + + + + Rectangle + +This tool can be used to paint rectangles. Click and hold the &LMB; to indicate +one corner of the rectangle, drag to the opposite corner, and release the +button. + +If you hold &Shift; while drawing, a square will be drawn instead of a +rectangle. Holding &Ctrl; will change the way the rectangle is constructed. +Normally, the first mouse click indicates one corner and the second click the +opposite. With &Ctrl;, the initial mouse position indicates the center of the +rectangle, and the final mouse position indicates a corner. +You can press &Alt; while still keeping the &LMB; down to move the rectangle to +a different location. + +You can change between the corner/corner and center/corner drawing +methods as often as you want by pressing or releasing &Ctrl;, provided that you +keep the &LMB; pressed. With &Ctrl; pressed, mouse movements will affect all +four corners of the rectangle (relative to the center), without &Ctrl;, one +of the corners is unaffected. + + + + Ellipse + +Use this tool to paint an ellipse. The currently selected brush is used for +drawing the ellipse outline. Click and hold the &LMB; to indicate one corner of +the bounding rectangle of the ellipse, then move your mouse to +the opposite corner. &chalk; will show a preview of the ellipse using a thin +line. Release the button to draw the ellipse. + +If you hold &Shift; while drawing, a circle will be drawn instead of an +ellipse. Holding &Ctrl; will change the way the ellipse is constructed: instead +of two corners, the initial mouse position indicates the ellipse center, and the +final mouse position indicates one of the corners of the bounding rectangle. +You can press &Alt; while still keeping the &LMB; down to move the ellipse to a +different location. + +You can change between the corner/corner and center/corner drawing +methods as often as you want by pressing or releasing &Ctrl;, provided that you +keep the &LMB; pressed. With &Ctrl; pressed, mouse movements will +affect all four corners of the bounding rectangle (relative to the center), +without &Ctrl;, the corner opposite to the one you are moving remains still. + + + + Polygon + +With this tool you can draw polygons. Click the &LMB; to indicate the +starting point and successive vertices, then double-click or press &Enter; to +connect the last vertex to the starting point. + + + + Polyline + +Polylines are drawn like polygons, with the difference that the double-click +indicating the end of the polyline does not connect the last vertex to the +first one. + + + + Star + +This tool creates star-shaped objects. Press the &LMB; to indicate the center, +and drag the mouse to change the size and rotation of the star. + +You can press &Alt; while still keeping the &LMB; down to move the star to a +different location. + + + + Bezier + +You can draw Bezier curves by using this tool. Click the &LMB; to indicate the +starting point of the curve, then click again for consecutive control points +of the curve. + + + +Drawing a Bezier curve + + + + + +Drawing a Bezier curve + +Drawing a Bezier curve + + + + +&chalk; will show a blue line with two handles when you add a control point. +You can drag these handles to change the direction of the curve in that point. + + + +Modifying a Bezier curve + + + + + +Modifying a Bezier curve + +Modifying a Bezier curve + + + + +You can click on a previously inserted control point to modify it. With an intermediate +control point (&ie; a point that is not the starting point and not the ending +point), you can move the direction handles seperately to have the curve enter +and leave the point in different directions. After editing a point, you can +just click on the canvas to continue adding points to the curve. + + +Pressing Delete will remove the currently selected control +point from the curve. Double-click the &LMB; on any point of the curve or +press &Enter; to finish drawing, or press &Esc; to cancel the entire curve. +You can use &Ctrl; while keeping the &LMB; pressed to move the entire curve to +a different position. + + + +A finished Bezier curve + + + + + +A finished Bezier curve + +A finished Bezier curve + + + + + + Duplicate + +You can use this tool to duplicate parts of an image. Press &Shift; and click +with the &LMB; on the location you want to duplicate from. &chalk; will +indicate this location by an outline of your current brush. Then click with +the &LMB; to designate the location where you want to duplicate to, and drag +with the mouse. You will then duplicate whatever is at the source location to +the current (destination) location. + +While you are painting the duplicate, both your cursor in the destination +location and the brush outline in the source location will move, in order to +give you visual feedback. + +You can also use this tool to correct colors in a part of the image: use the +Healing option for that. + + + + Paint with +filters + +This tool allows you to pick a filter and draw with it. The image below shows +the effect of using a large circular brush and painting with, from left to +right, the Maximize Channel, Minimize Channel, Invert, and Desaturate filters. + + + +Painting with filters + + + + + +Painting with filters + +Painting with filters + + + + + + Crop + +With this tool you can crop a layer or an image to a certain rectangular area. +Click and drag with the &LMB; to define an area. This area is designated by an +outline with 8 handles. You can then use the handles to change the size of the +area which the image or layer is to be cropped to. You can also click and drag +inside the area to move the outline in its entirety. + +Double-click outside the area (i.e. on a part of the image that is to be removed) +to confirm the cropping operation. + + + + Move + +With this tool, you can move the current layer or selection by dragging the +mouse. + + + + Transform + +With this tool you can quickly transform the current selection or layer. +Handles will appear at the corners and sides, with which you can resize the +selection or layer. You can perform rotations by moving the mouse above or to +the left of the handles and dragging it. You can also click anywhere inside +the selection or layer and move it by dragging the mouse. + + + + Perspective Transform + +This tool allows you to change the perspective of an image. Designate the area +which should become the new image by clicking at its top-left, top-right, +bottom-right and bottom-left corners. The area given by these four corners +will then be transformed so that the given corners become the corners of the +actual image. + + + + Contiguous Fill + +Use this tool to fill a contiguous area of one color with the current +foreground color or a pattern. Simply click to fill up the area. + + + + Gradient + +This tool fills the current layer or selection with the currently selected +gradient. Click the &LMB;, hold it, and drag the mouse to define two endpoints. +The gradient will be drawn along this line. If the line does not extend to the +border of the selection or layer, the color at the corresponding endpoint of +the gradient will be used to fill up the rest of the area at that side. + + + + Text + +With this tool you can add simple text to your image. Click the &LMB; on the +location at which you want have the text. Then enter the desired text in the +dialog window that appears. The text will be horizontally centered on, and +the top of the text will be at the same height as, the chosen location. + + + + Color Picker + +With this tool you can find the color values of a point. Click the &LMB; +somewhere in the image to see color information about that point in the +Control box. + + + + Pan + +This tool can be used to navigate through your image. Click and hold the &LMB; +and move the mouse to scroll in a certain direction. + + + + Zoom + +Use this tool to zoom in and out. Click the &LMB; to increase the zoom by +a factor 2 (e.g. 1:1 to 2:1), click the &RMB; to decrease the zoom by a factor +2 (e.g. 1:1 to 1:2). + + + + Perspective Grid + +You can create and edit a perspective grid with this tool. Click the &LMB; and +drag the mouse to indicate the first two corners of the grid, then click for +the third and fourth corners. The outline of the grid is now shown and you can +edit it if you are not completely happy. When you switch to a different tool, +the perspective grid will be subdivided and shown as thin gray lines. + +If you only see three corners instead of four, you probably +clicked instead of dragging initially. In this case you can still click the +handle of your now combined first and second corners and drag it to get four +separate corners. + +Clicking the Perspective Grid tool again later will allow +you to modify the grid. You can hide or remove the grid by choosing the +Hide Perspective Grid or Clear +Perspective Grid options from the View menu. + + + + Paint Selection + +This tool can be used to select custom areas. The currently selected brush is +used to select areas: instead of painting on the image, the area is selected. +For more information on selections, see the Selections chapter. + + + + + Erase Selection + +This tool works almost the same as the Paint Selection +tool, but a selection, if it exists at the mouse location, is removed instead +of created. + + + + + Select Rectangular + +You can use this tool to select rectangular areas. Operation is similar to the +Rectangle tool, and &Shift;, &Ctrl; and &Alt; can be used +like when painting rectangles. + + + + + Select Elliptical + +You can use this tool to select elliptical areas. Operation is similar to the +Ellipse tool, and &Shift;, &Ctrl; and &Alt; can be used +like when painting ellipses. + + + + Select +Polygonal + +You can use this tool to select polygonal areas. Operation is similar to the +Polygon tool, and &Shift;, &Ctrl; and &Alt; can be used +like when painting polygons. + + + + Select +Outline + +You can use this tool to select custom outlined areas. Click the &LMB; and drag +with your mouse, like when painting with the Brush tool, +to define the outline. When you release the mouse button, the outline will be +finished with a straight line between the current position and the start +position. + + + + + Select Contiguous + +With this tool you can select contiguous areas of a color. Click with the +&LMB; to select an area. + + + + + Select Similar + +With this tool you can select multiple areas with the same color. Detection is +done the same as with the contiguous fill, but the areas do not need to be +adjacent. + + + + Magnetic Selection + +With this tool you can easily select a visually distinct area. Click with the +&LMB; and move the mouse around the area that you want to select. If the area +has a well enough defined boundary, the selection will be drawn nicely around +it. You will see a number of control points appear, which connect the various +parts of the selection boundary. + +If you want more control over the area that is selected, press &Ctrl; to +switch to manual mode. You will now have to click for each control point. +In manual mode, you can also move control points by clicking on them with the +&LMB; and dragging with the mouse. + +When you want to return to automatic mode, simply press &Ctrl; again. You can +switch between these two modes as often as you like. + + + + Select Bezier + +With this tool you can select an area by drawing a Bezier outline. See the +description of the Bezier tool for details. + + + + + + + +The <guilabel>Brushes and Stuff</guilabel> Toolbar + + + +The Brushes and Stuff toolbar + + + + + +The Brushes and Stuff toolbar + +The Brushes and Stuff toolbar + + + + +This toolbar contains dropdown palettes in which you +can choose brush shapes, gradients, and fill patterns. It also contains a +dropdown box for painter's tools, and a tablet pressure setting. + + +<guilabel>Brush Shapes</guilabel> + + + +The Brush Shapes palette + + + + + +The Brush Shapes palette + +The Brush Shapes palette + + + + +In the Brush Shapes palette, you can choose +which brush to paint with. This brush is used for painting operations +like Freehand, Rectangle, +Ellipse, etcetera. You can choose a predefined +brush (in the Predefined Brushes tab, shown above), or +customize or create one. + + + +The Brush Shapes palette with the Autobrush tab + + + + + +The Brush Shapes palette with the Autobrush tab + +The Brush Shapes palette with the Autobrush +tab + + + + +The Autobrush tab allows you to create a customized +rectangular or ellipsoid brush. You can set its height and width using +the Size spin boxes. The link icon controls whether +the height and width are forced to be the same or not. If a connected link +picture is shown, changing one value will automatically change the other one +as well. A disconnected link indicates that both values can be set +independently. The fuzziness of the brush can be set with the +Fade spin boxes. Again, horizontal and vertical values can +be allowed to differ or not, depending on the state of the link button. + + + +The Brush Shapes palette with the Custom Brush tab + + + + + +The Brush Shapes palette with the Custom Brush tab + +The Brush Shapes palette with the Custom Brush +tab + + + + +The Custom Brush tab of this palette lets you +use the current image as a brush. With the Add to +Predefined Brushes button, you can save it for later use. + + + + +Gradients + + + +The Gradients palette + + + + + +The Gradients palette + +The Gradients palette + + + + +In the Gradients palette, you can choose a gradient +to paint with using the Gradient tool. Clicking once on a gradient in the +palette will show a larger preview. Click it again to make it the current +gradient. +You can create your own gradients with the Custom +Gradient button. + + + + +Patterns + + + +The Patterns palette + + + + + +The Patterns palette + +The Patterns palette + + + + +The Patterns palette allows you to choose a pattern +for operations like Pattern fill. Click a pattern to see a preview at +actual size, then click it again to select it. + + + +The Patterns palette with the Custom Pattern tab selected + + + + + +The Patterns palette with the Custom Pattern tab selected + +The Patterns palette with the Custom Pattern tab selected + + + + +You can also create a custom pattern, as is shown above. + + + + +Painter's tools + +With the Painter's tools dropdown box, you can +select the tool your painting operation should simulate. For example, you can +paint with a normal brush, an airbrush, or a filter. + + + + +Pressure variation + +This setting allows you to change &chalk;'s behaviour when you use a +tablet to paint with. When you change the pressure on the tablet, you can +choose between changing the line width (size), the +opacity, and the darkness. + + + + + + diff --git a/doc/chalk/commands.docbook b/doc/chalk/commands.docbook new file mode 100644 index 00000000..cc50aa29 --- /dev/null +++ b/doc/chalk/commands.docbook @@ -0,0 +1,14 @@ + +Command Reference + + +This chapter explains &chalk;'s user interface in detail. Each of the menus, +toolbars, palettes, and dialogs will be discussed. + + +&commands-menus; +&commands-toolbars; +&commands-palettes; +&commands-dialogs; + + diff --git a/doc/chalk/createdocument.png b/doc/chalk/createdocument.png new file mode 100644 index 00000000..79047af8 Binary files /dev/null and b/doc/chalk/createdocument.png differ diff --git a/doc/chalk/credits.docbook b/doc/chalk/credits.docbook new file mode 100644 index 00000000..d6c3defc --- /dev/null +++ b/doc/chalk/credits.docbook @@ -0,0 +1,63 @@ + + +Credits and License + + +&chalk; + + +Program copyright © 1999-2006 The &chalk; Team + + + +Contributors: + + +Adrian Page +Adrian.Page@tesco.net +Andrew Richards +physajr@phys.canterbury.ac.nz +Bart Coppens kde@bartcoppens.be +Boudewijn Rempt +boud@valdyas.org (current maintainer) +Carsten Pfeiffer +pfeiffer@kde.org +Casper Boemann cbr@boemann.dk +Cyrille Berger cyb@lepi.org +Danny Allen +dannya40uk@yahoo.co.uk +Dirk Schoenberger +dirk.schoenberger@sz-online.de +Gábor Lehel +illissius@gmail.com +John Califf +jcaliff@compuzone.net +Matthias Elter elter@kde.org +Melchior Franz melchior@kde.org +Michael Koch koch@kde.org +Michael Thaler +michael.thaler@ph.tum.de +Patrick Julien +freak@codepimps.org +Roger Larsson +roger.larsson@norran.net +Sven Langkamp +longamp@reallygood.de + + + + +Documentation copyright © 2005-2006 Boudewijn Rempt +boud@valdyas.org, Sander Koning +sanderkoning@kde.nl +with contributions from Casper Boemann, Bart Coppens, Cyrille Berger, Burkhard +Lueck, and Anne-Marie Mahfouf. + + + +&underFDL; +&underGPL; + + + + diff --git a/doc/chalk/crocusses-autocontrast.png b/doc/chalk/crocusses-autocontrast.png new file mode 100644 index 00000000..3e73db57 Binary files /dev/null and b/doc/chalk/crocusses-autocontrast.png differ diff --git a/doc/chalk/crocusses-blur.png b/doc/chalk/crocusses-blur.png new file mode 100644 index 00000000..3b31dbe1 Binary files /dev/null and b/doc/chalk/crocusses-blur.png differ diff --git a/doc/chalk/crocusses-brightnesscontrast.png b/doc/chalk/crocusses-brightnesscontrast.png new file mode 100644 index 00000000..b60ad77d Binary files /dev/null and b/doc/chalk/crocusses-brightnesscontrast.png differ diff --git a/doc/chalk/crocusses-bumpmap.png b/doc/chalk/crocusses-bumpmap.png new file mode 100644 index 00000000..cd1037c1 Binary files /dev/null and b/doc/chalk/crocusses-bumpmap.png differ diff --git a/doc/chalk/crocusses-coloradjustment.png b/doc/chalk/crocusses-coloradjustment.png new file mode 100644 index 00000000..8efbc9db Binary files /dev/null and b/doc/chalk/crocusses-coloradjustment.png differ diff --git a/doc/chalk/crocusses-colortoalpha.png b/doc/chalk/crocusses-colortoalpha.png new file mode 100644 index 00000000..232aab29 Binary files /dev/null and b/doc/chalk/crocusses-colortoalpha.png differ diff --git a/doc/chalk/crocusses-colortransfer.png b/doc/chalk/crocusses-colortransfer.png new file mode 100644 index 00000000..a6abfb6a Binary files /dev/null and b/doc/chalk/crocusses-colortransfer.png differ diff --git a/doc/chalk/crocusses-customconvolution.png b/doc/chalk/crocusses-customconvolution.png new file mode 100644 index 00000000..6a1da4fc Binary files /dev/null and b/doc/chalk/crocusses-customconvolution.png differ diff --git a/doc/chalk/crocusses-desaturate.png b/doc/chalk/crocusses-desaturate.png new file mode 100644 index 00000000..e2add125 Binary files /dev/null and b/doc/chalk/crocusses-desaturate.png differ diff --git a/doc/chalk/crocusses-edgebottom.png b/doc/chalk/crocusses-edgebottom.png new file mode 100644 index 00000000..4c42077f Binary files /dev/null and b/doc/chalk/crocusses-edgebottom.png differ diff --git a/doc/chalk/crocusses-edgeleft.png b/doc/chalk/crocusses-edgeleft.png new file mode 100644 index 00000000..4b384320 Binary files /dev/null and b/doc/chalk/crocusses-edgeleft.png differ diff --git a/doc/chalk/crocusses-edgeright.png b/doc/chalk/crocusses-edgeright.png new file mode 100644 index 00000000..e2071f65 Binary files /dev/null and b/doc/chalk/crocusses-edgeright.png differ diff --git a/doc/chalk/crocusses-embossall.png b/doc/chalk/crocusses-embossall.png new file mode 100644 index 00000000..eb937422 Binary files /dev/null and b/doc/chalk/crocusses-embossall.png differ diff --git a/doc/chalk/crocusses-embosshorvert.png b/doc/chalk/crocusses-embosshorvert.png new file mode 100644 index 00000000..685e34b1 Binary files /dev/null and b/doc/chalk/crocusses-embosshorvert.png differ diff --git a/doc/chalk/crocusses-embossvariable.png b/doc/chalk/crocusses-embossvariable.png new file mode 100644 index 00000000..cfeabd1a Binary files /dev/null and b/doc/chalk/crocusses-embossvariable.png differ diff --git a/doc/chalk/crocusses-gaussianblur.png b/doc/chalk/crocusses-gaussianblur.png new file mode 100644 index 00000000..bf1633eb Binary files /dev/null and b/doc/chalk/crocusses-gaussianblur.png differ diff --git a/doc/chalk/crocusses-gaussiannoise.png b/doc/chalk/crocusses-gaussiannoise.png new file mode 100644 index 00000000..cc0605c5 Binary files /dev/null and b/doc/chalk/crocusses-gaussiannoise.png differ diff --git a/doc/chalk/crocusses-invert.png b/doc/chalk/crocusses-invert.png new file mode 100644 index 00000000..9f1d9eb5 Binary files /dev/null and b/doc/chalk/crocusses-invert.png differ diff --git a/doc/chalk/crocusses-lenscorrection.png b/doc/chalk/crocusses-lenscorrection.png new file mode 100644 index 00000000..7bc8087f Binary files /dev/null and b/doc/chalk/crocusses-lenscorrection.png differ diff --git a/doc/chalk/crocusses-maximizechannel.png b/doc/chalk/crocusses-maximizechannel.png new file mode 100644 index 00000000..9e6dc3f9 Binary files /dev/null and b/doc/chalk/crocusses-maximizechannel.png differ diff --git a/doc/chalk/crocusses-meanremoval.png b/doc/chalk/crocusses-meanremoval.png new file mode 100644 index 00000000..a1df0ac0 Binary files /dev/null and b/doc/chalk/crocusses-meanremoval.png differ diff --git a/doc/chalk/crocusses-minimizechannel.png b/doc/chalk/crocusses-minimizechannel.png new file mode 100644 index 00000000..14e9fe07 Binary files /dev/null and b/doc/chalk/crocusses-minimizechannel.png differ diff --git a/doc/chalk/crocusses-oilpaint.png b/doc/chalk/crocusses-oilpaint.png new file mode 100644 index 00000000..d005ef3e Binary files /dev/null and b/doc/chalk/crocusses-oilpaint.png differ diff --git a/doc/chalk/crocusses-pixelize.png b/doc/chalk/crocusses-pixelize.png new file mode 100644 index 00000000..3fb5ba60 Binary files /dev/null and b/doc/chalk/crocusses-pixelize.png differ diff --git a/doc/chalk/crocusses-raindrops.png b/doc/chalk/crocusses-raindrops.png new file mode 100644 index 00000000..bdee271c Binary files /dev/null and b/doc/chalk/crocusses-raindrops.png differ diff --git a/doc/chalk/crocusses-randomnoise.png b/doc/chalk/crocusses-randomnoise.png new file mode 100644 index 00000000..d7525a3f Binary files /dev/null and b/doc/chalk/crocusses-randomnoise.png differ diff --git a/doc/chalk/crocusses-randompick.png b/doc/chalk/crocusses-randompick.png new file mode 100644 index 00000000..d3fb496d Binary files /dev/null and b/doc/chalk/crocusses-randompick.png differ diff --git a/doc/chalk/crocusses-roundcorners.png b/doc/chalk/crocusses-roundcorners.png new file mode 100644 index 00000000..d997aca7 Binary files /dev/null and b/doc/chalk/crocusses-roundcorners.png differ diff --git a/doc/chalk/crocusses-sharpen.png b/doc/chalk/crocusses-sharpen.png new file mode 100644 index 00000000..18998da9 Binary files /dev/null and b/doc/chalk/crocusses-sharpen.png differ diff --git a/doc/chalk/crocusses-smalltiles.png b/doc/chalk/crocusses-smalltiles.png new file mode 100644 index 00000000..0dcd880d Binary files /dev/null and b/doc/chalk/crocusses-smalltiles.png differ diff --git a/doc/chalk/crocusses-sobel.png b/doc/chalk/crocusses-sobel.png new file mode 100644 index 00000000..90506e6a Binary files /dev/null and b/doc/chalk/crocusses-sobel.png differ diff --git a/doc/chalk/crocusses-topedge.png b/doc/chalk/crocusses-topedge.png new file mode 100644 index 00000000..e52c0878 Binary files /dev/null and b/doc/chalk/crocusses-topedge.png differ diff --git a/doc/chalk/crocusses-unsharpmask.png b/doc/chalk/crocusses-unsharpmask.png new file mode 100644 index 00000000..7760cb74 Binary files /dev/null and b/doc/chalk/crocusses-unsharpmask.png differ diff --git a/doc/chalk/crocusses-wave.png b/doc/chalk/crocusses-wave.png new file mode 100644 index 00000000..053cd4e6 Binary files /dev/null and b/doc/chalk/crocusses-wave.png differ diff --git a/doc/chalk/crocusses-waveletnoise.png b/doc/chalk/crocusses-waveletnoise.png new file mode 100644 index 00000000..4088373d Binary files /dev/null and b/doc/chalk/crocusses-waveletnoise.png differ diff --git a/doc/chalk/crocusses.png b/doc/chalk/crocusses.png new file mode 100644 index 00000000..9b8913c3 Binary files /dev/null and b/doc/chalk/crocusses.png differ diff --git a/doc/chalk/developers-plugins.docbook b/doc/chalk/developers-plugins.docbook new file mode 100644 index 00000000..81a4ef49 --- /dev/null +++ b/doc/chalk/developers-plugins.docbook @@ -0,0 +1,1553 @@ + +Developing &chalk; Plugins + + +Introduction + + +&chalk; is infinitely extensible with plugins. Tools, filters, large +chunks of the user interface and even colorspaces are plugins. In fact, +&chalk; recognizes these six types of plugins: + + + +colorspaces — these define the channels that constitute +a single pixel +tools — anything that is done with a mouse or tablet +input device +paint operations — pluggable painting effects for +tools +image filters — change all pixels, or just the selected +pixels in a layer +viewplugins — extend Chalk’s user interface with new +dialog boxes, palettes and operations +import/export filters — read and write all kinds of +image formats + + + +&chalk; itself consists of three layered libraries and a directory with some +common support classes: chalkcolor, chalkimage and chalkui. Within +&chalk;, objects can by identified by a KisID, that is +the combination of a unique untranslated string (used when saving, for +instance) and a translated string for GUI purposes. + +A word on compatibility: &chalk; is still in development. From &chalk; 1.5 to +1.6 not many API changes are expected, but there may be some. From &chalk; 1.6 +to 2.0 we will move from &Qt;3 to &Qt;4, from &kde;3 to &kde;4, from +automake to cmake: many changes are to +be expected. If you develop a plugin for &chalk; and choose to do so in +&chalk;’s subversion repository, chances are excellent that we’ll help you +porting. These changes may also render parts of this document out of date. +Always check with the latest API documentation or the header files installed +on your system. + + + +ChalkColor + + +The first library is chalkcolor. This library loads the colorspace plugins. + +A colorspace plugin should implement the KisColorSpace +abstract class or, if the basic capabilities of the new colorspace will be +implemented by lcms (), extend KisAbstractColorSpace. The chalkcolor +library could be used from other applications and does not depend on +&koffice;. + + + + +ChalkImage + + +The libchalkimage library loads the filter and paintop plugins and is +responsible for working with image data: changing pixels, compositing and +painting. Brushes, palettes, gradients and patterns are also loaded by +libchalkimage. It is our stated goal to make libchalkimage independent of +&koffice;, but we currently share the gradient loading code with &koffice;. + +It is not easy at the moment to add new types of resources such as brushes, +palettes, gradients or patterns to &chalk;. (Adding new brushes, palettes, +gradients and patterns is easy, of course.) &chalk; follows the guidelines of +the Create project () for these. +Adding support for Photoshop's brush file format needs libchalkimage hacking; +adding more gimp brush data files not. + +ChalkImage loads the following types of plugins: + + + +&chalk; filters must extend and implement the abstract class +KisFilter, +KisFilterConfiguration and possibly +KisFilterConfigurationWidget. +An example of a filter is Unsharp Mask. +Paint operations or paintops are the set of operations +painting tools suchs as freehand or circle have access to. Examples of +paintops are pen, airbrush or eraser. Paintops should extend the +KisPaintop base class. Examples of new paintops could +be a chalk brush, an oilpaint brush or a complex programmable +brush. + + + + + +ChalkUI + + +The libchalkui library loads the tool and viewplugins. This library is a +&koffice; Part, but also contains a number of widgets that are useful for +graphics applications. Maybe we will have to split this library in chalkpart +and chalkui in the 2.0 release. For now, script writers are not given access +to this library and plugin writers are only allowed to use this library when +writing tools or viewplugins. ChalkUI loads the +following types of plugins: + + + +Tools are derived from KisTool or one +of the specialized tool base classes such as +KisToolPaint, KisToolNonPaint or +KisToolFreehand. A new tool could be a foreground +object selection tool. Painting tools (and that includes tools that paint on +the selection) can use any paintop to determine the way pixels are +changed. +Viewplugins are ordinary KParts that use +kxmlgui to insinuate themselves into &chalk;'s user +interface. Menu options, dialogs, toolbars — any kind of user interface +extension can be a viewplugin. In fact, important functionality like &chalk;'s +scripting support is written as a viewplugin. + + + + + +Import/Export filters + + +Import/Export filters are &koffice; filters, subclasses of +KoFilter. Filters read and write image data in any of +the myriad image formats in existence. And example of a new &chalk; +import/export filter could be a PDF filter. Filters are loaded by the +&koffice; libraries. + + + + + + + +Creating plugins + + +Plugins are written in C++ and can use all of &kde; and &Qt; and the &chalk; +developer API. Only viewplugins should use the &koffice; API. Don’t worry: +&chalk;’s API’s are quite clear and rather extensively documented (for free +software) and coding your first filter is really easy. + +If you do not want to use C++, you can write scripts in Python or Ruby; that +is a different thing altogether, though, and you cannot currently write tools, +colorspaces, paintops or import/export filters as scripts. + +&chalk; plugins use &kde;'s parts mechanism for loading, so the parts +documentation at is relevant here, too. + +Your distribution should have either installed the relevant header files with +&chalk; itself, or might have split the header files into either a &koffice; +dev or a &chalk; dev package. You can find the API documentation for &chalk;'s +public API at . + + + +Automake (and CMake) + + +&kde; 3.x and thus &koffice; 1.5 and 1.6 use automake; +&kde; 4.0 and &koffice; 2.0 use cmake. This tutorial +describes the automake way of creating plugins. + + +Plugins are &kde; modules and should be tagged as such in their +Makefile.am. Filters, tools, paintops, colorspaces and +import/export filters need .desktop files; +viewplugins need a KXMLGui +pluginname.rc file in addition. The easiest way to get +started is to checkout the chalk-plugins project from the &koffice; Subversion +repository and use it as the basis for your own project. We intend to prepare +a skeleton &chalk; plugin pack for KDevelop, but haven’t had the time to do +so yet. + + + +<filename>Makefile.am</filename> + + +Let's look at the skeleton for a plugin module. First, the +Makefile.am. This is what &kde; uses to generate the +makefile that builds your plugin: + + +kde_services_DATA = chalkLIBRARYNAME.desktop + +INCLUDES = $(all_includes) + +chalkLIBRARYNAME_la_SOURCES = sourcefile1.cc sourcefile2.cc + +kde_module_LTLIBRARIES = chalkLIBRARYNAME.la +noinst_HEADERS = header1.h header2.h + +chalkLIBRARYNAME_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkLIBRARY_la_LIBADD = -lchalkcommon + +chalkextensioncolorsfilters_la_METASOURCES = AUTO + + +This is the makefile for a filter plugin. Replace +LIBRARYNAME with the name of your work, and you are +set. + +If your plugin is a viewplugin, you will likely also install a .rc file with entries for menubars and toolbars. +Likewise, you may need to install cursors and icons. That is all done through +the ordinary &kde; Makefile.am magic incantantions: + + +chalkrcdir = $(kde_datadir)/chalk/chalkplugins +chalkrc_DATA = LIBRARYNAME.rc +EXTRA_DIST = $(chalkrc_DATA) + +chalkpics_DATA = \ + bla.png \ + bla_cursor.png +chalkpicsdir = $(kde_datadir)/chalk/pics + + + + + + +Desktop files + + +The .desktop file announces the type of plugin: + + +[Desktop Entry] +Encoding=UTF-8 +Icon= +Name=User-visible Name +ServiceTypes=Chalk/Filter +Type=Service +X-KDE-Library=chalkLIBRARYNAME +X-KDE-Version=2 + + +Possible ServiceTypes are: + + + +Chalk/Filter +Chalk/Paintop +Chalk/ViewPlugin +Chalk/Tool +Chalk/ColorSpace + + + +File import and export filters use the generic &koffice; filter framework and +need to be discussed separately. + + + + +Boilerplate + + +You also need a bit of boilerplate code that is called by the &kde; part +framework to instantiate the plugin — a header file and an implementation file. + +A header file: + +#ifndef TOOL_STAR_H_ +#define TOOL_STAR_H_ + +#include <kparts/plugin.h> + +/** +* A module that provides a star tool. +*/ +class ToolStar : public KParts::Plugin +{ + Q_OBJECT +public: + ToolStar(QObject *parent, const char *name, const QStringList &); + virtual ~ToolStar(); + +}; + +#endif // TOOL_STAR_H_ + + + + +And an implementation file: + +#include <kinstance.h> +#include <kgenericfactory.h> + +#include <kis_tool_registry.h> + +#include "tool_star.h" +#include "kis_tool_star.h" + + +typedef KGenericFactory<ToolStar> ToolStarFactory; +K_EXPORT_COMPONENT_FACTORY( chalktoolstar, ToolStarFactory( "chalk" ) ) + + +ToolStar::ToolStar(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + setInstance(ToolStarFactory::instance()); + if ( parent->inherits("KisToolRegistry") ) + { + KisToolRegistry * r = dynamic_cast<KisToolRegistry*>( parent ); + r -> add(new KisToolStarFactory()); + } + +} + +ToolStar::~ToolStar() +{ +} + +#include "tool_star.moc" + + + + + +Registries + + +Tools are loaded by the tool registry and register themselves with the tool +registry. Plugins like tools, filters and paintops are loaded only once: view +plugins are loaded for every view that is created. Note that we register +factories, generally speaking. For instance, with tools a new instance of a +tool is created for every pointer (mouse, stylus, eraser) for every few. And a +new paintop is created whenever a tool gets a mouse-down event. + + + +Filters call the filter registry: + + if (parent->inherits("KisFilterRegistry")) { + KisFilterRegistry * manager = dynamic_cast<KisFilterRegistry *>(parent); + manager->add(new KisFilterInvert()); + } + + +Paintops the paintop registry: + + if ( parent->inherits("KisPaintOpRegistry") ) { + KisPaintOpRegistry * r = dynamic_cast<KisPaintOpRegistry*>(parent); + r -> add ( new KisSmearyOpFactory ); + } + + +Colorspaces the colorspace registry (with some complications): + + if ( parent->inherits("KisColorSpaceFactoryRegistry") ) { + KisColorSpaceFactoryRegistry * f = dynamic_cast<isColorSpaceFactoryRegistry*>(parent); + + KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile()); + f->addProfile(defProfile); + + KisColorSpaceFactory * csFactory = new KisRgbColorSpaceFactory(); + f->add(csFactory); + + KisColorSpace * colorSpaceRGBA = new KisRgbColorSpace(f, 0); + KisHistogramProducerFactoryRegistry::instance() -> add( + new KisBasicHistogramProducerFactory<KisBasicU8HistogramProducer> + (KisID("RGB8HISTO", i18n("RGB8 Histogram")), colorSpaceRGBA) ); + } + + +View plugins do not have to register themselves, and they get access to a +KisView object: + + if ( parent->inherits("KisView") ) + { + setInstance(ShearImageFactory::instance()); + setXMLFile(locate("data","chalkplugins/shearimage.rc"), true); + + (void) new KAction(i18n("&Shear Image..."), 0, 0, this, SLOT(slotShearImage()), actionCollection(), "shearimage"); + (void) new KAction(i18n("&Shear Layer..."), 0, 0, this, SLOT(slotShearLayer()), actionCollection(), "shearlayer"); + + m_view = (KisView*) parent; + } + + +Remember that this means that a view plugin will be created for every view the +user creates: splitting a view means loading all view plugins again. + + + + +Plugin versioning + + +&chalk; 1.5 loads plugins with X-KDE-Version=2 set in the +.desktop file. &chalk; 1.6 plugins will +probably be binary incompatible with 1.5 plugins and will need the version +number 3. &chalk; 2.0 plugins will need the version number 3. Yes, this is not +entirely logical. + + + + + + + +Colorspaces + + +Colorspaces implement the KisColorSpace pure virtual +class. There are two types of colorspaces: those that can use +lcms for transformations between colorspaces, and those +that are too weird for lcms to handle. Examples of the +first are cmyk, rgb, yuv. An example of the latter is watercolor or wet & +sticky. Colorspaces that use lcms can be derived from +KisAbstractColorSpace, or of one of the base classes +that are specialized for a certain number of bits per channel. + +Implementing a colorspace is pretty easy. The general principle is that +colorspaces work on a simple array of bytes. The interpretation of these bytes +is up to the colorspace. For instance, a pixel in 16-bit GrayA consists of +four bytes: two bytes for the gray value and two bytes for the alpha value. +You are free to use a struct to work with the memory layout of a pixel in your +colorspace implementation, but that representation is not exported. The only +way the rest of &chalk; can know what channels and types of channels your +colorspace pixels consist of is through the +KisChannelInfo class. + +Filters and paintops make use of the rich set of methods offered by +KisColorSpace to do their work. In many cases, the +default implementation in KisAbstractColorSpace will +work, but more slowly than a custom implementation in your own colorspace +because KisAbstractColorSpace will convert all pixels +to 16-bit L*a*b and back. + + + +<classname>KisChannelInfo</classname> + + +(http://websvn.kde.org/trunk/koffice/chalk/chalkcolor/kis_channelinfo.h) + + +This class defines the channels that make up a single pixel in a particular +colorspace. A channel has the following important characteristics: + + +a name for display in the user interface +a position: the byte where the bytes representing this channel +start in the pixel. +a type: color, alpha, substance or substrate. Color is plain +color, alpha is see-throughishness, substance is a representation of amount of +pigment or things like that, substrate is the representation of the canvas. +(Note that this may be refactored at the drop of a hat.) +a valuetype: byte, short, integer, float — or +other. +size: the number of bytes this channel takes +color: a QColor representation of this +channel for user interface visualization, for instance in +histograms. +an abbreviaton for use in the GUI when there’s not much +space + + + + +<classname>KisCompositeOp</classname> + + +As per original Porter-Duff, there are many ways of combining pixels to get a +new color. The KisCompositeOp class defines most of +them: this set is not easily extensible except by hacking the chalkcolor +library. + +A colorspace plugin can support any subset of these possible composition +operations, but the set must always include "OVER" (same as "NORMAL") and +"COPY". The rest are more or less optional, although more is better, of +course. + + + + +<classname>KisColorSpace</classname> + + +The methods in the KisColorSpace pure virtual classs +can be divided into a number of groups: conversion, identification and +manipulation. + +All classes must be able to convert a pixel from and to 8 bit RGB (i.e., a +QColor), and preferably also to and from 16 bit L*a*b. +Additionally, there is a method to convert to any colorspace from the current +colorspace. + +Colorspaces are described by the KisChannelInfo vector, +number of channels, number of bytes in a single pixel, whether it supports +High Dynamic Range images and more. + +Manipulation is for instance the combining of two pixels in a new +pixel: bitBlt, darkening or convolving of pixels. + +Please consult the API documentation for a full description of all methods you +need to implement in a colorspace. + +KisAbstractColorSpace implements many of the virtual +methods of KisColorSpace using functions from the +lcms library. On top of +KisAbstractColorSpace there are base colorspace classes +for 8 and 16 bit integer and 16 and 32 bit float colorspaces that define +common operations to move between bit depths. + + + + + + +Filters + + +Filters are plugins that examine the pixels in a layer and them make changes +to them. Although &chalk; uses an efficient tiled memory backend to store +pixels, filter writers do not have to bother with that. When writing a filter +plugin for the &Java; imaging API, Photoshop or The Gimp, you need to take care +of tile edges and cobble tiles together: &chalk; hides that +implementation detail. + +Note that it is theoretically easy to replace the current tile +image data storage backend with another backend, but that backens are not true +plugins at the moment, for performance reasons. + +&chalk; uses iterators to read and write pixel values. Alternatively, you can +read a block of pixels into a memory buffer, mess with it and then write it +back as a block. But that is not necessarily more efficient, it may even be +slower than using the iterators; it may just be more convenient. See the API +documentation. + +&chalk; images are composed of layers, of which there are currently four +kinds: paint layers, group layers, adjustment layers (that contain a filter +that is applied dynamically to layers below the adjustment layer) and part +layers. Filters always operate on paint layers. Paint layers contain paint +devices, of the class KisPaintDevice. A paint device in +its turn gives access to the actual pixels. + +PaintDevices are generally passed around wrapped in +shared pointers. A shared pointer keeps track of in how many places the paint +device is currently used and deletes the paint device when it is no longer +used anywhere. You recognize the shared pointer version of a paint device +through its SP suffix. Just remember that you never have to +explicitly delete a KisPaintDeviceSP. + +Let's examine a very simple filter, one that inverts every pixel. The code for +this filter is in the koffice/chalk/plugins/filters/example directory. +The main method is + +KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, + KisFilterConfiguration* /*config*/, const QRect& rect). + +The function gets passed two paint devices, a configuration object (which is +not used in this simple filter) and a rect. The +rect describes the area of the +paint device which the filter should act on. This area is described by +integers, which means no sub-pixel accuracy. + +The src paint device is for reading from, the +dst paint device for writing to. These parameters may point +to the same actual paint device, or be two different paint devices. (Note: +this may change to only one paint device in the future.) + +Now, let's look at the code line by line: + + +void KisFilterInvert::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, + KisFilterConfiguration* /*config*/, const QRect& rect) +{ + Q_ASSERT(src != 0); + Q_ASSERT(dst != 0); + + KisRectIteratorPixel srcIt = src->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), false); + KisRectIteratorPixel dstIt = dst->createRectIterator(rect.x(), rect.y(), rect.width(), rect.height(), true ); + + int pixelsProcessed = 0; + setProgressTotalSteps(rect.width() * rect.height()); + + KisColorSpace * cs = src->colorSpace(); + Q_INT32 psize = cs->pixelSize(); + + while( ! srcIt.isDone() ) + { + if(srcIt.isSelected()) + { + memcpy(dstIt.rawData(), srcIt.oldRawData(), psize); + + cs->invertColor( dstIt.rawData(), 1); + } + setProgress(++pixelsProcessed); + ++srcIt; + ++dstIt; + } + setProgressDone(); // Must be called even if you don't really support progression +} + + + + +This creates an iterator to read the existing pixels. Chalk has three +types of iterators: horizontal, vertical and rectangular. The rect iterator +takes the most efficient path through the image data, but does not guarantee +anything about the location of the next pixel it returns. That means that you +cannot be sure that the pixel you will retrieve next will be adjacent to the +pixel you just got. The horizontal and vertical line iterators do guarantee +the location of the pixels they return. + + +(2) We create the destination iterator with the write +setting to true. This means that if the destination paint +device is smaller than the rect we write, it will automatically be enlarged to +fit every pixel we iterate over. Note that we have got a potential bug here: +if dst and src are not the same device, +then it is quite possible that the pixels returned by the iterators do not +correspond. For every position in the iterator, src may be, +for example, at 165,200, while dst could be at 20,8 — +and therefore the copy we perform below may distort the image... + + +Want to know if a pixel is selected? That is easy — use the +isSelected method. But selectedness is not a binary +property of a pixel, a pixel can be half selected, barely selected or almost +completely selected. That value you can also got from the iterator. Selections +are actually a mask paint device with a range between 0 and 255, where 0 is +completely unselected and 255 completely selected. The iterator has two +methods: isSelected() and +selectedNess(). The first returns true if a pixel is +selected to any extent (i.e., the mask value is greater than 1), the other +returns the maskvalue. + + +As noted above, this memcpy is a big bad bug... +rawData() returns the array of bytes which is the +current state of the pixel; oldRawData() returns the +array of bytes as it was before we created the iterator. However, we may be +copying the wrong pixel here. In actual practice, that will not happen too +often, unless dst already exists and is not aligned with +src. + + +But this is correct: instead of figuring out which byte represents which +channel, we use a function supplied by all colorspaces to invert the current +pixel. The colorspaces have a lot of pixel operations you can make use of. + + + + +This is not all there is to creating a filter. Filters have two other +important components: a configuration object and a configuration widget. The +two interact closely. The configuration widget creates a configuration object, +but can also be filled from a pre-existing configuration object. Configuration +objects can represtent themselves as XML and can be created from XML. That is +what makes adjustment layers possible. + + + +Iterators + + +There are three types of iterators: + + + +Horizontal lines +Vertical lines +Rectangular iterors + + + +The horizontal and vertical line iterators have a method to move the iterator +to the next row or column: nextRow() and +nextCol(). Using these is much faster than creating a +new iterator for every line or column. + +Iterators are thread-safe in &chalk;, so it is possible to divide the work +over multiple threads. However, future versions of &chalk; will use the +supportsThreading() method to determine whether your +filter can be applied to chunks of the image (&ie;, all pixels modified +independently, instead of changed by some value determined from an examination +of all pixels in the image) and automatically thread the execution your +filter. + + + + +<classname>KisFilterConfiguration</classname> + + +KisFilterConfiguration is a structure that is used to +save filter settings to disk, for instance for adjustment layers. The +scripting plugin uses the property map that’s at the back of +KisFilterConfigaration to make it possible to script +filters. Filters can provide a custom widget that &chalk; will show in the +filters gallery, the filter preview dialog or the tool option tab of the +paint-with-filters tool. + + +An example, taken from the oilpaint effect filter: + + +class KisOilPaintFilterConfiguration : public KisFilterConfiguration +{ + +public: + + KisOilPaintFilterConfiguration(Q_UINT32 brushSize, Q_UINT32 smooth) + : KisFilterConfiguration( "oilpaint", 1 ) + { + setProperty("brushSize", brushSize); + setProperty("smooth", smooth); + }; +public: + + inline Q_UINT32 brushSize() { return getInt("brushSize"); }; + inline Q_UINT32 smooth() {return getInt("smooth"); }; + +}; + + + + +<classname>KisFilterConfigurationWidget</classname> + + +Most filters can be tweaked by the user. You can create a configuration widget +that Chalk will use where-ever your filter is used. An example: + + + + +The Oilpaint dialog + + + + + +The Oilpaint dialog + +The Oilpaint dialog + + + + + +Note that only the left-hand side of this dialog is your responsibility: +&chalk; takes care of the rest. There are three ways of going about creating +an option widget: + + + +Use &Qt; Designer to create a widget base, and subclass it for +your filter +Use one of the simple widgets that show a number of sliders +for lists of integers, doubles or bools. These are useful if, like the above +screenshot, your filter can be configured by a number of integers, doubles or +bools. See the API dox for KisMultiIntegerFilterWidget, +KisMultiDoubleFilterWidget and +KisMultiBoolFilterWidget. +Hand-code a widget. This is not recommended, and if you do so +and want your filter to become part of &chalk;’s official release, then I’ll ask +you to replate your hand-coded widget with a &Qt; Designer +widget. + + + +The oilpaint filter uses the multi integer widget: + + + +KisFilterConfigWidget * KisOilPaintFilter::createConfigurationWidget(QWidget* parent, KisPaintDeviceSP /*dev*/) +{ + vKisIntegerWidgetParam param; + param.push_back( KisIntegerWidgetParam( 1, 5, 1, i18n("Brush size"), "brushSize" ) ); + param.push_back( KisIntegerWidgetParam( 10, 255, 30, i18n("Smooth"), "smooth" ) ); + return new KisMultiIntegerFilterWidget(parent, id().id().ascii(), id().id().ascii(), param ); +} + +KisFilterConfiguration* KisOilPaintFilter::configuration(QWidget* nwidget) +{ + KisMultiIntegerFilterWidget* widget = (KisMultiIntegerFilterWidget*) nwidget; + if( widget == 0 ) + { + return new KisOilPaintFilterConfiguration( 1, 30); + } else { + return new KisOilPaintFilterConfiguration( widget->valueAt( 0 ), widget->valueAt( 1 ) ); + } +} + +std::list<KisFilterConfiguration*> KisOilPaintFilter::listOfExamplesConfiguration(KisPaintDeviceSP ) +{ + std::list<KisFilterConfiguration*> list; + list.insert(list.begin(), new KisOilPaintFilterConfiguration( 1, 30)); + return list; +} + + + +You can see how it works: fill a vector with your integer parameters and +create the widget. The configuration() method +inspects the widget and creates the right filter configuration object, in this +case, of course, KisOilPaintFilterConfiguration. The +listOfExamplesConfiguration method (which should be +renamed to correct English...) returns a list with example configuration +objects for the filters gallery dialog. + + + + +Filters conclusion + + +There’s more to coding interesting filters, of course, but with this +explanation, the API documentation and access to our source code, you should +be able to get started. Don’t hesitate to contact the &chalk; developers on +IRC or on the mailing list. + + + + + + +Tools + + +Tools appear in &chalk;’s toolbox. This means that there is limited space for +new tools — think carefully whether a paint operation isn’t enough for +your purposes. Tools can use the mouse/tablet and keyboard in complex ways, +which paint operations cannot. This is the reason that Duplicate is a tool, +but airbrush a paint operation. + +Be careful with static data in your tool: a new instance of your tool is +created for every input device: mouse, stylus, eraser, airbrush — whatever. +Tools come divided into logical groups: + + +shape drawing tools (circle, rect) +freehand drawing tools (brush) +transform tools that mess up the geometry of a +layer +fill tools (like bucket fill or gradient) +view tools (that don’t change pixels, but alter the way you +view the canvas, such as zoom) +select tools (that change the selection +mask) + + + +The tool interface is described in the API documentation for +KisTool. There are three subclasses: +KisToolPaint, KisToolNonPaint +and KisToolShape (which is actually a subclass of +KisToolPaint) that specialize +KisTool for painting tasks (i.e., changing pixels) , +non-painting tasks and shape painting tasks. + +A tool has an option widget, just like filters. Currently, the option widgets +are shown in a tab in a dock window. We may change that to a strip under the +main menu (which then replaces the toolbar) for &chalk; 2.0, but for now, +design your option widget to fit in a tab. As always, it’s best to use &Qt; +Designer for the design of the option widget. + +A good example of a tool is the star tool: + + + +kis_tool_star.cc Makefile.am tool_star_cursor.png wdg_tool_star.ui +kis_tool_star.h Makefile.in tool_star.h +chalktoolstar.desktop tool_star.cc tool_star.png + + + +As you see, you need two images: one for the cursor and one for the toolbox. +tool_star.cc is just the plugin loader, similar to what +we have seen above. The real meat is in the implementation: + + + +KisToolStar::KisToolStar() + : KisToolShape(i18n("Star")), + m_dragging (false), + m_currentImage (0) +{ + setName("tool_star"); + setCursor(KisCursor::load("tool_star_cursor.png", 6, 6)); + m_innerOuterRatio=40; + m_vertices=5; +} + + + +The constructor sets the internal name — which is not translated +— and the call to the superclass sets the visible name. We also load the +cursor image and set a number of variables. + + + +void KisToolStar::update (KisCanvasSubject *subject) +{ + KisToolShape::update (subject); + if (m_subject) + m_currentImage = m_subject->currentImg(); +} + + + +The update() method is called when the tool is +selected. This is not a KisTool method, but a +KisCanvasObserver method. Canvas observers are notified +whenever something changes in the view, which can be useful for tools. + +The following methods (buttonPress, +move and buttonRelease) are +called by &chalk; when the input device (mouse, stylus, eraser etc.) is +pressed down, moved or released. Note that you also get move events if the +mouse button isn’t pressed. The events are not the regular &Qt; events, but +synthetic &chalk; events because we make use of low-level trickery to get +enough events to draw a smooth line. By default, toolkits like &Qt; (and GTK) +drop events if they are too busy to handle them, and we want them all. + + + +void KisToolStar::buttonPress(KisButtonPressEvent *event) +{ + if (m_currentImage && event->button() == LeftButton) { + m_dragging = true; + m_dragStart = event->pos(); + m_dragEnd = event->pos(); + m_vertices = m_optWidget->verticesSpinBox->value(); + m_innerOuterRatio = m_optWidget->ratioSpinBox->value(); + } +} + +void KisToolStar::move(KisMoveEvent *event) +{ + if (m_dragging) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + // move (alt) or resize star + if (event->state() & Qt::AltButton) { + KisPoint trans = event->pos() - m_dragEnd; + m_dragStart += trans; + m_dragEnd += trans; + } else { + m_dragEnd = event->pos(); + } + // draw new lines on canvas + draw(m_dragStart, m_dragEnd); + } +} + +void KisToolStar::buttonRelease(KisButtonReleaseEvent *event) +{ + if (!m_subject || !m_currentImage) + return; + + if (m_dragging && event->button() == LeftButton) { + // erase old lines on canvas + draw(m_dragStart, m_dragEnd); + m_dragging = false; + + if (m_dragStart == m_dragEnd) + return; + + if (!m_currentImage) + return; + + if (!m_currentImage->activeDevice()) + return; + + KisPaintDeviceSP device = m_currentImage->activeDevice ();; + KisPainter painter (device); + if (m_currentImage->undo()) painter.beginTransaction (i18n("Star")); + + painter.setPaintColor(m_subject->fgColor()); + painter.setBackgroundColor(m_subject->bgColor()); + painter.setFillStyle(fillStyle()); + painter.setBrush(m_subject->currentBrush()); + painter.setPattern(m_subject->currentPattern()); + painter.setOpacity(m_opacity); + painter.setCompositeOp(m_compositeOp); + KisPaintOp * op = + KisPaintOpRegistry::instance()->paintOp(m_subject->currentPaintop(), m_subject->currentPaintopSettings(), &painter); + painter.setPaintOp(op); // Painter takes ownership + + vKisPoint coord = starCoordinates(m_vertices, m_dragStart.x(), m_dragStart.y(), m_dragEnd.x(), m_dragEnd.y()); + + painter.paintPolygon(coord); + + device->setDirty( painter.dirtyRect() ); + notifyModified(); + + if (m_currentImage->undo()) { + m_currentImage->undoAdapter()->addCommand(painter.endTransaction()); + } + } +} + + + +The draw() method is an internal method of +KisToolStar and draws the outline of the star. We call +this from the move() method to give the user feedback +of the size and shape of their star. Note that we use the +Qt::NotROP raster operation, which means that calling +draw() a second time with the same start and end +point the previously drawn star will be deleted. + + + +void KisToolStar::draw(const KisPoint& start, const KisPoint& end ) +{ + if (!m_subject || !m_currentImage) + return; + + KisCanvasController *controller = m_subject->canvasController(); + KisCanvas *canvas = controller->kiscanvas(); + KisCanvasPainter p (canvas); + QPen pen(Qt::SolidLine); + + KisPoint startPos; + KisPoint endPos; + startPos = controller->windowToView(start); + endPos = controller->windowToView(end); + + p.setRasterOp(Qt::NotROP); + + vKisPoint points = starCoordinates(m_vertices, startPos.x(), startPos.y(), endPos.x(), endPos.y()); + + for (uint i = 0; i < points.count() - 1; i++) { + p.drawLine(points[i].floorQPoint(), points[i + 1].floorQPoint()); + } + p.drawLine(points[points.count() - 1].floorQPoint(), points[0].floorQPoint()); + + p.end (); +} + + + +The setup() method is essential: here we create the +action that will be plugged into the toolbox so users can actually select the +tool. We also assign a shortcut key. Note that there’s some hackery going on: +remember that we create an instance of the tool for every input device. This +also means that we call setup() for every input +device and that means that an action with the same name is added several times +to the action collection. However, everything seems to work, so why worry? + + + +void KisToolStar::setup(KActionCollection *collection) +{ + m_action = static_cast<KRadioAction *>(collection->action(name())); + + if (m_action == 0) { + KShortcut shortcut(Qt::Key_Plus); + shortcut.append(KShortcut(Qt::Key_F9)); + m_action = new KRadioAction(i18n("&Star"), + "tool_star", + shortcut, + this, + SLOT(activate()), + collection, + name()); + Q_CHECK_PTR(m_action); + + m_action->setToolTip(i18n("Draw a star")); + m_action->setExclusiveGroup("tools"); + m_ownAction = true; + } +} + + + +The starCoordinates() method contains some funky math +— but is not too interesting for the discussion of how to create a tool +plugins. + + + +KisPoint KisToolStar::starCoordinates(int N, double mx, double my, double x, double y) +{ + double R=0, r=0; + Q_INT32 n=0; + double angle; + + vKisPoint starCoordinatesArray(2*N); + + // the radius of the outer edges + R=sqrt((x-mx)*(x-mx)+(y-my)*(y-my)); + + // the radius of the inner edges + r=R*m_innerOuterRatio/100.0; + + // the angle + angle=-atan2((x-mx),(y-my)); + + //set outer edges + for(n=0;n<N;n++){ + starCoordinatesArray[2*n] = KisPoint(mx+R*cos(n * 2.0 * M_PI / N + angle),my+R*sin(n *2.0 * M_PI / N+angle)); + } + + //set inner edges + for(n=0;n<N;n++){ + starCoordinatesArray[2*n+1] = KisPoint(mx+r*cos((n + 0.5) * 2.0 * M_PI / N + angle),my+r*sin((n +0.5) * 2.0 * M_PI / N + angle)); + } + + return starCoordinatesArray; +} + + + +The createOptionWidget() method is called to create +the option widget that &chalk; will show in the tab. Since there is a tool per +input device per view, the state of a tool can be kept in the tool. This +method is only called once: the option widget is stored and retrieved the next +time the tool is activated. + + + +QWidget* KisToolStar::createOptionWidget(QWidget* parent) +{ + QWidget *widget = KisToolShape::createOptionWidget(parent); + + m_optWidget = new WdgToolStar(widget); + Q_CHECK_PTR(m_optWidget); + + m_optWidget->ratioSpinBox->setValue(m_innerOuterRatio); + + QGridLayout *optionLayout = new QGridLayout(widget, 1, 1); + super::addOptionWidgetLayout(optionLayout); + + optionLayout->addWidget(m_optWidget, 0, 0); + + return widget; +} + + + +Tool Conclusions + + +Tools are relatively simple plugins to create. You need to combine the +KisTool and KisCanvasObserver +interfaces in order to effectively create a tool. + + + + + + + +Paint operations + + +PaintOps are one of the more innovative types of plugins in Chalk (together +with pluggable colorspaces). A paint operation defines how tools change the +pixels they touch. Airbrush, aliased pencil or antialiased pixel brush: these +are all paint operations. But you could — with a lot of work — +create a paintop that reads Corel Painter XML brush definitions and uses those +to determine how painting is done. + +Paint operations are instantiated when a paint tool receives a +mouseDown event and are deleted when the mouseUp event is +received by a paint tool. In between, the paintop can keep track of previous +positions and other data, such as pressure levels if the user uses a tablet. + +The basic operation of a paint operation is to change pixels at the cursor +position of a paint tool. That can be done only once, or the paint op can +demand to be run at regular intervals, using a timer. The first would be +useful for a pencil-type paint op, the second, of course, for an +airbrush-type paintop. + +Paintops can have a small configuration widget which is placed in a toolbar. +Thus, paintop configuration widgets need to have a horizontal layout of +widgets that are not higher than a toolbar button. Otherwise, &chalk; will +look very funny. + +Let’s look at a simple paintop plugin, one that shows a little bit of +programmatic intelligence. First, in the header file, there’s a factory +defined. This factory creates a paintop when the active tool needs one: + + + +public: + KisSmearyOpFactory() {} + virtual ~KisSmearyOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("paintSmeary", i18n("Smeary Brush")); } + virtual bool userVisible(KisColorSpace * ) { return false; } + virtual QString pixmap() { return ""; } + +}; + + + +The factory also contains the KisID with the public and +private name for the paintop — make sure your paintop’s private name +does not clash with another paintop! — and may optionally return a +pixmap. &chalk; can then show the pixmap together with the name for visual +identifcation of your paintop. For instance, a painter’s knife paintop would +have the image of such an implement. + +The implementation of a paintop is very straightforward: + + + +KisSmearyOp::KisSmearyOp(KisPainter * painter) + : KisPaintOp(painter) +{ +} + +KisSmearyOp::~KisSmearyOp() +{ +} +void KisSmearyOp::paintAt(const KisPoint &pos, const KisPaintInformation& info) +{ + + + +The paintAt() method really is where it’s at, with +paintops. This method receives two parameters: the current position (which is +in floats, not in whole pixels) and a +KisPaintInformation object. which contains the +pressure, x and y tilt, and movement vector, and may in the future be extended +with other information. + + + + if (!m_painter->device()) return; + + KisBrush *brush = m_painter->brush(); + + + +A KisBrush is the representation of a Gimp brush file: +that is a mask, either a single mask or a series of masks. Actually, we don’t +use the brush here, except to determine the hotspot under the +cursor. + + + + Q_ASSERT(brush); + + if (!brush) return; + + if (! brush->canPaintFor(info) ) + return; + + KisPaintDeviceSP device = m_painter->device(); + KisColorSpace * colorSpace = device->colorSpace(); + KisColor kc = m_painter->paintColor(); + kc.convertTo(colorSpace); + + KisPoint hotSpot = brush->hotSpot(info); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + Q_INT32 x, y; + double xFraction, yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisPaintDeviceSP dab = new KisPaintDevice(colorSpace, "smeary dab"); + Q_CHECK_PTR(dab); + + + +We don’t change the pixels of a paint device directly: instead we create a +small paint device, a dab, and composite that onto the current paint device. + + + + m_painter->setPressure(info.pressure); + + + +As the comments say, the next bit code does some programmatic work to create +the actual dab. In this case, we draw a number of lines. When I am done with +this paintop, the length, position and thickness of the lines will be +dependent on pressure and paint load, and we’ll have create a stiff, smeary +oilpaint brush. But I haven’t had time to finish this yet. + + + + // Compute the position of the tufts. The tufts are arranged in a line + // perpendicular to the motion of the brush, i.e, the straight line between + // the current position and the previous position. + // The tufts are spread out through the pressure + + KisPoint previousPoint = info.movement.toKisPoint(); + KisVector2D brushVector(-previousPoint.y(), previousPoint.x()); + KisVector2D currentPointVector = KisVector2D(pos); + brushVector.normalize(); + + KisVector2D vl, vr; + + for (int i = 0; i < (NUMBER_OF_TUFTS / 2); ++i) { + // Compute the positions on the new vector. + vl = currentPointVector + i * brushVector; + KisPoint pl = vl.toKisPoint(); + dab->setPixel(pl.roundX(), pl.roundY(), kc); + + vr = currentPointVector - i * brushVector; + KisPoint pr = vr.toKisPoint(); + dab->setPixel(pr.roundX(), pr.roundY(), kc); + } + + vr = vr - vl; + vr.normalize(); + + + +Finally we blt the dab onto the original paint device and tell the painter +that we’ve dirtied a small rectangle of the paint device. + + + + if (m_source->hasSelection()) { + m_painter->bltSelection(x - 32, y - 32, m_painter->compositeOp(), dab.data(), + m_source->selection(), m_painter->opacity(), x - 32, y -32, 64, 64); + } + else { + m_painter->bitBlt(x - 32, y - 32, m_painter->compositeOp(), dab.data(), m_painter->opacity(), x - 32, y -32, 64, 64); + } + + m_painter->addDirtyRect(QRect(x -32, y -32, 64, 64)); +} + + +KisPaintOp * KisSmearyOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisSmearyOp(painter); + Q_CHECK_PTR(op); + return op; +} + + + +That’s all: paintops are easy and fun! + + + + + +View plugins + + +View plugins are the weirdest of the bunch: a view plugin is an ordinary KPart +that can provide a bit of user interface and some functionality. For instance, +the histogram tab is a view plugin, as is the rotate dialog. + + + + + +Import/Export filters + + +&chalk; works with the ordinary &koffice; file filter architecture. There is a +tutorial, a bit old, but still useful, at: . It is probably best +to cooperate with the &chalk; team when developing file filters and do the +development in the &koffice; filter tree. Note that you can test your filters +without running &chalk; using the koconverter utility. + +Filters have two sides: importing and exporting. These are usually two +different plugins that may share some code. + +The important Makefile.am entries are: + + + +service_DATA = chalk_XXX_import.desktop chalk_XXX_export.desktop +servicedir = $(kde_servicesdir) +kdelnk_DATA = chalk_XXX.desktop +kdelnkdir = $(kde_appsdir)/Office +libchalkXXXimport_la_SOURCES = XXXimport.cpp +libchalkXXXexport_la_SOURCES = XXXexport.cpp +METASOURCES = AUTO + + + +Whether you are building an import filter or an export filter, your work always +boils down to implementing the following function: + + + +virtual KoFilter::ConversionStatus convert(const QCString& from, const QCString& to); + + + +It is the settings in the .desktop files +that determine which way a filter converts: + +Import: + + + +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-xcf-gimp +X-KDE-Weight=1 +X-KDE-Library=libchalkXXXimport +ServiceTypes=KOfficeFilter + + + +Export: + + + +X-KDE-Export=image/x-xcf-gimp +X-KDE-Import=application/x-chalk +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Weight=1 +X-KDE-Library=libchalkXXXexport + + + +And yes, the mimetype chosen for the example is a hint. Please, pretty please, +implement an xcf filter? + + + +Import + + +The big problem with import filters is of course your code to read the data on +disk. The boilerplate for calling that code is fairly simple: + + +Note: we really, really should find a way to enable &chalk; to keep +a file open and only read data on a as-needed basis, instead of copying the +entire contents to the internal paint device representation. But that would +mean datamanager backends that know about tiff files and so on, and is not +currently implemented. It would be ideal if some file filters could implement +a class provisionally named KisFileDataManager, create +an object of that instance with the current file and pass that to KisDoc. But +&chalk; handles storage per layer, not per document, so this would be a hard +refactor to do. + + +KoFilter::ConversionStatus XXXImport::convert(const QCString&, const QCString& to) +{ + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast<KisDoc*>(m_chain -> outputDocument()); + KisView * view = static_cast<KisView*>(doc -> views().getFirst()); + + QString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + if (!filename.isEmpty()) { + + KURL url(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisImageXXXConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + + + +This is supposed to be an importfilter, so +if it is not called to convert to a &chalk; image, then something is +wrong. +The filter chain already has created an +output document for us. We need to cast it to KisDocM, +because &chalk; documents need special treatment. It would not, actually, be +all that bad an idea to check whether the result of the cast is not 0, because +if it is, importing will fail. +If we call this filter from the GUI, we try +to get the view. If there is a view, the conversion code can try to update the +progressbar. +The filter has the filename for our input +file for us. +KisDoc needs to be +prepared for import. Certain settings are initialized and undo is disabled. +Otherwise you could undo the adding of layers performed by the import filter +and that is weird behaviour. +I have chosed to implement the actual +importing code in a separate class that I instantiate here. You can also put +all your code right in this method, but that would be a bit +messy. +My importer returns a statuscode that I +can then use to set the status of the import filter. &koffice; takes care of +showing error messages. +If creating the +KisImage has succeeded we set the document's current +image to our newly created image. Then we are done: return +KoFilter::OK;. + + + + + + + diff --git a/doc/chalk/developers-scripting.docbook b/doc/chalk/developers-scripting.docbook new file mode 100644 index 00000000..fec163db --- /dev/null +++ b/doc/chalk/developers-scripting.docbook @@ -0,0 +1,534 @@ + +Scripting + + +In &chalk;, you can write scripts in Ruby or Python (the availability of the +interpreters might depend on what your distributions or the administrator of +your machine did install). Here you will find a description of the scripting +API. + +Some examples are distributed with &chalk;, and you might find them in +/usr/share/apps/chalk/scripts (or +/opt/kde/share/apps/chalk/scripts). + + + +Variables in the <classname>Krosschalkcore</classname> module + + +ChalkDocument returns a +Document object +ChalkScript returns a +ScriptProgress object + + + +You can retrieve an object using the get function of the +Krosschalkcore module, in Ruby you will have to write something like that: + +doc = Krosschalkcore::get("ChalkDocument") +script = Krosschalkcore::get("ChalkScript") + + + + + + +Functions in the <classname>Krosschalkcore</classname> module + + +Function: getBrush +This function returns a Brush taken from the list of +&chalk; resources. It takes one argument: the name of the brush. +For example (in Ruby): + +Krosschalkcore::getBrush("Circle (05)") + + +Function: getFilter +This function returns a Filter taken from the list of +&chalk; resources. It takes one argument: the name of the filter. +For example (in Ruby): + +Krosschalkcore::getFilter("invert") + + +Function: getPattern +This function returns a Pattern taken from the list of +&chalk; resources. It takes one argument: the name of the pattern. +For example (in Ruby): + +Krosschalkcore::getPattern("Bricks") + + +Function: loadBrush +This function loads a Brush and then returns it. +It takes one argument: the filename of the brush. + +Function: loadPattern +This function loads a Pattern and then returns it. +It takes one argument: the filename of the pattern. + +Function: newCircleBrush +This function returns a Brush with a circular shape. It +takes at least two arguments: width and height. It can take two other +arguments: width of the shading, and height of the shading. If the shading +is not specified, no shading will be used. +For example (in Ruby): + +Krosschalkcore::newCircleBrush(10,20) # create a plain circle +Krosschalkcore::newCircleBrush(10,20,5,10) # create a gradient + + +Function: newHSVColor +This function returns a new Color with the given HSV +triplet. It takes three arguments: hue component (0 to 255), saturation +component (0 to 255), value component (0 to 255). + +For example (in Ruby): + +Krosschalkcore::newHSVColor(255,125,0) + + +Function: newImage +This function returns a new Image. It takes four arguments: +width, height, colorspace id, name of the image. And in return you get an +Image object. +For example (in Ruby): + +Krosschalkcore::newImage(10,20, "RGBA", "kikoo") + + +Function: newRectBrush +This function returns a Brush with a rectangular shape. +It takes at least two arguments: width and height. It can take two other +arguments: width of the shading and height of the shading. If the shading is +not specified, no shading will be used. +For example (in Ruby): + + Krosschalkcore::newRectBrush(10,20) # create a plain rectangle + Krosschalkcore::newRectBrush(10,20,5,10) # create a gradient + + +Function: newRGBColor +This function returns a new Color with the given RGB +triplet. It takes three arguments: red component (0 to 255), blue component (0 to +255), green component (0 to 255). +For example (in Ruby): + +Krosschalkcore::newRGBColor(255,0,0) # create a red color +Krosschalkcore::newRGBColor(255,255,255) # create a white color + + + + + +Descriptions and function lists for various objects in +<classname>Krosschalkcore</classname> + + +Object: PaintLayer + + +Function: beginPainting + +Function: convertToColorspace +Convert the image to a colorspace. This function takes one argument: the name +of the destination colorspace. +For example (in Ruby): + +image.convertToColorspace("CMYK") + + +Function: createHistogram +This function creates a Histogram for this layer. It takes two arguments: +the type of the histogram ("RGB8HISTO"), and 0 if the histogram is linear, or +1 if it is logarithmic. + +Function: createHLineIterator +Create an iterator over a layer, it will iterate on a row. This function takes three arguments: +x (start in the row), y (vertical +position of the row), width of the row. + +Function: createPainter +This function creates a Painter which will allow you to +paint on the layer. + +Function: createRectIterator +Create an iterator over a layer, it will iterate on a rectangular area. This +function takes four arguments: x, y, +width of the rectangle, height of the rectangle. + +Function: createVLineIterator +Create an iterator over a layer, it will iterate on a column. This function +takes three arguments: x (horizontal position of the +column), y (start in the column), height of the column. + +Function: endPainting +This function closes the current undo entry and adds it to the history. + +Function: fastWaveletTransformation +Returns the fast wavelet transformation of the layer. + +Function: fastWaveletUntransformation +Untransforms a fast wavelet into this layer. It takes one argument: a wavelet +object. +For example (in Ruby): + +wavelet = layer.fastWaveletTransformation() +layer.fastWaveletUntransformation(wavelet) + + +Function: getHeight +Return the height of the layer. + +Function: getWidth +Return the width of the layer. + + + +Object: Filter + + +Function: getFilterConfiguration +This function returns the FilterConfiguration +associated with this filter. + +Function: process +This function will apply the filter. It takes at least one argument: the +source layer. You can also use these four aguments: x, +y, width, height. +(x,y,width,height) +defines the rectangular area on which the filter +will be computed. If the rectangle is not defined, then the filter will be +applied on the entire source layer. +For example (in Ruby) + +doc = Krosschalkcore::get("ChalkDocument") +image = doc.getImage() +layer = image.getActivePaintLayer() +width = layer.getWidth() +height = layer.getHeight() +filter = Krosschalkcore::getFilter("invert") +filter.process(layer, layer) +filter.process(layer, layer, 10, 10, 20, 20 ) + + + +Object: FilterConfiguration + + +Function: getProperty +This function returns the value of a parameter of the associated +Filter. It takes one argument: the name of the +parameter. + +Function: setProperty +This function defines a parameter of the associated +Filter. It takes two arguments: the name of the +parameter and the value, whose type depends on the +Filter. + + + +Object: Histogram + +This class allows you to access the histogram of a +PaintLayer. +Example (in Ruby): + + doc = krosschalkcore::get("ChalkDocument") + image = doc.getImage() + layer = image.getActiveLayer() + histo = layer.createHistogram("RGB8HISTO",0) + min = layer.getMin() * 255 + max = layer.getMax() * 255 + for i in min..max + print layer.getValue(i) + print "\n" + end + + + + +Function: getChannel +Return the selected channel. + +Function: getCount +This function returns the number of pixels used by the histogram. + +Function: getHighest +This function returns the highest value of the histogram. + +Function: getLowest +This function returns the lowest value of the histogram. + +Function: getMax +This function returns the maximum bound of the histogram (values at greater +position than the maximum are null). The value is in the range 0.0 – 1.0. + +Function: getMean +This function returns the mean of the histogram. + +Function: getMin +This function returns the minimum bound of the histogram (values at smaller +position than the minimum are null). The value is in the range 0.0 – 1.0. + +Function: getNumberOfBins +Return the number of bins of this histogram. + +Function: getTotal +This function returns the sum of all values of the histogram. + +Function: getValue +Return the value of a bin of the histogram. This function takes one argument: +index, in the range [0..255]. + +Function: setChannel +Select the channel of the layer on which to get the result of the histogram. +This function takes one argument: the channel number. + + + +Object: ScriptProgress +ScriptProgress is used to manage the progress bar +of the status bar in &chalk;. +For example (in Ruby): + +script = Krosschalkcore::get("ChalkScript") +script.setProgressTotalSteps(1000) +script.setProgressStage("progressive", 0) +for i in 1..900 + script.incProgress() +end +script.setProgressStage("brutal", 1000) + + + +Function: incProgress +This function increments the progress by one step. + +Function: setProgress +This function sets the value of the progress. It takes one argument: +the value of the progress. + +Function: setProgressStage +This function sets the value of the progress and displays the text. + +Function: setProgressTotalSteps +This function set the number of steps that the script will require. It takes +one argument: the maximum value of the progress + + + +Object: Wavelet +This object holds the coefficients of a wavelet transformation of a +PaintLayer. + + +Function: getDepth +Returns the depth of the layer. + +Function: getNCoeff +Returns the value of the Nth coefficient. The function takes one argument: the +index of the coefficient. + +Function: getNumCoeffs +Returns the number of coefficients in this wavelet (= size * size * depth). + +Function: getSize +Returns the size of the wavelet (size = width = height). + +Function: getXYCoeff +Returns the value of a coefficient. The function takes two arguments: +x and y. + +Function: setNCoeff +Set the value of the Nth coefficient. The function takes two arguments: the +index of the coefficient and the new value of the coefficient. + +Function: setXYCoeff +Set the value of a coefficient. The function takes three arguments: +x, y, and the new value of the +coefficient. + + + +Object: Painter + + +Function: convolve +This function applies a convolution kernel to an image. It takes at least three arguments: +a list of kernels (all lists need to have the same size), +factor, and offset. + +The value of a pixel will be given by the following function: K * P / factor + offset, +where K is the kernel and P is the neighbourhood. + +It can take the following optional arguments: borderOp +(control how to convolve the pixels on the border of an image: 0 = use the +default color, 1 = use the pixel on the opposite side of the image, 2 = use +the border pixel, 3 = avoid border pixels), channel (1 for +color, 2 for alpha, 3 for both), x, y, +width, height. + +Function: setFillThreshold +Sets the fill threshold. It takes one argument: the threshold. + +Function: fillColor +Starts filling with a color. It takes two arguments: x and +y. + +Function: fillPattern +Starts filling with a pattern. It takes two arguments: x +and y. + +Function: paintPolyline +This function will paint a polyline. It takes two arguments: a list of x +positions, and a list of y positions. + +Function: paintLine +This function will paint a line. It takes five arguments: +x1, y1, x2, +y2, and pressure. + + +Function: paintBezierCurve +This function will paint a Bezier curve. It takes ten arguments: +x1, y1, p1, +cx1, cy1, cx2, +cx2, x2, y2, +p2, where (x1,y1) is +the start position, p1 is the pressure at the start, +(x2,y2) is the end position, +p2 is the pressure at the end. +(cx1,cy1) and +(cx2,cy2) are the positions of the +control points. + +Function: paintEllipse +This function will paint an ellipse. It takes five arguments: +x1, y1, x2, +y2, pressure, where +(x1,y1) and +(x2,y2) are the positions of the two +centers. + +Function: paintPolygon +This function will paint a polygon. It takes two arguments: a list of x +positions and a list of y positions. + +Function: paintRect +This function will paint a rectangle. It takes five arguments: +x, y, width +height, pressure. + +Function: paintAt +This function will paint at a given position. +It takes three arguments: x, y, +pressure. + +Function: setPaintColor +This function sets the paint color (also called foreground color). It takes +one argument: a Color. + +Function: setBackgroundColor +This function sets the background color. It takes one argument: a +Color. + +Function: setPattern +This function sets the pattern used for filling. It takes one argument: a +Pattern object. + +Function: setBrush +This function sets the brush used for painting. It takes one argument: a +Brush object. + +Function: setPaintOp +This function defines the paint operation. It takes one argument: the name of +the paint operation. + +Function: setDuplicateOffset +This function defines the duplicate offset. It takes two arguments: the +horizontal offset and the vertical offset. + +Function: setOpacity +This function set the opacity of the painting. It takes one argument: the +opacity, in the range 0 to 255. + +Function: setStrokeStyle +This function sets the style of the stroke. It takes one argument: 0 for none, +or 1 for brush. + +Function: setFillStyle +This function sets the fill style of the Painter. +It takes one argument: 0 for none, 1 for fill with foreground color, 2 for +fill with background color, 3 for fill with pattern. + + + +Object: Iterator +This object allows you to change pixel values one by one. +The name of some functions depends on the colorspace, for instance, if the +colorspace of the layer is RGB, you will have setR, +setG and setB, and for +CMYK: setC, setM, +setY and setK. In the documentation +below we will assume that the colorspace is called ABC, with three channels: +A, B and C. + + +Functions: setA, +setB, setC +Those functions take one argument: the new value of one of the channels of +this pixel. + +Function: setABC +Set the value of all channels. This function takes one argument: an array with +the new values for all channels. + +Functions: getA, +getB, getC +Return the value of one of the channels of this pixel. + +Function: getABC +Return an array with the values of all channels. + +Function: darken +Darken a pixel. This function takes at least one argument: +shade (amount used to darken all color channels). This +function can take the following optional argument: +compensation (to limit the darkening). + +Function: invertColor +Invert the color of a pixel. + +Function: next +Increment the position, go to the next pixel. + +Function: isDone +Return true if the iterator is at the end (no more pixels are +available). + + + + + + + +Resources + + +Here are hints or partial lists of resources for &chalk;. + +For Brush and Pattern: You can get +the name and the associated brush or pattern from the selector in &chalk;'s +toolbar. + +A list of ids for colorspaces in &chalk;: LABA, RGBA, RGBA16, RGBAF32, +RGBAF16HALF, LMSAF32, GRAYA, GRAYA16, CMYK, CMYKA16. + + + + + diff --git a/doc/chalk/developers.docbook b/doc/chalk/developers.docbook new file mode 100644 index 00000000..212bb9fa --- /dev/null +++ b/doc/chalk/developers.docbook @@ -0,0 +1,13 @@ + +Developer's information + + +This chapter contains information for developers or other enthousiasts who +want to get more out of &chalk;. + + +&developers-scripting; +&developers-plugins; + + + diff --git a/doc/chalk/dialogs-addpalette.png b/doc/chalk/dialogs-addpalette.png new file mode 100644 index 00000000..6f249d96 Binary files /dev/null and b/doc/chalk/dialogs-addpalette.png differ diff --git a/doc/chalk/dialogs-blur.png b/doc/chalk/dialogs-blur.png new file mode 100644 index 00000000..3318d844 Binary files /dev/null and b/doc/chalk/dialogs-blur.png differ diff --git a/doc/chalk/dialogs-brightnesscontrast.png b/doc/chalk/dialogs-brightnesscontrast.png new file mode 100644 index 00000000..39d8c652 Binary files /dev/null and b/doc/chalk/dialogs-brightnesscontrast.png differ diff --git a/doc/chalk/dialogs-bumpmap.png b/doc/chalk/dialogs-bumpmap.png new file mode 100644 index 00000000..5c20347f Binary files /dev/null and b/doc/chalk/dialogs-bumpmap.png differ diff --git a/doc/chalk/dialogs-coloradjustment.png b/doc/chalk/dialogs-coloradjustment.png new file mode 100644 index 00000000..b18a8023 Binary files /dev/null and b/doc/chalk/dialogs-coloradjustment.png differ diff --git a/doc/chalk/dialogs-colorrange.png b/doc/chalk/dialogs-colorrange.png new file mode 100644 index 00000000..6f11b374 Binary files /dev/null and b/doc/chalk/dialogs-colorrange.png differ diff --git a/doc/chalk/dialogs-colortoalpha.png b/doc/chalk/dialogs-colortoalpha.png new file mode 100644 index 00000000..bc99c3e8 Binary files /dev/null and b/doc/chalk/dialogs-colortoalpha.png differ diff --git a/doc/chalk/dialogs-colortransfer.png b/doc/chalk/dialogs-colortransfer.png new file mode 100644 index 00000000..00d86095 Binary files /dev/null and b/doc/chalk/dialogs-colortransfer.png differ diff --git a/doc/chalk/dialogs-convertimagetype.png b/doc/chalk/dialogs-convertimagetype.png new file mode 100644 index 00000000..3df33c65 Binary files /dev/null and b/doc/chalk/dialogs-convertimagetype.png differ diff --git a/doc/chalk/dialogs-convertlayertype.png b/doc/chalk/dialogs-convertlayertype.png new file mode 100644 index 00000000..85f6977c Binary files /dev/null and b/doc/chalk/dialogs-convertlayertype.png differ diff --git a/doc/chalk/dialogs-cubism.png b/doc/chalk/dialogs-cubism.png new file mode 100644 index 00000000..b2e3b741 Binary files /dev/null and b/doc/chalk/dialogs-cubism.png differ diff --git a/doc/chalk/dialogs-customconvolution.png b/doc/chalk/dialogs-customconvolution.png new file mode 100644 index 00000000..ee15631b Binary files /dev/null and b/doc/chalk/dialogs-customconvolution.png differ diff --git a/doc/chalk/dialogs-documentinformation.png b/doc/chalk/dialogs-documentinformation.png new file mode 100644 index 00000000..2462853f Binary files /dev/null and b/doc/chalk/dialogs-documentinformation.png differ diff --git a/doc/chalk/dialogs-dropshadow.png b/doc/chalk/dialogs-dropshadow.png new file mode 100644 index 00000000..c2e0b15f Binary files /dev/null and b/doc/chalk/dialogs-dropshadow.png differ diff --git a/doc/chalk/dialogs-emboss.png b/doc/chalk/dialogs-emboss.png new file mode 100644 index 00000000..552d4676 Binary files /dev/null and b/doc/chalk/dialogs-emboss.png differ diff --git a/doc/chalk/dialogs-filtersgallery.png b/doc/chalk/dialogs-filtersgallery.png new file mode 100644 index 00000000..492a506b Binary files /dev/null and b/doc/chalk/dialogs-filtersgallery.png differ diff --git a/doc/chalk/dialogs-gaussiannoise.png b/doc/chalk/dialogs-gaussiannoise.png new file mode 100644 index 00000000..3de3ace9 Binary files /dev/null and b/doc/chalk/dialogs-gaussiannoise.png differ diff --git a/doc/chalk/dialogs-histogram.png b/doc/chalk/dialogs-histogram.png new file mode 100644 index 00000000..252e3a31 Binary files /dev/null and b/doc/chalk/dialogs-histogram.png differ diff --git a/doc/chalk/dialogs-imageproperties.png b/doc/chalk/dialogs-imageproperties.png new file mode 100644 index 00000000..893cf95d Binary files /dev/null and b/doc/chalk/dialogs-imageproperties.png differ diff --git a/doc/chalk/dialogs-imagerestoration.png b/doc/chalk/dialogs-imagerestoration.png new file mode 100644 index 00000000..16b1ae2c Binary files /dev/null and b/doc/chalk/dialogs-imagerestoration.png differ diff --git a/doc/chalk/dialogs-imagesize.png b/doc/chalk/dialogs-imagesize.png new file mode 100644 index 00000000..5028a38e Binary files /dev/null and b/doc/chalk/dialogs-imagesize.png differ diff --git a/doc/chalk/dialogs-layerproperties.png b/doc/chalk/dialogs-layerproperties.png new file mode 100644 index 00000000..83c6738d Binary files /dev/null and b/doc/chalk/dialogs-layerproperties.png differ diff --git a/doc/chalk/dialogs-layersize.png b/doc/chalk/dialogs-layersize.png new file mode 100644 index 00000000..afab719f Binary files /dev/null and b/doc/chalk/dialogs-layersize.png differ diff --git a/doc/chalk/dialogs-lenscorrection.png b/doc/chalk/dialogs-lenscorrection.png new file mode 100644 index 00000000..c550758c Binary files /dev/null and b/doc/chalk/dialogs-lenscorrection.png differ diff --git a/doc/chalk/dialogs-newadjustmentlayer.png b/doc/chalk/dialogs-newadjustmentlayer.png new file mode 100644 index 00000000..67ff729b Binary files /dev/null and b/doc/chalk/dialogs-newadjustmentlayer.png differ diff --git a/doc/chalk/dialogs-newlayer.png b/doc/chalk/dialogs-newlayer.png new file mode 100644 index 00000000..acb22f10 Binary files /dev/null and b/doc/chalk/dialogs-newlayer.png differ diff --git a/doc/chalk/dialogs-oilpaint.png b/doc/chalk/dialogs-oilpaint.png new file mode 100644 index 00000000..71d277cd Binary files /dev/null and b/doc/chalk/dialogs-oilpaint.png differ diff --git a/doc/chalk/dialogs-pixelize.png b/doc/chalk/dialogs-pixelize.png new file mode 100644 index 00000000..6ae16526 Binary files /dev/null and b/doc/chalk/dialogs-pixelize.png differ diff --git a/doc/chalk/dialogs-raindrops.png b/doc/chalk/dialogs-raindrops.png new file mode 100644 index 00000000..65e462aa Binary files /dev/null and b/doc/chalk/dialogs-raindrops.png differ diff --git a/doc/chalk/dialogs-randomnoise.png b/doc/chalk/dialogs-randomnoise.png new file mode 100644 index 00000000..405d4313 Binary files /dev/null and b/doc/chalk/dialogs-randomnoise.png differ diff --git a/doc/chalk/dialogs-randompick.png b/doc/chalk/dialogs-randompick.png new file mode 100644 index 00000000..8eb4f47d Binary files /dev/null and b/doc/chalk/dialogs-randompick.png differ diff --git a/doc/chalk/dialogs-rotateimage.png b/doc/chalk/dialogs-rotateimage.png new file mode 100644 index 00000000..2f18b18e Binary files /dev/null and b/doc/chalk/dialogs-rotateimage.png differ diff --git a/doc/chalk/dialogs-rotatelayer.png b/doc/chalk/dialogs-rotatelayer.png new file mode 100644 index 00000000..ebbdfc0b Binary files /dev/null and b/doc/chalk/dialogs-rotatelayer.png differ diff --git a/doc/chalk/dialogs-roundcorners.png b/doc/chalk/dialogs-roundcorners.png new file mode 100644 index 00000000..141ed039 Binary files /dev/null and b/doc/chalk/dialogs-roundcorners.png differ diff --git a/doc/chalk/dialogs-separateimage.png b/doc/chalk/dialogs-separateimage.png new file mode 100644 index 00000000..9e807a44 Binary files /dev/null and b/doc/chalk/dialogs-separateimage.png differ diff --git a/doc/chalk/dialogs-shearimage.png b/doc/chalk/dialogs-shearimage.png new file mode 100644 index 00000000..384486b7 Binary files /dev/null and b/doc/chalk/dialogs-shearimage.png differ diff --git a/doc/chalk/dialogs-shearlayer.png b/doc/chalk/dialogs-shearlayer.png new file mode 100644 index 00000000..bf6903c8 Binary files /dev/null and b/doc/chalk/dialogs-shearlayer.png differ diff --git a/doc/chalk/dialogs-smalltiles.png b/doc/chalk/dialogs-smalltiles.png new file mode 100644 index 00000000..5581d6a3 Binary files /dev/null and b/doc/chalk/dialogs-smalltiles.png differ diff --git a/doc/chalk/dialogs-sobel.png b/doc/chalk/dialogs-sobel.png new file mode 100644 index 00000000..b2a8e0e4 Binary files /dev/null and b/doc/chalk/dialogs-sobel.png differ diff --git a/doc/chalk/dialogs-substrate.png b/doc/chalk/dialogs-substrate.png new file mode 100644 index 00000000..e9fbf0fa Binary files /dev/null and b/doc/chalk/dialogs-substrate.png differ diff --git a/doc/chalk/dialogs-unsharpmask.png b/doc/chalk/dialogs-unsharpmask.png new file mode 100644 index 00000000..882faf39 Binary files /dev/null and b/doc/chalk/dialogs-unsharpmask.png differ diff --git a/doc/chalk/dialogs-wave.png b/doc/chalk/dialogs-wave.png new file mode 100644 index 00000000..ab1559be Binary files /dev/null and b/doc/chalk/dialogs-wave.png differ diff --git a/doc/chalk/dialogs-waveletnoise.png b/doc/chalk/dialogs-waveletnoise.png new file mode 100644 index 00000000..d126eff5 Binary files /dev/null and b/doc/chalk/dialogs-waveletnoise.png differ diff --git a/doc/chalk/faq.docbook b/doc/chalk/faq.docbook new file mode 100644 index 00000000..1e4f4fe4 --- /dev/null +++ b/doc/chalk/faq.docbook @@ -0,0 +1,51 @@ + +Questions and Answers + + +Sometimes, stuff does not work as one would like. &chalk; can crash — not all +that often, these days, but still. So you might need some help. The first thing +to do is trying to determine what was going on, exactly. Try to reproduce the +problem and write down what you did before the problem occurred. + +Then you can create a bug report: go to the Help menu and select +Report Bug. That way, we know exactly which version of +&chalk; you are using. Please try to make reasonably sure that your problem has +not been reported already! Also, please try to be as complete as possible in +describing your problem. + +You can also, if it is just that you cannot figure out how to do something +that you can do using Photoshop (or any other drawing program) using &chalk;, +or if you have some other question, e-mail the &chalk; developers at our +mailing list kimageshop@kde.org, or e-mail the program or +documentation maintainer directly at boud@valdyas.org or +sanderkoning@kde.nl, respectively. + + + + +&reporting.bugs; +&updating.documentation; + + + + + diff --git a/doc/chalk/index.docbook b/doc/chalk/index.docbook new file mode 100644 index 00000000..faa92a1a --- /dev/null +++ b/doc/chalk/index.docbook @@ -0,0 +1,138 @@ + + + chalk'> + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + +The &chalk; Handbook + + + + +Boudewijn +Rempt + +boud@valdyas.org + + + +Casper +Boemann + +cbr@boemann.dk + + + +Cyrille +Berger + +cberger@cberger.net + + + +Sander +Koning + +sanderkoning@kde.nl + + + + + +2005-2006 +Boudewijn Rempt +Casper Boemann +Cyrille Berger +Sander Koning + + +&FDLNotice; + + + +2006-09-13 +1.6 + + + + + +&chalk; is part of the &koffice; package. &chalk; is a photo retouching, image +editing application, but above all, a paint application that will allow you to +create original art on your computer as if you were working with paint and +brushes, pencils, pen and ink — or, at least, it will one day. We are +continually working on extending &chalk; and making it better in every respect. + + + + +KDE +koffice +Chalk +image manipulation +graphics +painting + + + + +&introduction; +&tutorial; +&images; +&views; +&layers; +&selections; +&filters; +&colorspaces; +&commands; +&settings; +&developers; +&faq; +&credits; +&installation; + +&documentation.index; + + + diff --git a/doc/chalk/installation.docbook b/doc/chalk/installation.docbook new file mode 100644 index 00000000..88b94e47 --- /dev/null +++ b/doc/chalk/installation.docbook @@ -0,0 +1,73 @@ + +Installation + + +How to obtain &chalk; + + + +&install.intro.documentation; + + + + +Requirements + + + + +&chalk; depends on the following libraries, apart from what &koffice; needs +itself: + + +Image +Magick — X11 Image Processing and Display +Package +Little CMS +— A free color management system in 100K +OpenEXR + + + + +You can find a list of changes in the ChangeLog file or on +&chalk;'s website. + + + + +Compilation and Installation + + + + + +&install.compile.documentation; + + + + + + + diff --git a/doc/chalk/introduction.docbook b/doc/chalk/introduction.docbook new file mode 100644 index 00000000..9384bcbc --- /dev/null +++ b/doc/chalk/introduction.docbook @@ -0,0 +1,153 @@ + +Introduction + + +What is &chalk;? + +&chalk;, part of &koffice;, can do everything you want with images — or +it will be able to one day. Everything from photo retouching, image editing, +and last but not least creating original art on your computer as if you were +working with real paint and brushes, pencils, pen and ink. Every day +&chalk; becomes a little better, a little more useful. We are working on it, +anyway. We, that is, Adrian, Bart, Boudewijn, Casper, Cyrille, Michael and Sven. +It could be you, too — whether you would like to help with some artwork +for the user interface, cool ideas for the todo, helpful bug reports, usability +reviews or even actual code, you will not be snubbed by us. + + +&chalk; is as much yours as it is ours. It should be fun, innovative, and +experimental — first and foremost a pleasure to use and to hack on. + + + + +Key features + +The most important features &chalk; currently has to offer, are: + + +Plugins: Chalk is extensible through plugins. There are tools, +colorspaces, paint operations, filters and kpart-based user interface plugins. + + +Scriptable: &chalk; is scriptable in Python and Ruby using +Kross, the cross language scripting engine that originated in Kexi. The +scripting is compatible with PyQt/KDE and Korundum for adding GUI +items, such as dialog boxes. + +Color models: &chalk; uses lcms for a dependable color +workflow using icc profiles for importing, exporting, selecting paint colors, +printing, cutting and pasting. 8, 16, and 32 bit colorspaces are available +(RGB, CMYK, L*a*b*, ...) and colors can be selected from a color wheel, rgb or +grayscale sliders or with a palette. + +Editing and viewing: Unlimited undo and redo are available. +You can cut, copy and paste between lagers and images, with conversion through +icc profiles if this is necessary. OpenGL is supported for display. The view +can be made fullscreen and can be split. Rulers are available, the +image can be zoomed, and for maximizing the workspace all palette windows can +be hidden in one go. Also a histogram palette is available. + +Images and layers: Layers and entire images can be mirrored, +sheared, rotated and scaled, converted between colorspaces, and layers in +different colorspaces can be merged. An image can be separated into colorspace +channels. + +Layers: Layers can be added, removed, grouped, locked, made +(in)visible, and re-ordered. Adjustment layers (layers which perform a filter +function) can be added as well. A layer can be saved as a separate image and +its colorspace can be changed. + +Tools: Through the innovative paintOp plugin system, all +painting tools (brush, ellipse, line, etc.) can paint aliased, anti-aliased, +erase, airbrush and more. + +Filters: &chalk; can multithread the operation of some +filters. Filters can be previewed in the filter gallery. Available filters +include color adjustment, sharpen or blur, emboss, raindrops, and +more. + +Brushes: The GIMP brush shapes can be used, both colored and +grayscale brushes and pipe brushes. Custom brushes can be created, even from +entire layers or images. Colored brushes can also be used as +masks. + + + + +Color management + +One of the most distinguishing features in &chalk; is its color management. +If you put two screens side to side, you will notice that there is often a lot +of difference in the way they display colors. Even white, especially white, is +often not the same thing at all. On one screen it can be a dirty yellow, on +another screen a sickly bluish. Very seldom is it a creamy milk-white. The same +holds, unfortunately, for scanners, printers and digital cameras. So, if you +want to see the right colors on screen and on paper, being the colors that you +saw when taking your snapshot, you will have to compensate. + +&chalk; can do this for you: in &chalk;, a color is (almost) never just a set of +numbers, one for each color channel; it is a set of numbers with information +attached. And that extra information is contained in a profile: your image has a +profile, your scanner has a profile, your camera should have a profile and your +screen has a profile. When passing information from your image to your screen, +the profiles are checked and the correct color is computed. This may cause a +little slowness, now and then, but the result is that you can work with colors, +instead of almost meaningless RGB triplets. + +Available colorspaces are: 8 bit/channel RGB, CMYK, grayscale and wet +watercolors, 16 bit/channel RGB, CMYK, grayscale and L*a*b*, half +RGB, and 32 bit float RGB (HDR) and LMS. + + + + +Image formats + +&chalk; currently supports the following image formats, both for importing and +exporting, apart from its own: PNG, TIFF, JPEG, Dicom, XCF, PSD, GIF, BMP, +XPM, Targa, RGB, and OpenEXR. Additionally, &chalk; can import +ICO files. PSD (the Photoshop file format) is only supported up to version 6, +from version 7 on, the Photoshop file format is closed. + +Embedded icc profiles and exif information are preserved on export to +supporting file formats. &chalk;'s native file format stores icc and exif +information. + + + + + + +About this manual + +We are assuming you have got a good working knowledge of &kde; and of your +operating system. The first chapter will give you a quick tour of &chalk;'s +cool features; the other chapters will expand on that information. + + +This manual is not complete. The invitation to join us and help out extends to +the manual, too! + + +Should you have any questions, comments or suggestions, please contact the +documentation maintainer at sanderkoning@kde.nl. + + + + +About the application maintainer + +Hi! I'm Boudewijn Rempt — the current maintainer of &chalk;. I was +educated as a linguist, retrained as a database developer, work as a Java +hacker, study theology and I have always liked to paint and sketch a little. +Conspiciously absent in my life have been two important things for a developer +of an image app: mathematics and experience with graphic design. That means that +I am probably not the best person to explain the niceties of using an image +editor or a paint application to you. If you catch me in an error, please don't +hesitate to mail me: boud@valdyas.org. + + + + + diff --git a/doc/chalk/mainscreen.png b/doc/chalk/mainscreen.png new file mode 100644 index 00000000..cce13569 Binary files /dev/null and b/doc/chalk/mainscreen.png differ diff --git a/doc/chalk/mountains-burn.png b/doc/chalk/mountains-burn.png new file mode 100644 index 00000000..812c89d2 Binary files /dev/null and b/doc/chalk/mountains-burn.png differ diff --git a/doc/chalk/mountains-color.png b/doc/chalk/mountains-color.png new file mode 100644 index 00000000..aa34bece Binary files /dev/null and b/doc/chalk/mountains-color.png differ diff --git a/doc/chalk/mountains-darken.png b/doc/chalk/mountains-darken.png new file mode 100644 index 00000000..3b1ba616 Binary files /dev/null and b/doc/chalk/mountains-darken.png differ diff --git a/doc/chalk/mountains-divide.png b/doc/chalk/mountains-divide.png new file mode 100644 index 00000000..b2778f65 Binary files /dev/null and b/doc/chalk/mountains-divide.png differ diff --git a/doc/chalk/mountains-dodge.png b/doc/chalk/mountains-dodge.png new file mode 100644 index 00000000..47f198a9 Binary files /dev/null and b/doc/chalk/mountains-dodge.png differ diff --git a/doc/chalk/mountains-hue.png b/doc/chalk/mountains-hue.png new file mode 100644 index 00000000..09adb913 Binary files /dev/null and b/doc/chalk/mountains-hue.png differ diff --git a/doc/chalk/mountains-lighten.png b/doc/chalk/mountains-lighten.png new file mode 100644 index 00000000..8149ef33 Binary files /dev/null and b/doc/chalk/mountains-lighten.png differ diff --git a/doc/chalk/mountains-multiply.png b/doc/chalk/mountains-multiply.png new file mode 100644 index 00000000..a8769394 Binary files /dev/null and b/doc/chalk/mountains-multiply.png differ diff --git a/doc/chalk/mountains-normal.png b/doc/chalk/mountains-normal.png new file mode 100644 index 00000000..675eb53b Binary files /dev/null and b/doc/chalk/mountains-normal.png differ diff --git a/doc/chalk/mountains-original.png b/doc/chalk/mountains-original.png new file mode 100644 index 00000000..1927e618 Binary files /dev/null and b/doc/chalk/mountains-original.png differ diff --git a/doc/chalk/mountains-overlay.png b/doc/chalk/mountains-overlay.png new file mode 100644 index 00000000..4351c1b6 Binary files /dev/null and b/doc/chalk/mountains-overlay.png differ diff --git a/doc/chalk/mountains-saturation.png b/doc/chalk/mountains-saturation.png new file mode 100644 index 00000000..2893ed9e Binary files /dev/null and b/doc/chalk/mountains-saturation.png differ diff --git a/doc/chalk/mountains-screen.png b/doc/chalk/mountains-screen.png new file mode 100644 index 00000000..4d0f9223 Binary files /dev/null and b/doc/chalk/mountains-screen.png differ diff --git a/doc/chalk/mountains-value.png b/doc/chalk/mountains-value.png new file mode 100644 index 00000000..29714b93 Binary files /dev/null and b/doc/chalk/mountains-value.png differ diff --git a/doc/chalk/mountains.png b/doc/chalk/mountains.png new file mode 100644 index 00000000..78c9ca86 Binary files /dev/null and b/doc/chalk/mountains.png differ diff --git a/doc/chalk/newimage.png b/doc/chalk/newimage.png new file mode 100644 index 00000000..210f0912 Binary files /dev/null and b/doc/chalk/newimage.png differ diff --git a/doc/chalk/palettes-colors-gray.png b/doc/chalk/palettes-colors-gray.png new file mode 100644 index 00000000..23bd973a Binary files /dev/null and b/doc/chalk/palettes-colors-gray.png differ diff --git a/doc/chalk/palettes-colors-hsv.png b/doc/chalk/palettes-colors-hsv.png new file mode 100644 index 00000000..2ff42357 Binary files /dev/null and b/doc/chalk/palettes-colors-hsv.png differ diff --git a/doc/chalk/palettes-colors-palettes.png b/doc/chalk/palettes-colors-palettes.png new file mode 100644 index 00000000..4f0b379a Binary files /dev/null and b/doc/chalk/palettes-colors-palettes.png differ diff --git a/doc/chalk/palettes-colors-rgb.png b/doc/chalk/palettes-colors-rgb.png new file mode 100644 index 00000000..bbf64883 Binary files /dev/null and b/doc/chalk/palettes-colors-rgb.png differ diff --git a/doc/chalk/palettes-colors-watercolors.png b/doc/chalk/palettes-colors-watercolors.png new file mode 100644 index 00000000..63fae210 Binary files /dev/null and b/doc/chalk/palettes-colors-watercolors.png differ diff --git a/doc/chalk/palettes-controlbox-bezier.png b/doc/chalk/palettes-controlbox-bezier.png new file mode 100644 index 00000000..4e42caee Binary files /dev/null and b/doc/chalk/palettes-controlbox-bezier.png differ diff --git a/doc/chalk/palettes-controlbox-brush.png b/doc/chalk/palettes-controlbox-brush.png new file mode 100644 index 00000000..c3c3ed08 Binary files /dev/null and b/doc/chalk/palettes-controlbox-brush.png differ diff --git a/doc/chalk/palettes-controlbox-colorpicker.png b/doc/chalk/palettes-controlbox-colorpicker.png new file mode 100644 index 00000000..7733c18d Binary files /dev/null and b/doc/chalk/palettes-controlbox-colorpicker.png differ diff --git a/doc/chalk/palettes-controlbox-contiguousfill.png b/doc/chalk/palettes-controlbox-contiguousfill.png new file mode 100644 index 00000000..57777af9 Binary files /dev/null and b/doc/chalk/palettes-controlbox-contiguousfill.png differ diff --git a/doc/chalk/palettes-controlbox-crop.png b/doc/chalk/palettes-controlbox-crop.png new file mode 100644 index 00000000..79091134 Binary files /dev/null and b/doc/chalk/palettes-controlbox-crop.png differ diff --git a/doc/chalk/palettes-controlbox-duplicate.png b/doc/chalk/palettes-controlbox-duplicate.png new file mode 100644 index 00000000..74ec92e4 Binary files /dev/null and b/doc/chalk/palettes-controlbox-duplicate.png differ diff --git a/doc/chalk/palettes-controlbox-ellipse.png b/doc/chalk/palettes-controlbox-ellipse.png new file mode 100644 index 00000000..14ab3733 Binary files /dev/null and b/doc/chalk/palettes-controlbox-ellipse.png differ diff --git a/doc/chalk/palettes-controlbox-fill.png b/doc/chalk/palettes-controlbox-fill.png new file mode 100644 index 00000000..1120d06b Binary files /dev/null and b/doc/chalk/palettes-controlbox-fill.png differ diff --git a/doc/chalk/palettes-controlbox-gradient.png b/doc/chalk/palettes-controlbox-gradient.png new file mode 100644 index 00000000..857824c3 Binary files /dev/null and b/doc/chalk/palettes-controlbox-gradient.png differ diff --git a/doc/chalk/palettes-controlbox-histogram.png b/doc/chalk/palettes-controlbox-histogram.png new file mode 100644 index 00000000..1dccaecd Binary files /dev/null and b/doc/chalk/palettes-controlbox-histogram.png differ diff --git a/doc/chalk/palettes-controlbox-line.png b/doc/chalk/palettes-controlbox-line.png new file mode 100644 index 00000000..c0671204 Binary files /dev/null and b/doc/chalk/palettes-controlbox-line.png differ diff --git a/doc/chalk/palettes-controlbox-overview.png b/doc/chalk/palettes-controlbox-overview.png new file mode 100644 index 00000000..483e3ec3 Binary files /dev/null and b/doc/chalk/palettes-controlbox-overview.png differ diff --git a/doc/chalk/palettes-controlbox-paintwithfilters.png b/doc/chalk/palettes-controlbox-paintwithfilters.png new file mode 100644 index 00000000..2a0ca8ef Binary files /dev/null and b/doc/chalk/palettes-controlbox-paintwithfilters.png differ diff --git a/doc/chalk/palettes-controlbox-polygon.png b/doc/chalk/palettes-controlbox-polygon.png new file mode 100644 index 00000000..47cfbbc1 Binary files /dev/null and b/doc/chalk/palettes-controlbox-polygon.png differ diff --git a/doc/chalk/palettes-controlbox-polyline.png b/doc/chalk/palettes-controlbox-polyline.png new file mode 100644 index 00000000..c0671204 Binary files /dev/null and b/doc/chalk/palettes-controlbox-polyline.png differ diff --git a/doc/chalk/palettes-controlbox-rectangle.png b/doc/chalk/palettes-controlbox-rectangle.png new file mode 100644 index 00000000..14ab3733 Binary files /dev/null and b/doc/chalk/palettes-controlbox-rectangle.png differ diff --git a/doc/chalk/palettes-controlbox-select.png b/doc/chalk/palettes-controlbox-select.png new file mode 100644 index 00000000..0d5e0010 Binary files /dev/null and b/doc/chalk/palettes-controlbox-select.png differ diff --git a/doc/chalk/palettes-controlbox-selectcontiguous.png b/doc/chalk/palettes-controlbox-selectcontiguous.png new file mode 100644 index 00000000..591c8096 Binary files /dev/null and b/doc/chalk/palettes-controlbox-selectcontiguous.png differ diff --git a/doc/chalk/palettes-controlbox-selectmagnetic.png b/doc/chalk/palettes-controlbox-selectmagnetic.png new file mode 100644 index 00000000..4fb3ac1b Binary files /dev/null and b/doc/chalk/palettes-controlbox-selectmagnetic.png differ diff --git a/doc/chalk/palettes-controlbox-selectsimilar.png b/doc/chalk/palettes-controlbox-selectsimilar.png new file mode 100644 index 00000000..8eb14a9e Binary files /dev/null and b/doc/chalk/palettes-controlbox-selectsimilar.png differ diff --git a/doc/chalk/palettes-controlbox-star.png b/doc/chalk/palettes-controlbox-star.png new file mode 100644 index 00000000..a14f709e Binary files /dev/null and b/doc/chalk/palettes-controlbox-star.png differ diff --git a/doc/chalk/palettes-controlbox-text.png b/doc/chalk/palettes-controlbox-text.png new file mode 100644 index 00000000..98691950 Binary files /dev/null and b/doc/chalk/palettes-controlbox-text.png differ diff --git a/doc/chalk/palettes-controlbox-transform.png b/doc/chalk/palettes-controlbox-transform.png new file mode 100644 index 00000000..19ff42ba Binary files /dev/null and b/doc/chalk/palettes-controlbox-transform.png differ diff --git a/doc/chalk/palettes-layers-layers.png b/doc/chalk/palettes-layers-layers.png new file mode 100644 index 00000000..06e20ff6 Binary files /dev/null and b/doc/chalk/palettes-layers-layers.png differ diff --git a/doc/chalk/palettes-layers-scriptsmanager.png b/doc/chalk/palettes-layers-scriptsmanager.png new file mode 100644 index 00000000..07cea20e Binary files /dev/null and b/doc/chalk/palettes-layers-scriptsmanager.png differ diff --git a/doc/chalk/preferences-color.png b/doc/chalk/preferences-color.png new file mode 100644 index 00000000..77cc9b86 Binary files /dev/null and b/doc/chalk/preferences-color.png differ diff --git a/doc/chalk/preferences-display.png b/doc/chalk/preferences-display.png new file mode 100644 index 00000000..7c4dfa36 Binary files /dev/null and b/doc/chalk/preferences-display.png differ diff --git a/doc/chalk/preferences-general.png b/doc/chalk/preferences-general.png new file mode 100644 index 00000000..38232182 Binary files /dev/null and b/doc/chalk/preferences-general.png differ diff --git a/doc/chalk/preferences-grid.png b/doc/chalk/preferences-grid.png new file mode 100644 index 00000000..48a9376a Binary files /dev/null and b/doc/chalk/preferences-grid.png differ diff --git a/doc/chalk/preferences-performance.png b/doc/chalk/preferences-performance.png new file mode 100644 index 00000000..045f3585 Binary files /dev/null and b/doc/chalk/preferences-performance.png differ diff --git a/doc/chalk/preferences-sidebar.png b/doc/chalk/preferences-sidebar.png new file mode 100644 index 00000000..cc72e177 Binary files /dev/null and b/doc/chalk/preferences-sidebar.png differ diff --git a/doc/chalk/preferences-tablet.png b/doc/chalk/preferences-tablet.png new file mode 100644 index 00000000..366a46d4 Binary files /dev/null and b/doc/chalk/preferences-tablet.png differ diff --git a/doc/chalk/settings.docbook b/doc/chalk/settings.docbook new file mode 100644 index 00000000..01fecf88 --- /dev/null +++ b/doc/chalk/settings.docbook @@ -0,0 +1,229 @@ + + +Settings + +This chapter describes the various settings that affect the way &chalk; +functions and looks. + + +The <guilabel>Preferences</guilabel> dialog + + +A number of options to configure &chalk; are available via the +Preferences dialog, which is available via +SettingsConfigure +&chalk;.... The dialog is divided into several +sections, which you can open via the sidebar at the left, shown below. + + + + +The available Preferences sections + + + + + +The available Preferences sections + +The available Preferences sections + + + + + +The <guilabel>General</guilabel> section + + + +The General section + + + + + +The General section + +The General section + + + + + +This section offers three options. First of all, the setting in the +Cursor shape: dropdown box determines what the drawing +cursor looks like. You can choose between a cursor resembling the actual tool +you are working with, a normal cursor, a crosshair, and a brush-shaped cursor. +Then you can select the Palette Behavior. You can set +here when palettes may be docked (set aside at a window +border): always (Allow docking), never +(Allow only floating), or when there is enough space +(Allow docking only on large screens). The last option is +Palette font size: which determines the text size used in +the palettes. Set this to a larger value if you have trouble reading the text, +with the side effect that the palettes will take more space. + + + + + +The <guilabel>Display</guilabel> section + + + +The Display section + + + + + +The Display section + +The Display section + + + + + +This section contains just one option. If your graphics card and driver have +OpenGL support, you can enable it here to make drawing faster (the +processor of yor graphics card will take over part of the calculations). Be +warned, though: there are a few cases where enabling OpenGL is known to +introduce erratic behavior. + + + + + +The <guilabel>Color Management</guilabel> section + + + +The Color Management section + + + + + +The Color Management section + +The Color Management section + + + + + +Here you can set various options related to colorspaces in rendering, editing +and printing of images. The topmost option can be used to set the default +color model for creating new images (useful if you usually want to create CMYK +images, for instance). Use the Display options to let +&chalk; know what color profile your monitor uses, and how rendering should be +done. Under Printing, you can set the color model and +profile for your printer. The next option determines what &chalk; should do +when you paste an image into it that was copied from another application. If +Use Blackpoint compensation is checked, whenever a +colorspace conversion is needed, the black points of the source and +destination colorspaces are matched. + + + + + +The <guilabel>Performance</guilabel> section + + + +The Performance section + + + + + +The Performance section + +The Performance section + + + + + +Two options are available here. The Maximum number of tiles kept in +memory setting indicates how many tiles (image subparts) &chalk; +will keep in memory. The default setting should be reasonable, if you are low +or very high on memory, you may want to decrease or increase this option, +respectively. The Swappiness: option determines how eager +&chalk; will be to swap to disk. + + + + + +The <guilabel>Tablet</guilabel> section + + + +The Tablet section + + + + + +The Tablet section + +The Tablet section + + + + + +If you have a tablet device attached, you can enable it and set its pressure +sensitivity in this section. + +You need to activate the tablet devices you want to use with &chalk;. There +are three supported devices: the cursor, the eraser and the stylus. You can +activate them using the tablet sections. Only use the configuration options of +a device if you use a non-Wacom tablet, and if the behavior of the tablet is +unexpected, like moving when you press on the tablet for instance. In this +situation, you can use the dialog to make sure you have a correct interaction: +values (position, pressure, tilt...) are sent from the tablet to the computer +in a given order, it might happen that some tablets do not use the default +order. You can set this in the configuration options of a device. + + + + + +The <guilabel>Grid</guilabel> section + + + +The Grid section + + + + + +The Grid section + +The Grid section + + + + + +In this section, you can fine-tune &chalk;'s grid. The line styles for the +grid can be set in the Styles option set. +Colors allows you to choose the line colors for the grid. +The horizontal and vertical spacing between the main lines can be set under +Spacing, as well as the amount of subdivisions (in how +many smaller parts a grid section is subdivided). Furthermore you can set the +Offset: usually the grid is painted starting at the top +left corner, if you want the first main grid lines not to start there, you can +enter an offset (displacement) here. + + + + + + + diff --git a/doc/chalk/tool-bezier-example.png b/doc/chalk/tool-bezier-example.png new file mode 100644 index 00000000..111ac2fc Binary files /dev/null and b/doc/chalk/tool-bezier-example.png differ diff --git a/doc/chalk/tool-bezier-example2.png b/doc/chalk/tool-bezier-example2.png new file mode 100644 index 00000000..607ef541 Binary files /dev/null and b/doc/chalk/tool-bezier-example2.png differ diff --git a/doc/chalk/tool-bezier-example3.png b/doc/chalk/tool-bezier-example3.png new file mode 100644 index 00000000..7bbc917e Binary files /dev/null and b/doc/chalk/tool-bezier-example3.png differ diff --git a/doc/chalk/tool-bezier.png b/doc/chalk/tool-bezier.png new file mode 100644 index 00000000..357cfa80 Binary files /dev/null and b/doc/chalk/tool-bezier.png differ diff --git a/doc/chalk/tool-brush.png b/doc/chalk/tool-brush.png new file mode 100644 index 00000000..9b6c79c3 Binary files /dev/null and b/doc/chalk/tool-brush.png differ diff --git a/doc/chalk/tool-colorpicker.png b/doc/chalk/tool-colorpicker.png new file mode 100644 index 00000000..daf5a94e Binary files /dev/null and b/doc/chalk/tool-colorpicker.png differ diff --git a/doc/chalk/tool-contiguousfill.png b/doc/chalk/tool-contiguousfill.png new file mode 100644 index 00000000..ddd1b6b1 Binary files /dev/null and b/doc/chalk/tool-contiguousfill.png differ diff --git a/doc/chalk/tool-crop.png b/doc/chalk/tool-crop.png new file mode 100644 index 00000000..829727dd Binary files /dev/null and b/doc/chalk/tool-crop.png differ diff --git a/doc/chalk/tool-duplicate.png b/doc/chalk/tool-duplicate.png new file mode 100644 index 00000000..968e7961 Binary files /dev/null and b/doc/chalk/tool-duplicate.png differ diff --git a/doc/chalk/tool-ellipse.png b/doc/chalk/tool-ellipse.png new file mode 100644 index 00000000..ba945656 Binary files /dev/null and b/doc/chalk/tool-ellipse.png differ diff --git a/doc/chalk/tool-eraseselection.png b/doc/chalk/tool-eraseselection.png new file mode 100644 index 00000000..f26b0f62 Binary files /dev/null and b/doc/chalk/tool-eraseselection.png differ diff --git a/doc/chalk/tool-gradient.png b/doc/chalk/tool-gradient.png new file mode 100644 index 00000000..22239a52 Binary files /dev/null and b/doc/chalk/tool-gradient.png differ diff --git a/doc/chalk/tool-line.png b/doc/chalk/tool-line.png new file mode 100644 index 00000000..3efd3608 Binary files /dev/null and b/doc/chalk/tool-line.png differ diff --git a/doc/chalk/tool-move.png b/doc/chalk/tool-move.png new file mode 100644 index 00000000..7a588bbe Binary files /dev/null and b/doc/chalk/tool-move.png differ diff --git a/doc/chalk/tool-paintselection.png b/doc/chalk/tool-paintselection.png new file mode 100644 index 00000000..654bfbd9 Binary files /dev/null and b/doc/chalk/tool-paintselection.png differ diff --git a/doc/chalk/tool-paintwithfilters-example.png b/doc/chalk/tool-paintwithfilters-example.png new file mode 100644 index 00000000..7e10f5d1 Binary files /dev/null and b/doc/chalk/tool-paintwithfilters-example.png differ diff --git a/doc/chalk/tool-paintwithfilters.png b/doc/chalk/tool-paintwithfilters.png new file mode 100644 index 00000000..9eb5a824 Binary files /dev/null and b/doc/chalk/tool-paintwithfilters.png differ diff --git a/doc/chalk/tool-pan.png b/doc/chalk/tool-pan.png new file mode 100644 index 00000000..63adf1c5 Binary files /dev/null and b/doc/chalk/tool-pan.png differ diff --git a/doc/chalk/tool-perspectivegrid.png b/doc/chalk/tool-perspectivegrid.png new file mode 100644 index 00000000..30d671fe Binary files /dev/null and b/doc/chalk/tool-perspectivegrid.png differ diff --git a/doc/chalk/tool-perspectivetransform.png b/doc/chalk/tool-perspectivetransform.png new file mode 100644 index 00000000..611947f6 Binary files /dev/null and b/doc/chalk/tool-perspectivetransform.png differ diff --git a/doc/chalk/tool-polygon.png b/doc/chalk/tool-polygon.png new file mode 100644 index 00000000..b4fabae1 Binary files /dev/null and b/doc/chalk/tool-polygon.png differ diff --git a/doc/chalk/tool-polyline.png b/doc/chalk/tool-polyline.png new file mode 100644 index 00000000..f59b09bf Binary files /dev/null and b/doc/chalk/tool-polyline.png differ diff --git a/doc/chalk/tool-rectangle.png b/doc/chalk/tool-rectangle.png new file mode 100644 index 00000000..83ddd599 Binary files /dev/null and b/doc/chalk/tool-rectangle.png differ diff --git a/doc/chalk/tool-selectbezier.png b/doc/chalk/tool-selectbezier.png new file mode 100644 index 00000000..33690580 Binary files /dev/null and b/doc/chalk/tool-selectbezier.png differ diff --git a/doc/chalk/tool-selectcontiguous.png b/doc/chalk/tool-selectcontiguous.png new file mode 100644 index 00000000..acf04cd3 Binary files /dev/null and b/doc/chalk/tool-selectcontiguous.png differ diff --git a/doc/chalk/tool-selectelliptical.png b/doc/chalk/tool-selectelliptical.png new file mode 100644 index 00000000..e7cba67f Binary files /dev/null and b/doc/chalk/tool-selectelliptical.png differ diff --git a/doc/chalk/tool-selectmagnetic.png b/doc/chalk/tool-selectmagnetic.png new file mode 100644 index 00000000..63489bcd Binary files /dev/null and b/doc/chalk/tool-selectmagnetic.png differ diff --git a/doc/chalk/tool-selectoutline.png b/doc/chalk/tool-selectoutline.png new file mode 100644 index 00000000..5646f6b1 Binary files /dev/null and b/doc/chalk/tool-selectoutline.png differ diff --git a/doc/chalk/tool-selectpolygonal.png b/doc/chalk/tool-selectpolygonal.png new file mode 100644 index 00000000..dded2a46 Binary files /dev/null and b/doc/chalk/tool-selectpolygonal.png differ diff --git a/doc/chalk/tool-selectrectangular.png b/doc/chalk/tool-selectrectangular.png new file mode 100644 index 00000000..217f6b5d Binary files /dev/null and b/doc/chalk/tool-selectrectangular.png differ diff --git a/doc/chalk/tool-selectsimilar.png b/doc/chalk/tool-selectsimilar.png new file mode 100644 index 00000000..4177294b Binary files /dev/null and b/doc/chalk/tool-selectsimilar.png differ diff --git a/doc/chalk/tool-star.png b/doc/chalk/tool-star.png new file mode 100644 index 00000000..72a68a21 Binary files /dev/null and b/doc/chalk/tool-star.png differ diff --git a/doc/chalk/tool-text.png b/doc/chalk/tool-text.png new file mode 100644 index 00000000..b1ac269d Binary files /dev/null and b/doc/chalk/tool-text.png differ diff --git a/doc/chalk/tool-transform.png b/doc/chalk/tool-transform.png new file mode 100644 index 00000000..c00eeebb Binary files /dev/null and b/doc/chalk/tool-transform.png differ diff --git a/doc/chalk/tool-zoom.png b/doc/chalk/tool-zoom.png new file mode 100644 index 00000000..99eb7496 Binary files /dev/null and b/doc/chalk/tool-zoom.png differ diff --git a/doc/chalk/toolbar-brushes-brushshapes-autobrush.png b/doc/chalk/toolbar-brushes-brushshapes-autobrush.png new file mode 100644 index 00000000..c39cacad Binary files /dev/null and b/doc/chalk/toolbar-brushes-brushshapes-autobrush.png differ diff --git a/doc/chalk/toolbar-brushes-brushshapes-custombrush.png b/doc/chalk/toolbar-brushes-brushshapes-custombrush.png new file mode 100644 index 00000000..bd57d6e9 Binary files /dev/null and b/doc/chalk/toolbar-brushes-brushshapes-custombrush.png differ diff --git a/doc/chalk/toolbar-brushes-brushshapes-predefined.png b/doc/chalk/toolbar-brushes-brushshapes-predefined.png new file mode 100644 index 00000000..677d0e27 Binary files /dev/null and b/doc/chalk/toolbar-brushes-brushshapes-predefined.png differ diff --git a/doc/chalk/toolbar-brushes-gradients.png b/doc/chalk/toolbar-brushes-gradients.png new file mode 100644 index 00000000..89ae348e Binary files /dev/null and b/doc/chalk/toolbar-brushes-gradients.png differ diff --git a/doc/chalk/toolbar-brushes-patterns-custompattern.png b/doc/chalk/toolbar-brushes-patterns-custompattern.png new file mode 100644 index 00000000..29d0fe1c Binary files /dev/null and b/doc/chalk/toolbar-brushes-patterns-custompattern.png differ diff --git a/doc/chalk/toolbar-brushes-patterns.png b/doc/chalk/toolbar-brushes-patterns.png new file mode 100644 index 00000000..367fa3ef Binary files /dev/null and b/doc/chalk/toolbar-brushes-patterns.png differ diff --git a/doc/chalk/toolbar-brushesandstuff.png b/doc/chalk/toolbar-brushesandstuff.png new file mode 100644 index 00000000..e37d1a83 Binary files /dev/null and b/doc/chalk/toolbar-brushesandstuff.png differ diff --git a/doc/chalk/toolbar-chalk.png b/doc/chalk/toolbar-chalk.png new file mode 100644 index 00000000..e39c6777 Binary files /dev/null and b/doc/chalk/toolbar-chalk.png differ diff --git a/doc/chalk/toolbar-edit.png b/doc/chalk/toolbar-edit.png new file mode 100644 index 00000000..c65c1969 Binary files /dev/null and b/doc/chalk/toolbar-edit.png differ diff --git a/doc/chalk/toolbar-file.png b/doc/chalk/toolbar-file.png new file mode 100644 index 00000000..5b8293bd Binary files /dev/null and b/doc/chalk/toolbar-file.png differ diff --git a/doc/chalk/toolbar-navigation.png b/doc/chalk/toolbar-navigation.png new file mode 100644 index 00000000..6fd40b6a Binary files /dev/null and b/doc/chalk/toolbar-navigation.png differ diff --git a/doc/chalk/toolbar-transformationtools.png b/doc/chalk/toolbar-transformationtools.png new file mode 100644 index 00000000..07e41208 Binary files /dev/null and b/doc/chalk/toolbar-transformationtools.png differ diff --git a/doc/chalk/toolbars-button-zoomin.png b/doc/chalk/toolbars-button-zoomin.png new file mode 100644 index 00000000..896f1c12 Binary files /dev/null and b/doc/chalk/toolbars-button-zoomin.png differ diff --git a/doc/chalk/toolbars-button-zoomout.png b/doc/chalk/toolbars-button-zoomout.png new file mode 100644 index 00000000..124ab6fb Binary files /dev/null and b/doc/chalk/toolbars-button-zoomout.png differ diff --git a/doc/chalk/tutorial-quick-starts.docbook b/doc/chalk/tutorial-quick-starts.docbook new file mode 100644 index 00000000..b22d3250 --- /dev/null +++ b/doc/chalk/tutorial-quick-starts.docbook @@ -0,0 +1,183 @@ + +Quick start guides + +Crop an area and save it + +Aim: from a picture, crop an area and save that area in a new file + +Open &chalk; with the original picture. + + +The original picture + + + + +The original picture + + + +Select the Select Rectangular tool in the +&chalk; toolbar. + + +The Select a rectangular area tool + + + + +The Select a rectangular area tool + + + +Select the area you want to make a new picture with. &chalk; makes the +outside area grey. + + +The selected area + + + + +The selected area + + + +Then use the +EditCopy +menu item or &Ctrl;C to +copy the selected area. + +Click again on the Edit menu. +Use the Paste into new image item. + + +The Edit menu + + + + +The Edit menu + + + +&chalk; opens a new window with the selected area as new image. + + +The new image + + + + +The new image + + + +Save the new image. + + + +Draw a rectangle on your picture + +Aim: draw a coloured rectangle on your picture + +Open &chalk; with the original picture. My picture consists of a view of +a toolbar in which I want to point an icon by putting a red rectangle around +it. + + +The original picture + + + + +The original picture + + + +Enable the Brushes and Stuff toolbar using +SettingsToolbars +menu. +Also make sure the palettes are viewed. If not, use the +ViewPalettes +menu. + + +&chalk; view + + + + +&chalk; view + + + +Click on the Brush Shapes icon in the +Brushes and Stuff toolbar. + + +The Brush Shapes icon + + + + +The Brush Shapes icon + + + +Select which brush shape you want to use among the predefined +brushes. + + +Selecting a brush shape + + + + +Selecting a brush shape + + + +Select the drawing shape on the &chalk; toolbar. I choose a +rectangle. + + +Selecting the Rectangle icon + + + + +Selecting the Rectangle icon + + + +In the Colors palette, select the color you want by clicking on one of the +tabs and then choosing the color. + + +Choosing the color + + + + +Choosing the color + + + +Finally draw your shape on your picture and save the new picture! + + +Drawing + + + + +Drawing + + + +Thanks go to Anne-Marie Mahfouf for providing this tutorial. + + + + diff --git a/doc/chalk/tutorial-quick-starts1.png b/doc/chalk/tutorial-quick-starts1.png new file mode 100644 index 00000000..562e1595 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts1.png differ diff --git a/doc/chalk/tutorial-quick-starts10.png b/doc/chalk/tutorial-quick-starts10.png new file mode 100644 index 00000000..fc76f188 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts10.png differ diff --git a/doc/chalk/tutorial-quick-starts11.png b/doc/chalk/tutorial-quick-starts11.png new file mode 100644 index 00000000..7cd5f601 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts11.png differ diff --git a/doc/chalk/tutorial-quick-starts12.png b/doc/chalk/tutorial-quick-starts12.png new file mode 100644 index 00000000..a74ea54f Binary files /dev/null and b/doc/chalk/tutorial-quick-starts12.png differ diff --git a/doc/chalk/tutorial-quick-starts2.png b/doc/chalk/tutorial-quick-starts2.png new file mode 100644 index 00000000..fe54bf6a Binary files /dev/null and b/doc/chalk/tutorial-quick-starts2.png differ diff --git a/doc/chalk/tutorial-quick-starts3.png b/doc/chalk/tutorial-quick-starts3.png new file mode 100644 index 00000000..b1f4223b Binary files /dev/null and b/doc/chalk/tutorial-quick-starts3.png differ diff --git a/doc/chalk/tutorial-quick-starts4.png b/doc/chalk/tutorial-quick-starts4.png new file mode 100644 index 00000000..1d6fcacb Binary files /dev/null and b/doc/chalk/tutorial-quick-starts4.png differ diff --git a/doc/chalk/tutorial-quick-starts5.png b/doc/chalk/tutorial-quick-starts5.png new file mode 100644 index 00000000..ceb18de9 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts5.png differ diff --git a/doc/chalk/tutorial-quick-starts6.png b/doc/chalk/tutorial-quick-starts6.png new file mode 100644 index 00000000..69176011 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts6.png differ diff --git a/doc/chalk/tutorial-quick-starts7.png b/doc/chalk/tutorial-quick-starts7.png new file mode 100644 index 00000000..92c6ab18 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts7.png differ diff --git a/doc/chalk/tutorial-quick-starts8.png b/doc/chalk/tutorial-quick-starts8.png new file mode 100644 index 00000000..fb2bed36 Binary files /dev/null and b/doc/chalk/tutorial-quick-starts8.png differ diff --git a/doc/chalk/tutorial-quick-starts9.png b/doc/chalk/tutorial-quick-starts9.png new file mode 100644 index 00000000..db763b6c Binary files /dev/null and b/doc/chalk/tutorial-quick-starts9.png differ diff --git a/doc/chalk/tutorial-select-layer-1.png b/doc/chalk/tutorial-select-layer-1.png new file mode 100644 index 00000000..29f8b0bf Binary files /dev/null and b/doc/chalk/tutorial-select-layer-1.png differ diff --git a/doc/chalk/tutorial-select-layer-10.png b/doc/chalk/tutorial-select-layer-10.png new file mode 100644 index 00000000..a2d92fc6 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-10.png differ diff --git a/doc/chalk/tutorial-select-layer-11.png b/doc/chalk/tutorial-select-layer-11.png new file mode 100644 index 00000000..75a6c10c Binary files /dev/null and b/doc/chalk/tutorial-select-layer-11.png differ diff --git a/doc/chalk/tutorial-select-layer-12.png b/doc/chalk/tutorial-select-layer-12.png new file mode 100644 index 00000000..95487fa7 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-12.png differ diff --git a/doc/chalk/tutorial-select-layer-13.png b/doc/chalk/tutorial-select-layer-13.png new file mode 100644 index 00000000..449ec903 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-13.png differ diff --git a/doc/chalk/tutorial-select-layer-2.png b/doc/chalk/tutorial-select-layer-2.png new file mode 100644 index 00000000..4552f0af Binary files /dev/null and b/doc/chalk/tutorial-select-layer-2.png differ diff --git a/doc/chalk/tutorial-select-layer-3.png b/doc/chalk/tutorial-select-layer-3.png new file mode 100644 index 00000000..a9a7a9bd Binary files /dev/null and b/doc/chalk/tutorial-select-layer-3.png differ diff --git a/doc/chalk/tutorial-select-layer-4.png b/doc/chalk/tutorial-select-layer-4.png new file mode 100644 index 00000000..a3506440 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-4.png differ diff --git a/doc/chalk/tutorial-select-layer-5.png b/doc/chalk/tutorial-select-layer-5.png new file mode 100644 index 00000000..f0e88e46 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-5.png differ diff --git a/doc/chalk/tutorial-select-layer-6.png b/doc/chalk/tutorial-select-layer-6.png new file mode 100644 index 00000000..eac0b247 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-6.png differ diff --git a/doc/chalk/tutorial-select-layer-7.png b/doc/chalk/tutorial-select-layer-7.png new file mode 100644 index 00000000..6580b54b Binary files /dev/null and b/doc/chalk/tutorial-select-layer-7.png differ diff --git a/doc/chalk/tutorial-select-layer-8.png b/doc/chalk/tutorial-select-layer-8.png new file mode 100644 index 00000000..503c0223 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-8.png differ diff --git a/doc/chalk/tutorial-select-layer-9.png b/doc/chalk/tutorial-select-layer-9.png new file mode 100644 index 00000000..cebfde39 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-9.png differ diff --git a/doc/chalk/tutorial-select-layer-sample.png b/doc/chalk/tutorial-select-layer-sample.png new file mode 100644 index 00000000..4def7ed3 Binary files /dev/null and b/doc/chalk/tutorial-select-layer-sample.png differ diff --git a/doc/chalk/tutorial-select-layer.docbook b/doc/chalk/tutorial-select-layer.docbook new file mode 100644 index 00000000..65a7b6ee --- /dev/null +++ b/doc/chalk/tutorial-select-layer.docbook @@ -0,0 +1,263 @@ + +A Small selections and layers tutorial + + + +The starting image + + + + + +The starting image + +The starting image + + + + +The image above is the image we will work with. Start chalk with this +image (in the documentation folder +$KDEDIR/share/doc/HTML/en/chalk/tutorial-select-layer-sample.png) +and save it to your Home folder (by choosing Save Image As...). + +Then open it in &chalk; — your screen will look a bit like this (we have +zoomed in): + + + +Chalk with the starting image + + + + + +The starting image + +The starting image + + + + +Now try to select the outline of the head with the Select Outline tool: + + + +The Select Outline tool + + + + + +The Select Outline tool + +The Select Outline tool + + + + +After you select it, it should look a bit like this picture: + + + +The picture after selecting the head + + + + + +The picture after selecting the head + +The picture after selecting the head + + + + +If you accidently select too much, you can cut that part easily off by switching the tool to Subtract mode: + + + +The Subtract mode + + + + + +The Subtract mode + +The Subtract mode + + + + +Now it's time to make the edges of the selection a bit fuzzy. This can be done by applying Feather to the selection. + + + +Feather selection + + + + + +Feather selection + +Feather selection + + + + +Now cut the selection, using +EditCut. +Delete the current layer with +LayerRemove +Layer. Paste your selection, with +EditPaste. +Now we give ourselves a bit more room to work in by resizing the image a bit. +Use the ImageChange Image +Size... dialog for this. + + + +The Image Size dialog + + + + + +The Image Size dialog + +The Image Size dialog + + + + +Add a new layer, and place it below the old layer. You do this by selecting +the new layer in the layerbox, and then pressing the little 'down' arrow at the bottom. +Now we are going to select the area around the head with a contiguous select +(the tool has a selection-with-bucketfill icon at the border). + + + +The Select Contiguous tool + + + + + +The Select Contiguous tool + +The Select Contiguous tool + + + + +Make sure to select Sample merged in the tool options: + + + +The Sample merged option + + + + + +The Sample merged option + +The Sample merged option + + + + +Feather the selection again, and invert it. +Select the Contiguous Fill tool (this is a different tool than +the Contiguous Select tool) and use it on the layer. + + + +The Contiguous Fill tool + + + + + +The Contiguous Fill tool + +The Contiguous Fill tool + + + + +Deselect with SelectDeselect. +You'll notice some artefacts of the feathering at the sides. You can select them easily with a rectangular selection and then cut them. + + + +The Select Rectangular tool + + + + + +The Select Rectangular tool + +The Select Rectangular tool + + + + +Move the shadow layer a bit down and to the right to make it look nice. + + + +Moving the shadow layer + + + + + +Moving the shadow layer + +Moving the shadow layer + + + + +Now you can use the Crop tool to make the image better fit around the head. + + + +The Crop tool + + + + + +The Crop tool + +The Crop tool + + + + +Save the image, and you're done :-) + + + +The resulting image + + + + + +The resulting image + +The resulting image + + + + +Thanks go to Bart Coppens for providing this tutorial. The original is available at http://www.bartcoppens.be/chalk/hackergotchi.html. + + + diff --git a/doc/chalk/tutorial-starting.docbook b/doc/chalk/tutorial-starting.docbook new file mode 100644 index 00000000..bed91f24 --- /dev/null +++ b/doc/chalk/tutorial-starting.docbook @@ -0,0 +1,117 @@ + +Starting to know &chalk; + + +So, let's show you all the niceties. You can start &chalk; either on its own +or from the &koffice; shell. In your &kde; menus, &chalk; should be placed +either under Graphics or under Office — it depends a bit on who packaged +&koffice; for you. Or do what I do: press +&Alt;F2 (which opens the +minicli), type chalk and +press OK. + + + +A little later, you'll be greeted by a dialog: + + + + +The Create Document dialog + + + + + +The Create Document dialog + +The Create Document dialog + + + + + +This is standard for &koffice;: you can create a new document, choose a +document from among your files or select a document you had opened in an earlier +session. We have got a bunch of templates here, ordered by color model. &chalk; +is a very flexible application and can handle many different types of images: +CMYK images for printers, RGB images for +the web, RGB images with high channel depths for +photographers, watercolor images for painters — and more. For now, choose +Custom Document. That will allow +us to see the New Image dialog box: + + + + +The New Image dialog + + + + + +The New Image dialog + +The New Image dialog + + + + + +Here you can give your document a name, determine the dimensions and the +resolution. The combination of width/height and resolution determines how big +your image will be on screen or on paper: if your image has a resolution of +100x100 dpi, and your image is 1000x1000 pixels big, then, if everything is +configured correctly, your image will be exactly 10 inches long and 10 inches +wide if you check with a ruler, no matter the resolution of your screen or of +your printer — if shown at 100%. However, life is seldom so well-regulated +that this actually works out. For now, just think pixels, not inches. + + + +The next group of options is a lot more interesting than resolution: &chalk; +is an enormously flexible application and you can work with many kinds of +images. For this tutorial, just select RGB (8 +bits/channel). You can also select a profile. For now, we leave this +at the default setting of sRGB built-in - (lcms internal). + + + +In the third option group, you can select the initial canvas color and the +amount of opacity/transparency of this color. Furthermore you can +add a description of the contents. We leave these options at their default +settings as well, so click Create to actually create the new +image. + + + +You will now see the main &chalk; screen. + + + + +&chalk;'s main screen + + + + + +&chalk;'s main screen + +&chalk;'s main screen + + + + + +On the left hand side and on the top, there are toolbars which offer you access +to tools for painting, editing, and selecting. +You can find a more detailed description of these toolbars here. The actual painting area is in the +middle. On the right side of your screen, there are various palettes, which you +can read more about in this section. +Finally, there is a menu bar at the top of the screen, as usually. Read more +about it here. + + + diff --git a/doc/chalk/tutorial-tablet-1.png b/doc/chalk/tutorial-tablet-1.png new file mode 100644 index 00000000..5ab3d648 Binary files /dev/null and b/doc/chalk/tutorial-tablet-1.png differ diff --git a/doc/chalk/tutorial-tablet-2.png b/doc/chalk/tutorial-tablet-2.png new file mode 100644 index 00000000..a2cf0023 Binary files /dev/null and b/doc/chalk/tutorial-tablet-2.png differ diff --git a/doc/chalk/tutorial-tablet-3.png b/doc/chalk/tutorial-tablet-3.png new file mode 100644 index 00000000..4986cbde Binary files /dev/null and b/doc/chalk/tutorial-tablet-3.png differ diff --git a/doc/chalk/tutorial-tablet.docbook b/doc/chalk/tutorial-tablet.docbook new file mode 100644 index 00000000..05a57504 --- /dev/null +++ b/doc/chalk/tutorial-tablet.docbook @@ -0,0 +1,141 @@ + +Working with tablets + +This tutorial is intended to describe you the first steps with working +with a tablet with &chalk;. The tutorial assumes you are using &Linux;. + + +Configuring it + + +As any hardware it nearly works out of the box. &Linux; should recognize it +fine, but you might have to configure the X11 server by hand. The best way to +do this is to follow the instruction on the Wacom &Linux; howto: . + +Then, in &chalk;, you need to enable the various tools (in the +Tablet section of the +SettingsConfigure +&chalk;... dialog) — you can find more +information in the tablet settings +section. + + + + + +First contact with the tablet + + +There are three devices of your tablet that you can use with &chalk;: + + + +the cursor, the mouse that was shipped with the Wacom +tablet +the eraser, the round part on the top of the pen +the stylus, the thin point on the bottom of the pen + + + +By default, when you use the stylus or the cursor on the tablet, the Brush +tool and the pixel brush painting operation will get selected. The eraser +device is associated to the pixel eraser painting operation. +But if you select a different tool or a different painting operation with one +device, &chalk; will remember the association when you switch between devices. + + + + + +Outlines of a flower + + +Even if you knew how to draw before you started with a tablet, you will need +to adapt to the tablet. It doesn't feel the same. So I suggest to start with +something simple, like a flower, and to use a picture as a model: + + + + +A flower + + + + + +A flower + +A flower + + + + + +First, you will need to create a new layer for the outline. I advise you to +lock the layer with the picture, it will prevent you from making mistakes. + +Drawing the outline of the flower seems pretty easy, but for your first +experience you will have a great difficulty to precisely follow the line on +the screen while your hand has to move on the tablet. Eventually you will get +something like this: + + + + +The outline of the flower + + + + + +The outline of the flower + +The outline of the flower + + + + + + + +Colorization + + +For the colorization, you will need to create a third layer. You will +have to move it below the layer with the outlines, and do not forget to lock +the outline layer. + +It's mostly easier than the outline part, just select the color you want to +use (either with the color selector or with the color picker), then for most +of the work you can use the fill tool: with the mouse, click on the part you +want to fill, as by default the fill tool will take the outline into +consideration. On the following image, the different colors of the heart of +the flower are not seperated by outlines, to do them I just completed the +missing outline with a yellow or brown line to create the separation between +the different colors. + + + + +The colored flower + + + + + +The colored flower + +The colored flower + + + + + +The resulting image looks and feels like old fashion clipart, mostly because +it lacks shadows and illumination, which are not covered by this tutorial. + + + + + diff --git a/doc/chalk/tutorial.docbook b/doc/chalk/tutorial.docbook new file mode 100644 index 00000000..fbf0ea5b --- /dev/null +++ b/doc/chalk/tutorial.docbook @@ -0,0 +1,14 @@ + +Tutorial + + +The toolbars and palettes shown in these tutorials may not match your +installation of &chalk;. Our apologies for this inconvenience. + + +&tutorial-starting; +&tutorial-select-layer; +&tutorial-quick-starts; +&tutorial-tablet; + + diff --git a/doc/chalk/using-colorspaces.docbook b/doc/chalk/using-colorspaces.docbook new file mode 100644 index 00000000..6a3c5481 --- /dev/null +++ b/doc/chalk/using-colorspaces.docbook @@ -0,0 +1,149 @@ + +Colorspaces + + +This chapter gives information on what colorspaces are, which colorspaces +&chalk; offers, and what you should keep in mind when using them. + + + +Introduction to colorspaces + + +What is a colorspace? + + +In short, a colorspace is a way to represent colors by specifying a number of +parameters. As parameters, one can choose for example the amounts of red, +green and blue light needed for the color. This results in the commonly known +RGB colorspace. One can visualize this as a three-dimensional space, with each +of the red, green, and blue light components being an axis in the colorspace. +A color then corresponds to a certain point in this colorspace, defined by its +coordinates on the three axes. + + +To be more precise, a colorspace is a combination of a color model (indicating +which axes are present) and a mapping function (indicating which values +correspond to which colors). + + +Not every color can be represented in every colorspace. Some colorspaces +define more, or different, colors than others. The set of colors that can be +represented in a certain colorspace is called its gamut. Because gamuts +can differ widely, it is not guaranteed that images in a certain colorspace +can be converted to another colorspace without having to substitute certain +colors for others, even if they are based on the same color model. + + + + + + + +Available colorspaces + + +&chalk; offers colorspaces based on RGB, CMYK, Lab, LMS, YCbCr, and Gray +color models. These are shortly discussed in this section. + + + +The RGB color models + + +The abbreviation RGB stands for Red, Green, Blue, and the color model with +this name refers to the three light components that are emitted in displays +(televisions, computer monitors, etcetera) to create a certain color. This +color model is used by default in virtually any standard painting application. + +When defining a color in the RGB model, its red, green and blue components are +specified. If all components are absent (each component is emitted at 0 +percent intensity, so no light at all), the color is pure black. If all +components are fully present (100 percent intensity), the color is pure white. +If one component is present at full intensity and the other two are absent, +the pure respective color is obtained. + +Two more examples: if both red and green are emitted at 100 percent and blue +is not emitted, pure yellow is obtained. A color with all three components at +the same intensity is a shade of gray. + +There are various colorspaces that implement the RGB model. For example, the +so-called RGB8 colorspace represents each color with 8 bits per component. +Since 8 bits allow for 256 distinct values, the total number of different +colors that can be specified in this colorspace is 256 (red) * 256 (green) * +256 (blue), or about 16.7 million colors. In &chalk;, a couple of RGB +colorspaces are available, for example RGB32, which is able to distinguish +between 4.2 billion values per component. + + + + + +The CMYK color model + + +CMYK is the abbreviation for Cyan, Magenta, Yellow, blacK (although officially +the K stands for Key, black is much more commonly used). This color model is +based on ink: a color is specified by the amount of ink needed for a point +to be perceived as having that color. + +Since CMYK colors are used by printers while RGB colors are used on-screen, +one often wants to convert RGB colors to CMYK colors. As this cannot always be +done correctly, printed images may turn out to look quite different than what +is perceived on-screen. + + + + + +The L*a*b* color model + + +This color model uses three parameters for a color: its +luminance or lightness (L*, which lies between 0 for black and +100 for white), its position between absolute red and absolute green (a*, +which is negative for colors closer to green and positive for colors closer to +red), and its position between yellow and blue (b*, which is negative for +colors closer to blue and positive for colors closer to yellow). + + + + + +The LMS color model + + +This model is based on the contribution of actual light wave lengths to the +color. The human eye is sensitive to three types of light waves, distinguished +by their wave lengths: long (L), middle (M) and short (S) waves. The eye's +sensitivity for a certain color on these three wavelengths can be expressed in +L, M and S coordinates. + + + + + +The YCbCr color model + + +The YCbCr model is often used for video systems. The Y parameter indicates the +luminance or lightness of the color (which can be seen as a gray-tone), the Cb +and Cr parameters indicate the chrominance (color tone): Cb places the color +on a scale between blue and yellow, Cr indicates the place of the color +between red and green. + + + + +The Gray color model + + +The Gray color model simply represents colors as shades of gray (with black +and white being the extremes). + + + + + + + diff --git a/doc/chalk/using-filters.docbook b/doc/chalk/using-filters.docbook new file mode 100644 index 00000000..7dd8cf8d --- /dev/null +++ b/doc/chalk/using-filters.docbook @@ -0,0 +1,923 @@ + +Filters + + +&chalk; comes with a number of filters. These can be used to enhance or +otherwise modify the image, either in whole or in part. Some filters are +applied directly, others are customizable, meaning that you are presented with +a dialog in which you can tune the result to your liking before the filter is +applied. If a selection is active, a filter is applied on the selected part of +the image. If no selection is active, the entire image is modified. + +This chapter describes the available filters in detail. To make comparing the +filters easier, each filter has been applied to the same image and each description +contains a comparison image, showing the result of applying the filter described. +The original image (with thanks to the photographer, Christian Peper) is shown +below at half the original size. The sample images demonstrating the +results of applying the filters, with the original image at the left and the +modified image at the right, are shown at 25% of the original size. + +Some filters yield reasonable results for most images. For +other filters though, quite some tweaking needs to be done before the desired +outcome is achieved. If a filter does not do what you want, it might need +more or less customising. The examples in this chapter are exaggerated to +give a good impression of the filters. You will usually want to have more +gentle modifications. + +Tip: If you want to apply a filter to everything except a certain part of your +image (for example, you want to desaturate your image except for the centre), +select the part you do not want to apply the filter to, use the +SelectInvert +menu option, and then apply the filter. + + +See the Dialogs for working with +filters section for descriptions of the settings available for the +customizable filters. + + + +The original image + + + + + +The original image + +The original image + + + + +The Auto Contrast filter + +The Auto Contrast filter changes the contrast of your image to what should be +the best settings. Usually this works out fine, but in some cases (for example +photos taken under unusual lighting circumstances), the filter will not yield +satisfying results. + + +You can find the Auto Contrast filter in the Filter +Adjust menu. This filter is not customizable. + + +The image with the Auto Contrast filter applied to it + + + + + +The image with the Auto Contrast filter applied to it + +The image with the Auto Contrast filter applied to it + + + + + +The Blur filter + +You can use the Blur filter to blur your image (give it a fuzzy look). + + +You can find the filter in the Filter +Blur menu. +See the section on the +Blur dialog +for more information on its settings. + + +The image with the Blur filter applied to it + + + + + +The image with the Blur filter applied to it + +The image with the Blur filter applied to it + + + + + +The Brightness / Contrast filter + +With this filter, you can adjust the brightness and contrast of your image. + + +You can find the filter in the Filter +Adjust menu. +See the section on the +Brightness / Contrast dialog +for more information on its settings. + + +The image with the Brightness / Contrast filter applied to it + + + + + +The image with the Brightness / Contrast filter applied to it + +The image with the Brightness / Contrast filter applied to it + + + + + +The Bumpmap filter + +The Bumpmap filter takes two layers and uses one of these to convert the other +one so that it will give an illusion of depth. The object layer (the layer to be +transformed) is the actual layer that should receive the three-dimensional +looks. The bumpmap layer is a grayscale layer, which is read and used to +determine the height for each point of the object layer. Alternatively, the +same layer can be used as both object layer and bumpmap layer. + + +You can find the filter in the Filter +Map menu. +See the section on the +Bumpmap dialog for more information on its +settings. + + +The image with the Bumpmap filter applied to it + + + + + +The image with the Bumpmap filter applied to it + +The image with the Bumpmap filter applied to it + + + + + +The CImg Image Restoration filter + +With this filter, you can perform minor enhancements to your image, for +example removing small scratches or adding a slight blur. The difference +between our sample original image and the result of applying this filter with +standard settings is virtually none. + + +You can find the filter in the Filter +Enhance menu. +See the section on the +Image Restoration dialog +for more information on its settings. + + + + +The Color Adjustment filter + +This filter allows you to change the looks of your image by increasing or +decreasing the abundance of certain colors. + + +You can find the filter in the Filter +Adjust menu. +See the section on the +Color Adjustment dialog +for more information on its settings. + + +The image with the Color Adjustment filter applied to it + + + + + +The image with the Color Adjustment filter applied to it + +The image with the Color Adjustment filter applied to it + + + + + +The Color to Alpha filter + +This filter changes a color or color range in your image to become +transparent, effectively clearing regions with those colors. + + +You can find the filter in the Filter +Colors menu. +See the section on the +Color to Alpha dialog +for more information on its settings. + + +The image with the Color to Alpha filter applied to it + + + + + +The image with the Color to Alpha filter applied to it + +The image with the Color to Alpha filter applied to it + + + + + +The Color Transfer filter + +With this filter, you can re-color an image using the colors from another +image. Each color in your current image will be replaced by the most alike +color used in the other image. + + +You can find the filter in the Filter +Colors menu. +See the section on the +Color Transfer dialog +for more information on its settings. + + +The image with the Color Transfer filter applied to it + + + + + +The image with the Color Transfer filter applied to it + +The image with the Color Transfer filter applied to it + + + + + +The Custom Convolution filter + +This filter allows you to distort your image by setting a number of +parameters. + + +You can find the filter in the Filter +Enhance menu. +See the section on the +Custom Convolution dialog +for more information on its settings. + + +The image with the Custom Convolution filter applied to it + + + + + +The image with the Custom Convolution filter applied to it + +The image with the Custom Convolution filter applied to it + + + + + +The Desaturate filter + +This filter converts your image to grayscale by setting the saturation of each +pixel's color to zero. + + +You can find the filter in the Filter +Adjust menu. +This filter is not customizable. + + +The image with the Desaturate filter applied to it + + + + + +The image with the Desaturate filter applied to it + +The image with the Desaturate filter applied to it + + + + + +The Edge Detection filters + +These filters try to detect edges (boundaries) in the picture +and modify the image such that only these edges retain their respective colors, +while the rest of the image is turned gray. Through the use of lighting the +image will then get a three-dimensional look. + +There are four edge detection filters available. Each of these detects edges +from a different side (possibly considering other parts of the image as being +edges) and will therefore obtain a different resulting image. + + +You can find the filters in the Filter +Edge Detection menu. +These filters are not customizable. + + +The image with the Bottom Edge Detection filter applied to +it + + + + + +The image with the Bottom Edge Detection filter applied to it + +The image with the Bottom Edge Detection filter applied to +it + + + + + +The Emboss filters + +Emboss filters work somewhat like edge detection filters, with the difference +that embossed images are entirely gray. Areas in the picture are detected and +are given a certain height level, which is made visible by using +grayscale borders, making the image look like it is three-dimensional. + + +You can find the filters in the Filter +Emboss menu. +Except for the Emboss with Variable Depth filter, these filters are not +customizable. See the section on the +Emboss dialog +for more information on the settings of the Emboss with Variable Depth filter. + + +The image with the Emboss in All Directions filter applied to it + + + + + +The image with the Emboss in All Directions filter applied to it + +The image with the Emboss in All Directions filter applied to +it + + + +The image with the Emboss with Variable depth filter applied to +it + + + + + +The image with the Emboss with Variable depth filter applied to it + +The image with the Emboss with Variable depth filter applied to +it + + + + + +The Gaussian Blur filter + +This filter makes the image a little fuzzy by blurring it in a pseudo-random +way. A gaussian algorithm is used for finding the extent to which each part of +the image should be blurred. + + +You can find the filter in the Filter +Blur menu. +This filter is not customizable. + + +The image with the Gaussian Blur filter applied to it + + + + + +The image with the Gaussian Blur filter applied to it + +The image with the Gaussian Blur filter applied to +it + + + + + +The Gaussian Noise Reduction filter + +With this filter, you can remove noise from your image. + + +You can find the filter in the Filter +Enhance menu. +See the section on the +Gaussian Noise Reduction dialog +for more information on its settings. + + +The image with the Gaussian Noise Reduction filter applied to it + + + + + +The image with the Gaussian Noise Reduction filter applied to it + +The image with the Gaussian Noise Reduction filter applied to it + + + + + +The Invert filter + +This filter inverts all colors. The Red, Green and Blue component of each pixel +are taken and subtracted from 255. This means that red becomes cyan, green +becomes purple, and blue becomes yellow. The resulting values form the new +pixel color. + + +You can find the filter in the Filter +Adjust menu. +This filter is not customizable. + + +The image with the Invert filter applied to it + + + + + +The image with the Invert filter applied to it + +The image with the Invert filter applied to it + + + + + +The Lens Correction filter + +This filter can fix distortions in your image resulting from for example +pincushion lens effects, and modify some lighting. + + +You can find the filter in the Filter +Other menu. +See the section on the +Lens Correction dialog +for more information on its settings. + + +The image with the Lens Correction filter applied to it + + + + + +The image with the Lens Correction filter applied to it + +The image with the Lens Correction filter applied to it + + + + + +The Maximize Channel filter + +This filter gives each pixel in your image a new color: only the color channel +that contributes the most to the color of a pixel is retained (except for +gray pixels, which are kept gray). + + +You can find the filter in the Filter +Colors menu. +This filter is not customizable. + + +The image with the Maximize Channel filter applied to it + + + + + +The image with the Maximize Channel filter applied to it + +The image with the Maximize Channel filter applied to it + + + + + +The Mean Removal filter + +This filter sharpens the image by changing the colors of neighboring pixels +with approximately the same color, so that small differences are evened out. + + +You can find the filter in the Filter +Enhance menu. +This filter is not customizable. + + +The image with the Mean Removal filter applied to it + + + + + +The image with the Mean Removal filter applied to it + +The image with the Mean Removal filter applied to +it + + + + + +The Minimize Channel filter + +This filter gives each pixel in your image a new color: the color channel +that contributes the most to the color of a pixel is removed (except for +gray pixels, which are kept gray). + + +You can find the filter in the Filter +Colors menu. +This filter is not customizable. + + +The image with the Minimize Channel filter applied to it + + + + + +The image with the Minimize Channel filter applied to it + +The image with the Minimize Channel filter applied to it + + + + + +The Oilpaint filter + +An oilpaint effect is given to the image by creating patch-shaped areas in which +the most important color is applied to the entire area. + + +You can find the filter in the Filter +Artistic menu. +See the section on the +Oilpaint dialog +for more information on its settings. + + +The image with the Oilpaint filter applied to it + + + + + +The image with the Oilpaint filter applied to it + +The image with the Oilpaint filter applied to +it + + + + + +The Pixelize filter + +The image is pixelated by taking a square area and giving it the mean color +value of the pixels it contains. + + +You can find the filter in the Filter +Artistic menu. +See the section on the +Pixelize dialog +for more information on its settings. + + +The image with the Pixelize filter applied to it + + + + + +The image with the Pixelize filter applied to it + +The image with the Pixelize filter applied to +it + + + + + +The Raindrops filter + +This filter makes it look like raindrops have fallen on the image by distorting +drop-shaped areas with a lens-like effect as one would see when looking +at the image through a real raindrop. Some raindrops will have a fish-eye lens +effect. + + +You can find the filter in the Filter +Artistic menu. +See the section on the +Raindrops dialog +for more information on its settings. + + +The image with the Raindrops filter applied to it + + + + + +The image with the Raindrops filter applied to it + +The image with the Raindrops filter applied to +it + + + + + +The Random Noise filter + +With this filter, random noise can be added to your image. + + +You can find the filter in the Filter +Other menu. +See the section on the +Random Noise dialog +for more information on its settings. + + +The image with the Random Noise filter applied to it + + + + + +The image with the Random Noise filter applied to it + +The image with the Random Noise filter applied to it + + + + + +The Random Pick filter + +This filter distorts the image by interchanging pixels. + + +You can find the filter in the Filter +Other menu. +See the section on the +Random Pick dialog +for more information on its settings. + + +The image with the Random Pick filter applied to it + + + + + +The image with the Random Pick filter applied to it + +The image with the Random Pick filter applied to it + + + + + +The Round Corners filter + +This filter just rounds off the corners of the image. This is done by making +the outside of the rounded corner transparent. + + +You can find the filter in the Filter +Map menu. +See the section on the +Round Corners dialog +for more information on its settings. + + +The image with the Round Corners filter applied to it + + + + + +The image with the Round Corners filter applied to it + +The image with the Round Corners filter applied to +it + + + + + +The Sharpen filter + +This filter sharpens the image. + + +You can find the filter in the Filter +Enhance menu. +This filter is not customizable. + + +The image with the Sharpen filter applied to it + + + + + +The image with the Sharpen filter applied to it + +The image with the Sharpen filter applied to it + + + + + +The Small Tiles filter + +The picture is reduced in size and repeated multiple times. + + +You can find the filter in the Filter +Map menu. +See the section on the +Small Tiles dialog +for more information on its settings. + + +The image with the Small Tiles filter applied to it + + + + + +The image with the Small Tiles filter applied to it + +The image with the Small Tiles filter applied to +it + + + + + +The Sobel filter + +This is a more enhanced edge detection filter. + + +You can find the filter in the Filter +Edge Detection menu. +See the section on the +Sobel dialog +for more information on its settings. + + +The image with the Sobel filter applied to it + + + + + +The image with the Sobel filter applied to it + +The image with the Sobel filter applied to it + + + + + +The Unsharp Mask filter + +This filter sharpens part of your image. (The name unsharp is +historical: parts would be masked off while the rest would be made less sharp.) + + +You can find the filter in the Filter +Enhance menu. +See the section on the +Unsharp Mask dialog +for more information on its settings. + + +The image with the Unsharp Mask filter applied to it + + + + + +The image with the Unsharp Mask filter applied to it + +The image with the Unsharp Mask filter applied to it + + + + + +The Wave filter + +This filter transforms your image into a wave shape. + + +You can find the filter in the Filter +Other menu. +See the section on the +Wave dialog +for more information on its settings. + + +The image with the Wave filter applied to it + + + + + +The image with the Wave filter applied to it + +The image with the Wave filter applied to it + + + + + +The Wavelet Noise Reduction filter + +This filter reduces noise in the image by giving loose pixels a color close to +the surrounding area. This causes small details to be lost, but can enhance the +general view of the image when this is hampered by too many unnecessary details. + + +You can find the filter in the Filter +Enhance menu. +See the section on the +Wavelet Noise Reduction dialog +for more information on its settings. + + +The image with the Wavelet Noise Reduction filter applied to +it + + + + + +The image with the Wavelet Noise Reduction filter applied to it + +The image with the Wavelet Noise Reduction filter applied to +it + + + + + + diff --git a/doc/chalk/using-images.docbook b/doc/chalk/using-images.docbook new file mode 100644 index 00000000..4def5a41 --- /dev/null +++ b/doc/chalk/using-images.docbook @@ -0,0 +1,66 @@ + +Images + + +Creating and modifying images is one of &chalk;'s core functionalities. While +most of the other chapters in this manual focus on the things you can do when +painting or editing, this chapter shows you what you can do with respect to +the images themselves. + + + +Working with files + + +Unless you are doing some quick sketching, working with &chalk; will most +likely involve files. You can open existing images — &chalk; can work +with a large number of file formats, see Image formats — +or start &chalk; to create a new one. When you are done or if you want to +continue at a later time, you can easily save your work. + + + + +Opening existing files +When you start &chalk;, you can open an existing image with +the Open Existing Document button at the lower left of +the opening dialog. You can also use the +FileOpen +menu option (&Ctrl;O). +This will bring up the Open Document dialog in which you +can choose an image to open. The opening dialog and the +File menu also contain a list of the most recently used +files for quick access. + + +Saving your work in progress +With the +FileSave +and FileSave As... +menu options (or their respective shortcuts &Ctrl;S and &Ctrl;&Shift;S), you can save your +work. The former option will save the modifications to the current image, the +latter option will show the Save Document dialog in which +you can give a new file name for the image. If this is the first time you save +the image, Save will ask for a file name as well. + + + +Creating a new image +From the opening dialog (available via the +FileNew +menu option or the &Ctrl;N keys), you can create a +fully custom document or choose one of the image templates. These templates +offer a quick way of creating a new image. See the Starting to know &chalk; tutorial. + + + + + + + + diff --git a/doc/chalk/using-layers.docbook b/doc/chalk/using-layers.docbook new file mode 100644 index 00000000..3ca80291 --- /dev/null +++ b/doc/chalk/using-layers.docbook @@ -0,0 +1,620 @@ + +Layers + + +This chapter gives an overview of how layers work in &chalk;. + + + +Background information on layers + + +Extensive use of &chalk; will almost require you to have some knowledge of +layers. Using layers, you can work on one part of the image without touching +the rest of it, and most effects are best applied on a layer, instead of on +the whole image. Of course, if you do want to apply an effect to an entire +image, &chalk; does offer you that possibility, and there is nothing against +it. + +The idea behind layers is quite simple. As the name suggests, layers lie on +top of each other, and together form the layer stack. The final resulting +image is that what you see when looking through the stack from top to bottom. +This means that usually the upper layers of your image will have more or less +transparency, since you cannot look through a layer which has no transparency. +(&chalk; works with opaqueness instead of transparency. A layer that is 100 +percent opaque is 0 percent transparent, and vice versa.) A layer higher in +the stack gets applied later than one lower in the stack. For example, if your +image contains four layers, numbered from 1 (lowest) to 4 (highest), the +effect that layer number 4 adds to the image, is applied to the result from +applying layers 1 through 3. + +Every image you edit in &chalk; contains layers. When you create a new image, +the layer box (usually shown at the bottom right of your screen, see this section) will contain +one layer. The painting and editing you do is then applied to that layer. Once +you add more layers, you can choose on which part of the image you want to +work, by selecting the respective layer. All further painting is then applied +to that layer, until you select another one. + +Layers are also an excellent way to check whether adding certain effects (or +applying certain image modifications) come out right. Add a layer which +contains what you want to try out, and show or hide it with the eye icon in +the layer box. You can especially profit from this method if you have multiple +effects to check out: show and hide them in any combination, and decide which +you like best. And since you can move the layers around, you can also +experiment with the order in which the effects are applied. + +See the Selections and layers +tutorial for a small hands-on introduction. + + + + +The layer box + +The layer box is the instrument you will use most to work with layers. It +gives an overview of the layers that are present in your image, and using it +you can manage layers by adding, removing, reordering or modifying them. + +The layer box consists of three parts. The middle part gives an overview of the +layers in the image. At the top, you can set some properties for the current +layer. At the bottom, a couple of layer management options can be found. The +next sections describe these three parts in more detail. + + + +Layer overview + +This part shows you which layers are present in your image. In a tree-like +structure, the layer group hierarchy is shown: layers that are contained within +a layer group are displayed a bit to the right to indicate their belonging to +that group. + +For each layer, a thumbnail preview and its name are shown. The layer name +is preceded by a folder icon if it is a group layer. Furthermore, two +indicators are present: the eye icon shows whether the layer is currently +visible (an open eye indicates that the layer is visible, a closed eye +indicates that it is not), and the lock icon shows whether the layer is +locked. No changes can be made to a locked layer. + +When you click on a layer's eye icon, its visibility is switched from on to +off or vice versa. Clicking on the lock icon enables or disables editing of +that layer. You can click on the name of the current layer to rename it. +Note that to rename a layer, it has to be the current one. You do not need to +activate a layer in order to make it (in)visible or (un)locked via the eye and +lock icons, respectively: these work directly. + +Doubleclick on a layer entry in the list to open the Layer +Properties dialog. This dialog shows a layer's colorspace and +profile. You can also change its name, opacity and composite mode here. + + + + +Layer options + +The top of the layer box contains two controls for setting properties of the +currently selected layer. The list box at the left allows you to quickly set +the layer's composite mode. The spin field and slider at the right can be used +to change the layer's opacity. + +At the bottom of the layer box, there are five buttons. From left to right, +these are as follows. The New Layer icon brings up a +submenu from which you can choose which type of layer you want to add. This +menu can also be opened by clicking with the &RMB; on the layer box. The +Move Layer Down and Move Layer Up +buttons move the current layer one level down and up, respectively, within the +current layer group. If the layer is already the last or first within the +layer group, trying to move it further will move it out of the layer group. +The Layer Properties button opens the Layer +Properties dialog, just as when you would have doubleclicked +on the layer. The Delete Layer button deletes the +current layer. + + + + + + +Working with layers + + +Because layers are quite important when extensively using &chalk;, you can +perform a lot of operations on them. These are all available via the Layer menu. Some of +the possibilities: + + + +Add, remove, and duplicate layers; +Create and edit layer masks; +Flip, rotate, scale and shear layers; +Convert layers between colorspaces; +Save layers as images; +View layer histograms. + + + + + +Adjustment Layers + +Adjustment layers are layers that consist of a filter and an optional +selection. The filter effect is applied to the composite image of all +layers under the adjustment layer in the current layer group. The big +thing is, adjustment layers apply these effects non-destructively. The +original image data is not modified. + +Almost all &chalk; filters are suitable for use in adjustment +layers -- even filters that would downgrade the image quality. For instance, +the raindrops filter converts to 8-bit RGB before working its magic. If you +would try to use this filter directly on a 16-bit L*a*b* layer, &chalk; would +warn you about the conversion to RGB and back again this filter would cause. +Not so with adjustment layers: the original data isn't touched, so applying +the filter is safe. + +What about the colorspace of an adjustment layer then? In order to examine +this issue, you need to know what happens when &chalk; renders an adjustment +layer. + + + +Adjustment layers and selections + +If the currently active layer has an active selection, then that selection +will be copied and used as a mask for the adjustment layer. If there is no +active selection, then there will be no mask and the adjustment will apply to +the entire extent of the layers under the adjustment layer in the current +group. There is no way of adding a mask to an existing +adjustment layer. + +If there is a mask in the adjustment layer, you can edit the mask using the +ordinary painting tools and painting operations. + + + + + +A note on projections + + +&chalk; composites the layers bottom to top, within each layer group. The +aggregate -- or the projection as it is also called -- is then filtered by +the adjustment layer. If there are layers on top of the adjustment layer, +those are composited onto the projection. &chalk; converts all layer data before +compositing, so if the bottom-most layer in an image is grayscale, all layers +are converted to grayscale before compositing -- and that means that the +adjustment layer projection will be grayscale, too. + +With this knowledge you'll understand why &chalk; can often offer better +performance working with layers on top of an adjustment layer which is on top +of a complex layer structure: &chalk; uses the projection and doesn't even look +anymore at the layers under the adjustment layer. Unless, of course, you +change one of them. + + + + + + +Compositing modes + + +Layers can be composited in various ways, each yielding a different effect. +This section describes the available compositing modes. Each description is +accompanied by an example: on top of an original image (see below), a rainbow +gradient is added. + + + + +The original image + + + + + +The original image + +The original image + + + + + +<guilabel>Normal</guilabel> + + +The Normal mode does nothing special. It adds the layer +to the image, and if no other special effects like opacity are changed, the +underlying layers will only be visible at places where the new layer is +itself transparent. + + + + +The gradient applied with the Normal compositing +mode + + + + + +The gradient applied with the Normal compositing +mode + +The gradient applied with the Normal compositing +mode + + + + + + + +<guilabel>Multiply</guilabel> + + +The Multiply mode blends the two layers so that the +bottom layer gets colorized by the new layer. The resulting +image is generally quite dark. + + + + +The gradient applied with the Multiply compositing +mode + + + + + +The gradient applied with the Multiply compositing +mode + +The gradient applied with the Multiply compositing +mode + + + + + + + +<guilabel>Burn</guilabel>, <guilabel>Dodge</guilabel>, +<guilabel>Divide</guilabel> and <guilabel>Screen</guilabel> + + +The Burn, Dodge, +Divide and Screen modes all add an +extra burning effect by following contours instead of using +straight lines. In addition, Burn and +Divide use the inverted colors instead of the actual +colors of the composited layer. + + + + +The gradient applied with the Burn compositing +mode + + + + + +The gradient applied with the Burn compositing +mode + +The gradient applied with the Burn compositing +mode + + + + + + +The gradient applied with the Dodge compositing +mode + + + + + +The gradient applied with the Dodge compositing +mode + +The gradient applied with the Dodge compositing +mode + + + + + + +The gradient applied with the Divide compositing +mode + + + + + +The gradient applied with the Divide compositing +mode + +The gradient applied with the Divide compositing +mode + + + + + + +The gradient applied with the Screen compositing +mode + + + + + +The gradient applied with the Screen compositing +mode + +The gradient applied with the Screen compositing +mode + + + + + + + +<guilabel>Overlay</guilabel> + + +Like Multiply, the Overlay mode +colorizes the underlying layer. The resulting image is about as light as +the original layer. + + + + +The gradient applied with the Overlay compositing +mode + + + + + +The gradient applied with the Overlay compositing +mode + +The gradient applied with the Overlay compositing +mode + + + + + + + +<guilabel>Darken</guilabel> + + +The Darken mode darkens the underlying layer while +colorizing it to match the colors in the composited layer. + + + + +The gradient applied with the Darken compositing +mode + + + + + +The gradient applied with the Darken compositing +mode + +The gradient applied with the Darken compositing +mode + + + + + + + +<guilabel>Lighten</guilabel> + + +The Lighten mode lightens the underlying layer while +colorizing it to match the colors in the composited layer. + + + + +The gradient applied with the Lighten compositing +mode + + + + + +The gradient applied with the Lighten compositing +mode + +The gradient applied with the Lighten compositing +mode + + + + + + + +<guilabel>Hue</guilabel>, <guilabel>Saturation</guilabel> and +<guilabel>Value</guilabel> + + +The Hue, Saturation and +Value modes respectively apply the hue, saturation and +value components of the composited layer to the underlying layer. + + + + +The gradient applied with the Hue compositing +mode + + + + + +The gradient applied with the Hue compositing +mode + +The gradient applied with the Hue compositing +mode + + + + + + +The gradient applied with the Saturation compositing +mode + + + + + +The gradient applied with the Saturation compositing +mode + +The gradient applied with the Saturation compositing +mode + + + + + + +The gradient applied with the Value compositing +mode + + + + + +The gradient applied with the Value compositing +mode + +The gradient applied with the Value compositing +mode + + + + + + + +<guilabel>Color</guilabel> + + +The Color mode colorizes the underlying layer, yielding +very strong colors. + + + + +The gradient applied with the Color compositing +mode + + + + + +The gradient applied with the Color compositing +mode + +The gradient applied with the Color compositing +mode + + + + + + + + + +Layer Masks + + +Basically, a layer mask is a mask that you place on your paint layer. This +will literally mask areas of the layer, so that the content underneath shows +through. You can paint on it with greyscale colors: the more black the color, +the less the layer under it will shine through, the more white, the less the +layer under it will be shown. So complete white will let nothing through, +complete black will let everything through. Basically, it is a bit like +selecting a piece of your image, and then cutting it, so that the selected +bits go away. So what is the use for a mask here? The big advantage is that it +is non-destructive: if you decide that you masked out the wrong part of your +layer, you can easily remove the mask and start anew, something a lot harder +(not to say near impossible, especially in between sessions) with regular +selection-cutting. + +So, how to create a mask? There are 2 ways: + + + + +Start from scratch. +LayerMaskCreate +Mask. The mask starts with everything being +retained, that is, a complete white mask. Basically you will not see any +changes as long as you do not paint on it. + + +Start from the current selection. +LayerMaskMask +From Selection. The selectedness will be converted +to whiteness. This means that fully selected area will be visible, fully +unselected areas will be invisible, and the rest will be partially visible, +depending on how much the area was selected. + + + + +Editing the mask + + +First, make sure you are editing the mask, not the layer, by making sure +LayerMaskEdit +Mask is checked. (This is checked by default.) Then +you can paint on the layer just like before, only now you are +painting on the mask, instead of on the layer itself. To stop painting on the +mask, you can uncheck the Edit Mask checkbox. There's +also the option to show the mask, through checking +LayerMaskShow +Mask. (This is not checked by +default). This option will render the entire layer as a visual representation +of the mask in greyscale, instead of the actual layer. This can be handy to +see where your mask is, but it might be not as handy when you want to edit it, +since you cannot look at the actual layer. + +Other actions: you can also remove the mask if you are not satisfied with it, +and want to start over again, or just want to remove it, with +LayerMaskRemove +Mask. You can also apply the mask, +meaning that the mask will be made permanently. This means that the mask is +removed, but that its effect of transparency will be committed to the layer. + + + + + + diff --git a/doc/chalk/using-selections-1.png b/doc/chalk/using-selections-1.png new file mode 100644 index 00000000..3efc76bb Binary files /dev/null and b/doc/chalk/using-selections-1.png differ diff --git a/doc/chalk/using-selections-2.png b/doc/chalk/using-selections-2.png new file mode 100644 index 00000000..f2e3febc Binary files /dev/null and b/doc/chalk/using-selections-2.png differ diff --git a/doc/chalk/using-selections-3.png b/doc/chalk/using-selections-3.png new file mode 100644 index 00000000..059d2983 Binary files /dev/null and b/doc/chalk/using-selections-3.png differ diff --git a/doc/chalk/using-selections-4.png b/doc/chalk/using-selections-4.png new file mode 100644 index 00000000..0cfec2cb Binary files /dev/null and b/doc/chalk/using-selections-4.png differ diff --git a/doc/chalk/using-selections-5.png b/doc/chalk/using-selections-5.png new file mode 100644 index 00000000..c220306d Binary files /dev/null and b/doc/chalk/using-selections-5.png differ diff --git a/doc/chalk/using-selections-6.png b/doc/chalk/using-selections-6.png new file mode 100644 index 00000000..7c99accd Binary files /dev/null and b/doc/chalk/using-selections-6.png differ diff --git a/doc/chalk/using-selections.docbook b/doc/chalk/using-selections.docbook new file mode 100644 index 00000000..675088ec --- /dev/null +++ b/doc/chalk/using-selections.docbook @@ -0,0 +1,200 @@ + +Selections + + +This chapter gives a short introduction on selections. + +You can select a part of an image masking off the rest. This is handy when +you want to cut, copy or just modify a part of the image without affecting +the rest. For processing selected objects &chalk; applies a mask. Each pixel of +the selection is processed based on a value of its mask, or the level +of the selection, that can range from 0 (unselected) to 255 +(selected). Yes, that is right, you can have fractionally selected pixels. +And by working on individual pixels you can paint your selection. + +The selection mask is visualized with unselected pixels having a blueish +tint, and selected pixels looking like normal. Fractionally selected pixels +are shown as something in between. Additionally a red border is drawn around +the selected areas. Fractionally selected pixels are inside the border, so +even inside the red border you can possibly see the blueish tint on some pixels. + + + +Making a selection + +A whole range of tools exist to make selections. From rectangles, ellipses +and freehand to the more exotic like color range select. When you make +several selections they add up. So a rectangle select followed by an +ellipse select select both areas. Later on, you can subtract areas from +the selection by using, for example, the Erase Selection tool. + +To get back to normal (no active selection), choose +SelectDeselect +. To select all pixels, choose +SelectSelect All +. + +You may think that those two actions give the same result, but it +is much more efficient to have no active selection than to have selected +everything. + +After having deselected you can bring your selection back by choosing +SelectReselect +. + + + + +Painting your selection + +As said above you can essentially paint your selection, and just like +when you paint normally you can choose to paint your selection freehand or +guided with rectangles, ellipses, &etc;. You also have the choice of different +paint tools like pen, brush, airbrush, &etc;. Choose the guide tool, and the +paint tool in the toolbox, and go ahead and paint your +selection. + +The guide tools work just like you may be used to from other applications. So +holding down shift while drawing a rectangle or an ellipse still forces them to +be a square or a circle respectively. + + + +Painting a selection + + + + + +Painting a selection + +Painting a selection + + + +Painting a selection + + + + + +Painting a selection + +Painting a selection + + + + + + +Unselecting + +All the selection paint tools have an option to add or subtract from the +selection. This means that you can use all your familiar tools to both select +and unselect. There is also a true selection eraser among the selection paint +tools. + + + +Unselecting + + + + + +Unselecting + +Unselecting + + + + + +Making a new selection + +When you want to make a new selection, replacing the currently active one, you +first need to deselect the active selection. Choose +SelectDeselect +. + + + + +Selecting a contiguous area (magic wand) + +To follow the analogy of painting your selection &chalk; also provides an +equivalent to filling a contiguous area. Some paint applications call this +selection tool the magic wand tool. What it does is select the nearby +pixels as long as they have nearly the same color as the pixel you click +on. The selection floods out from the point you click on. In the fuzziness +option you can set how different the colors are allowed to be before the +flooding stops. + + + +Before the magic wand + + + + + +Before the magic wand + +Before the magic wand + + + + +A magic wand selection + + + + + +A magic wand selection + +A magic wand selection + + + + + + +Selecting similar colors + +The Select Similar tool lets you pick a pixel and then select all pixels that +have a similar color. Picking a color in one corner of the image may select a +pixel in another corner if they have similar color. +With the Fuzziness option you can set how similar the colors must be to become +selected. + + + +Selecting similar colors + + + + + +Selecting similar colors + +Selecting similar colors + + + + + +Inverting the selection + +In some cases it is easier to specify your selection the other way around. That +is, first you select the parts that ultimately should not be selected and then +then you choose +SelectInvert +. +What invert does, is that for every pixel it flips the selection level so to +speak, by setting it to 256 minus the current selection level. Thus what was +selected becomes unselected and vice versa. + + + + diff --git a/doc/chalk/using-views.docbook b/doc/chalk/using-views.docbook new file mode 100644 index 00000000..e9d184a9 --- /dev/null +++ b/doc/chalk/using-views.docbook @@ -0,0 +1,167 @@ + +Views + + +One of the most important things you need to know when working with a painting +or image editing application, is how to adapt the view of your image to your +(changing) needs. This chapter describes the various possibilities &chalk; +offers. + + + +Zooming + + +By zooming, you can view your images at various levels of detail. Zooming out +will show a larger part of the image, but with less detail. &chalk; offers a +couple of options that affect which part of the image is shown: + + + + +Zooming in +Zooming in allows you to see more details, but you will only +see a smaller part of the image. You can zoom in by choosing the +ViewZoom +in menu item, by clicking the + + Zoom in button on the +toolbar, or by pressing the &Ctrl;+ keys. +You can zoom in up to 1600% (a 16:1 ratio) via a number of fixed zoom levels. + + + +Zooming out +Zooming out allows you to see a larger part of the image while +losing some detail. Zooming out can be done by choosing the +ViewZoom +out menu item, by clicking the + + Zoom out button on the +toolbar, or by pressing the &Ctrl;- keys. +You can zoom out up to 0.2% (a 1:500 ratio) via a number of fixed zoom levels. + + + +Going back to 100% +As viewing your image at its real size is quite handy at +times, you can do so via the +ViewActual +pixels menu item or by pressing &Ctrl;0. + + + +Zooming in and out from the Overview +tab +The Overview tab of the control box +(usually found at the right hand side of the &chalk; window) also allows you +to change the zoom level by using the slider or the spinbox. Slightly +different zoom levels are available here, so if zooming in or out as described +above does not produce a view you want, you can try using this option. The +1:1 button offers another way of getting back to a 100% +zoom. + + +Special zooms +There are two more special ways of zooming. The +ViewFit to +Page menu item zooms your image such that it is +as large as possible while remaining entirely visible. The +ViewFull Screen +Mode menu item (pressing &Ctrl;&Shift;F will also activate +this mode) enlarges the &chalk; window to fill your entire screen, removing +the title bar as well. Although this is not a real way of +zooming, it can help you by showing just that little bit more of your +image. + + + + + + + +Working with views + + +Apart from changing the zoom level of your view, you can also open different +views for the same image. This way, you can for example look at two different +parts of your image that would not fit on your screen together otherwise. + + + + +New view windows +You can open a new &chalk; window for your image by choosing +ViewNew +View Both windows are independent from each other +(so you can select different tools, view different parts of your image, +&etc;), but changes you make to the image in one window are immediately +visible in the other. To close a window, use the normal window closing button. +There is also an option ViewClose +All Views, which closes all newly created views and +leaves only the original window open. + + +Splitting views +You can also split a window into two views. Like a new window, +one view of a split window has its own settings for brushes, zoom levels and +the like, but both views are shown in the same window. To split your window, +choose ViewSplit +View. The viewing area of the &chalk; window will +then be divided into two halves. You can switch between horizontal and +vertical division with the +ViewSplitter +Orientation menu, and get back to one view by +choosing ViewRemove +View. + + + + + + + +Miscellaneous view options + + +&chalk; also offers two options that can help you with knowing where you are. + + + + +Rulers +You can have &chalk; show rulers along the sides of your +image, indicating x and y coordinates. To do so, choose +ViewShow +Rulers or press &Ctrl;R. The rulers will +automatically adapt to your zoom level to show a proper amount of +subdivisions. To remove the rulers, choose the same menu option (now called +Hide Rulers) or press &Ctrl;R again. + + +Grid +In order to see grid lines, choose +ViewShow +Grid. You can set the distance between grid lines +with ViewGrid +Spacing and you can choose different colours for the +lines in the SettingsConfigure +&chalk;... dialog (see the Grid section of the Settings +chapter). + + + + + + + + diff --git a/doc/kchart/index.docbook b/doc/kchart/index.docbook index 8fdfac40..3d9414f7 100644 --- a/doc/kchart/index.docbook +++ b/doc/kchart/index.docbook @@ -1,6 +1,7 @@ + chalk'> @@ -764,11 +765,11 @@ menu and quit &kchart; with -Exporting to Graphic Formats: SVG, PNG, JPG, &krita;, &karbon14;, Gimp and +<title>Exporting to Graphic Formats: SVG, PNG, JPG, &chalk;, &karbon14;, Gimp and more For further processing, the chart can also be exported as a graphics file. -Many formats are available. Using either PNG, SVG, JPG or &krita; will likely +Many formats are available. Using either PNG, SVG, JPG or &chalk; will likely produce the best result. @@ -971,7 +972,7 @@ The original document will not be modified. Saves a document to any supported format. The original document will not be modified. You can also choose -among many image formats like PNG, SVG, &krita;, Gimp or JPG. +among many image formats like PNG, SVG, &chalk;, Gimp or JPG. diff --git a/doc/kivio/working.docbook b/doc/kivio/working.docbook index 809b8aeb..eb883b67 100644 --- a/doc/kivio/working.docbook +++ b/doc/kivio/working.docbook @@ -83,7 +83,7 @@ SGI Image (RGB) (.rgb) X PixMap Image (.xpm) JPEG 2000 Image (.jp2) -Krita Document (.kra) +Chalk Document (.kra) Adobe Illustrator Document (.ai) TIFF Image (.tiff) ILM EXR Image (.exr) diff --git a/doc/koffice/index.docbook b/doc/koffice/index.docbook index 4c194a7f..48b90f08 100644 --- a/doc/koffice/index.docbook +++ b/doc/koffice/index.docbook @@ -1,6 +1,7 @@ + chalk'> @@ -60,7 +61,7 @@ &kpresenter; (screen and slide presentations) &kivio; (a flowchart application) Karbon14 (a vector drawing application) -&krita; (a pixel based drawing application) +&chalk; (a pixel based drawing application) &kugar; (a tool for generating business quality reports) Kexi (an integrated environment for managing data) &kchart; (a charts/graphs generation application) diff --git a/doc/koshell/index.docbook b/doc/koshell/index.docbook index dc43b5d9..364c925d 100644 --- a/doc/koshell/index.docbook +++ b/doc/koshell/index.docbook @@ -1,6 +1,7 @@ + chalk'> @@ -57,7 +58,7 @@ Please respect the format of the date (DD/MM/YYYY) and of the version KChart KPlato Kexi -Krita +Chalk Kivio Kugar KFormula @@ -85,7 +86,7 @@ Word-processor/Desktop Publishing Program.) Kexi (An integrated environment for databases.) &kivio; (A flowchart creator.) Karbon14 (A vector drawing program.) -&krita; (A pixel based drawing program.) +&chalk; (A pixel based drawing program.) &kchart; (A chart and graph creator.) &kformula; (A formula editor.) &kugar; (A report generation tool.) diff --git a/doc/kword/index.docbook b/doc/kword/index.docbook index 3a07e5c8..0c71b947 100644 --- a/doc/kword/index.docbook +++ b/doc/kword/index.docbook @@ -1,6 +1,7 @@ + chalk'> @@ -117,7 +118,7 @@ Environment. Other applications in &koffice; include: &kpresenter; (A presentation creator.) &karbon14; (A vector drawing program.) &kivio; (A flowchart creator) -&krita; (A pixel based drawing program.) +&chalk; (A pixel based drawing program.) &kugar; (A report generation tool.) &kexi; (An integrated environment for databases.) &kchart; (A chart and graph creator.) diff --git a/filters/Makefile.am b/filters/Makefile.am index 4e18acc7..e8473741 100644 --- a/filters/Makefile.am +++ b/filters/Makefile.am @@ -32,7 +32,7 @@ KUGARDIR = kugar endif if compile_filter_KRITA -KRITADIR = krita +KRITADIR = chalk endif if compile_filter_KIVIO diff --git a/filters/chalk/Makefile.am b/filters/chalk/Makefile.am new file mode 100644 index 00000000..0d8732eb --- /dev/null +++ b/filters/chalk/Makefile.am @@ -0,0 +1,34 @@ +if have_openexr +OPENEXR_SUBDIR=openexr +endif + +if include_imagemagick_filter +IMAGEMAGICK_SUBDIR=magick +endif + +if include_graphicsmagick_filter +GRAPHICSMAGICK_SUBDIR=gmagick +endif + +if have_png +PNG_SUBDIR=png +endif + +if include_jpeg_filter +JPEG_SUBDIR=jpeg +endif + +if include_tiff_filter +TIFF_SUBDIR=tiff +endif + +if have_exif +LIBKISEXIF=libkisexif +endif + +if include_PDF +PDF_SUBDIR=pdf +endif + +SUBDIRS = $(IMAGEMAGICK_SUBDIR) $(OPENEXR_SUBDIR) $(PNG_SUBDIR) $(LIBKISEXIF) \ + $(JPEG_SUBDIR) $(TIFF_SUBDIR) raw $(PDF_SUBDIR) $(GRAPHICSMAGICK_SUBDIR) diff --git a/filters/chalk/configure.in.in b/filters/chalk/configure.in.in new file mode 100644 index 00000000..6eb8d91e --- /dev/null +++ b/filters/chalk/configure.in.in @@ -0,0 +1,66 @@ +# Check if the tiff lib is available +AC_FIND_TIFF +AM_CONDITIONAL(have_tiff, test -n "$LIBTIFF") + +AC_FIND_PNG +AM_CONDITIONAL(have_png, test -n "$LIBPNG") + +AC_FIND_JPEG +AM_CONDITIONAL(have_jpeg, test -n "$LIBJPEG") + +#--------------------------------------------------------- +# libexif detection +# taken from libkexif's configure.in.in +#--------------------------------------------------------- + +LIBEXIF=no + +#PKG_CHECK_MODULES(LIBEXIF, libexif >= 0.5.7, , +# [ AC_MSG_WARN([libexif >= 0.5.7 not found.]) +# LIBEXIF=yes ]) + + +#PKG_CHECK_MODULES(LIBEXIF06, libexif >= 0.6.9, +# AC_DEFINE(HAVE_EXIF06,1,[check for libexif > 0.6]), +# AC_MSG_WARN([Using old version of libexif.])) + +PKG_CHECK_MODULES(LIBEXIF, libexif >= 0.6.12 , , + [ AC_MSG_WARN([libexif >= 0.6.12 not found.]) + LIBEXIF=yes ]) + +AC_SUBST(LIBEXIF_LIBS) +AC_SUBST(LIBEXIF_CFLAGS) + +#--------------------------------------------------------- +# libexif detection +#--------------------------------------------------------- +AC_MSG_CHECKING([if C++ program with exif can be compiled]) +AC_LANG_SAVE +AC_LANG_CPLUSPLUS +ac_save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $LIBEXIF_CFLAGS" +AC_CACHE_VAL(exif_build, +[ + AC_TRY_COMPILE([ + extern "C" { +#include +#include +} + ],[ + ExifLoader *l = exif_loader_new (); + exif_loader_write_file (l,"kikoo"); + return 0; + ], exif_build=yes, + exif_build=no) +]) +AC_MSG_RESULT($exif_build) +if test "$exif_build" = "no"; then + LIBEXIF="" +fi +CXXFLAGS="$ac_save_CXXFLAGS" +AC_LANG_RESTORE + + +AM_CONDITIONAL(have_exif, test -n "$LIBEXIF") +AM_CONDITIONAL(include_jpeg_filter, test -n "$LIBJPEG" -a -n "$LIBEXIF") +AM_CONDITIONAL(include_tiff_filter, test -n "$LIBTIFF" -a -n "$LIBEXIF") diff --git a/filters/chalk/gmagick/Makefile.am b/filters/chalk/gmagick/Makefile.am new file mode 100644 index 00000000..4d74db2a --- /dev/null +++ b/filters/chalk/gmagick/Makefile.am @@ -0,0 +1,44 @@ +kde_module_LTLIBRARIES = libchalkgmagickimport.la libchalkgmagickexport.la + +libchalkgmagickexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBGMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBGMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkgmagickexport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBGMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +libchalkgmagickimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBGMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBGMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkgmagickimport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBGMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) $(LIBGMAGICK_CPPFLAGS) \ + $(all_includes) + +service_DATA = chalk_magick_import.desktop chalk_magick_export.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_magick.desktop +kdelnkdir = $(kde_appsdir)/.hidden + +libchalkgmagickimport_la_SOURCES = magickimport.cpp kis_image_magick_converter.cc +libchalkgmagickexport_la_SOURCES = magickexport.cpp kis_image_magick_converter.cc + +METASOURCES = AUTO + + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/filters/chalk/gmagick/chalk_magick.desktop b/filters/chalk/gmagick/chalk_magick.desktop new file mode 100644 index 00000000..171834ef --- /dev/null +++ b/filters/chalk/gmagick/chalk_magick.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +MimeType=image/x-xcf-gimp;image/gif;image/cgm;image/x-bmp;image/x-ico;image/x-pcx;image/x-portable-pixmap;image/x-targa;image/x-xbm;image/x-xcf;image/x-xpm;image/x-vnd.adobe.photoshop;image/x-rgb +Type=Application +Icon=chalk +Categories= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi diff --git a/filters/chalk/gmagick/chalk_magick_export.desktop b/filters/chalk/gmagick/chalk_magick_export.desktop new file mode 100644 index 00000000..5021233a --- /dev/null +++ b/filters/chalk/gmagick/chalk_magick_export.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Name=Chalk Magick Export Filter +Name[bg]=Филтър за експортиране от Chalk в Magick +Name[br]=Sil ezporzh Magick evit Chalk +Name[ca]=Filtre d'exportació Magick per a Chalk +Name[cy]=Hidl Allforio Magick Chalk +Name[da]=Chalk Magick-eksportfilter +Name[de]=Chalk Magick-Exportfilter +Name[el]=Φίλτρο εξαγωγής Magick του Chalk +Name[eo]=Chalk Magick-eksportfiltrilo +Name[es]=Filtro de exportación a Magick de Chalk +Name[et]=Chalk Magick'i ekspordifilter +Name[eu]=Chalk-ren Magick esportaziorako iragazkia +Name[fa]=پالایۀ صادرات Chalk Magick +Name[fi]=Chalk Magick -vientisuodin +Name[fr]=Filtre d'exportation Magick de Chalk +Name[fy]=Chalk Magick Eksportfilter +Name[ga]=Scagaire Easpórtála Magick Chalk +Name[gl]=Filtro de Exportación de Magick para Chalk +Name[he]=מסנן יצוא מ־Chalk ל־Magick +Name[hr]=Chalk Magick filtar izvoza +Name[hu]=Chalk Magick exportszűrő +Name[is]=Chalk Magick útflutningssía +Name[it]=Filtro di esportazione Magick per Chalk +Name[ja]=Chalk Magick エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ Magick សម្រាប់ Chalk +Name[lt]=Chalk Magick eksportavimo filtras +Name[lv]=Chalk Magick eksporta filtrs +Name[ms]=Penapis Eksport Chalk Magick +Name[nb]=Magick-eksportfilter for Chalk +Name[nds]=Magick-Exportfilter för Chalk +Name[ne]=क्रिता म्याजिक निर्यात फिल्टर +Name[nl]=Chalk Magick Exportfilter +Name[nn]=Magick-eksportfilter for Chalk +Name[pl]=Filtr eksportu do formatu Magick z Chalk +Name[pt]=Filtro de Exportação de Magick para o Chalk +Name[pt_BR]=Filtro de exportação Magick para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в Magick +Name[se]=Chalk Magick-olggosfievrridansilli +Name[sk]=Magick filter pre export do Chalk +Name[sl]=Izvozni filter Magick za Krito +Name[sr]=Chalk-ин филтер за извоз у Magick +Name[sr@Latn]=Chalk-in filter za izvoz u Magick +Name[sv]=Chalk Magick-exportfilter +Name[uk]=Фільтр експорту Magick для Chalk +Name[uz]=Chalk Magick eksport filteri +Name[uz@cyrillic]=Chalk Magick экспорт филтери +Name[zh_CN]=Chalk Magick 导出过滤器 +Name[zh_TW]=Chalk Magick 匯出過濾程式 +X-KDE-Export=image/gif,image/cgm,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xpm,image/x-rgb,image/x-eps +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Import=application/x-chalk +X-KDE-Weight=1 +X-KDE-Library=libchalkgmagickexport diff --git a/filters/chalk/gmagick/chalk_magick_import.desktop b/filters/chalk/gmagick/chalk_magick_import.desktop new file mode 100644 index 00000000..c487f0c4 --- /dev/null +++ b/filters/chalk/gmagick/chalk_magick_import.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Type=Service +Name=Chalk Magick Import Filter +Name[bg]=Филтър за импортиране от Magick в Chalk +Name[br]=Sil enporzh Magick evit Chalk +Name[ca]=Filtre d'importació Magick per a Chalk +Name[cs]=Importní filtr formátu Magick pro Kritu +Name[cy]=Hidl Mewnforio Chalk Magick +Name[da]=Chalk Magick-importfilter +Name[de]=Chalk Magick-Importfilter +Name[el]=Φίλτρο εισαγωγής Magick του Chalk +Name[eo]=Chalk Magick-importfiltrilo +Name[es]=Filtro de importación a Magick de Chalk +Name[et]=Chalk Magick'i impordifilter +Name[eu]=Chalk-ren Magick inportaziorako iragazkia +Name[fa]=پالایۀ واردات Chalk Magick +Name[fi]=Chalk Magick-tuontisuodin +Name[fr]=Filtre d'importation Magick de Chalk +Name[fy]=Chalk Magick Ymportfilter +Name[ga]=Scagaire Iompórtála Magick Chalk +Name[gl]=Filtro de Importación de Magick para Chalk +Name[he]=מסנן יבוא מ־Magick ל־Chalk +Name[hi]=के-रीता मैजिक आयात फ़िल्टर +Name[hr]=Chalk Magick filtar uvoza +Name[hu]=Chalk Magick importszűrő +Name[is]=Chalk Magick innflutningssía +Name[it]=Filtro di importazione Magick per Chalk +Name[ja]=Chalk Magick インポートフィルタ +Name[km]=តម្រង​នាំចូល Magick សម្រាប់ Chalk +Name[lo]= ຕົວຕອງການນຳເຂົ້າ WML ຂອງເອກະສານຂໍ້ຄວາມ K +Name[lt]=Chalk Magick importavimo filtras +Name[lv]=Chalk Magick importa filtrs +Name[ms]=Penapis Import Chalk Magick +Name[nb]=Magick-importfilter for Chalk +Name[nds]=Magick-Importfilter för Chalk +Name[ne]=क्रिता म्याजिक आयात फिल्टर +Name[nl]=Chalk Magick Importfilter +Name[nn]=Magick-importfilter for Chalk +Name[pl]=Filtr importu formatu Magick do Chalk +Name[pt]=Filtro de Importação de Magick para o Chalk +Name[pt_BR]=Filtro de importação Magick para o Chalk +Name[ru]=Фильтр импорта рисунков Magick в Chalk +Name[se]=Chalk Magick-sisafievrridansilli +Name[sk]=Magick filter pre import do Chalk +Name[sl]=Uvozni filter Magick za Krito +Name[sr]=Chalk-ин филтер за увоз из Magick-а +Name[sr@Latn]=Chalk-in filter za uvoz iz Magick-a +Name[sv]=Chalk Magick-importfilter +Name[ta]=Chalk மாயk இறக்குமதி வடிகட்டி +Name[tg]=Филтри Воридоти Chalk Magick +Name[tr]=Chalk Magick Alma Filtresi +Name[uk]=Фільтр імпорту Magick для Chalk +Name[uz]=Chalk Magick import filteri +Name[uz@cyrillic]=Chalk Magick импорт филтери +Name[zh_CN]=Chalk Magick 导入过滤器 +Name[zh_TW]=Chalk Magick 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-xcf-gimp,image/gif,image/cgm,image/x-bmp,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xcf,image/x-xpm,image/x-vnd.adobe.photoshop,image/x-rgb,image/x-eps +X-KDE-Weight=1 +X-KDE-Library=libchalkgmagickimport +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/gmagick/configure.in.bot b/filters/chalk/gmagick/configure.in.bot new file mode 100644 index 00000000..0f05276f --- /dev/null +++ b/filters/chalk/gmagick/configure.in.bot @@ -0,0 +1,23 @@ +if test -z "$LIBGMAGICK_LIBS" -a -z "$LIBMAGICK_LIBS"; then + echo "" + echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export" + echo "filter will not be compiled. You can download GraphicsMagick from" + echo "http://www.graphicsmagick.org/. The GraphicsMagick filter allows chalk to" + echo "read and write XCF, PSD, GIF, BMP, and many other image formats." + echo "" + echo "If you have problems compiling GraphicsMagick, please try configuring it using" + echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk." + echo "" + all_tests=bad + AC_DEFINE([include_imagemagick_filter],"",[don't use magick filter]) +fi + +if test -z "$LIBGMAGICK_LIBS" -a ! -z "$LIBMAGICK_LIBS"; then + + echo "" + echo "You're missing GraphicsMagick (>=1.1.7). chalk's GraphicsMagick import/export" + echo "filter will not be compiled. But ImageMagick was found, which mean that chalk" + echo "will be able to read and write XCF, PSD, GIF, BMP, and many other image formats." + echo "But the ImageMagick filter is deprecated and we strongly advise you to install" + echo "GraphicsMagick either from your distribution or from http://www.graphicsmagick.org/" +fi diff --git a/filters/chalk/gmagick/kis_image_magick_converter.cc b/filters/chalk/gmagick/kis_image_magick_converter.cc new file mode 100644 index 00000000..a0545569 --- /dev/null +++ b/filters/chalk/gmagick/kis_image_magick_converter.cc @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2002 Patrick Julien + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_undo_adapter.h" +#include "kis_image_magick_converter.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_iterators_pixel.h" +#include "kis_colorspace.h" +#include "kis_profile.h" +#include "kis_annotation.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_device.h" + +#include "../../../config.h" + +namespace { + + const TQ_UINT8 PIXEL_BLUE = 0; + const TQ_UINT8 PIXEL_GREEN = 1; + const TQ_UINT8 PIXEL_RED = 2; + const TQ_UINT8 PIXEL_ALPHA = 3; + + static const TQ_UINT8 PIXEL_CYAN = 0; + static const TQ_UINT8 PIXEL_MAGENTA = 1; + static const TQ_UINT8 PIXEL_YELLOW = 2; + static const TQ_UINT8 PIXEL_BLACK = 3; + static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4; + + static const TQ_UINT8 PIXEL_GRAY = 0; + static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1; + + /** + * Make this more flexible -- although... ImageMagick + * isn't that flexible either. + */ + TQString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8) + { + + if (type == GRAYColorspace) { + if (imageDepth == 8) + return "GRAYA"; + else if ( imageDepth == 16 ) + return "GRAYA16" ; + } + else if (type == CMYKColorspace) { + if (imageDepth == 8) + return "CMYK"; + else if ( imageDepth == 16 ) { + return "CMYK16"; + } + } + else if (type == LABColorspace) { + kdDebug(41008) << "Lab!\n"; + return "LABA"; + } + else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) { + if (imageDepth == 8) + return "RGBA"; + else if (imageDepth == 16) + return "RGBA16"; + } + return ""; + + } + + ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs ) + { + if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace; + if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace; + if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace; + if ( cs->id() == KisID("LABA") ) return LABColorspace; + + kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n"; + return RGBColorspace; + + } + + KisProfile * getProfileForProfileInfo(const Image * image) + { + size_t length; + + const unsigned char * profiledata = GetImageProfile(image, "ICM", &length); + if( profiledata == NULL ) + return 0; + TQByteArray rawdata; + rawdata.resize(length); + memcpy(rawdata.data(), profiledata, length); + + KisProfile* p = new KisProfile(rawdata); + return p; + +#if 0 + return 0; + + if (image->profiles == NULL) + return 0; + + const char *name; + const StringInfo *profile; + + KisProfile * p = 0; + + ResetImageProfileIterator(image); + for (name = GetNextImageProfile(image); name != (char *) NULL; ) + { + profile = GetImageProfile(image, name); + if (profile == (StringInfo *) NULL) + continue; + + // XXX: Hardcoded for icc type -- is that correct for us? + if (TQString::compare(name, "icc") == 0) { + TQByteArray rawdata; + rawdata.resize(profile->length); + memcpy(rawdata.data(), profile->datum, profile->length); + + p = new KisProfile(rawdata); + if (p == 0) + return 0; + } + name = GetNextImageProfile(image); + } + return p; +#endif + } + + void setAnnotationsForImage(const Image * src, KisImageSP image) + { + size_t length; + + const unsigned char * profiledata = GetImageProfile(src, "IPTC", &length); + if( profiledata != NULL ) + { + TQByteArray rawdata; + rawdata.resize(length); + memcpy(rawdata.data(), profiledata, length); + + KisAnnotation* annotation = new KisAnnotation(TQString("IPTC"), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); + } + for(int i = 0; i < src->generic_profiles; i++) + { + TQByteArray rawdata; + rawdata.resize(length); + memcpy(rawdata.data(), src->generic_profile[i].info, src->generic_profile[i].length); + + KisAnnotation* annotation = new KisAnnotation(TQString(src->generic_profile[i].name), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); + } + + const ImageAttribute* imgAttr = GetImageAttribute(src, NULL); + while(imgAttr) + { + TQByteArray rawdata; + int len = strlen(imgAttr -> value) + 1; + rawdata.resize(len); + memcpy(rawdata.data(), imgAttr -> value, len); + + KisAnnotation* annotation = new KisAnnotation( TQString("chalk_attribute:%1").tqarg(TQString(imgAttr -> key)), "", rawdata ); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); + + imgAttr = imgAttr->next; + } +#if 0 + return; + if (src->profiles == NULL) + return; + + const char *name = 0; + const StringInfo *profile; + KisAnnotation* annotation = 0; + + // Profiles and so + ResetImageProfileIterator(src); + while((name = GetNextImageProfile(src))) { + profile = GetImageProfile(src, name); + if (profile == (StringInfo *) NULL) + continue; + + // XXX: icc will be written seperately? + if (TQString::compare(name, "icc") == 0) + continue; + + TQByteArray rawdata; + rawdata.resize(profile->length); + memcpy(rawdata.data(), profile->datum, profile->length); + + annotation = new KisAnnotation(TQString(name), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); + } + + // Attributes, since we have no hint on if this is an attribute or a profile + // annotation, we prefix it with 'chalk_attribute:'. XXX This needs to be rethought! + // The joys of imagemagick. From at version 6.2.1 (dfaure has 6.2.0 and confirms the + // old way of doing things) they changed the src -> attributes + // to void* and require us to use the iterator functions. So we #if around that, *sigh* +#if MagickLibVersion >= 0x621 + const ImageAttribute * attr; + ResetImageAttributeIterator(src); + while ( (attr = GetNextImageAttribute(src)) ) { +#else + ImageAttribute * attr = src -> attributes; + while (attr) { +#endif + TQByteArray rawdata; + int len = strlen(attr -> value) + 1; + rawdata.resize(len); + memcpy(rawdata.data(), attr -> value, len); + + annotation = new KisAnnotation( + TQString("chalk_attribute:%1").tqarg(TQString(attr -> key)), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); +#if MagickLibVersion < 0x620 + attr = attr -> next; +#endif + } + +#endif + } + } + + void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd) + { + while(it != annotationsEnd) { + if (!(*it) || (*it) -> type() == TQString()) { + kdDebug(41008) << "Warning: empty annotation" << endl; + ++it; + continue; + } + + kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl; + + if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute + if (!SetImageAttribute(dst, + (*it) -> type().mid(strlen("chalk_attribute:")).ascii(), + (*it) -> annotation() . data()) ) { + kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n"; + } + } else { // Profile + unsigned char * profiledata = new unsigned char[(*it) -> annotation() . size()]; + memcpy( profiledata, (*it) -> annotation() . data(), (*it) -> annotation() . size()); + if (!ProfileImage(dst, (*it) -> type().ascii(), + profiledata, (*it) -> annotation() . size(), MagickFalse)) { + kdDebug(41008) << "Storing failed!" << endl; + } + } + ++it; + } + } + + + void InitGlobalMagick() + { + static bool init = false; + + if (!init) { + KApplication *app = KApplication::kApplication(); + + InitializeMagick(*app -> argv()); + atexit(DestroyMagick); + init = true; + } + } + + /* + * ImageMagick progress monitor callback. Unfortunately it doesn't support passing in some user + * data which complicates things quite a bit. The plan was to allow the user start multiple + * import/scans if he/she so wished. However, without passing user data it's not possible to tell + * on which task we have made progress on. + * + * Additionally, ImageMagick is thread-safe, not re-entrant... i.e. IM does not relinquish held + * locks when calling user defined callbacks, this means that the same thread going back into IM + * would deadlock since it would try to acquire locks it already holds. + */ +#if 0 + MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *) + { + KApplication *app = KApplication::kApplication(); + + Q_ASSERT(app); + + if (app -> hasPendingEvents()) + app -> processEvents(); + + printf("%s\n", text); + return MagickTrue; + } +#else + unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *) + { + KApplication *app = KApplication::kApplication(); + + Q_ASSERT(app); + + if (app -> hasPendingEvents()) + app -> processEvents(); + + printf("%s\n", text); + return true; + } +#endif + + + +KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter) +{ + InitGlobalMagick(); + init(doc, adapter); + SetMonitorHandler(monitor); + m_stop = false; +} + +KisImageMagickConverter::~KisImageMagickConverter() +{ +} + +KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob) +{ + Image *image; + Image *images; + ExceptionInfo ei; + ImageInfo *ii; + + if (m_stop) { + m_img = 0; + return KisImageBuilder_RESULT_INTR; + } + + GetExceptionInfo(&ei); + ii = CloneImageInfo(0); + + if (isBlob) { + + // TODO : Test. Does BlobToImage even work? + Q_ASSERT(uri.isEmpty()); + images = BlobToImage(ii, &m_data[0], m_data.size(), &ei); + } else { + + qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1); + + if (ii -> filename[MaxTextExtent - 1]) { + emit notifyProgressError(); + return KisImageBuilder_RESULT_PATH; + } + + images = ReadImage(ii, &ei); + + } + + if (ei.severity != UndefinedException) + { + CatchException(&ei); + kdDebug(41008) << "Exceptions happen when loading" << endl; + return KisImageBuilder_RESULT_FAILURE; + } + + + if (images == 0) { + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + } + + emit notifyProgressStage(i18n("Importing..."), 0); + + m_img = 0; + + while ((image = RemoveFirstImageFromList(&images))) { + if(image->rows == 0 or image->columns == 0) return KisImageBuilder_RESULT_FAILURE; + ViewInfo *vi = OpenCacheView(image); + + // Determine image depth -- for now, all channels of an imported image are of the same depth + unsigned long imageDepth = image->depth; + kdDebug(41008) << "Image depth: " << imageDepth << "\n"; + + TQString csName; + KisColorSpace * cs = 0; + ColorspaceType colorspaceType; + + // Determine image type -- rgb, grayscale or cmyk + if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) { + if (imageDepth == 8) + csName = "GRAYA"; + else if ( imageDepth == 16 ) + csName = "GRAYA16" ; + colorspaceType = GRAYColorspace; + } + else { + colorspaceType = image->colorspace; + csName = getColorSpaceName(image -> colorspace, imageDepth); + } + + kdDebug(41008) << "image has " << csName << " colorspace\n"; + + KisProfile * profile = getProfileForProfileInfo(image); + if (profile) + { + kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n"; + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile); + } + else + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),""); + + if (!cs) { + kdDebug(41008) << "Chalk does not support colorspace " << image -> colorspace << "\n"; + CloseCacheView(vi); + DestroyImage(image); + DestroyExceptionInfo(&ei); + DestroyImageList(images); + DestroyImageInfo(ii); + emit notifyProgressError(); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + + if( ! m_img) { + m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image"); + Q_CHECK_PTR(m_img); + m_img->blockSignals(true); // Don't send out signals while we're building the image + + // XXX I'm assuming seperate layers won't have other profile things like EXIF + setAnnotationsForImage(image, m_img); + } + + if (image -> columns && image -> rows) { + + // Opacity (set by the photoshop import filter) + TQ_UINT8 opacity = OPACITY_OPAQUE; + const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]"); + if (attr != 0) { + opacity = TQ_UINT8_MAX - Downscale(TQString(attr->value).toInt()); + } + + KisPaintLayerSP layer = 0; + + attr = GetImageAttribute(image, "[layer-name]"); + if (attr != 0) { + layer = new KisPaintLayer(m_img, attr->value, opacity); + } + else { + layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity); + } + + Q_ASSERT(layer); + + // Layerlocation (set by the photoshop import filter) + TQ_INT32 x_offset = 0; + TQ_INT32 y_offset = 0; + + attr = GetImageAttribute(image, "[layer-xpos]"); + if (attr != 0) { + x_offset = TQString(attr->value).toInt(); + } + + attr = GetImageAttribute(image, "[layer-ypos]"); + if (attr != 0) { + y_offset = TQString(attr->value).toInt(); + } + + + for (TQ_UINT32 y = 0; y < image->rows; y ++) + { + const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei); + + if(!pp) + { + CloseCacheView(vi); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + } + + IndexPacket * indexes = GetCacheViewIndexes(vi); + + KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true); + + if (colorspaceType== CMYKColorspace) { + if (imageDepth == 8) { + int x = 0; + while (!hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + *(ptr++) = Downscale(pp->red); // cyan + *(ptr++) = Downscale(pp->green); // magenta + *(ptr++) = Downscale(pp->blue); // yellow + *(ptr++) = Downscale(indexes[x]); // Black +// XXX: Warning! This ifdef messes up the paren matching big-time! +#ifdef HAVE_MAGICK6 + if (image->matte != MagickFalse) { +#else + if (image->matte == true) { +#endif + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + } + else { + *(ptr++) = OPACITY_OPAQUE; + } + ++x; + pp++; + ++hiter; + } + } + } + else if (colorspaceType == LABColorspace) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + + *(ptr++) = ScaleQuantumToShort(pp->red); + *(ptr++) = ScaleQuantumToShort(pp->green); + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + else if (colorspaceType == RGBColorspace || + colorspaceType == sRGBColorspace || + colorspaceType == TransparentColorspace) + { + if (imageDepth == 8) { + while(! hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + // XXX: not colorstrategy and bitdepth independent + *(ptr++) = Downscale(pp->blue); + *(ptr++) = Downscale(pp->green); + *(ptr++) = Downscale(pp->red); + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + + pp++; + ++hiter; + } + } + else if (imageDepth == 16) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + // XXX: not colorstrategy independent + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = ScaleQuantumToShort(pp->green); + *(ptr++) = ScaleQuantumToShort(pp->red); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + } + else if ( colorspaceType == GRAYColorspace) { + if (imageDepth == 8) { + while(! hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + // XXX: not colorstrategy and bitdepth independent + *(ptr++) = Downscale(pp->blue); + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + + pp++; + ++hiter; + } + } + else if (imageDepth == 16) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + // XXX: not colorstrategy independent + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + } + + emit notifyProgress(y * 100 / image->rows); + + if (m_stop) { + CloseCacheView(vi); + DestroyImage(image); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + m_img = 0; + return KisImageBuilder_RESULT_INTR; + } + } + m_img->addLayer(layer.data(), m_img->rootLayer()); + layer->paintDevice()->move(x_offset, y_offset); + } + + emit notifyProgressDone(); + CloseCacheView(vi); + DestroyImage(image); + } + + emit notifyProgressDone(); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + return KisImageBuilder_RESULT_OK; + } + + KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri) + { + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) { + return KisImageBuilder_RESULT_NOT_EXIST; + } + + KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE; + TQString tmpFile; + + if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) { + KURL uriTF; + uriTF.setPath( tmpFile ); + result = decode(uriTF, false); + KIO::NetAccess::removeTempFile(tmpFile); + } + + return result; + } + + + KisImageSP KisImageMagickConverter::image() + { + return m_img; + } + + void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter) + { + m_doc = doc; + m_adapter = adapter; + m_job = 0; + } + + KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd) + { + Image *image; + ExceptionInfo ei; + ImageInfo *ii; + + if (!layer) + return KisImageBuilder_RESULT_INVALID_ARG; + + KisImageSP img = layer->image(); + if (!img) + return KisImageBuilder_RESULT_EMPTY; + + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!uri.isLocalFile()) + return KisImageBuilder_RESULT_NOT_LOCAL; + + + TQ_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels(); + + GetExceptionInfo(&ei); + + ii = CloneImageInfo(0); + + qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1); + + if (ii -> filename[MaxTextExtent - 1]) { + emit notifyProgressError(); + return KisImageBuilder_RESULT_PATH; + } + + if (!img -> width() || !img -> height()) + return KisImageBuilder_RESULT_EMPTY; + + if (layerBytesPerChannel < 2) { + ii->depth = 8; + } + else { + ii->depth = 16; + } + + ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace()); + + image = AllocateImage(ii); +// SetImageColorspace(image, ii->colorspace); + image -> columns = img -> width(); + image -> rows = img -> height(); + + kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n"; + kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n"; + +#ifdef HAVE_MAGICK6 + // if ( layer-> hasAlpha() ) + image -> matte = MagickTrue; + // else + // image -> matte = MagickFalse; +#else + // image -> matte = layer -> hasAlpha(); + image -> matte = true; +#endif + + TQ_INT32 y, height, width; + + height = img -> height(); + width = img -> width(); + + bool alpha = true; + TQString ext = TQFileInfo(TQFile::encodeName(uri.path())).extension(false).upper(); + if (ext == "BMP") { + alpha = false; + qstrncpy(ii->magick, "BMP2", MaxTextExtent - 1); + } + else if (ext == "RGB") { + qstrncpy(ii->magick, "SGI", MaxTextExtent - 1); + } + + for (y = 0; y < height; y++) { + + // Allocate pixels for this scanline + PixelPacket * pp = SetImagePixels(image, 0, y, width, 1); + + if (!pp) { + DestroyExceptionInfo(&ei); + DestroyImage(image); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + + } + + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false); + if (alpha) + SetImageType(image, TrueColorMatteType); + else + SetImageType(image, TrueColorType); + + if (image->colorspace== CMYKColorspace) { + + IndexPacket * indexes = GetIndexes(image); + int x = 0; + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]); + pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_CMYK_ALPHA]); + indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]); + x++; + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_CYAN]); + pp -> green = Upscale(d[PIXEL_MAGENTA]); + pp -> blue = Upscale(d[PIXEL_YELLOW]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]); + + indexes[x]= Upscale(d[PIXEL_BLACK]); + + x++; + pp++; + ++it; + } + } + } + else if (image->colorspace== RGBColorspace || + image->colorspace == sRGBColorspace || + image->colorspace == TransparentColorspace) + { + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_RED]); + pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_ALPHA]); + + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_RED]); + pp -> green = Upscale(d[PIXEL_GREEN]); + pp -> blue = Upscale(d[PIXEL_BLUE]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_ALPHA]); + + pp++; + ++it; + } + } + } + else if (image->colorspace == GRAYColorspace) + { + SetImageType(image, GrayscaleMatteType); + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]); + pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_GRAY_ALPHA]); + + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_GRAY]); + pp -> green = Upscale(d[PIXEL_GRAY]); + pp -> blue = Upscale(d[PIXEL_GRAY]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]); + + pp++; + ++it; + } + } + } + else { + kdDebug(41008) << "Unsupported image format\n"; + return KisImageBuilder_RESULT_INVALID_ARG; + } + + emit notifyProgressStage(i18n("Saving..."), y * 100 / height); + +#ifdef HAVE_MAGICK6 + if (SyncImagePixels(image) == MagickFalse) + kdDebug(41008) << "Syncing pixels failed\n"; +#else + if (!SyncImagePixels(image)) + kdDebug(41008) << "Syncing pixels failed\n"; +#endif + } + + // set the annotations + exportAnnotationsForImage(image, annotationsStart, annotationsEnd); + + // XXX: Write to a temp file, then have Chalk use KIO to copy temp + // image to remote location. + + WriteImage(ii, image); + DestroyExceptionInfo(&ei); + DestroyImage(image); + emit notifyProgressDone(); + return KisImageBuilder_RESULT_OK; + } + + void KisImageMagickConverter::ioData(KIO::Job *job, const TQByteArray& data) + { + if (data.isNull() || data.isEmpty()) { + emit notifyProgressStage(i18n("Loading..."), 0); + return; + } + + if (m_data.empty()) { + Image *image; + ImageInfo *ii; + ExceptionInfo ei; + + ii = CloneImageInfo(0); + GetExceptionInfo(&ei); + image = PingBlob(ii, data.data(), data.size(), &ei); + + if (image == 0 || ei.severity == BlobError) { + DestroyExceptionInfo(&ei); + DestroyImageInfo(ii); + job -> kill(); + emit notifyProgressError(); + return; + } + + DestroyImage(image); + DestroyExceptionInfo(&ei); + DestroyImageInfo(ii); + emit notifyProgressStage(i18n("Loading..."), 0); + } + + Q_ASSERT(data.size() + m_data.size() <= m_size); + memcpy(&m_data[m_data.size()], data.data(), data.count()); + m_data.resize(m_data.size() + data.count()); + emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size); + + if (m_stop) + job -> kill(); + } + + void KisImageMagickConverter::ioResult(KIO::Job *job) + { + m_job = 0; + + if (job -> error()) + emit notifyProgressError(); + + decode(KURL(), true); + } + + void KisImageMagickConverter::ioTotalSize(KIO::Job * /*job*/, KIO::filesize_t size) + { + m_size = size; + m_data.reserve(size); + emit notifyProgressStage(i18n("Loading..."), 0); + } + + void KisImageMagickConverter::cancel() + { + m_stop = true; + } + + /** + * @name readFilters + * @return Provide a list of file formats the application can read. + */ + TQString KisImageMagickConverter::readFilters() + { + TQString s; + TQString all; + TQString name; + TQString description; + unsigned long matches; + +/*#ifdef HAVE_MAGICK6 +#ifdef HAVE_OLD_GETMAGICKINFOLIST + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches); +#else // HAVE_OLD_GETMAGICKINFOLIST + ExceptionInfo ei; + GetExceptionInfo(&ei); + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches, &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_OLD_GETMAGICKINFOLIST +#else // HAVE_MAGICK6*/ + const MagickInfo *mi; + ExceptionInfo ei; + GetExceptionInfo(&ei); + mi = GetMagickInfo("*", &ei); + DestroyExceptionInfo(&ei); +// #endif // HAVE_MAGICK6 + + if (!mi) + return s; + +/*#ifdef HAVE_MAGICK6 + for (unsigned long i = 0; i < matches; i++) { + const MagickInfo *info = mi[i]; + if (info -> stealth) + continue; + + if (info -> decoder) { + name = info -> name; + description = info -> description; + kdDebug(41008) << "Found import filter for: " << name << "\n"; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#else*/ + for (; mi; mi = reinterpret_cast(mi -> next)) { + if (mi -> stealth) + continue; + if (mi -> decoder) { + name = mi -> name; + description = mi -> description; + kdDebug(41008) << "Found import filter for: " << name << "\n"; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +// #endif + + all += "|" + i18n("All Images"); + all += "\n"; + + return all + s; + } + + TQString KisImageMagickConverter::writeFilters() + { + TQString s; + TQString all; + TQString name; + TQString description; + unsigned long matches; + +/*#ifdef HAVE_MAGICK6 +#ifdef HAVE_OLD_GETMAGICKINFOLIST + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches); +#else // HAVE_OLD_GETMAGICKINFOLIST + ExceptionInfo ei; + GetExceptionInfo(&ei); + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches, &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_OLD_GETMAGICKINFOLIST +#else // HAVE_MAGICK6*/ + const MagickInfo *mi; + ExceptionInfo ei; + GetExceptionInfo(&ei); + mi = GetMagickInfo("*", &ei); + DestroyExceptionInfo(&ei); +// #endif // HAVE_MAGICK6 + + if (!mi) { + kdDebug(41008) << "Eek, no magick info!\n"; + return s; + } + +/*#ifdef HAVE_MAGICK6 + for (unsigned long i = 0; i < matches; i++) { + const MagickInfo *info = mi[i]; + kdDebug(41008) << "Found export filter for: " << info -> name << "\n"; + if (info -> stealth) + continue; + + if (info -> encoder) { + name = info -> name; + + description = info -> description; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#else*/ + for (; mi; mi = reinterpret_cast(mi -> next)) { + kdDebug(41008) << "Found export filter for: " << mi -> name << "\n"; + if (mi -> stealth) + continue; + + if (mi -> encoder) { + name = mi -> name; + + description = mi -> description; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +// #endif + + + all += "|" + i18n("All Images"); + all += "\n"; + + return all + s; + } + +#include "kis_image_magick_converter.moc" + diff --git a/filters/chalk/gmagick/kis_image_magick_converter.h b/filters/chalk/gmagick/kis_image_magick_converter.h new file mode 100644 index 00000000..28bd94ce --- /dev/null +++ b/filters/chalk/gmagick/kis_image_magick_converter.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_IMAGE_MAGICK_CONVERTER_H_ +#define KIS_IMAGE_MAGICK_CONVERTER_H_ + +#include +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_progress_subject.h" + +class TQString; +class KURL; +class KisDoc; +class KisNameServer; +class KisUndoAdapter; +/** + * Image import/export plugins can use these results to report about success or failure. + */ +enum KisImageBuilder_Result { + KisImageBuilder_RESULT_FAILURE = -400, + KisImageBuilder_RESULT_NOT_EXIST = -300, + KisImageBuilder_RESULT_NOT_LOCAL = -200, + KisImageBuilder_RESULT_BAD_FETCH = -100, + KisImageBuilder_RESULT_INVALID_ARG = -50, + KisImageBuilder_RESULT_OK = 0, + KisImageBuilder_RESULT_PROGRESS = 1, + KisImageBuilder_RESULT_EMPTY = 100, + KisImageBuilder_RESULT_BUSY = 150, + KisImageBuilder_RESULT_NO_URI = 200, + KisImageBuilder_RESULT_UNSUPPORTED = 300, + KisImageBuilder_RESULT_INTR = 400, + KisImageBuilder_RESULT_PATH = 500, + KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600 +}; + + + +/** + * Build a KisImage representation of an image file. + */ +class KisImageMagickConverter : public KisProgressSubject { + typedef TQObject super; + Q_OBJECT + TQ_OBJECT + +public: + KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter); + virtual ~KisImageMagickConverter(); + +public slots: + virtual void cancel(); + +public: + KisImageBuilder_Result buildImage(const KURL& uri); + KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd); + KisImageSP image(); + +public: + static TQString readFilters(); + static TQString writeFilters(); + +private slots: + void ioData(KIO::Job *job, const TQByteArray& data); + void ioResult(KIO::Job *job); + void ioTotalSize(KIO::Job *job, KIO::filesize_t size); + +private: + KisImageMagickConverter(const KisImageMagickConverter&); + KisImageMagickConverter& operator=(const KisImageMagickConverter&); + void init(KisDoc *doc, KisUndoAdapter *adapter); + KisImageBuilder_Result decode(const KURL& uri, bool isBlob); + +private: + KisImageSP m_img; + KisDoc *m_doc; + KisUndoAdapter *m_adapter; + TQValueVector m_data; + KIO::TransferJob *m_job; + KIO::filesize_t m_size; + bool m_stop; +}; + +#endif // KIS_IMAGE_MAGICK_CONVERTER_H_ + diff --git a/filters/chalk/gmagick/magickexport.cpp b/filters/chalk/gmagick/magickexport.cpp new file mode 100644 index 00000000..e56f53d2 --- /dev/null +++ b/filters/chalk/gmagick/magickexport.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory MagickExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkgmagickexport, MagickExportFactory("kofficefilters")) + +MagickExport::MagickExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +MagickExport::~MagickExport() +{ +} + +KoFilter::ConversiontqStatus MagickExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "magick export! From: " << from << ", To: " << to << "\n"; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + // XXX: Add dialog about flattening layers here + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + KURL url; + url.setPath(filename); + + KisImageSP img = output->currentImage(); + + KisImageMagickConverter ib(output, output->undoAdapter()); + + KisPaintDeviceSP pd = new KisPaintDevice(*img->projection()); + KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd); + + vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations(); + if (ib.buildFile(url, l, beginIt, endIt) == KisImageBuilder_RESULT_OK) { + return KoFilter::OK; + } + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/gmagick/magickexport.h b/filters/chalk/gmagick/magickexport.h new file mode 100644 index 00000000..6ea7e238 --- /dev/null +++ b/filters/chalk/gmagick/magickexport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef MAGICKEXPORT_H_ +#define MAGICKEXPORT_H_ + +#include + +class MagickExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + MagickExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~MagickExport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // MAGICKEXPORT_H_ + diff --git a/filters/chalk/gmagick/magickimport.cpp b/filters/chalk/gmagick/magickimport.cpp new file mode 100644 index 00000000..dbfe6da8 --- /dev/null +++ b/filters/chalk/gmagick/magickimport.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory MagickImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkgmagickimport, MagickImportFactory("kofficefilters")) + +MagickImport::MagickImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +MagickImport::~MagickImport() +{ +} + +KoFilter::ConversiontqStatus MagickImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using MagickImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url; + url.setPath(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisImageMagickConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/gmagick/magickimport.h b/filters/chalk/gmagick/magickimport.h new file mode 100644 index 00000000..3373f129 --- /dev/null +++ b/filters/chalk/gmagick/magickimport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef MAGICKIMPORT_H_ +#define MAGICKIMPORT_H_ + +#include + +class MagickImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + MagickImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~MagickImport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // MAGICKIMPORT_H_ + diff --git a/filters/chalk/jpeg/Makefile.am b/filters/chalk/jpeg/Makefile.am new file mode 100644 index 00000000..40a47d81 --- /dev/null +++ b/filters/chalk/jpeg/Makefile.am @@ -0,0 +1,51 @@ +noinst_LTLIBRARIES = libchalkconverter.la +kde_module_LTLIBRARIES = libchalkjpegimport.la libchalkjpegexport.la + +libchalkconverter_la_LDFLAGS = $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkconverter_la_SOURCES = kis_jpeg_converter.cc iccjpeg.c +libchalkconverter_la_LIBADD = $(top_builddir)/filters/chalk/libkisexif/libkisexif.la + +libchalkjpegexport_la_LDFLAGS = -avoid-version -module -no-undefined \ + $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkjpegexport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \ + libchalkconverter.la $(KOFFICE_LIBS) -ljpeg -lexif + +libchalkjpegimport_la_LDFLAGS = -avoid-version -module -no-undefined \ + $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkjpegimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \ + libchalkconverter.la $(KOFFICE_LIBS) -ljpeg -lexif + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + -I$(top_srcdir)/filters/chalk/libkisexif \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +service_DATA = chalk_jpeg_import.desktop chalk_jpeg_export.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_jpeg.desktop +kdelnkdir = $(kde_appsdir)/.hidden + +libchalkjpegimport_la_SOURCES = kis_jpeg_import.cc +libchalkjpegexport_la_SOURCES = kis_wdg_options_jpeg.ui kis_jpeg_export.cc + +METASOURCES = AUTO + + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + diff --git a/filters/chalk/jpeg/chalk_jpeg.desktop b/filters/chalk/jpeg/chalk_jpeg.desktop new file mode 100644 index 00000000..13239199 --- /dev/null +++ b/filters/chalk/jpeg/chalk_jpeg.desktop @@ -0,0 +1,58 @@ +[Desktop Entry] +Categories= +Exec=chalk %u +GenericName=Application for Drawing and Handling of Images +GenericName[bg]=Приложение за рисуване и обработка на изображения +GenericName[ca]=Aplicació per a dibuix i modificació d'imatges +GenericName[da]=Tegne- og billedbehandlingsprogram +GenericName[de]=Programm zum Zeichnen und Bearbeiten von Bildern +GenericName[el]=Εφαρμογή για επεξεργασία και χειρισμό εικόνων +GenericName[eo]=Aplikaĵo por Desegnado kaj Mastrumado de Bildoj +GenericName[es]=Aplicación para dibujo y manipulación de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[fa]=کاربرد برای ترسیم و به کار بردن تصاویر +GenericName[fi]=Ohjelma kuvien piirtämiseen ja käsittelyyn +GenericName[fr]=Application pour dessiner et manipuler des images +GenericName[fy]=Aplikaasje om ôfbyldings mei te tekenjen en te bewurkjen +GenericName[gl]=Aplicación de Debuxo e Manipulación de Imaxes +GenericName[he]=יישום לצביעה וניהול תמונות +GenericName[hu]=Rajzoló és képkezelő +GenericName[is]=Teikni og myndvinnsluforrit +GenericName[it]=Applicazione di disegno e gestione di immagini +GenericName[ja]=描画と画像操作のためのアプリケーション +GenericName[km]=កម្មវិធី​សម្រាប់​គូរ និង​ដោះស្រាយ​នៃ​រូបភាព +GenericName[lv]=Programma zīmēšanai un attēlu apstrādei +GenericName[nb]=Program for tegning og bildehåndtering +GenericName[nds]=Programm för't Teken un Bildhanteren +GenericName[ne]=रेखाचित्र र छविहरूको ह्यान्डल गर्न अनुप्रयोग +GenericName[nl]=Toepassing om afbeeldingen te tekenen en te bewerken +GenericName[pl]=Program do rysowania i obróbki obrazków +GenericName[pt]=Aplicação de Desenho e Manipulação de Imagens +GenericName[pt_BR]=Aplicação de Desenho e Manipulação de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Prográmma sárgumii ja govvegieđaheapmái +GenericName[sk]=Aplikácia na kresnenie a manilupáciu s obrázkami +GenericName[sl]=Program za risanje in rokovanje s slikami +GenericName[sr]=Програм за цртање и обраду слика +GenericName[sr@Latn]=Program za crtanje i obradu slika +GenericName[sv]=Program för att rita och hantera bilder +GenericName[uk]=Програма для малювання і обробки зображень +GenericName[uz]=Rasm chizish dasturi +GenericName[uz@cyrillic]=Расм чизиш дастури +GenericName[zh_CN]=绘制和操纵图像的应用程序 +GenericName[zh_TW]=影像繪製與處理應用程式 +Icon=chalk +MimeType=image/jpeg +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Path= +StartupNotify=true +Terminal=false +Type=Application +X-DCOP-ServiceType=multi +X-KDE-StartupNotify=true +X-KDE-SubstituteUID=false +X-KDE-Username= diff --git a/filters/chalk/jpeg/chalk_jpeg_export.desktop b/filters/chalk/jpeg/chalk_jpeg_export.desktop new file mode 100644 index 00000000..17d776dd --- /dev/null +++ b/filters/chalk/jpeg/chalk_jpeg_export.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Icon= +Name=Chalk PNG Export Filter +Name[bg]=Филтър за експортиране от Chalk в PNG +Name[br]=Sil ezporzh PNG evit Chalk +Name[ca]=Filtre d'exportació PNG per a Chalk +Name[da]=Chalk PNG-eksportfilter +Name[de]=Chalk PNG-Exportfilter +Name[el]=Φίλτρο εξαγωγής PNG του Chalk +Name[eo]=Chalk PNG-eksportfiltrilo +Name[es]=Filtro de exportación a PNG de Chalk +Name[et]=Chalk PNG ekspordifilter +Name[fa]=پالایۀ صادرات Chalk PNG +Name[fi]=Chalk PNG -viestisuodin +Name[fr]=Filtre d'exportation PNG de Chalk +Name[fy]=Chalk PNG Eksportfilter +Name[ga]=Scagaire Easpórtála PNG Chalk +Name[gl]=Filtro de Exportación de PNG para Chalk +Name[he]=Chalk PNG מסנן יצוא +Name[hr]=Chalk PNG filtar izvoza +Name[hu]=Chalk PNG exportszűrő +Name[is]=Chalk PNG útflutningssía +Name[it]=Filtro di esportazione PNG per Chalk +Name[ja]=Chalk PNG エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ PNG សម្រាប់ Chalk +Name[lt]=Chalk PNG eksportavimo filtras +Name[lv]=Chalk PNG eksporta filtrs +Name[nb]=PNG-eksportfilter for Chalk +Name[nds]=PNG-Exportfilter för Chalk +Name[ne]=क्रिता पीएनजी निर्यात फिल्टर +Name[nl]=Chalk PNG Exportfilter +Name[pl]=Filtr eksportu do formatu PNG dla Chalk +Name[pt]=Filtro de Exportação de PNG para o Chalk +Name[pt_BR]=Filtro de Exportação de PNG para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в PNG +Name[se]=Chalk PNG-olggosfievrridansilli +Name[sk]=Exportný filter Chalk PNG +Name[sl]=Izvozni filter PNG za Krito +Name[sr]=Chalk-ин филтер за извоз у PNG +Name[sr@Latn]=Chalk-in filter za izvoz u PNG +Name[sv]=Chalk PNG-exportfilter +Name[uk]=Фільтр експорту PNG для Chalk +Name[uz]=Chalk PNG eksport filteri +Name[uz@cyrillic]=Chalk PNG экспорт филтери +Name[zh_CN]=Chalk PNG 导出过滤器 +Name[zh_TW]=Chalk PNG 匯出過濾程式 +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Export=image/jpeg +X-KDE-Import=application/x-chalk +X-KDE-Library=libchalkjpegexport +X-KDE-Weight=1 diff --git a/filters/chalk/jpeg/chalk_jpeg_import.desktop b/filters/chalk/jpeg/chalk_jpeg_import.desktop new file mode 100644 index 00000000..736c2c7b --- /dev/null +++ b/filters/chalk/jpeg/chalk_jpeg_import.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Icon= +Name=Chalk PNG Import Filter +Name[bg]=Филтър за импортиране от PNG в Chalk +Name[br]=Sil enporzh PNG evit Chalk +Name[ca]=Filtre d'importació PNG per a Chalk +Name[da]=Chalk PNG-importfilter +Name[de]=Chalk PNG-Importfilter +Name[el]=Φίλτρο εισαγωγής PNG του Chalk +Name[eo]=Chalk PNG-importfiltrilo +Name[es]=Filtro de importación a PNG de Chalk +Name[et]=Chalk PNG impordifilter +Name[fa]=پالایۀ واردات Chalk PNG +Name[fi]=Chalk PNG -tuontisuodin +Name[fr]=Filtre d'importation PNG de Chalk +Name[fy]=Chalk PNG Ymportfilter +Name[ga]=Scagaire Iompórtála PNG Chalk +Name[gl]=Filtro de Importación de PNG para Chalk +Name[he]=Chalk PNG מסנן יבוא +Name[hr]=Chalk PNG filtar uvoza +Name[hu]=Chalk PNG importszűrő +Name[is]=Chalk PNG innflutningssía +Name[it]=Filtro di importazione PNG per Chalk +Name[ja]=Chalk PNG インポートフィルタ +Name[km]=តម្រង​នាំចូល PNG សម្រាប់ Chalk +Name[lt]=Chalk PNG importavimo filtras +Name[lv]=Chalk PNG importa filtrs +Name[nb]=PNG-importfilter for Chalk +Name[nds]=PNG-Importfilter för Chalk +Name[ne]=क्रिता पीएनजी आयात फिल्टर +Name[nl]=Chalk PNG Importfilter +Name[pl]=Filtr importu z formatu PNG dla Chalk +Name[pt]=Filtro de Importação de PNG para o Chalk +Name[pt_BR]=Filtro de Importação de PNG para o Chalk +Name[ru]=Фильтр импорта рисунков PNG в Chalk +Name[se]=Chalk PNG-olggosfievrridansilli +Name[sk]=PNG filter pre import do Chalk +Name[sl]=Uvozni filter PNG za Krito +Name[sr]=Chalk-ин филтер за увоз из PNG-а +Name[sr@Latn]=Chalk-in filter za uvoz iz PNG-a +Name[sv]=Chalk PNG-importfilter +Name[uk]=Фільтр імпорту PNG для Chalk +Name[uz]=Chalk PNG import filteri +Name[uz@cyrillic]=Chalk PNG импорт филтери +Name[zh_CN]=Chalk PNG 导入过滤器 +Name[zh_TW]=Chalk PNG 匯入過濾程式 +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Export=application/x-chalk +X-KDE-Import=image/jpeg +X-KDE-Library=libchalkjpegimport +X-KDE-Weight=1 diff --git a/filters/chalk/jpeg/configure.in.bot b/filters/chalk/jpeg/configure.in.bot new file mode 100644 index 00000000..ecbc3393 --- /dev/null +++ b/filters/chalk/jpeg/configure.in.bot @@ -0,0 +1,7 @@ +if test -z "$LIBJPEG" -o -z "$LIBEXIF"; then + echo "" + echo "You're missing libjpeg or libexif 0.6.12 or later (binaries and/or headers)." + echo "chalk won't be able to import/export jpeg" + echo "" + all_tests=bad +fi diff --git a/filters/chalk/jpeg/iccjpeg.c b/filters/chalk/jpeg/iccjpeg.c new file mode 100644 index 00000000..7abe1ff4 --- /dev/null +++ b/filters/chalk/jpeg/iccjpeg.c @@ -0,0 +1,270 @@ +/* + * Little cms + * Copyright (C) 1998-2004 Marti Maria + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * iccprofile.c + * + * This file provides code to read and write International Color Consortium + * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has + * defined a standard format for including such data in JPEG "APP2" markers. + * The code given here does not know anything about the internal structure + * of the ICC profile data; it just knows how to put the profile data into + * a JPEG file being written, or get it back out when reading. + * + * This code depends on new features added to the IJG JPEG library as of + * IJG release 6b; it will not compile or work with older IJG versions. + * + * NOTE: this code would need surgery to work on 16-bit-int machines + * with ICC profiles exceeding 64K bytes in size. If you need to do that, + * change all the "unsigned int" variables to "INT32". You'll also need + * to find a malloc() replacement that can allocate more than 64K. + */ + +#include "iccjpeg.h" +#include /* define malloc() */ + + +/* + * Since an ICC profile can be larger than the maximum size of a JPEG marker + * (64K), we need provisions to split it into multiple markers. The format + * defined by the ICC specifies one or more APP2 markers containing the + * following data: + * Identifying string ASCII "ICC_PROFILE\0" (12 bytes) + * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte) + * Number of markers Total number of APP2's used (1 byte) + * Profile data (remainder of APP2 data) + * Decoders should use the marker sequence numbers to reassemble the profile, + * rather than assuming that the APP2 markers appear in the correct sequence. + */ + +#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ +#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ +#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ +#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) + + +/* + * This routine writes the given ICC profile data into a JPEG file. + * It *must* be called AFTER calling jpeg_start_compress() and BEFORE + * the first call to jpeg_write_scanlines(). + * (This ordering ensures that the APP2 marker(s) will appear after the + * SOI and JFIF or Adobe markers, but before all else.) + */ + +void +write_icc_profile (j_compress_ptr cinfo, + const JOCTET *icc_data_ptr, + unsigned int icc_data_len) +{ + unsigned int num_markers; /* total number of markers we'll write */ + int cur_marker = 1; /* per spec, counting starts at 1 */ + unsigned int length; /* number of bytes to write in this marker */ + + /* Calculate the number of markers we'll need, rounding up of course */ + num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER; + if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len) + num_markers++; + + while (icc_data_len > 0) { + /* length of profile to put in this marker */ + length = icc_data_len; + if (length > MAX_DATA_BYTES_IN_MARKER) + length = MAX_DATA_BYTES_IN_MARKER; + icc_data_len -= length; + + /* Write the JPEG marker header (APP2 code and marker length) */ + jpeg_write_m_header(cinfo, ICC_MARKER, + (unsigned int) (length + ICC_OVERHEAD_LEN)); + + /* Write the marker identifying string "ICC_PROFILE" (null-terminated). + * We code it in this less-than-transparent way so that the code works + * even if the local character set is not ASCII. + */ + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x5F); + jpeg_write_m_byte(cinfo, 0x50); + jpeg_write_m_byte(cinfo, 0x52); + jpeg_write_m_byte(cinfo, 0x4F); + jpeg_write_m_byte(cinfo, 0x46); + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x4C); + jpeg_write_m_byte(cinfo, 0x45); + jpeg_write_m_byte(cinfo, 0x0); + + /* Add the sequencing info */ + jpeg_write_m_byte(cinfo, cur_marker); + jpeg_write_m_byte(cinfo, (int) num_markers); + + /* Add the profile data */ + while (length--) { + jpeg_write_m_byte(cinfo, *icc_data_ptr); + icc_data_ptr++; + } + cur_marker++; + } +} + + +/* + * Prepare for reading an ICC profile + */ + +void +setup_read_icc_profile (j_decompress_ptr cinfo) +{ + /* Tell the library to keep any APP2 data it may tqfind */ + jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF); +} + + +/* + * Handy subroutine to test whether a saved marker is an ICC profile marker. + */ + +static boolean +marker_is_icc (jpeg_saved_marker_ptr marker) +{ + return + marker->marker == ICC_MARKER && + marker->data_length >= ICC_OVERHEAD_LEN && + /* verify the identifying string */ + GETJOCTET(marker->data[0]) == 0x49 && + GETJOCTET(marker->data[1]) == 0x43 && + GETJOCTET(marker->data[2]) == 0x43 && + GETJOCTET(marker->data[3]) == 0x5F && + GETJOCTET(marker->data[4]) == 0x50 && + GETJOCTET(marker->data[5]) == 0x52 && + GETJOCTET(marker->data[6]) == 0x4F && + GETJOCTET(marker->data[7]) == 0x46 && + GETJOCTET(marker->data[8]) == 0x49 && + GETJOCTET(marker->data[9]) == 0x4C && + GETJOCTET(marker->data[10]) == 0x45 && + GETJOCTET(marker->data[11]) == 0x0; +} + + +/* + * See if there was an ICC profile in the JPEG file being read; + * if so, reassemble and return the profile data. + * + * TRUE is returned if an ICC profile was found, FALSE if not. + * If TRUE is returned, *icc_data_ptr is set to point to the + * returned data, and *icc_data_len is set to its length. + * + * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc() + * and must be freed by the caller with free() when the caller no longer + * needs it. (Alternatively, we could write this routine to use the + * IJG library's memory allocator, so that the data would be freed implicitly + * at jpeg_finish_decompress() time. But it seems likely that many apps + * will prefer to have the data stick around after decompression finishes.) + * + * NOTE: if the file contains invalid ICC APP2 markers, we just silently + * return FALSE. You might want to issue an error message instead. + */ + +boolean +read_icc_profile (j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len) +{ + jpeg_saved_marker_ptr marker; + int num_markers = 0; + int seq_no; + JOCTET *icc_data; + unsigned int total_length; +#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */ + char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */ + unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */ + unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */ + + *icc_data_ptr = NULL; /* avoid confusion if FALSE return */ + *icc_data_len = 0; + + /* This first pass over the saved markers discovers whether there are + * any ICC markers and verifies the consistency of the marker numbering. + */ + + for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++) + marker_present[seq_no] = 0; + + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { + if (marker_is_icc(marker)) { + if (num_markers == 0) + num_markers = GETJOCTET(marker->data[13]); + else if (num_markers != GETJOCTET(marker->data[13])) + return FALSE; /* inconsistent num_markers fields */ + seq_no = GETJOCTET(marker->data[12]); + if (seq_no <= 0 || seq_no > num_markers) + return FALSE; /* bogus sequence number */ + if (marker_present[seq_no]) + return FALSE; /* duplicate sequence numbers */ + marker_present[seq_no] = 1; + data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN; + } + } + + if (num_markers == 0) + return FALSE; + + /* Check for missing markers, count total space needed, + * compute offset of each marker's part of the data. + */ + + total_length = 0; + for (seq_no = 1; seq_no <= num_markers; seq_no++) { + if (marker_present[seq_no] == 0) + return FALSE; /* missing sequence number */ + data_offset[seq_no] = total_length; + total_length += data_length[seq_no]; + } + + if (total_length <= 0) + return FALSE; /* found only empty markers? */ + + /* Allocate space for assembled data */ + icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET)); + if (icc_data == NULL) + return FALSE; /* oops, out of memory */ + + /* and fill it in */ + for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { + if (marker_is_icc(marker)) { + JOCTET FAR *src_ptr; + JOCTET *dst_ptr; + unsigned int length; + seq_no = GETJOCTET(marker->data[12]); + dst_ptr = icc_data + data_offset[seq_no]; + src_ptr = marker->data + ICC_OVERHEAD_LEN; + length = data_length[seq_no]; + while (length--) { + *dst_ptr++ = *src_ptr++; + } + } + } + + *icc_data_ptr = icc_data; + *icc_data_len = total_length; + + return TRUE; +} diff --git a/filters/chalk/jpeg/iccjpeg.h b/filters/chalk/jpeg/iccjpeg.h new file mode 100644 index 00000000..8828dc99 --- /dev/null +++ b/filters/chalk/jpeg/iccjpeg.h @@ -0,0 +1,99 @@ +/* + * Little cms + * Copyright (C) 1998-2004 Marti Maria + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * iccprofile.h + * + * This file provides code to read and write International Color Consortium + * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has + * defined a standard format for including such data in JPEG "APP2" markers. + * The code given here does not know anything about the internal structure + * of the ICC profile data; it just knows how to put the profile data into + * a JPEG file being written, or get it back out when reading. + * + * This code depends on new features added to the IJG JPEG library as of + * IJG release 6b; it will not compile or work with older IJG versions. + * + * NOTE: this code would need surgery to work on 16-bit-int machines + * with ICC profiles exceeding 64K bytes in size. See iccprofile.c + * for details. + */ +#ifndef ICCJPEG +#define ICCJPEG + +#include /* needed to define "FILE", "NULL" */ +#include "jpeglib.h" + + +/* + * This routine writes the given ICC profile data into a JPEG file. + * It *must* be called AFTER calling jpeg_start_compress() and BEFORE + * the first call to jpeg_write_scanlines(). + * (This ordering ensures that the APP2 marker(s) will appear after the + * SOI and JFIF or Adobe markers, but before all else.) + */ + +extern void write_icc_profile JPP((j_compress_ptr cinfo, + const JOCTET *icc_data_ptr, + unsigned int icc_data_len)); + + +/* + * Reading a JPEG file that may contain an ICC profile requires two steps: + * + * 1. After jpeg_create_decompress() but before jpeg_read_header(), + * call setup_read_icc_profile(). This routine tells the IJG library + * to save in memory any APP2 markers it may find in the file. + * + * 2. After jpeg_read_header(), call read_icc_profile() to find out + * whether there was a profile and obtain it if so. + */ + + +/* + * Prepare for reading an ICC profile + */ + +extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo)); + + +/* + * See if there was an ICC profile in the JPEG file being read; + * if so, reassemble and return the profile data. + * + * TRUE is returned if an ICC profile was found, FALSE if not. + * If TRUE is returned, *icc_data_ptr is set to point to the + * returned data, and *icc_data_len is set to its length. + * + * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc() + * and must be freed by the caller with free() when the caller no longer + * needs it. (Alternatively, we could write this routine to use the + * IJG library's memory allocator, so that the data would be freed implicitly + * at jpeg_finish_decompress() time. But it seems likely that many apps + * will prefer to have the data stick around after decompression finishes.) + */ + +extern boolean read_icc_profile JPP((j_decompress_ptr cinfo, + JOCTET **icc_data_ptr, + unsigned int *icc_data_len)); + +#endif diff --git a/filters/chalk/jpeg/kis_jpeg_converter.cc b/filters/chalk/jpeg/kis_jpeg_converter.cc new file mode 100644 index 00000000..8daebc00 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_converter.cc @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_jpeg_converter.h" + +#include + +extern "C" { +#include +} + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern "C" { +#include +#include +} + +#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ +#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ +#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ +#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) + +namespace { + + J_COLOR_SPACE getColorTypeforColorSpace( KisColorSpace * cs) + { + if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) + { + return JCS_GRAYSCALE; + } + if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) + { + return JCS_RGB; + } + if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) + { + return JCS_CMYK; + } + KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ; + return JCS_UNKNOWN; + } + + TQString getColorSpaceForColorType(J_COLOR_SPACE color_type) { + kdDebug(41008) << "color_type = " << color_type << endl; + if(color_type == JCS_GRAYSCALE) + { + return "GRAYA"; + } else if(color_type == JCS_RGB) { + return "RGBA"; + } else if(color_type == JCS_CMYK) { + return "CMYK"; + } + return ""; + } + +} + +KisJPEGConverter::KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter) +{ + m_doc = doc; + m_adapter = adapter; + m_job = 0; + m_stop = false; +} + +KisJPEGConverter::~KisJPEGConverter() +{ +} + +KisImageBuilder_Result KisJPEGConverter::decode(const KURL& uri) +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + + // open the file + FILE *fp = fopen(TQFile::encodeName(uri.path()), "rb"); + if (!fp) + { + return (KisImageBuilder_RESULT_NOT_EXIST); + } + jpeg_stdio_src(&cinfo, fp); + + jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF); + /* Save APP0..APP15 markers */ + for (int m = 0; m < 16; m++) + jpeg_save_markers (&cinfo, JPEG_APP0 + m, 0xFFFF); + + +// setup_read_icc_profile(&cinfo); + // read header + jpeg_read_header(&cinfo, true); + + // start reading + jpeg_start_decompress(&cinfo); + + // Get the colorspace + TQString csName = getColorSpaceForColorType(cinfo.out_color_space); + if(csName.isEmpty()) { + kdDebug(41008) << "unsupported colorspace : " << cinfo.out_color_space << endl; + jpeg_destroy_decompress(&cinfo); + fclose(fp); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + uchar* profile_data; + uint profile_len; + KisProfile* profile = 0; + TQByteArray profile_rawdata; + if( read_icc_profile (&cinfo, &profile_data, &profile_len)) + { + profile_rawdata.resize(profile_len); + memcpy(profile_rawdata.data(), profile_data, profile_len); + cmsHPROFILE hProfile = cmsOpenProfileFromMem(profile_data, (DWORD)profile_len); + + if (hProfile != (cmsHPROFILE) NULL) { + profile = new KisProfile( profile_rawdata); + Q_CHECK_PTR(profile); + kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl; + if(!profile->isSuitableForOutput()) + { + kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user + } + } + } + + // Retrieve a pointer to the colorspace + KisColorSpace* cs; + if (profile && profile->isSuitableForOutput()) + { + kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n"; + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile); + } + else + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),""); + + if(cs == 0) + { + kdDebug(41008) << "unknown colorspace" << endl; + jpeg_destroy_decompress(&cinfo); + fclose(fp); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + + // Create the cmsTransform if needed + + cmsHTRANSFORM transform = 0; + if(profile && !profile->isSuitableForOutput()) + { + transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(), + cs->getProfile()->profile() , cs->colorSpaceType(), + INTENT_PERCEPTUAL, 0); + } + + // Creating the KisImageSP + if( ! m_img) { + m_img = new KisImage(m_doc->undoAdapter(), cinfo.image_width, cinfo.image_height, cs, "built image"); + Q_CHECK_PTR(m_img); + if(profile && !profile->isSuitableForOutput()) + { + m_img -> addAnnotation( new KisAnnotation( profile->productName(), "", profile_rawdata) ); + } + } + + KisPaintLayerSP layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX); + + // Read exif information if any + + // Read data + JSAMPROW row_pointer = new JSAMPLE[cinfo.image_width *cinfo.num_components]; + + for (; cinfo.output_scanline < cinfo.image_height;) { + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.output_scanline, cinfo.image_width, true); + jpeg_read_scanlines(&cinfo, &row_pointer, 1); + TQ_UINT8 *src = row_pointer; + switch(cinfo.out_color_space) + { + case JCS_GRAYSCALE: + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + d[1] = TQ_UINT8_MAX; + ++it; + } + break; + case JCS_RGB: + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + d[2] = *(src++); + d[1] = *(src++); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + d[3] = TQ_UINT8_MAX; + ++it; + } + break; + case JCS_CMYK: + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + d[0] = TQ_UINT8_MAX - *(src++); + d[1] = TQ_UINT8_MAX - *(src++); + d[2] = TQ_UINT8_MAX - *(src++); + d[3] = TQ_UINT8_MAX - *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + d[4] = TQ_UINT8_MAX; + ++it; + } + break; + default: + return KisImageBuilder_RESULT_UNSUPPORTED; + } + } + + m_img->addLayer(layer.data(), m_img->rootLayer(), 0); + + // Read exif informations + + kdDebug(41008) << "Looking for exif information" << endl; + + for (jpeg_saved_marker_ptr marker = cinfo.marker_list; marker != NULL; marker = marker->next) { + kdDebug(41008) << "Marker is " << marker->marker << endl; + if (marker->marker != (JOCTET) (JPEG_APP0 + 1) || + marker->data_length < 14) + continue; /* Exif data is in an APP1 marker of at least 14 octets */ + + if (GETJOCTET (marker->data[0]) != (JOCTET) 0x45 || + GETJOCTET (marker->data[1]) != (JOCTET) 0x78 || + GETJOCTET (marker->data[2]) != (JOCTET) 0x69 || + GETJOCTET (marker->data[3]) != (JOCTET) 0x66 || + GETJOCTET (marker->data[4]) != (JOCTET) 0x00 || + GETJOCTET (marker->data[5]) != (JOCTET) 0x00) + continue; /* no Exif header */ + kdDebug(41008) << "Found exif information of length : "<< marker->data_length << endl; + KisExifIO exifIO(layer->paintDevice()->exifInfo()); + exifIO.readExifFromMem( marker->data , marker->data_length ); + // Interpret orientation tag + ExifValue v; + if( layer->paintDevice()->exifInfo()->getValue("Qt::Orientation", v) && v.type() == ExifValue::EXIF_TYPE_SHORT) + { + switch(v.asShort(0)) // + { + case 2: + layer->paintDevice()->mirrorY(); + break; + case 3: + image()->rotate(M_PI, 0); + break; + case 4: + layer->paintDevice()->mirrorX(); + break; + case 5: + image()->rotate(M_PI/2, 0); + layer->paintDevice()->mirrorY(); + break; + case 6: + image()->rotate(M_PI/2, 0); + break; + case 7: + image()->rotate(M_PI/2, 0); + layer->paintDevice()->mirrorX(); + break; + case 8: + image()->rotate(-M_PI/2 + 2*M_PI, 0); + break; + default: + break; + } + v.setValue(0, (TQ_UINT16)1); + layer->paintDevice()->exifInfo()->setValue("Qt::Orientation", v); + } + break; + } + + // Finish decompression + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(fp); + delete []row_pointer; + return KisImageBuilder_RESULT_OK; +} + + + +KisImageBuilder_Result KisJPEGConverter::buildImage(const KURL& uri) +{ + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) { + return KisImageBuilder_RESULT_NOT_EXIST; + } + + // We're not set up to handle asynchronous loading at the moment. + KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE; + TQString tmpFile; + + if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) { + KURL uriTF; + uriTF.setPath( tmpFile ); + result = decode(uriTF); + KIO::NetAccess::removeTempFile(tmpFile); + } + + return result; +} + + +KisImageSP KisJPEGConverter::image() +{ + return m_img; +} + + +KisImageBuilder_Result KisJPEGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo) +{ + if (!layer) + return KisImageBuilder_RESULT_INVALID_ARG; + + KisImageSP img = layer -> image(); + if (!img) + return KisImageBuilder_RESULT_EMPTY; + + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!uri.isLocalFile()) + return KisImageBuilder_RESULT_NOT_LOCAL; + // Open file for writing + FILE *fp = fopen(TQFile::encodeName(uri.path()), "wb"); + if (!fp) + { + return (KisImageBuilder_RESULT_FAILURE); + } + uint height = img->height(); + uint width = img->width(); + // Initialize structure + struct jpeg_compress_struct cinfo; + jpeg_create_compress(&cinfo); + // Initialize error output + struct jpeg_error_mgr jerr; + cinfo.err = jpeg_std_error(&jerr); + // Initialize output stream + jpeg_stdio_dest(&cinfo, fp); + + cinfo.image_width = width; // image width and height, in pixels + cinfo.image_height = height; + cinfo.input_components = img->colorSpace()->nColorChannels(); // number of color channels per pixel */ + J_COLOR_SPACE color_type = getColorTypeforColorSpace(img->colorSpace()); + if(color_type == JCS_UNKNOWN) + { + KIO::del(uri); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + cinfo.in_color_space = color_type; // colorspace of input image + + + // Set default compression parameters + jpeg_set_defaults(&cinfo); + // Customize them + jpeg_set_quality(&cinfo, options.quality, true); + + if(options.progressive) + { + jpeg_simple_progression (&cinfo); + } + + // Start compression + jpeg_start_compress(&cinfo, true); + // Save exif information if any available + if(exifInfo) + { + kdDebug(41008) << "Trying to save exif information" << endl; + KisExifIO exifIO(exifInfo); + unsigned char* exif_data; + unsigned int exif_size; + exifIO.saveExifToMem( &exif_data, &exif_size); + kdDebug(41008) << "Exif informations size is " << exif_size << endl; + if (exif_size < MAX_DATA_BYTES_IN_MARKER) + { + jpeg_write_marker(&cinfo, JPEG_APP0 + 1, exif_data, exif_size); + } else { + kdDebug(41008) << "exif informations couldn't be saved." << endl; + } + } + + + // Save annotation + vKisAnnotationSP_it it = annotationsStart; + while(it != annotationsEnd) { + if (!(*it) || (*it) -> type() == TQString()) { + kdDebug(41008) << "Warning: empty annotation" << endl; + ++it; + continue; + } + + kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl; + + if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute + // FIXME + kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl; + } else { // Profile + //char* name = new char[(*it)->type().length()+1]; + write_icc_profile(& cinfo, (uchar*)(*it)->annotation().data(), (*it)->annotation().size()); + } + ++it; + } + + + // Write data information + + JSAMPROW row_pointer = new JSAMPLE[width*cinfo.input_components]; + int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels(); + + for (; cinfo.next_scanline < height;) { + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, cinfo.next_scanline, width, false); + TQ_UINT8 *dst = row_pointer; + switch(color_type) + { + case JCS_GRAYSCALE: + if(color_nb_bits == 16) + { + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + *(dst++) = d[0] / TQ_UINT8_MAX; + ++it; + } + } else { + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + *(dst++) = d[0]; + ++it; + } + } + break; + case JCS_RGB: + if(color_nb_bits == 16) + { + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + *(dst++) = d[2] / TQ_UINT8_MAX; + *(dst++) = d[1] / TQ_UINT8_MAX; + *(dst++) = d[0] / TQ_UINT8_MAX; + ++it; + } + } else { + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + *(dst++) = d[2]; + *(dst++) = d[1]; + *(dst++) = d[0]; + ++it; + } + } + break; + case JCS_CMYK: + if(color_nb_bits == 16) + { + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + *(dst++) = TQ_UINT8_MAX - d[0] / TQ_UINT8_MAX; + *(dst++) = TQ_UINT8_MAX - d[1] / TQ_UINT8_MAX; + *(dst++) = TQ_UINT8_MAX - d[2] / TQ_UINT8_MAX; + *(dst++) = TQ_UINT8_MAX - d[3] / TQ_UINT8_MAX; + ++it; + } + } else { + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + *(dst++) = TQ_UINT8_MAX - d[0]; + *(dst++) = TQ_UINT8_MAX - d[1]; + *(dst++) = TQ_UINT8_MAX - d[2]; + *(dst++) = TQ_UINT8_MAX - d[3]; + ++it; + } + } + break; + default: + KIO::del(uri); + return KisImageBuilder_RESULT_UNSUPPORTED; + } + jpeg_write_scanlines(&cinfo, &row_pointer, 1); + } + + + // Writting is over + jpeg_finish_compress(&cinfo); + fclose(fp); + + delete [] row_pointer; + // Free memory + jpeg_destroy_compress(&cinfo); + + return KisImageBuilder_RESULT_OK; +} + + +void KisJPEGConverter::cancel() +{ + m_stop = true; +} + +#include "kis_jpeg_converter.moc" + diff --git a/filters/chalk/jpeg/kis_jpeg_converter.h b/filters/chalk/jpeg/kis_jpeg_converter.h new file mode 100644 index 00000000..8500d146 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_converter.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_JPEG_CONVERTER_H_ +#define _KIS_JPEG_CONVERTER_H_ + +#include + +extern "C" { +#include +} + +#include + +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_annotation.h" +class KisDoc; +class KisUndoAdapter; +class KisExifInfo; + +/** + * Image import/export plugins can use these results to report about success or failure. + */ +enum KisImageBuilder_Result { + KisImageBuilder_RESULT_FAILURE = -400, + KisImageBuilder_RESULT_NOT_EXIST = -300, + KisImageBuilder_RESULT_NOT_LOCAL = -200, + KisImageBuilder_RESULT_BAD_FETCH = -100, + KisImageBuilder_RESULT_INVALID_ARG = -50, + KisImageBuilder_RESULT_OK = 0, + KisImageBuilder_RESULT_PROGRESS = 1, + KisImageBuilder_RESULT_EMPTY = 100, + KisImageBuilder_RESULT_BUSY = 150, + KisImageBuilder_RESULT_NO_URI = 200, + KisImageBuilder_RESULT_UNSUPPORTED = 300, + KisImageBuilder_RESULT_INTR = 400, + KisImageBuilder_RESULT_PATH = 500, + KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600 +}; + +struct KisJPEGOptions { + int quality; + bool progressive; +}; + +class KisJPEGConverter : public KisProgressSubject { + Q_OBJECT + TQ_OBJECT + public: + KisJPEGConverter(KisDoc *doc, KisUndoAdapter *adapter); + virtual ~KisJPEGConverter(); + public: + KisImageBuilder_Result buildImage(const KURL& uri); + KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisJPEGOptions options, KisExifInfo* exifInfo); + /** Retrieve the constructed image + */ + KisImageSP image(); + public slots: + virtual void cancel(); + private: + KisImageBuilder_Result decode(const KURL& uri); + private: + KisImageSP m_img; + KisDoc *m_doc; + KisUndoAdapter *m_adapter; + bool m_stop; + KIO::TransferJob *m_job; +}; + +#endif diff --git a/filters/chalk/jpeg/kis_jpeg_export.cc b/filters/chalk/jpeg/kis_jpeg_export.cc new file mode 100644 index 00000000..edfbbc02 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_export.cc @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_jpeg_export.h" + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_jpeg_converter.h" +#include "kis_wdg_options_jpeg.h" + + +class KisExifInfoVisitor : public KisLayerVisitor +{ + public: + KisExifInfoVisitor() : + m_exifInfo(0), + m_countPaintLayer(0) + { }; + public: + virtual bool visit(KisPaintLayer* layer) { + m_countPaintLayer++; + if( layer->paintDevice()->hasExifInfo()) + m_exifInfo = layer->paintDevice()->exifInfo(); + return true; + }; + virtual bool visit(KisGroupLayer* layer) + { + kdDebug(41008) << "Visiting on grouplayer " << layer->name() << "\n"; + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + return true; + } + virtual bool visit(KisPartLayer *) { return true; }; + virtual bool visit(KisAdjustmentLayer* ) { return true; }; + public: + inline uint countPaintLayer() { return m_countPaintLayer; } + inline KisExifInfo* exifInfo() {return m_exifInfo; } + private: + KisExifInfo* m_exifInfo; + uint m_countPaintLayer; +}; + + +typedef KGenericFactory KisJPEGExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkjpegexport, KisJPEGExportFactory("kofficefilters")) + +KisJPEGExport::KisJPEGExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisJPEGExport::~KisJPEGExport() +{ +} + +KoFilter::ConversiontqStatus KisJPEGExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "JPEG export! From: " << from << ", To: " << to << "\n"; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + + KDialogBase* kdb = new KDialogBase(0, "", false, i18n("JPEG Export Options"), KDialogBase::Ok | KDialogBase::Cancel); + + KisWdgOptionsJPEG* wdg = new KisWdgOptionsJPEG(kdb); + kdb->setMainWidget(wdg); + kapp->restoreOverrideCursor(); + if(kdb->exec() == TQDialog::Rejected) + { + return KoFilter::OK; // FIXME Cancel doesn't exist :( + } + KisJPEGOptions options; + options.progressive = wdg->progressive->isChecked(); + options.quality = wdg->qualityLevel->value(); + + delete kdb; + // XXX: Add dialog about flattening layers here + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + KURL url; + url.setPath(filename); + + KisImageSP img = output->currentImage(); + Q_CHECK_PTR(img); + + KisJPEGConverter kpc(output, output->undoAdapter()); + + KisPaintDeviceSP pd = new KisPaintDevice(*img->projection()); + KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd); + + vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations(); + KisImageBuilder_Result res; + + KisExifInfoVisitor eIV; + eIV.visit( img->rootLayer() ); + + KisExifInfo* eI = 0; + if(eIV.countPaintLayer() == 1) + eI = eIV.exifInfo(); + + if ( (res = kpc.buildFile(url, l, beginIt, endIt, options, eI)) == KisImageBuilder_RESULT_OK) { + kdDebug(41008) << "success !" << endl; + return KoFilter::OK; + } + kdDebug(41008) << " Result = " << res << endl; + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/jpeg/kis_jpeg_export.h b/filters/chalk/jpeg/kis_jpeg_export.h new file mode 100644 index 00000000..a0f47351 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_export.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_JPEG_EXPORT_H_ +#define _KIS_JPEG_EXPORT_H_ + +#include + +class KisJPEGExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisJPEGExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisJPEGExport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/jpeg/kis_jpeg_import.cc b/filters/chalk/jpeg/kis_jpeg_import.cc new file mode 100644 index 00000000..2ca7c4c2 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_import.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_jpeg_import.h" + +#include + +#include + +#include +#include +#include +#include + +#include "kis_jpeg_converter.h" + +typedef KGenericFactory JPEGImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkjpegimport, JPEGImportFactory("kofficefilters")) + +KisJPEGImport::KisJPEGImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisJPEGImport::~KisJPEGImport() +{ +} + +KoFilter::ConversiontqStatus KisJPEGImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using JPEGImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc->prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url; + url.setPath(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisJPEGConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/jpeg/kis_jpeg_import.h b/filters/chalk/jpeg/kis_jpeg_import.h new file mode 100644 index 00000000..4cfb62c2 --- /dev/null +++ b/filters/chalk/jpeg/kis_jpeg_import.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_JPEG_IMPORT_H_ +#define _KIS_JPEG_IMPORT_H_ + +#include + +class KisJPEGImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisJPEGImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisJPEGImport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/jpeg/kis_wdg_options_jpeg.ui b/filters/chalk/jpeg/kis_wdg_options_jpeg.ui new file mode 100644 index 00000000..06c39edc --- /dev/null +++ b/filters/chalk/jpeg/kis_wdg_options_jpeg.ui @@ -0,0 +1,149 @@ + +KisWdgOptionsJPEG + + + KisWdgOptionsJPEG + + + + 0 + 0 + 167 + 87 + + + + + unnamed + + + 0 + + + + tqlayout4 + + + + unnamed + + + + textLabel1 + + + Quality: + + + AlignTop + + + + + tqlayout5 + + + + unnamed + + + + qualityLevel + + + 0 + + + 100 + + + 1 + + + 1 + + + 80 + + + Horizontal + + + Below + + + 10 + + + These settings determine how much information is lost during compression + + + + + tqlayout4 + + + + unnamed + + + + textLabel3 + + + Smallest + + + + + textLabel4 + + + Best + + + AlignVCenter|AlignRight + + + + + + + + + + + progressive + + + Pr&ogressive + + + Use progressive when publishing on the Internet + + + <p>Progressive is useful if you intend to publish your image on the Internet.<br> +Enabling progressive will cause the image to be displayed by the browser even while downloading.</p> + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 61 + + + + + + + diff --git a/filters/chalk/libkisexif/Makefile.am b/filters/chalk/libkisexif/Makefile.am new file mode 100644 index 00000000..96ccd5b5 --- /dev/null +++ b/filters/chalk/libkisexif/Makefile.am @@ -0,0 +1,20 @@ +INCLUDES = \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) +METASOURCES = AUTO +libkisexif_la_LDFLAGS = $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +noinst_LTLIBRARIES = libkisexif.la + + +libkisexif_la_SOURCES = kis_exif_io.cpp diff --git a/filters/chalk/libkisexif/kis_exif_io.cpp b/filters/chalk/libkisexif/kis_exif_io.cpp new file mode 100644 index 00000000..f02b49b7 --- /dev/null +++ b/filters/chalk/libkisexif/kis_exif_io.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_exif_io.h" + +#include + +extern "C" { +#include +#include +} + +KisExifIO::KisExifIO(KisExifInfo* ei) : m_exifInfo(ei) +{ +} + +void KisExifIO::readExifFromFile( const char* fileName) +{ + readExifData( exif_data_new_from_file(fileName) ); +} + +void KisExifIO::readExifFromMem( const unsigned char* data , unsigned int size) +{ + readExifData( exif_data_new_from_data(data, size) ); +} + +void KisExifIO::saveExifToMem( unsigned char** data, unsigned int *size) +{ + ExifData* exifData = exif_data_new(); + writeExifData( exifData ); + exif_data_save_data( exifData, data, size); +} + +ExifValue::ExifType KisExifIO::format2type(ExifFormat format) +{ + switch(format) + { + case EXIF_FORMAT_BYTE: + return ExifValue::EXIF_TYPE_BYTE; + case EXIF_FORMAT_ASCII: + return ExifValue::EXIF_TYPE_ASCII; + case EXIF_FORMAT_SHORT: + return ExifValue::EXIF_TYPE_SHORT; + case EXIF_FORMAT_LONG: + return ExifValue::EXIF_TYPE_LONG; + case EXIF_FORMAT_RATIONAL: + return ExifValue::EXIF_TYPE_RATIONAL; + case EXIF_FORMAT_SBYTE: + return ExifValue::EXIF_TYPE_SBYTE; + case EXIF_FORMAT_SSHORT: + return ExifValue::EXIF_TYPE_SSHORT; + case EXIF_FORMAT_SLONG: + return ExifValue::EXIF_TYPE_SLONG; + case EXIF_FORMAT_SRATIONAL: + return ExifValue::EXIF_TYPE_SRATIONAL; + case EXIF_FORMAT_FLOAT: + return ExifValue::EXIF_TYPE_FLOAT; + case EXIF_FORMAT_DOUBLE: + return ExifValue::EXIF_TYPE_DOUBLE; + default: + case EXIF_FORMAT_UNDEFINED: + return ExifValue::EXIF_TYPE_UNDEFINED; + } +} + +void KisExifIO::readExifData( ExifData* exifData) +{ + ExifValue::ByteOrder bO; + if(exif_data_get_byte_order( exifData) == EXIF_BYTE_ORDER_MOTOROLA) + { + bO = ExifValue::BYTE_ORDER_MOTOROLA; + } else { + bO = ExifValue::BYTE_ORDER_INTEL; + } + static ExifIfd ifds[5] = { + EXIF_IFD_0, + EXIF_IFD_1, + EXIF_IFD_EXIF, + EXIF_IFD_INTEROPERABILITY, + EXIF_IFD_GPS + }; + for(int ifd = 0; ifd < 5; ifd ++) + { + ExifContent* content = exifData->ifd[ifds[ifd]]; + kdDebug() << "There are " << content->count << " values in ifd=" << ifd << endl; + for (uint i = 0; i < content->count; i++) + { + ExifEntry* entry = content->entries[i]; + TQString tagname = exif_tag_get_name ( entry->tag ); +// kdDebug() << "found tag : " << tagname << endl; + // TQString tagname = exif_tag_get_name_in_ifd ( entry->tag, EXIF_IFD_0 ); TODO: would be better to rely on 0.6.13 when it becomes more common, as it supports better other IFD (GPS and interoperrabilibity) + ExifValue value( format2type(entry->format), entry->data, entry->size, ifds[ifd], entry->components, bO ); +// exif_entry_dump( entry, 4); +// kdDebug() << "value = " << value.toString() << endl; + m_exifInfo->setValue( tagname, value); + } + } + +} + +ExifFormat KisExifIO::type2format( ExifValue::ExifType type) +{ + switch(type) + { + case ExifValue::EXIF_TYPE_BYTE: + return EXIF_FORMAT_BYTE; + case ExifValue::EXIF_TYPE_ASCII: + return EXIF_FORMAT_ASCII; + case ExifValue::EXIF_TYPE_SHORT: + return EXIF_FORMAT_SHORT; + case ExifValue::EXIF_TYPE_LONG: + return EXIF_FORMAT_LONG; + case ExifValue::EXIF_TYPE_RATIONAL: + return EXIF_FORMAT_RATIONAL; + case ExifValue::EXIF_TYPE_SBYTE: + return EXIF_FORMAT_SBYTE; + case ExifValue::EXIF_TYPE_SSHORT: + return EXIF_FORMAT_SSHORT; + case ExifValue::EXIF_TYPE_SLONG: + return EXIF_FORMAT_SLONG; + case ExifValue::EXIF_TYPE_SRATIONAL: + return EXIF_FORMAT_SRATIONAL; + case ExifValue::EXIF_TYPE_FLOAT: + return EXIF_FORMAT_FLOAT; + case ExifValue::EXIF_TYPE_DOUBLE: + return EXIF_FORMAT_DOUBLE; + default: + case ExifValue::EXIF_TYPE_UNDEFINED: + return EXIF_FORMAT_UNDEFINED; + } +} + + +void KisExifIO::writeExifData( ExifData* exifData) +{ + ExifValue::ByteOrder bO; + if(exif_data_get_byte_order( exifData) == EXIF_BYTE_ORDER_MOTOROLA) + { + bO = ExifValue::BYTE_ORDER_MOTOROLA; + } else { + bO = ExifValue::BYTE_ORDER_INTEL; + } + + for( KisExifInfo::evMap::const_iterator it = m_exifInfo->begin(); it != m_exifInfo->end(); ++it) + { + ExifValue ev = it.data(); + if(ev.ifd() != -1) + { + ExifEntry * entry = exif_entry_new(); + ExifContent* content = exifData->ifd[ev.ifd()]; + exif_content_add_entry(content, entry); + kdDebug() << "Saving tag:" << it.key() << " " << ev.toString() << endl; + ExifTag tag = exif_tag_from_name( it.key().ascii()); + entry->components = ev.components(); + entry->format = type2format( ev.type()); + entry->tag = tag; +// exif_entry_dump(entry, 2); + ev.convertToData(&entry->data, &entry->size, bO); + } + } +} diff --git a/filters/chalk/libkisexif/kis_exif_io.h b/filters/chalk/libkisexif/kis_exif_io.h new file mode 100644 index 00000000..58928811 --- /dev/null +++ b/filters/chalk/libkisexif/kis_exif_io.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_EXIF_IO_H +#define KIS_EXIF_IO_H + +extern "C" { +#include +} + +#include + +class KisExifIO { + public: + KisExifIO( KisExifInfo* ei); + public: + void readExifFromFile( const char* fileName ); + void readExifFromMem( const unsigned char* data , unsigned int size); + void saveExifToMem( unsigned char** data , unsigned int *size); + private: + void readExifData( ExifData* exifData ); + void writeExifData( ExifData* exifData ); + ExifFormat type2format( ExifValue::ExifType type); + ExifValue::ExifType format2type(ExifFormat format); + private: + KisExifInfo* m_exifInfo; +}; + +#endif diff --git a/filters/chalk/magick/Makefile.am b/filters/chalk/magick/Makefile.am new file mode 100644 index 00000000..b64ea1ce --- /dev/null +++ b/filters/chalk/magick/Makefile.am @@ -0,0 +1,44 @@ +kde_module_LTLIBRARIES = libchalkmagickimport.la libchalkmagickexport.la + +libchalkmagickexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkmagickexport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +libchalkmagickimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkmagickimport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) \ + $(all_includes) + +service_DATA = chalk_magick_import.desktop chalk_magick_export.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_magick.desktop +kdelnkdir = $(kde_appsdir)/Office + +libchalkmagickimport_la_SOURCES = magickimport.cpp kis_image_magick_converter.cc +libchalkmagickexport_la_SOURCES = magickexport.cpp kis_image_magick_converter.cc + +METASOURCES = AUTO + + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/filters/chalk/magick/chalk_magick.desktop b/filters/chalk/magick/chalk_magick.desktop new file mode 100644 index 00000000..621ad158 --- /dev/null +++ b/filters/chalk/magick/chalk_magick.desktop @@ -0,0 +1,58 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +MimeType=image/x-xcf-gimp;image/gif;image/cgm;image/x-bmp;image/x-ico;image/x-pcx;image/x-portable-pixmap;image/x-targa;image/x-xbm;image/x-xcf;image/x-xpm;image/x-vnd.adobe.photoshop;image/x-rgb +Type=Application +Icon=chalk +Categories=Qt;KDE;Office;Graphics; +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +NoDisplay=true diff --git a/filters/chalk/magick/chalk_magick_export.desktop b/filters/chalk/magick/chalk_magick_export.desktop new file mode 100644 index 00000000..9bbdedc8 --- /dev/null +++ b/filters/chalk/magick/chalk_magick_export.desktop @@ -0,0 +1,55 @@ +[Desktop Entry] +Name=Chalk Magick Export Filter +Name[bg]=Филтър за експортиране от Chalk в Magick +Name[br]=Sil ezporzh Magick evit Chalk +Name[ca]=Filtre d'exportació Magick per a Chalk +Name[cy]=Hidl Allforio Magick Chalk +Name[da]=Chalk Magick-eksportfilter +Name[de]=Chalk Magick-Exportfilter +Name[el]=Φίλτρο εξαγωγής Magick του Chalk +Name[eo]=Chalk Magick-eksportfiltrilo +Name[es]=Filtro de exportación a Magick de Chalk +Name[et]=Chalk Magick'i ekspordifilter +Name[eu]=Chalk-ren Magick esportaziorako iragazkia +Name[fa]=پالایۀ صادرات Chalk Magick +Name[fi]=Chalk Magick -vientisuodin +Name[fr]=Filtre d'exportation Magick de Chalk +Name[fy]=Chalk Magick Eksportfilter +Name[ga]=Scagaire Easpórtála Magick Chalk +Name[gl]=Filtro de Exportación de Magick para Chalk +Name[he]=מסנן יצוא מ־Chalk ל־Magick +Name[hr]=Chalk Magick filtar izvoza +Name[hu]=Chalk Magick exportszűrő +Name[is]=Chalk Magick útflutningssía +Name[it]=Filtro di esportazione Magick per Chalk +Name[ja]=Chalk Magick エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ Magick សម្រាប់ Chalk +Name[lt]=Chalk Magick eksportavimo filtras +Name[lv]=Chalk Magick eksporta filtrs +Name[ms]=Penapis Eksport Chalk Magick +Name[nb]=Magick-eksportfilter for Chalk +Name[nds]=Magick-Exportfilter för Chalk +Name[ne]=क्रिता म्याजिक निर्यात फिल्टर +Name[nl]=Chalk Magick Exportfilter +Name[nn]=Magick-eksportfilter for Chalk +Name[pl]=Filtr eksportu do formatu Magick z Chalk +Name[pt]=Filtro de Exportação de Magick para o Chalk +Name[pt_BR]=Filtro de exportação Magick para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в Magick +Name[se]=Chalk Magick-olggosfievrridansilli +Name[sk]=Magick filter pre export do Chalk +Name[sl]=Izvozni filter Magick za Krito +Name[sr]=Chalk-ин филтер за извоз у Magick +Name[sr@Latn]=Chalk-in filter za izvoz u Magick +Name[sv]=Chalk Magick-exportfilter +Name[uk]=Фільтр експорту Magick для Chalk +Name[uz]=Chalk Magick eksport filteri +Name[uz@cyrillic]=Chalk Magick экспорт филтери +Name[zh_CN]=Chalk Magick 导出过滤器 +Name[zh_TW]=Chalk Magick 匯出過濾程式 +X-KDE-Export=image/gif,image/cgm,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xpm,image/x-rgb,image/x-eps +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Import=application/x-chalk +X-KDE-Weight=1 +X-KDE-Library=libchalkmagickexport diff --git a/filters/chalk/magick/chalk_magick_import.desktop b/filters/chalk/magick/chalk_magick_import.desktop new file mode 100644 index 00000000..0d32448f --- /dev/null +++ b/filters/chalk/magick/chalk_magick_import.desktop @@ -0,0 +1,61 @@ +[Desktop Entry] +Type=Service +Name=Chalk Magick Import Filter +Name[bg]=Филтър за импортиране от Magick в Chalk +Name[br]=Sil enporzh Magick evit Chalk +Name[ca]=Filtre d'importació Magick per a Chalk +Name[cs]=Importní filtr formátu Magick pro Kritu +Name[cy]=Hidl Mewnforio Chalk Magick +Name[da]=Chalk Magick-importfilter +Name[de]=Chalk Magick-Importfilter +Name[el]=Φίλτρο εισαγωγής Magick του Chalk +Name[eo]=Chalk Magick-importfiltrilo +Name[es]=Filtro de importación a Magick de Chalk +Name[et]=Chalk Magick'i impordifilter +Name[eu]=Chalk-ren Magick inportaziorako iragazkia +Name[fa]=پالایۀ واردات Chalk Magick +Name[fi]=Chalk Magick-tuontisuodin +Name[fr]=Filtre d'importation Magick de Chalk +Name[fy]=Chalk Magick Ymportfilter +Name[ga]=Scagaire Iompórtála Magick Chalk +Name[gl]=Filtro de Importación de Magick para Chalk +Name[he]=מסנן יבוא מ־Magick ל־Chalk +Name[hi]=के-रीता मैजिक आयात फ़िल्टर +Name[hr]=Chalk Magick filtar uvoza +Name[hu]=Chalk Magick importszűrő +Name[is]=Chalk Magick innflutningssía +Name[it]=Filtro di importazione Magick per Chalk +Name[ja]=Chalk Magick インポートフィルタ +Name[km]=តម្រង​នាំចូល Magick សម្រាប់ Chalk +Name[lo]= ຕົວຕອງການນຳເຂົ້າ WML ຂອງເອກະສານຂໍ້ຄວາມ K +Name[lt]=Chalk Magick importavimo filtras +Name[lv]=Chalk Magick importa filtrs +Name[ms]=Penapis Import Chalk Magick +Name[nb]=Magick-importfilter for Chalk +Name[nds]=Magick-Importfilter för Chalk +Name[ne]=क्रिता म्याजिक आयात फिल्टर +Name[nl]=Chalk Magick Importfilter +Name[nn]=Magick-importfilter for Chalk +Name[pl]=Filtr importu formatu Magick do Chalk +Name[pt]=Filtro de Importação de Magick para o Chalk +Name[pt_BR]=Filtro de importação Magick para o Chalk +Name[ru]=Фильтр импорта рисунков Magick в Chalk +Name[se]=Chalk Magick-sisafievrridansilli +Name[sk]=Magick filter pre import do Chalk +Name[sl]=Uvozni filter Magick za Krito +Name[sr]=Chalk-ин филтер за увоз из Magick-а +Name[sr@Latn]=Chalk-in filter za uvoz iz Magick-a +Name[sv]=Chalk Magick-importfilter +Name[ta]=Chalk மாயk இறக்குமதி வடிகட்டி +Name[tg]=Филтри Воридоти Chalk Magick +Name[tr]=Chalk Magick Alma Filtresi +Name[uk]=Фільтр імпорту Magick для Chalk +Name[uz]=Chalk Magick import filteri +Name[uz@cyrillic]=Chalk Magick импорт филтери +Name[zh_CN]=Chalk Magick 导入过滤器 +Name[zh_TW]=Chalk Magick 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-xcf-gimp,image/gif,image/cgm,image/x-bmp,image/x-ico,image/x-pcx,image/x-portable-pixmap,image/x-targa,image/x-xbm,image/x-xcf,image/x-xpm,image/x-vnd.adobe.photoshop,image/x-rgb,image/x-eps +X-KDE-Weight=1 +X-KDE-Library=libchalkmagickimport +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/magick/configure.in.bot b/filters/chalk/magick/configure.in.bot new file mode 100644 index 00000000..2d3cb2ca --- /dev/null +++ b/filters/chalk/magick/configure.in.bot @@ -0,0 +1,15 @@ +# ImageMagick is deprecated, we don't care anymore if it's not here +# +#if test -z "$LIBMAGICK_LIBS"; then +# echo "" +# echo "You're missing ImageMagick (>=6.1.0). chalk's ImageMagick import/export" +# echo "filter will not be compiled. You can download ImageMagick from" +# echo "http://www.imagemagick.org/. The ImageMagick filter allows chalk to" +# echo "read and write XCF, PSD, GIF, BMP, and many other image formats." +# echo "" +# echo "If you have problems compiling ImageMagick, please try configuring it using" +# echo "the --without-magick-plus-plus flag, the C++ API isn't needed for chalk." +# echo "" +# all_tests=bad +#fi + diff --git a/filters/chalk/magick/kis_image_magick_converter.cc b/filters/chalk/magick/kis_image_magick_converter.cc new file mode 100644 index 00000000..ee6267ad --- /dev/null +++ b/filters/chalk/magick/kis_image_magick_converter.cc @@ -0,0 +1,1087 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_undo_adapter.h" +#include "kis_image_magick_converter.h" +#include "kis_meta_registry.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_iterators_pixel.h" +#include "kis_colorspace.h" +#include "kis_profile.h" +#include "kis_annotation.h" +#include "kis_paint_layer.h" +#include "kis_group_layer.h" +#include "kis_paint_device.h" + +#include "../../../config.h" + +namespace { + + const TQ_UINT8 PIXEL_BLUE = 0; + const TQ_UINT8 PIXEL_GREEN = 1; + const TQ_UINT8 PIXEL_RED = 2; + const TQ_UINT8 PIXEL_ALPHA = 3; + + static const TQ_UINT8 PIXEL_CYAN = 0; + static const TQ_UINT8 PIXEL_MAGENTA = 1; + static const TQ_UINT8 PIXEL_YELLOW = 2; + static const TQ_UINT8 PIXEL_BLACK = 3; + static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4; + + static const TQ_UINT8 PIXEL_GRAY = 0; + static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1; + + /** + * Make this more flexible -- although... ImageMagick + * isn't that flexible either. + */ + TQString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8) + { + + if (type == GRAYColorspace) { + if (imageDepth == 8) + return "GRAYA"; + else if ( imageDepth == 16 ) + return "GRAYA16" ; + } + else if (type == CMYKColorspace) { + if (imageDepth == 8) + return "CMYK"; + else if ( imageDepth == 16 ) { + return "CMYK16"; + } + } + else if (type == LABColorspace) { + kdDebug(41008) << "Lab!\n"; + return "LABA"; + } + else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) { + if (imageDepth == 8) + return "RGBA"; + else if (imageDepth == 16) + return "RGBA16"; + } + return ""; + + } + + ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs ) + { + if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace; + if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace; + if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace; + if ( cs->id() == KisID("LABA") ) return LABColorspace; + + kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n"; + return RGBColorspace; + + } + + KisProfile * getProfileForProfileInfo(const Image * image) + { +#ifndef HAVE_MAGICK6 + return 0; +#else + + if (image->profiles == NULL) + return 0; + + const char *name; + const StringInfo *profile; + + KisProfile * p = 0; + + ResetImageProfileIterator(image); + for (name = GetNextImageProfile(image); name != (char *) NULL; ) + { + profile = GetImageProfile(image, name); + if (profile == (StringInfo *) NULL) + continue; + + // XXX: Hardcoded for icc type -- is that correct for us? + if (TQString::compare(name, "icc") == 0) { + TQByteArray rawdata; + rawdata.resize(profile->length); + memcpy(rawdata.data(), profile->datum, profile->length); + + p = new KisProfile(rawdata); + if (p == 0) + return 0; + } + name = GetNextImageProfile(image); + } + return p; +#endif + } + + void setAnnotationsForImage(const Image * src, KisImageSP image) + { +#ifndef HAVE_MAGICK6 + return; +#else + if (src->profiles == NULL) + return; + + const char *name = 0; + const StringInfo *profile; + KisAnnotation* annotation = 0; + + // Profiles and so + ResetImageProfileIterator(src); + while((name = GetNextImageProfile(src))) { + profile = GetImageProfile(src, name); + if (profile == (StringInfo *) NULL) + continue; + + // XXX: icc will be written seperately? + if (TQString::compare(name, "icc") == 0) + continue; + + TQByteArray rawdata; + rawdata.resize(profile->length); + memcpy(rawdata.data(), profile->datum, profile->length); + + annotation = new KisAnnotation(TQString(name), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); + } + + // Attributes, since we have no hint on if this is an attribute or a profile + // annotation, we prefix it with 'chalk_attribute:'. XXX This needs to be rethought! + // The joys of imagemagick. From at version 6.2.1 (dfaure has 6.2.0 and confirms the + // old way of doing things) they changed the src -> attributes + // to void* and require us to use the iterator functions. So we #if around that, *sigh* +#if MagickLibVersion >= 0x621 + const ImageAttribute * attr; + ResetImageAttributeIterator(src); + while ( (attr = GetNextImageAttribute(src)) ) { +#else + ImageAttribute * attr = src -> attributes; + while (attr) { +#endif + TQByteArray rawdata; + int len = strlen(attr -> value) + 1; + rawdata.resize(len); + memcpy(rawdata.data(), attr -> value, len); + + annotation = new KisAnnotation( + TQString("chalk_attribute:%1").tqarg(TQString(attr -> key)), "", rawdata); + Q_CHECK_PTR(annotation); + + image -> addAnnotation(annotation); +#if MagickLibVersion < 0x620 + attr = attr -> next; +#endif + } + +#endif + } + } + + void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd) + { +#ifndef HAVE_MAGICK6 + return; +#else + while(it != annotationsEnd) { + if (!(*it) || (*it) -> type() == TQString()) { + kdDebug(41008) << "Warning: empty annotation" << endl; + ++it; + continue; + } + + kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl; + + if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute + if (!SetImageAttribute(dst, + (*it) -> type().mid(strlen("chalk_attribute:")).ascii(), + (*it) -> annotation() . data()) ) { + kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n"; + } + } else { // Profile + if (!ProfileImage(dst, (*it) -> type().ascii(), + (unsigned char*)(*it) -> annotation() . data(), + (*it) -> annotation() . size(), MagickFalse)) { + kdDebug(41008) << "Storing failed!" << endl; + } + } + ++it; + } +#endif + } + + + void InitGlobalMagick() + { + static bool init = false; + + if (!init) { + KApplication *app = KApplication::kApplication(); + + InitializeMagick(*app -> argv()); + atexit(DestroyMagick); + init = true; + } + } + + /* + * ImageMagick progress monitor callback. Unfortunately it doesn't support passing in some user + * data which complicates things quite a bit. The plan was to allow the user start multiple + * import/scans if he/she so wished. However, without passing user data it's not possible to tell + * on which task we have made progress on. + * + * Additionally, ImageMagick is thread-safe, not re-entrant... i.e. IM does not relinquish held + * locks when calling user defined callbacks, this means that the same thread going back into IM + * would deadlock since it would try to acquire locks it already holds. + */ +#ifdef HAVE_MAGICK6 + MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *) + { + KApplication *app = KApplication::kApplication(); + + Q_ASSERT(app); + + if (app -> hasPendingEvents()) + app -> processEvents(); + + printf("%s\n", text); + return MagickTrue; + } +#else + unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *) + { + KApplication *app = KApplication::kApplication(); + + Q_ASSERT(app); + + if (app -> hasPendingEvents()) + app -> processEvents(); + + printf("%s\n", text); + return true; + } +#endif + + + +KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter) +{ + InitGlobalMagick(); + init(doc, adapter); + SetMonitorHandler(monitor); + m_stop = false; +} + +KisImageMagickConverter::~KisImageMagickConverter() +{ +} + +KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob) +{ + Image *image; + Image *images; + ExceptionInfo ei; + ImageInfo *ii; + + if (m_stop) { + m_img = 0; + return KisImageBuilder_RESULT_INTR; + } + + GetExceptionInfo(&ei); + ii = CloneImageInfo(0); + + if (isBlob) { + + // TODO : Test. Does BlobToImage even work? + Q_ASSERT(uri.isEmpty()); + images = BlobToImage(ii, &m_data[0], m_data.size(), &ei); + } else { + + qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1); + + if (ii -> filename[MaxTextExtent - 1]) { + emit notifyProgressError(); + return KisImageBuilder_RESULT_PATH; + } + + images = ReadImage(ii, &ei); + + } + + if (ei.severity != UndefinedException) + CatchException(&ei); + + if (images == 0) { + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + } + + emit notifyProgressStage(i18n("Importing..."), 0); + + m_img = 0; + + while ((image = RemoveFirstImageFromList(&images))) { + ViewInfo *vi = OpenCacheView(image); + + // Determine image depth -- for now, all channels of an imported image are of the same depth + unsigned long imageDepth = image->depth; + kdDebug(41008) << "Image depth: " << imageDepth << "\n"; + + TQString csName; + KisColorSpace * cs = 0; + ColorspaceType colorspaceType; + + // Determine image type -- rgb, grayscale or cmyk + if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) { + if (imageDepth == 8) + csName = "GRAYA"; + else if ( imageDepth == 16 ) + csName = "GRAYA16" ; + colorspaceType = GRAYColorspace; + } + else { + colorspaceType = image->colorspace; + csName = getColorSpaceName(image -> colorspace, imageDepth); + } + + kdDebug(41008) << "image has " << csName << " colorspace\n"; + + KisProfile * profile = getProfileForProfileInfo(image); + if (profile) + { + kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n"; + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile); + } + else + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),""); + + if (!cs) { + kdDebug(41008) << "Chalk does not support colorspace " << image -> colorspace << "\n"; + CloseCacheView(vi); + DestroyImage(image); + DestroyExceptionInfo(&ei); + DestroyImageList(images); + DestroyImageInfo(ii); + emit notifyProgressError(); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + + if( ! m_img) { + m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image"); + Q_CHECK_PTR(m_img); + m_img->blockSignals(true); // Don't send out signals while we're building the image + + // XXX I'm assuming seperate layers won't have other profile things like EXIF + setAnnotationsForImage(image, m_img); + } + + if (image -> columns && image -> rows) { + + // Opacity (set by the photoshop import filter) + TQ_UINT8 opacity = OPACITY_OPAQUE; + const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]"); + if (attr != 0) { + opacity = TQ_UINT8_MAX - Downscale(TQString(attr->value).toInt()); + } + + KisPaintLayerSP layer = 0; + + attr = GetImageAttribute(image, "[layer-name]"); + if (attr != 0) { + layer = new KisPaintLayer(m_img, attr->value, opacity); + } + else { + layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity); + } + + Q_ASSERT(layer); + + // Layerlocation (set by the photoshop import filter) + TQ_INT32 x_offset = 0; + TQ_INT32 y_offset = 0; + + attr = GetImageAttribute(image, "[layer-xpos]"); + if (attr != 0) { + x_offset = TQString(attr->value).toInt(); + } + + attr = GetImageAttribute(image, "[layer-ypos]"); + if (attr != 0) { + y_offset = TQString(attr->value).toInt(); + } + + + for (TQ_UINT32 y = 0; y < image->rows; y ++) + { + const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei); + + if(!pp) + { + CloseCacheView(vi); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + } + + IndexPacket * indexes = GetCacheViewIndexes(vi); + + KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true); + + if (colorspaceType== CMYKColorspace) { + if (imageDepth == 8) { + int x = 0; + while (!hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + *(ptr++) = Downscale(pp->red); // cyan + *(ptr++) = Downscale(pp->green); // magenta + *(ptr++) = Downscale(pp->blue); // yellow + *(ptr++) = Downscale(indexes[x]); // Black +// XXX: Warning! This ifdef messes up the paren matching big-time! +#ifdef HAVE_MAGICK6 + if (image->matte != MagickFalse) { +#else + if (image->matte == true) { +#endif + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + } + else { + *(ptr++) = OPACITY_OPAQUE; + } + ++x; + pp++; + ++hiter; + } + } + } + else if (colorspaceType == LABColorspace) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + + *(ptr++) = ScaleQuantumToShort(pp->red); + *(ptr++) = ScaleQuantumToShort(pp->green); + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + else if (colorspaceType == RGBColorspace || + colorspaceType == sRGBColorspace || + colorspaceType == TransparentColorspace) + { + if (imageDepth == 8) { + while(! hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + // XXX: not colorstrategy and bitdepth independent + *(ptr++) = Downscale(pp->blue); + *(ptr++) = Downscale(pp->green); + *(ptr++) = Downscale(pp->red); + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + + pp++; + ++hiter; + } + } + else if (imageDepth == 16) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + // XXX: not colorstrategy independent + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = ScaleQuantumToShort(pp->green); + *(ptr++) = ScaleQuantumToShort(pp->red); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + } + else if ( colorspaceType == GRAYColorspace) { + if (imageDepth == 8) { + while(! hiter.isDone()) + { + TQ_UINT8 *ptr= hiter.rawData(); + // XXX: not colorstrategy and bitdepth independent + *(ptr++) = Downscale(pp->blue); + *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity); + + pp++; + ++hiter; + } + } + else if (imageDepth == 16) { + while(! hiter.isDone()) + { + TQ_UINT16 *ptr = reinterpret_cast(hiter.rawData()); + // XXX: not colorstrategy independent + *(ptr++) = ScaleQuantumToShort(pp->blue); + *(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity); + + pp++; + ++hiter; + } + } + } + + emit notifyProgress(y * 100 / image->rows); + + if (m_stop) { + CloseCacheView(vi); + DestroyImage(image); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + m_img = 0; + return KisImageBuilder_RESULT_INTR; + } + } + m_img->addLayer(layer.data(), m_img->rootLayer()); + layer->paintDevice()->move(x_offset, y_offset); + } + + emit notifyProgressDone(); + CloseCacheView(vi); + DestroyImage(image); + } + + emit notifyProgressDone(); + DestroyImageList(images); + DestroyImageInfo(ii); + DestroyExceptionInfo(&ei); + return KisImageBuilder_RESULT_OK; + } + + KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri) + { + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) { + return KisImageBuilder_RESULT_NOT_EXIST; + } + + KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE; + TQString tmpFile; + + if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) { + KURL uriTF; + uriTF.setPath( tmpFile ); + result = decode(uriTF, false); + KIO::NetAccess::removeTempFile(tmpFile); + } + + return result; + } + + + KisImageSP KisImageMagickConverter::image() + { + return m_img; + } + + void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter) + { + m_doc = doc; + m_adapter = adapter; + m_job = 0; + } + + KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd) + { + Image *image; + ExceptionInfo ei; + ImageInfo *ii; + + if (!layer) + return KisImageBuilder_RESULT_INVALID_ARG; + + KisImageSP img = layer->image(); + if (!img) + return KisImageBuilder_RESULT_EMPTY; + + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!uri.isLocalFile()) + return KisImageBuilder_RESULT_NOT_LOCAL; + + + TQ_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels(); + + GetExceptionInfo(&ei); + + ii = CloneImageInfo(0); + + qstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1); + + if (ii -> filename[MaxTextExtent - 1]) { + emit notifyProgressError(); + return KisImageBuilder_RESULT_PATH; + } + + if (!img -> width() || !img -> height()) + return KisImageBuilder_RESULT_EMPTY; + + if (layerBytesPerChannel < 2) { + ii->depth = 8; + } + else { + ii->depth = 16; + } + + ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace()); + + image = AllocateImage(ii); + SetImageColorspace(image, ii->colorspace); + image -> columns = img -> width(); + image -> rows = img -> height(); + + kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n"; + kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n"; + +#ifdef HAVE_MAGICK6 + // if ( layer-> hasAlpha() ) + image -> matte = MagickTrue; + // else + // image -> matte = MagickFalse; +#else + // image -> matte = layer -> hasAlpha(); + image -> matte = true; +#endif + + TQ_INT32 y, height, width; + + height = img -> height(); + width = img -> width(); + + bool alpha = true; + TQString ext = TQFileInfo(TQFile::encodeName(uri.path())).extension(false).upper(); + if (ext == "BMP") { + alpha = false; + qstrncpy(ii->magick, "BMP2", MaxTextExtent - 1); + } + else if (ext == "RGB") { + qstrncpy(ii->magick, "SGI", MaxTextExtent - 1); + } + + for (y = 0; y < height; y++) { + + // Allocate pixels for this scanline + PixelPacket * pp = SetImagePixels(image, 0, y, width, 1); + + if (!pp) { + DestroyExceptionInfo(&ei); + DestroyImage(image); + emit notifyProgressError(); + return KisImageBuilder_RESULT_FAILURE; + + } + + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false); + if (alpha) + SetImageType(image, TrueColorMatteType); + else + SetImageType(image, TrueColorType); + + if (image->colorspace== CMYKColorspace) { + + IndexPacket * indexes = GetIndexes(image); + int x = 0; + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]); + pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_CMYK_ALPHA]); + indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]); + x++; + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_CYAN]); + pp -> green = Upscale(d[PIXEL_MAGENTA]); + pp -> blue = Upscale(d[PIXEL_YELLOW]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]); + + indexes[x]= Upscale(d[PIXEL_BLACK]); + + x++; + pp++; + ++it; + } + } + } + else if (image->colorspace== RGBColorspace || + image->colorspace == sRGBColorspace || + image->colorspace == TransparentColorspace) + { + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_RED]); + pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_ALPHA]); + + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_RED]); + pp -> green = Upscale(d[PIXEL_GREEN]); + pp -> blue = Upscale(d[PIXEL_BLUE]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_ALPHA]); + + pp++; + ++it; + } + } + } + else if (image->colorspace == GRAYColorspace) + { + SetImageType(image, GrayscaleMatteType); + if (layerBytesPerChannel == 2) { + while (!it.isDone()) { + + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]); + pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]); + pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]); + if (alpha) + pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_GRAY_ALPHA]); + + pp++; + ++it; + } + } + else { + while (!it.isDone()) { + TQ_UINT8 * d = it.rawData(); + pp -> red = Upscale(d[PIXEL_GRAY]); + pp -> green = Upscale(d[PIXEL_GRAY]); + pp -> blue = Upscale(d[PIXEL_GRAY]); + if (alpha) + pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]); + + pp++; + ++it; + } + } + } + else { + kdDebug(41008) << "Unsupported image format\n"; + return KisImageBuilder_RESULT_INVALID_ARG; + } + + emit notifyProgressStage(i18n("Saving..."), y * 100 / height); + +#ifdef HAVE_MAGICK6 + if (SyncImagePixels(image) == MagickFalse) + kdDebug(41008) << "Syncing pixels failed\n"; +#else + if (!SyncImagePixels(image)) + kdDebug(41008) << "Syncing pixels failed\n"; +#endif + } + + // set the annotations + exportAnnotationsForImage(image, annotationsStart, annotationsEnd); + + // XXX: Write to a temp file, then have Chalk use KIO to copy temp + // image to remote location. + + WriteImage(ii, image); + DestroyExceptionInfo(&ei); + DestroyImage(image); + emit notifyProgressDone(); + return KisImageBuilder_RESULT_OK; + } + + void KisImageMagickConverter::ioData(KIO::Job *job, const TQByteArray& data) + { + if (data.isNull() || data.isEmpty()) { + emit notifyProgressStage(i18n("Loading..."), 0); + return; + } + + if (m_data.empty()) { + Image *image; + ImageInfo *ii; + ExceptionInfo ei; + + ii = CloneImageInfo(0); + GetExceptionInfo(&ei); + image = PingBlob(ii, data.data(), data.size(), &ei); + + if (image == 0 || ei.severity == BlobError) { + DestroyExceptionInfo(&ei); + DestroyImageInfo(ii); + job -> kill(); + emit notifyProgressError(); + return; + } + + DestroyImage(image); + DestroyExceptionInfo(&ei); + DestroyImageInfo(ii); + emit notifyProgressStage(i18n("Loading..."), 0); + } + + Q_ASSERT(data.size() + m_data.size() <= m_size); + memcpy(&m_data[m_data.size()], data.data(), data.count()); + m_data.resize(m_data.size() + data.count()); + emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size); + + if (m_stop) + job -> kill(); + } + + void KisImageMagickConverter::ioResult(KIO::Job *job) + { + m_job = 0; + + if (job -> error()) + emit notifyProgressError(); + + decode(KURL(), true); + } + + void KisImageMagickConverter::ioTotalSize(KIO::Job * /*job*/, KIO::filesize_t size) + { + m_size = size; + m_data.reserve(size); + emit notifyProgressStage(i18n("Loading..."), 0); + } + + void KisImageMagickConverter::cancel() + { + m_stop = true; + } + + /** + * @name readFilters + * @return Provide a list of file formats the application can read. + */ + TQString KisImageMagickConverter::readFilters() + { + TQString s; + TQString all; + TQString name; + TQString description; + unsigned long matches; + +#ifdef HAVE_MAGICK6 +#ifdef HAVE_OLD_GETMAGICKINFOLIST + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches); +#else // HAVE_OLD_GETMAGICKINFOLIST + ExceptionInfo ei; + GetExceptionInfo(&ei); + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches, &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_OLD_GETMAGICKINFOLIST +#else // HAVE_MAGICK6 + const MagickInfo *mi; + ExceptionInfo ei; + GetExceptionInfo(&ei); + mi = GetMagickInfo("*", &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_MAGICK6 + + if (!mi) + return s; + +#ifdef HAVE_MAGICK6 + for (unsigned long i = 0; i < matches; i++) { + const MagickInfo *info = mi[i]; + if (info -> stealth) + continue; + + if (info -> decoder) { + name = info -> name; + description = info -> description; + kdDebug(41008) << "Found import filter for: " << name << "\n"; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#else + for (; mi; mi = reinterpret_cast(mi -> next)) { + if (mi -> stealth) + continue; + if (mi -> decoder) { + name = mi -> name; + description = mi -> description; + kdDebug(41008) << "Found import filter for: " << name << "\n"; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#endif + + all += "|" + i18n("All Images"); + all += "\n"; + + return all + s; + } + + TQString KisImageMagickConverter::writeFilters() + { + TQString s; + TQString all; + TQString name; + TQString description; + unsigned long matches; + +#ifdef HAVE_MAGICK6 +#ifdef HAVE_OLD_GETMAGICKINFOLIST + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches); +#else // HAVE_OLD_GETMAGICKINFOLIST + ExceptionInfo ei; + GetExceptionInfo(&ei); + const MagickInfo **mi; + mi = GetMagickInfoList("*", &matches, &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_OLD_GETMAGICKINFOLIST +#else // HAVE_MAGICK6 + const MagickInfo *mi; + ExceptionInfo ei; + GetExceptionInfo(&ei); + mi = GetMagickInfo("*", &ei); + DestroyExceptionInfo(&ei); +#endif // HAVE_MAGICK6 + + if (!mi) { + kdDebug(41008) << "Eek, no magick info!\n"; + return s; + } + +#ifdef HAVE_MAGICK6 + for (unsigned long i = 0; i < matches; i++) { + const MagickInfo *info = mi[i]; + kdDebug(41008) << "Found export filter for: " << info -> name << "\n"; + if (info -> stealth) + continue; + + if (info -> encoder) { + name = info -> name; + + description = info -> description; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#else + for (; mi; mi = reinterpret_cast(mi -> next)) { + kdDebug(41008) << "Found export filter for: " << mi -> name << "\n"; + if (mi -> stealth) + continue; + + if (mi -> encoder) { + name = mi -> name; + + description = mi -> description; + + if (!description.isEmpty() && !description.tqcontains('/')) { + all += "*." + name.lower() + " *." + name + " "; + s += "*." + name.lower() + " *." + name + "|"; + s += i18n(description.utf8()); + s += "\n"; + } + } + } +#endif + + + all += "|" + i18n("All Images"); + all += "\n"; + + return all + s; + } + +#include "kis_image_magick_converter.moc" + diff --git a/filters/chalk/magick/kis_image_magick_converter.h b/filters/chalk/magick/kis_image_magick_converter.h new file mode 100644 index 00000000..28bd94ce --- /dev/null +++ b/filters/chalk/magick/kis_image_magick_converter.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef KIS_IMAGE_MAGICK_CONVERTER_H_ +#define KIS_IMAGE_MAGICK_CONVERTER_H_ + +#include +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_progress_subject.h" + +class TQString; +class KURL; +class KisDoc; +class KisNameServer; +class KisUndoAdapter; +/** + * Image import/export plugins can use these results to report about success or failure. + */ +enum KisImageBuilder_Result { + KisImageBuilder_RESULT_FAILURE = -400, + KisImageBuilder_RESULT_NOT_EXIST = -300, + KisImageBuilder_RESULT_NOT_LOCAL = -200, + KisImageBuilder_RESULT_BAD_FETCH = -100, + KisImageBuilder_RESULT_INVALID_ARG = -50, + KisImageBuilder_RESULT_OK = 0, + KisImageBuilder_RESULT_PROGRESS = 1, + KisImageBuilder_RESULT_EMPTY = 100, + KisImageBuilder_RESULT_BUSY = 150, + KisImageBuilder_RESULT_NO_URI = 200, + KisImageBuilder_RESULT_UNSUPPORTED = 300, + KisImageBuilder_RESULT_INTR = 400, + KisImageBuilder_RESULT_PATH = 500, + KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600 +}; + + + +/** + * Build a KisImage representation of an image file. + */ +class KisImageMagickConverter : public KisProgressSubject { + typedef TQObject super; + Q_OBJECT + TQ_OBJECT + +public: + KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter); + virtual ~KisImageMagickConverter(); + +public slots: + virtual void cancel(); + +public: + KisImageBuilder_Result buildImage(const KURL& uri); + KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd); + KisImageSP image(); + +public: + static TQString readFilters(); + static TQString writeFilters(); + +private slots: + void ioData(KIO::Job *job, const TQByteArray& data); + void ioResult(KIO::Job *job); + void ioTotalSize(KIO::Job *job, KIO::filesize_t size); + +private: + KisImageMagickConverter(const KisImageMagickConverter&); + KisImageMagickConverter& operator=(const KisImageMagickConverter&); + void init(KisDoc *doc, KisUndoAdapter *adapter); + KisImageBuilder_Result decode(const KURL& uri, bool isBlob); + +private: + KisImageSP m_img; + KisDoc *m_doc; + KisUndoAdapter *m_adapter; + TQValueVector m_data; + KIO::TransferJob *m_job; + KIO::filesize_t m_size; + bool m_stop; +}; + +#endif // KIS_IMAGE_MAGICK_CONVERTER_H_ + diff --git a/filters/chalk/magick/magickexport.cpp b/filters/chalk/magick/magickexport.cpp new file mode 100644 index 00000000..09f351c1 --- /dev/null +++ b/filters/chalk/magick/magickexport.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory MagickExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkmagickexport, MagickExportFactory("kofficefilters")) + +MagickExport::MagickExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +MagickExport::~MagickExport() +{ +} + +KoFilter::ConversiontqStatus MagickExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "magick export! From: " << from << ", To: " << to << "\n"; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + // XXX: Add dialog about flattening layers here + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + KURL url; + url.setPath(filename); + + KisImageSP img = output->currentImage(); + + KisImageMagickConverter ib(output, output->undoAdapter()); + + KisPaintDeviceSP pd = new KisPaintDevice(*img->projection()); + KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd); + + vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations(); + if (ib.buildFile(url, l, beginIt, endIt) == KisImageBuilder_RESULT_OK) { + return KoFilter::OK; + } + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/magick/magickexport.h b/filters/chalk/magick/magickexport.h new file mode 100644 index 00000000..6ea7e238 --- /dev/null +++ b/filters/chalk/magick/magickexport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef MAGICKEXPORT_H_ +#define MAGICKEXPORT_H_ + +#include + +class MagickExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + MagickExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~MagickExport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // MAGICKEXPORT_H_ + diff --git a/filters/chalk/magick/magickimport.cpp b/filters/chalk/magick/magickimport.cpp new file mode 100644 index 00000000..b5f73d19 --- /dev/null +++ b/filters/chalk/magick/magickimport.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +typedef KGenericFactory MagickImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkmagickimport, MagickImportFactory("kofficefilters")) + +MagickImport::MagickImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +MagickImport::~MagickImport() +{ +} + +KoFilter::ConversiontqStatus MagickImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using MagickImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url; + url.setPath(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisImageMagickConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/magick/magickimport.h b/filters/chalk/magick/magickimport.h new file mode 100644 index 00000000..3373f129 --- /dev/null +++ b/filters/chalk/magick/magickimport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002 Patrick Julien + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef MAGICKIMPORT_H_ +#define MAGICKIMPORT_H_ + +#include + +class MagickImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + MagickImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~MagickImport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // MAGICKIMPORT_H_ + diff --git a/filters/chalk/openexr/Makefile.am b/filters/chalk/openexr/Makefile.am new file mode 100644 index 00000000..26470890 --- /dev/null +++ b/filters/chalk/openexr/Makefile.am @@ -0,0 +1,51 @@ +AM_CPPFLAGS= \ + -I$(srcdir) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + -I$(top_srcdir)/chalk/colorspaces/rgb_f32 \ + -I$(top_srcdir)/chalk/colorspaces/rgb_f16half \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(OPENEXR_CFLAGS) \ + $(all_includes) + +kde_module_LTLIBRARIES = libchalk_openexr_import.la libchalk_openexr_export.la + +libchalk_openexr_export_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalk_openexr_export_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(OPENEXR_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la \ + $(top_builddir)/chalk/colorspaces/rgb_f32/libchalk_rgb_f32.la \ + $(top_builddir)/chalk/colorspaces/rgb_f16half/libchalk_rgb_f16half.la + + +libchalk_openexr_import_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts -L../../../lib/kofficecore/.libs/ -lkofficecore \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalk_openexr_import_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(OPENEXR_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la \ + $(top_builddir)/chalk/colorspaces/rgb_f32/libchalk_rgb_f32.la \ + $(top_builddir)/chalk/colorspaces/rgb_f16half/libchalk_rgb_f16half.la + + +service_DATA = chalk_openexr_import.desktop chalk_openexr_export.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_openexr.desktop +kdelnkdir = $(kde_appsdir)/.hidden + +libchalk_openexr_import_la_SOURCES = kis_openexr_import.cpp +libchalk_openexr_export_la_SOURCES = kis_openexr_export.cpp + +METASOURCES = AUTO + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + diff --git a/filters/chalk/openexr/chalk_openexr.desktop b/filters/chalk/openexr/chalk_openexr.desktop new file mode 100644 index 00000000..26f81ccd --- /dev/null +++ b/filters/chalk/openexr/chalk_openexr.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +MimeType=image/x-exr +Type=Application +Icon=chalk +Categories= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi diff --git a/filters/chalk/openexr/chalk_openexr_export.desktop b/filters/chalk/openexr/chalk_openexr_export.desktop new file mode 100644 index 00000000..92b68518 --- /dev/null +++ b/filters/chalk/openexr/chalk_openexr_export.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Chalk OpenEXR Export Filter +Name[bg]=Филтър за експортиране от Chalk в OpenEXR +Name[br]=Sil ezporzh OpenEXR evit Chalk +Name[ca]=Filtre d'exportació OpenEXR per a Chalk +Name[cy]=Hidl Allforio OpenEXR Chalk +Name[da]=Chalk OpenEXR-eksportfilter +Name[de]=Chalk OpenEXR-Exportfilter +Name[el]=Φίλτρο εξαγωγής OpenEXR του Chalk +Name[eo]=Chalk OpenEXR-eksportfiltrilo +Name[es]=Filtro de exportación a OpenEXR de Chalk +Name[et]=Chalk OpenEXR'i ekspordifilter +Name[fa]=پالایۀ صادرات Chalk OpenEXR +Name[fi]=Chalk OpenEXR -vientisuodin +Name[fr]=Filtre d'exportation OpenEXR de Chalk +Name[fy]=Chalk OpenEXR Eksportfilter +Name[ga]=Scagaire Easpórtála OpenEXR Chalk +Name[gl]=Filtro de Exportación de OpenEXR de Chalk +Name[he]=Chalk OpenEXR מסנן יצוא +Name[hr]=Chalk OpenEXR filtar izvoza +Name[hu]=Chalk OpenEXR exportszűrő +Name[is]=Chalk OpenEXR útflutningssía +Name[it]=Filtro di esportazione OpenEXR per Chalk +Name[ja]=Chalk OpenEXR エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ OpenEXR សម្រាប់ Chalk +Name[lt]=Chalk OpenEXR eksportavimo filtras +Name[lv]=Chalk OpenEXR eksporta filtrs +Name[nb]=OpenEXR-eksportfilter for Chalk +Name[nds]=OpenEXR-Exportfilter för Chalk +Name[ne]=क्रिता खुलाEXR निर्यात फिल्टर +Name[nl]=Chalk OpenEXR Exportfilter +Name[pl]=Filtr eksportu do formatu OpenEXR z Chalk +Name[pt]=Filtro de Exportação de OpenEXR do Chalk +Name[pt_BR]=Filtro de Exportação de OpenEXR do Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в OpenEXR +Name[se]=Chalk OpenEXR-olggosfievrridansilli +Name[sk]=Exportný filter Chalk OpenEXR +Name[sl]=Izvozni filter OpenEXR za Krito +Name[sr]=Chalk-ин филтер за извоз у OpenEXR +Name[sr@Latn]=Chalk-in filter za izvoz u OpenEXR +Name[sv]=Chalk OpenEXR-exportfilter +Name[uk]=Фільтр експорту OpenEXR для Chalk +Name[uz]=Chalk OpenEXR eksport filteri +Name[uz@cyrillic]=Chalk OpenEXR экспорт филтери +Name[zh_CN]=Chalk OpenEXR 导出过滤器 +Name[zh_TW]=Chalk OpenEXR 匯出過濾程式 +X-KDE-Export=image/x-exr +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Import=application/x-chalk +X-KDE-Weight=1 +X-KDE-Library=libchalk_openexr_export diff --git a/filters/chalk/openexr/chalk_openexr_import.desktop b/filters/chalk/openexr/chalk_openexr_import.desktop new file mode 100644 index 00000000..60f6bc54 --- /dev/null +++ b/filters/chalk/openexr/chalk_openexr_import.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Type=Service +Name=Chalk OpenEXR Import Filter +Name[bg]=Филтър за импортиране от OpenEXR в Chalk +Name[br]=Sil enporzh OpenEXR evit Chalk +Name[ca]=Filtre d'importació OpenEXR per a Chalk +Name[cy]=Hidl Mewnforio OpenEXR Chalk +Name[da]=Chalk OpenEXR-importfilter +Name[de]=Chalk OpenEXR-Importfilter +Name[el]=Φίλτρο εισαγωγής OpenEXR του Chalk +Name[eo]=Chalk OpenEXR-importfiltrilo +Name[es]=Filtro de importación a OpenEXR de Chalk +Name[et]=Chalk OpenEXR'i impordifilter +Name[fa]=پالایۀ واردات Chalk OpenEXR +Name[fi]=Chalk OpenEXR -tuontisuodin +Name[fr]=Filtre d'importation OpenEXT de Chalk +Name[fy]=Chalk OpenEXR Ymportfilter +Name[ga]=Scagaire Iompórtála OpenEXR Chalk +Name[gl]=Filtro de Importación de OpenEXR para Chalk +Name[he]=Chalk OpenEXR מסנן יבוא +Name[hr]=Chalk OpenEXR filtar uvoza +Name[hu]=Chalk OpenEXR importszűrő +Name[is]=Chalk OpenEXR innflutningssía +Name[it]=Filtro di importazione OpenEXR per Chalk +Name[ja]=Chalk OpenEXR インポートフィルタ +Name[km]=តម្រង​នាំចូល OpenEXR សម្រាប់ Chalk +Name[lt]=Chalk OpenEXR importavimo filtras +Name[lv]=Chalk OpenEXR importa filtrs +Name[nb]=OpenEXR-importfilter for Chalk +Name[nds]=OpenEXR-Importfilter för Chalk +Name[ne]=क्रिता खुलाEXR आयात फिल्टर +Name[nl]=Chalk OpenEXR Importfilter +Name[pl]=Filtr importu formatu OpenEXR do Chalk +Name[pt]=Filtro de Importação de OpenEXR para o Chalk +Name[pt_BR]=Filtro de Importação de OpenEXR para o Chalk +Name[ru]=Фильтр импорта рисунков OpenEXR в Chalk +Name[se]=Chalk OpenEXR-sisafievrridansilli +Name[sk]=OpenEXR filter pre import do Chalk +Name[sl]=Uvozni filter OpenEXR za Krito +Name[sr]=Chalk-ин филтер за увоз из OpenEXR-а +Name[sr@Latn]=Chalk-in filter za uvoz iz OpenEXR-a +Name[sv]=Chalk OpenEXR-importfilter +Name[uk]=Фільтр імпорту OpenEXR для Chalk +Name[uz]=Chalk OpenEXR import filteri +Name[uz@cyrillic]=Chalk OpenEXR импорт филтери +Name[zh_CN]=Chalk OpenEXR 导入过滤器 +Name[zh_TW]=Chalk OpenEXR 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-exr +X-KDE-Weight=1 +X-KDE-Library=libchalk_openexr_import +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/openexr/configure.in.bot b/filters/chalk/openexr/configure.in.bot new file mode 100644 index 00000000..3a743f82 --- /dev/null +++ b/filters/chalk/openexr/configure.in.bot @@ -0,0 +1,9 @@ +if test -z "$OPENEXR_LIBS"; then + echo "" + echo "You're missing the OpenEXR library. Chalk's OpenEXR import/export filter will " + echo "not be compiled. You can download OpenEXR from http://www.openexr.com or " + echo "install it from an appropriate binary package." + echo "" + all_tests=bad +fi + diff --git a/filters/chalk/openexr/kis_openexr_export.cpp b/filters/chalk/openexr/kis_openexr_export.cpp new file mode 100644 index 00000000..4859f5d9 --- /dev/null +++ b/filters/chalk/openexr/kis_openexr_export.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +#include +#include + +#include +#include +#include + +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_annotation.h" +#include "kis_types.h" +#include "kis_iterators_pixel.h" +#include "kis_abstract_colorspace.h" +#include "kis_paint_device.h" +#include "kis_rgb_f32_colorspace.h" +#include "kis_rgb_f16half_colorspace.h" + +#include "kis_openexr_export.h" + +using namespace std; +using namespace Imf; +using namespace Imath; + +typedef KGenericFactory KisOpenEXRExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalk_openexr_export, KisOpenEXRExportFactory("kofficefilters")) + +KisOpenEXRExport::KisOpenEXRExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisOpenEXRExport::~KisOpenEXRExport() +{ +} + +KoFilter::ConversiontqStatus KisOpenEXRExport::convert(const TQCString& from, const TQCString& to) +{ + if (to != "image/x-exr" || from != "application/x-chalk") { + return KoFilter::NotImplemented; + } + + kdDebug(41008) << "Chalk exporting to OpenEXR\n"; + + // XXX: Add dialog about flattening layers here + + KisDoc *doc = dynamic_cast(m_chain -> inputDocument()); + TQString filename = m_chain -> outputFile(); + + if (!doc) { + return KoFilter::CreationError; + } + + if (filename.isEmpty()) { + return KoFilter::FileNotFound; + } + + KisImageSP img = new KisImage(*doc -> currentImage()); + Q_CHECK_PTR(img); + + // Don't store this information in the document's undo adapter + bool undo = doc -> undoAdapter() -> undo(); + doc -> undoAdapter() -> setUndo(false); + + img -> flatten(); + + KisPaintLayerSP layer = dynamic_cast(img->activeLayer().data()); + Q_ASSERT(layer); + + doc -> undoAdapter() -> setUndo(undo); + + //KisF32RgbColorSpace * cs = static_cast((KisColorSpaceRegistry::instance() -> get(KisID("RGBAF32", "")))); + KisRgbF16HalfColorSpace *cs = dynamic_cast(layer->paintDevice()->colorSpace()); + + if (cs == 0) { + // We could convert automatically, but the conversion wants to be done with + // selectable profiles and rendering intent. + KMessageBox::information(0, i18n("The image is using an unsupported color space. " + "Please convert to 16-bit floating point RGB/Alpha " + "before saving in the OpenEXR format.")); + + // Don't show the couldn't save error dialog. + doc -> setErrorMessage("USER_CANCELED"); + + return KoFilter::WrongFormat; + } + + Box2i displayWindow(V2i(0, 0), V2i(img -> width() - 1, img -> height() - 1)); + + TQRect dataExtent = layer -> exactBounds(); + int dataWidth = dataExtent.width(); + int dataHeight = dataExtent.height(); + + Box2i dataWindow(V2i(dataExtent.left(), dataExtent.top()), V2i(dataExtent.right(), dataExtent.bottom())); + + RgbaOutputFile file(TQFile::encodeName(filename), displayWindow, dataWindow, WRITE_RGBA); + + TQMemArray pixels(dataWidth); + + for (int y = 0; y < dataHeight; ++y) { + + file.setFrameBuffer(pixels.data() - dataWindow.min.x - (dataWindow.min.y + y) * dataWidth, 1, dataWidth); + + KisHLineIterator it = layer->paintDevice()->createHLineIterator(dataWindow.min.x, dataWindow.min.y + y, dataWidth, false); + Rgba *rgba = pixels.data(); + + while (!it.isDone()) { + + // XXX: Currently we use unmultiplied data so premult it. + half unmultipliedRed; + half unmultipliedGreen; + half unmultipliedBlue; + half alpha; + + cs -> getPixel(it.rawData(), &unmultipliedRed, &unmultipliedGreen, &unmultipliedBlue, &alpha); + rgba -> r = unmultipliedRed * alpha; + rgba -> g = unmultipliedGreen * alpha; + rgba -> b = unmultipliedBlue * alpha; + rgba -> a = alpha; + ++it; + ++rgba; + } + file.writePixels(); + } + + //vKisAnnotationSP_it beginIt = img -> beginAnnotations(); + //vKisAnnotationSP_it endIt = img -> endAnnotations(); + return KoFilter::OK; +} + +#include "kis_openexr_export.moc" + diff --git a/filters/chalk/openexr/kis_openexr_export.h b/filters/chalk/openexr/kis_openexr_export.h new file mode 100644 index 00000000..56568e57 --- /dev/null +++ b/filters/chalk/openexr/kis_openexr_export.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_OPENEXR_EXPORT_H_ +#define KIS_OPENEXR_EXPORT_H_ + +#include + +class KisOpenEXRExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + KisOpenEXRExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisOpenEXRExport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // KIS_OPENEXR_EXPORT_H_ + diff --git a/filters/chalk/openexr/kis_openexr_import.cpp b/filters/chalk/openexr/kis_openexr_import.cpp new file mode 100644 index 00000000..974d4a67 --- /dev/null +++ b/filters/chalk/openexr/kis_openexr_import.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include +#include + +#include +#include +//#include +//#include +//#include +//#include + +#include + +#include "kis_types.h" +#include "kis_openexr_import.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_meta_registry.h" +#include "kis_layer.h" +#include "kis_paint_layer.h" +#include "kis_annotation.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_iterators_pixel.h" +#include "kis_abstract_colorspace.h" +#include "kis_rgb_f32_colorspace.h" +#include "kis_rgb_f16half_colorspace.h" + +using namespace std; +using namespace Imf; +using namespace Imath; + +typedef KGenericFactory KisOpenEXRImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalk_openexr_import, KisOpenEXRImportFactory("kofficefilters")) + +KisOpenEXRImport::KisOpenEXRImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisOpenEXRImport::~KisOpenEXRImport() +{ +} + +KoFilter::ConversiontqStatus KisOpenEXRImport::convert(const TQCString& from, const TQCString& to) +{ + if (from != "image/x-exr" || to != "application/x-chalk") { + return KoFilter::NotImplemented; + } + + kdDebug(41008) << "\n\n\nChalk importing from OpenEXR\n"; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + if (!doc) { + return KoFilter::CreationError; + } + + doc -> prepareForImport(); + + TQString filename = m_chain -> inputFile(); + + if (filename.isEmpty()) { + return KoFilter::FileNotFound; + } + + RgbaInputFile file(TQFile::encodeName(filename)); + Box2i dataWindow = file.dataWindow(); + Box2i displayWindow = file.displayWindow(); + + kdDebug(41008) << "Data window: " << TQRect(dataWindow.min.x, dataWindow.min.y, dataWindow.max.x - dataWindow.min.x + 1, dataWindow.max.y - dataWindow.min.y + 1) << endl; + kdDebug(41008) << "Display window: " << TQRect(displayWindow.min.x, displayWindow.min.y, displayWindow.max.x - displayWindow.min.x + 1, displayWindow.max.y - displayWindow.min.y + 1) << endl; + + int imageWidth = displayWindow.max.x - displayWindow.min.x + 1; + int imageHeight = displayWindow.max.y - displayWindow.min.y + 1; + + TQString imageName = "Imported from OpenEXR"; + + int dataWidth = dataWindow.max.x - dataWindow.min.x + 1; + int dataHeight = dataWindow.max.y - dataWindow.min.y + 1; + + KisRgbF16HalfColorSpace *cs = static_cast((KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBAF16HALF", ""),""))); + + if (cs == 0) { + return KoFilter::InternalError; + } + + doc -> undoAdapter() -> setUndo(false); + + KisImageSP image = new KisImage(doc->undoAdapter(), imageWidth, imageHeight, cs, imageName); + + if (image == 0) { + return KoFilter::CreationError; + } + + KisPaintLayerSP layer = dynamic_cast(image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data()); + + if (layer == 0) { + return KoFilter::CreationError; + } + + TQMemArray pixels(dataWidth); + + for (int y = 0; y < dataHeight; ++y) { + + file.setFrameBuffer(pixels.data() - dataWindow.min.x - (dataWindow.min.y + y) * dataWidth, 1, dataWidth); + file.readPixels(dataWindow.min.y + y); + + KisHLineIterator it = layer->paintDevice()->createHLineIterator(dataWindow.min.x, dataWindow.min.y + y, dataWidth, true); + Rgba *rgba = pixels.data(); + + while (!it.isDone()) { + + // XXX: For now unmultiply the alpha, though compositing will be faster if we + // keep it premultiplied. + half unmultipliedRed = rgba -> r; + half unmultipliedGreen = rgba -> g; + half unmultipliedBlue = rgba -> b; + + if (rgba -> a >= HALF_EPSILON) { + unmultipliedRed /= rgba -> a; + unmultipliedGreen /= rgba -> a; + unmultipliedBlue /= rgba -> a; + } + + cs -> setPixel(it.rawData(), unmultipliedRed, unmultipliedGreen, unmultipliedBlue, rgba -> a); + ++it; + ++rgba; + } + } + + layer->setDirty(); + doc -> setCurrentImage(image); + doc -> undoAdapter() -> setUndo(true); + doc -> setModified(false); + + return KoFilter::OK; +} + +#include "kis_openexr_import.moc" + diff --git a/filters/chalk/openexr/kis_openexr_import.h b/filters/chalk/openexr/kis_openexr_import.h new file mode 100644 index 00000000..f8cd5144 --- /dev/null +++ b/filters/chalk/openexr/kis_openexr_import.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005 Adrian Page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_OPENEXR_IMPORT_H_ +#define KIS_OPENEXR_IMPORT_H_ + +#include + +class KisOpenEXRImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + KisOpenEXRImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisOpenEXRImport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // KIS_OPENEXR_IMPORT_H_ + diff --git a/filters/chalk/pdf/Makefile.am b/filters/chalk/pdf/Makefile.am new file mode 100644 index 00000000..9357a98a --- /dev/null +++ b/filters/chalk/pdf/Makefile.am @@ -0,0 +1,30 @@ +INCLUDES = \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) $(POPPLER_CFLAGS) + +servicedir = $(kde_servicesdir) + +kdelnkdir = $(kde_appsdir)/.hidden + +METASOURCES = AUTO +kde_module_LTLIBRARIES = libchalkpdfimport.la +libchalkpdfimport_la_LDFLAGS = -avoid-version -module -no-undefined $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkpdfimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \ + -lpoppler-qt $(KOFFICE_LIBS) $(POPPLER_LIBS) + +noinst_HEADERS = kis_pdf_import.h kis_pdf_import_widget.h +libchalkpdfimport_la_SOURCES = kis_pdf_import.cpp pdfimportwidgetbase.ui \ + kis_pdf_import_widget.cpp +kde_services_DATA = chalk_pdf_import.desktop +kdelnk_DATA = chalk_pdf.desktop diff --git a/filters/chalk/pdf/chalk_pdf.desktop b/filters/chalk/pdf/chalk_pdf.desktop new file mode 100644 index 00000000..b518da84 --- /dev/null +++ b/filters/chalk/pdf/chalk_pdf.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Categories= +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +Icon=chalk +MimeType=application/pdf +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Path= +StartupNotify=true +Terminal=false +TerminalOptions= +Type=Application +X-DCOP-ServiceType=multi +X-KDE-StartupNotify=true +X-KDE-SubstituteUID=false +X-KDE-Username= diff --git a/filters/chalk/pdf/chalk_pdf_import.desktop b/filters/chalk/pdf/chalk_pdf_import.desktop new file mode 100644 index 00000000..cfc6e1ea --- /dev/null +++ b/filters/chalk/pdf/chalk_pdf_import.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Type=Service +Name=Chalk PDF Import Filter +Name[bg]=Филтър за импортиране от PDF в Chalk +Name[br]=Sil enporzh PDF evit Chalk +Name[ca]=Filtre d'importació PDF per a Chalk +Name[da]=Chalk PDF-importfilter +Name[de]=Chalk PDF-Importfilter +Name[el]=Φίλτρο εισαγωγής PDF του Chalk +Name[eo]=Chalk PD-importfiltrilo +Name[es]=Filtro de importación a PDF de Chalk +Name[et]=Chalk PDF impordifilter +Name[fa]=پالایۀ واردات Chalk PDF +Name[fr]=Filtre d'importation PDF de Chalk +Name[fy]=Chalk PDF Ymportfilter +Name[ga]=Scagaire Iompórtála PDF Chalk +Name[gl]=Filtro de Importación de PDF para Chalk +Name[hr]=Chalk PDF filtar uvoza +Name[hu]=Chalk PDF importszűrő +Name[it]=Filtro di importazione PDF per Chalk +Name[ja]=Chalk PDF インポートフィルタ +Name[km]=តម្រង​នាំចូល PNG របស់​រាប់ Chalk +Name[lt]=Chalk PDF importavimo filtras +Name[lv]=Chalk PDF importa filtrs +Name[nb]=PDF-importfilter for Chalk +Name[nds]=PDF-Importfilter för Chalk +Name[ne]=क्रिता PDF आयात फिल्टर +Name[nl]=Chalk PDF Importfilter +Name[pl]=Filtr importu formatu PDF do Chalk +Name[pt]=Filtro de Importação de PDF para o Chalk +Name[pt_BR]=Filtro de Importação de PDF para o Chalk +Name[ru]=Фильтр импорта документов PDF в Chalk +Name[se]=Chalk PDF-sisafievrridansilli +Name[sk]=PDF filter pre import do Chalk +Name[sl]=Uvozni filter PDF za Krito +Name[sr]=Chalk-ин филтер за увоз из PDF-а +Name[sr@Latn]=Chalk-in filter za uvoz iz PDF-a +Name[sv]=Chalk PDF-importfilter +Name[uk]=Фільтр імпорту PDF для Chalk +Name[uz]=Chalk uchun PDF import filteri +Name[uz@cyrillic]=Chalk учун PDF импорт филтери +Name[zh_TW]=Chalk PDF 匯入過濾程式 +Comment= +Comment[uz]=PDF-fayllarni Chalk bilan oʻqish vositasi +Comment[uz@cyrillic]=PDF-файлларни Chalk билан ўқиш воситаси +ServiceTypes=KOfficeFilter +X-KDE-Available= +X-KDE-Export=application/x-chalk +X-KDE-Import=application/pdf +X-KDE-Weight=1 +X-KDE-Library=libchalkpdfimport diff --git a/filters/chalk/pdf/configure.in.bot b/filters/chalk/pdf/configure.in.bot new file mode 100644 index 00000000..89bd198e --- /dev/null +++ b/filters/chalk/pdf/configure.in.bot @@ -0,0 +1,7 @@ +if test -z "$POPPLER_LIBS"; then + echo "" + echo "You're missing libpoppler 0.5.1 or later (binaries and/or headers)." + echo "chalk won't be able to import pdf" + echo "note that the qt-binding of libpoppler is required" + echo "" +fi diff --git a/filters/chalk/pdf/configure.in.in b/filters/chalk/pdf/configure.in.in new file mode 100644 index 00000000..e4343277 --- /dev/null +++ b/filters/chalk/pdf/configure.in.in @@ -0,0 +1,4 @@ +# Compile the pdf import filter only if Poppler is available +PKG_CHECK_MODULES(POPPLER, poppler-qt >= 0.5.1, have_poppler=yes, have_poppler=no) + +AM_CONDITIONAL(include_PDF, test "x$have_poppler" = xyes) diff --git a/filters/chalk/pdf/kis_pdf_import.cpp b/filters/chalk/pdf/kis_pdf_import.cpp new file mode 100644 index 00000000..2cef93e9 --- /dev/null +++ b/filters/chalk/pdf/kis_pdf_import.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_pdf_import.h" + +// poppler's headers +#include + +// TQt's headers +#include +#include // TODO that too +#include + +// KDE's headers +#include +#include +#include +#include +#include +#include + +#include + +// koffice's headers +#include + +// chalk's headers +#include +#include +#include +#include +#include +#include +#include + +// plugins's headers +#include "kis_pdf_import_widget.h" + +typedef KGenericFactory PDFImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkpdfimport, PDFImportFactory("kofficefilters")) + +KisPDFImport::KisPDFImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisPDFImport::~KisPDFImport() +{ +} + +KisPDFImport::ConversiontqStatus KisPDFImport::convert(const TQCString& , const TQCString& ) +{ + TQString filename = m_chain -> inputFile(); + kdDebug(41008) << "Importing using PDFImport!" << filename << endl; + + if (filename.isEmpty()) + return KoFilter::FileNotFound; + + + KURL url; + url.setPath(filename); + + if (!KIO::NetAccess::exists(url, false, tqApp -> mainWidget())) { + return KoFilter::FileNotFound; + } + + // We're not set up to handle asynchronous loading at the moment. + TQString tmpFile; + if (KIO::NetAccess::download(url, tmpFile, tqApp -> mainWidget())) { + url.setPath( tmpFile ); + } + + Poppler::Document* pdoc = Poppler::Document::load( TQFile::encodeName(url.path() ) ); + + + if ( !pdoc) + { + kdDebug(41008) << "Error when reading the PDF" << endl; + return KoFilter::StorageCreationError; + } + + + while( pdoc->isLocked() ) + { + TQCString password; + int result = KPasswordDialog::getPassword(password, i18n("A password is required to read that pdf")); + if (result == KPasswordDialog::Accepted) + { + pdoc->unlock(password); + } else { + kdDebug(41008) << "Password canceled" << endl; + return KoFilter::StorageCreationError; + } + } + + KDialogBase* kdb = new KDialogBase(0, "", false, i18n("PDF Import Options"), KDialogBase::Ok | KDialogBase::Cancel); + + KisPDFImportWidget* wdg = new KisPDFImportWidget(pdoc, kdb); + kdb->setMainWidget(wdg); + kapp->restoreOverrideCursor(); + if(kdb->exec() == TQDialog::Rejected) + { + delete pdoc; + delete kdb; + return KoFilter::StorageCreationError; // FIXME Cancel doesn't exist :( + } + + // Init kis's doc + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + if (!doc) + { + delete pdoc; + delete kdb; + return KoFilter::CreationError; + } + + doc -> prepareForImport(); + // Create the chalk image + KisColorSpace* cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA"), ""); + int width = wdg->intWidth->value(); + int height = wdg->intHeight->value(); + KisImageSP img = new KisImage(doc->undoAdapter(), width, height, cs, "built image"); + img->blockSignals(true); // Don't send out signals while we're building the image + + // create a layer + TQValueList pages = wdg->pages(); + for(TQValueList::const_iterator it = pages.begin(); it != pages.end(); ++it) + { + KisPaintLayer* layer = new KisPaintLayer(img, TQString(i18n("Page %1")).tqarg( TQString::number(*it) + 1), TQ_UINT8_MAX); + layer->paintDevice()->convertFromTQImage( pdoc->getPage( *it )->renderToImage(wdg->intHorizontal->value(), wdg->intVertical->value() ), ""); + img->addLayer(layer, img->rootLayer(), 0); + } + + img->blockSignals(false); + doc -> setCurrentImage( img); + + KIO::NetAccess::removeTempFile(tmpFile); + + delete pdoc; + delete kdb; + return KoFilter::OK; +} + diff --git a/filters/chalk/pdf/kis_pdf_import.h b/filters/chalk/pdf/kis_pdf_import.h new file mode 100644 index 00000000..ab4535b9 --- /dev/null +++ b/filters/chalk/pdf/kis_pdf_import.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PDF_IMPORT_H +#define KIS_PDF_IMPORT_H + +#include + +class KisPDFImport : public KoFilter{ + Q_OBJECT + TQ_OBJECT + public: + KisPDFImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisPDFImport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/pdf/kis_pdf_import_widget.cpp b/filters/chalk/pdf/kis_pdf_import_widget.cpp new file mode 100644 index 00000000..6919876f --- /dev/null +++ b/filters/chalk/pdf/kis_pdf_import_widget.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_pdf_import_widget.h" + +// poppler's headers +#include + +// TQt's headers +#include + +// KDE's headers +#include +#include +#include + +KisPDFImportWidget::KisPDFImportWidget(Poppler::Document* pdfDoc, TQWidget * tqparent, const char * name) + : PDFImportWidgetBase(tqparent, name), m_pdfDoc(pdfDoc) +{ + m_pages.push_back(0); // The first page is selected + updateMaxCanvasSize(); + + for(int i = 1; i <= m_pdfDoc->getNumPages(); i++) + { + listPages->insertItem(TQString::number( i ) ); + } + + connect(intWidth, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHRes() ) ); + connect(intHeight, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHVer() ) ); + connect(intHorizontal, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateWidth() ) ); + connect(intVertical, TQT_SIGNAL( valueChanged ( int ) ), this, TQT_SLOT( updateHeight() ) ); + connect(boolAllPages, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectAllPages( bool ) ) ); + connect(boolFirstPage, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectFirstPage( bool ) ) ); + connect(boolSelectionPage, TQT_SIGNAL( toggled ( bool ) ), this, TQT_SLOT( selectSelectionOfPages( bool ) ) ); + connect(listPages, TQT_SIGNAL(selectionChanged () ), this, TQT_SLOT(updateSelectionOfPages())); +} + + +KisPDFImportWidget::~KisPDFImportWidget() +{ +} + +void KisPDFImportWidget::selectAllPages(bool v) +{ + if(v) + { + m_pages.clear(); + for(int i = 0; i < m_pdfDoc->getNumPages(); i++) + { + m_pages.push_back(i); + } + updateMaxCanvasSize(); + } +} +void KisPDFImportWidget::selectFirstPage(bool v) +{ + if(v) + { + m_pages.clear(); + m_pages.push_back(0); // The first page is selected + } +} +void KisPDFImportWidget::selectSelectionOfPages(bool v) +{ + if(v) + { + updateSelectionOfPages(); + updateMaxCanvasSize(); + } + +} + +void KisPDFImportWidget::updateSelectionOfPages() +{ + if(! boolSelectionPage->isChecked ()) boolSelectionPage->toggle(); + m_pages.clear(); + for(int i = 0; i < m_pdfDoc->getNumPages(); i++) + { + if(listPages->isSelected(i)) m_pages.push_back(i); + } +} + + +void KisPDFImportWidget::updateMaxCanvasSize() { + m_maxWidthInch = 0., m_maxHeightInch =0.; + for(TQValueList::const_iterator it = m_pages.begin(); it != m_pages.end(); ++it) + { + Poppler::Page *p = m_pdfDoc->getPage(*it ); + TQSize size = p->pageSize(); + if(size.width() > m_maxWidthInch) + { + m_maxWidthInch = size.width(); + } + if(size.height() > m_maxHeightInch) + { + m_maxHeightInch = size.height(); + } + } + m_maxWidthInch /= 72.; + m_maxHeightInch /= 72.; + kdDebug() << m_maxWidthInch << " " << m_maxHeightInch << endl; + updateWidth(); + updateHeight(); +} + +void KisPDFImportWidget::updateWidth() +{ + intWidth->blockSignals(true); + intWidth->setValue( (int) m_maxWidthInch * intHorizontal->value() + 1 ); + intWidth->blockSignals(false); +} +void KisPDFImportWidget::updateHeight() +{ + intHeight->blockSignals(true); + intHeight->setValue( (int) m_maxHeightInch * intVertical->value() + 1 ); + intHeight->blockSignals(false); +} +void KisPDFImportWidget::updateHRes() +{ + intHorizontal->blockSignals(true); + intHorizontal->setValue( (int) (intWidth->value() / m_maxWidthInch ) ); + intHorizontal->blockSignals(false); +} +void KisPDFImportWidget::updateHVer() +{ + intVertical->blockSignals(true); + intVertical->setValue( (int) (intHeight->value() / m_maxHeightInch ) ); + intVertical->blockSignals(false); +} + +#include "kis_pdf_import_widget.moc" diff --git a/filters/chalk/pdf/kis_pdf_import_widget.h b/filters/chalk/pdf/kis_pdf_import_widget.h new file mode 100644 index 00000000..8fe806a8 --- /dev/null +++ b/filters/chalk/pdf/kis_pdf_import_widget.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_PDF_IMPORT_WIDGET_H +#define KIS_PDF_IMPORT_WIDGET_H + +#include + +namespace Poppler { +class Document; +} + +class KisPDFImportWidget : public PDFImportWidgetBase +{ + Q_OBJECT + TQ_OBJECT + public: + KisPDFImportWidget(Poppler::Document* pdfDoc, TQWidget * tqparent, const char * name = ""); + + ~KisPDFImportWidget(); + public: + inline TQValueList pages() { return m_pages; } + private slots: + void selectAllPages(bool v); + void selectFirstPage(bool v); + void selectSelectionOfPages(bool v); + void updateSelectionOfPages(); + void updateWidth(); + void updateHeight(); + void updateHRes(); + void updateHVer(); + void updateMaxCanvasSize(); + private: + Poppler::Document* m_pdfDoc; + TQValueList m_pages; + double m_maxWidthInch, m_maxHeightInch; +}; + +#endif diff --git a/filters/chalk/pdf/pdfimportwidgetbase.ui b/filters/chalk/pdf/pdfimportwidgetbase.ui new file mode 100644 index 00000000..19da5d15 --- /dev/null +++ b/filters/chalk/pdf/pdfimportwidgetbase.ui @@ -0,0 +1,321 @@ + +PDFImportWidgetBase + + + PDFImportWidgetBase + + + + 0 + 0 + 462 + 210 + + + + PDFImportWidget + + + + unnamed + + + + groupBox1 + + + Dimensions + + + + unnamed + + + + textLabel1 + + + Resolution: + + + + + tqlayout6 + + + + unnamed + + + + spacer2_2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + tqlayout2 + + + + unnamed + + + + intVerticalqsdf + + + Vertical: + + + + + + Dots/inch + + + + kComboBox1 + + + + + intHorizontal + + + 999 + + + 72 + + + + + intVertical + + + 999 + + + 72 + + + + + textLabel5 + + + Horizontal: + + + + + + Dots/inch + + + + kComboBox2 + + + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 31 + 20 + + + + + + + + textLabel2 + + + Size: + + + + + tqlayout4 + + + + unnamed + + + + spacer2 + + + Horizontal + + + Fixed + + + + 20 + 20 + + + + + + tqlayout3 + + + + unnamed + + + + intHeight + + + 99999 + + + + + intWidthzqffs + + + Width: + + + + + intWidth + + + 99999 + + + + + intHeightqsdfq + + + Height: + + + + + + + spacer1 + + + Horizontal + + + Expanding + + + + 51 + 20 + + + + + + + + + + buttonGroup1 + + + Pages + + + + unnamed + + + + boolAllPages + + + &All pages + + + + + boolFirstPage + + + &First page + + + true + + + + + boolSelectionPage + + + &Selection of page + + + + + listPages + + + Multi + + + + + + + + + + boolFirstPage + listPages + intHorizontal + kComboBox1 + intVertical + kComboBox2 + intWidth + intHeight + + + + kcombobox.h + knuminput.h + knuminput.h + kcombobox.h + knuminput.h + knuminput.h + klistbox.h + + diff --git a/filters/chalk/png/Makefile.am b/filters/chalk/png/Makefile.am new file mode 100644 index 00000000..fbee1638 --- /dev/null +++ b/filters/chalk/png/Makefile.am @@ -0,0 +1,44 @@ +kde_module_LTLIBRARIES = libchalkpngimport.la libchalkpngexport.la + +libchalkpngexport_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkpngexport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la \ + -lpng + +libchalkpngimport_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkpngimport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la \ + -lpng + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +service_DATA = chalk_png_import.desktop chalk_png_export.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_png.desktop +kdelnkdir = $(kde_appsdir)/.hidden + +libchalkpngimport_la_SOURCES = kis_png_import.cc kis_png_converter.cc +libchalkpngexport_la_SOURCES = kis_wdg_options_png.ui kis_png_export.cc kis_png_converter.cc + +METASOURCES = AUTO + + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/filters/chalk/png/chalk_png.desktop b/filters/chalk/png/chalk_png.desktop new file mode 100644 index 00000000..3605566b --- /dev/null +++ b/filters/chalk/png/chalk_png.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +MimeType=image/png +Type=Application +Icon=chalk +Categories= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi diff --git a/filters/chalk/png/chalk_png_export.desktop b/filters/chalk/png/chalk_png_export.desktop new file mode 100644 index 00000000..e4f6711b --- /dev/null +++ b/filters/chalk/png/chalk_png_export.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Name=Chalk PNG Export Filter +Name[bg]=Филтър за експортиране от Chalk в PNG +Name[br]=Sil ezporzh PNG evit Chalk +Name[ca]=Filtre d'exportació PNG per a Chalk +Name[da]=Chalk PNG-eksportfilter +Name[de]=Chalk PNG-Exportfilter +Name[el]=Φίλτρο εξαγωγής PNG του Chalk +Name[eo]=Chalk PNG-eksportfiltrilo +Name[es]=Filtro de exportación a PNG de Chalk +Name[et]=Chalk PNG ekspordifilter +Name[fa]=پالایۀ صادرات Chalk PNG +Name[fi]=Chalk PNG -viestisuodin +Name[fr]=Filtre d'exportation PNG de Chalk +Name[fy]=Chalk PNG Eksportfilter +Name[ga]=Scagaire Easpórtála PNG Chalk +Name[gl]=Filtro de Exportación de PNG para Chalk +Name[he]=Chalk PNG מסנן יצוא +Name[hr]=Chalk PNG filtar izvoza +Name[hu]=Chalk PNG exportszűrő +Name[is]=Chalk PNG útflutningssía +Name[it]=Filtro di esportazione PNG per Chalk +Name[ja]=Chalk PNG エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ PNG សម្រាប់ Chalk +Name[lt]=Chalk PNG eksportavimo filtras +Name[lv]=Chalk PNG eksporta filtrs +Name[nb]=PNG-eksportfilter for Chalk +Name[nds]=PNG-Exportfilter för Chalk +Name[ne]=क्रिता पीएनजी निर्यात फिल्टर +Name[nl]=Chalk PNG Exportfilter +Name[pl]=Filtr eksportu do formatu PNG dla Chalk +Name[pt]=Filtro de Exportação de PNG para o Chalk +Name[pt_BR]=Filtro de Exportação de PNG para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в PNG +Name[se]=Chalk PNG-olggosfievrridansilli +Name[sk]=Exportný filter Chalk PNG +Name[sl]=Izvozni filter PNG za Krito +Name[sr]=Chalk-ин филтер за извоз у PNG +Name[sr@Latn]=Chalk-in filter za izvoz u PNG +Name[sv]=Chalk PNG-exportfilter +Name[uk]=Фільтр експорту PNG для Chalk +Name[uz]=Chalk PNG eksport filteri +Name[uz@cyrillic]=Chalk PNG экспорт филтери +Name[zh_CN]=Chalk PNG 导出过滤器 +Name[zh_TW]=Chalk PNG 匯出過濾程式 +X-KDE-Export=image/png +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Import=application/x-chalk +X-KDE-Weight=1 +X-KDE-Library=libchalkpngexport diff --git a/filters/chalk/png/chalk_png_import.desktop b/filters/chalk/png/chalk_png_import.desktop new file mode 100644 index 00000000..94b1c90f --- /dev/null +++ b/filters/chalk/png/chalk_png_import.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Type=Service +Name=Chalk PNG Import Filter +Name[bg]=Филтър за импортиране от PNG в Chalk +Name[br]=Sil enporzh PNG evit Chalk +Name[ca]=Filtre d'importació PNG per a Chalk +Name[da]=Chalk PNG-importfilter +Name[de]=Chalk PNG-Importfilter +Name[el]=Φίλτρο εισαγωγής PNG του Chalk +Name[eo]=Chalk PNG-importfiltrilo +Name[es]=Filtro de importación a PNG de Chalk +Name[et]=Chalk PNG impordifilter +Name[fa]=پالایۀ واردات Chalk PNG +Name[fi]=Chalk PNG -tuontisuodin +Name[fr]=Filtre d'importation PNG de Chalk +Name[fy]=Chalk PNG Ymportfilter +Name[ga]=Scagaire Iompórtála PNG Chalk +Name[gl]=Filtro de Importación de PNG para Chalk +Name[he]=Chalk PNG מסנן יבוא +Name[hr]=Chalk PNG filtar uvoza +Name[hu]=Chalk PNG importszűrő +Name[is]=Chalk PNG innflutningssía +Name[it]=Filtro di importazione PNG per Chalk +Name[ja]=Chalk PNG インポートフィルタ +Name[km]=តម្រង​នាំចូល PNG សម្រាប់ Chalk +Name[lt]=Chalk PNG importavimo filtras +Name[lv]=Chalk PNG importa filtrs +Name[nb]=PNG-importfilter for Chalk +Name[nds]=PNG-Importfilter för Chalk +Name[ne]=क्रिता पीएनजी आयात फिल्टर +Name[nl]=Chalk PNG Importfilter +Name[pl]=Filtr importu z formatu PNG dla Chalk +Name[pt]=Filtro de Importação de PNG para o Chalk +Name[pt_BR]=Filtro de Importação de PNG para o Chalk +Name[ru]=Фильтр импорта рисунков PNG в Chalk +Name[se]=Chalk PNG-olggosfievrridansilli +Name[sk]=PNG filter pre import do Chalk +Name[sl]=Uvozni filter PNG za Krito +Name[sr]=Chalk-ин филтер за увоз из PNG-а +Name[sr@Latn]=Chalk-in filter za uvoz iz PNG-a +Name[sv]=Chalk PNG-importfilter +Name[uk]=Фільтр імпорту PNG для Chalk +Name[uz]=Chalk PNG import filteri +Name[uz@cyrillic]=Chalk PNG импорт филтери +Name[zh_CN]=Chalk PNG 导入过滤器 +Name[zh_TW]=Chalk PNG 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/png +X-KDE-Weight=1 +X-KDE-Library=libchalkpngimport +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/png/configure.in.bot b/filters/chalk/png/configure.in.bot new file mode 100644 index 00000000..cda5270f --- /dev/null +++ b/filters/chalk/png/configure.in.bot @@ -0,0 +1,8 @@ +if test -z "$LIBPNG"; then + echo "" + echo "You're missing libpng (binaries and/or headers), chalk won't be able" + echo "to import/export png" + echo "" + all_tests=bad +fi + diff --git a/filters/chalk/png/kis_png_converter.cc b/filters/chalk/png/kis_png_converter.cc new file mode 100644 index 00000000..b7c48b50 --- /dev/null +++ b/filters/chalk/png/kis_png_converter.cc @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + // A big thank to Glenn Randers-Pehrson for it's wonderfull documentation of libpng available at http://www.libpng.org/pub/png/libpng-1.2.5-manual.html +#include "kis_png_converter.h" + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + + const TQ_UINT8 PIXEL_BLUE = 0; + const TQ_UINT8 PIXEL_GREEN = 1; + const TQ_UINT8 PIXEL_RED = 2; + const TQ_UINT8 PIXEL_ALPHA = 3; + + + int getColorTypeforColorSpace( KisColorSpace * cs , bool alpha) + { + if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) + { + return alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY; + } + if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) + { + return alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB; + } + + KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ; + return -1; + + } + + + TQString getColorSpaceForColorType(int color_type,int color_nb_bits) { + if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + switch(color_nb_bits) + { + case 8: + return "GRAYA"; + case 16: + return "GRAYA16"; + } + } else if(color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_RGB) { + switch(color_nb_bits) + { + case 8: + return "RGBA"; + case 16: + return "RGBA16"; + } + } else if(color_type == PNG_COLOR_TYPE_PALETTE) { + return "RGBA"; // <-- we will convert the index image to RGBA + } + return ""; + } + + + void fillText(png_text* p_text, char* key, TQString& text) + { + p_text->compression = PNG_TEXT_COMPRESSION_zTXt; + p_text->key = key; + char* textc = new char[text.length()+1]; + strcpy(textc, text.ascii()); + p_text->text = textc; + p_text->text_length = text.length()+1; + } + +} + +KisPNGConverter::KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter) +{ + Q_ASSERT(doc); + Q_ASSERT(adapter); + + m_doc = doc; + m_adapter = adapter; + m_stop = false; + m_max_row = 0; + m_img = 0; +} + +KisPNGConverter::~KisPNGConverter() +{ +} + +class KisPNGStream { + public: + KisPNGStream(TQ_UINT8* buf, TQ_UINT32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) { *m_buf = 0;}; + int nextValue() + { + if( m_posinc == 0) + { + m_posinc = 8; + m_buf++; + } + m_posinc -= m_depth; + return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) ); + } + void setNextValue(int v) + { + if( m_posinc == 0) + { + m_posinc = 8; + m_buf++; + *m_buf = 0; + } + m_posinc -= m_depth; + *m_buf = (v << m_posinc) | *m_buf; + } + private: + TQ_UINT32 m_posinc, m_depth; + TQ_UINT8* m_buf; +}; + +KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri) +{ + kdDebug(41008) << "Start decoding PNG File" << endl; + // open the file + kdDebug(41008) << TQFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl; + FILE *fp = fopen(TQFile::encodeName(uri.path()), "rb"); + if (!fp) + { + return (KisImageBuilder_RESULT_NOT_EXIST); + } + png_byte signature[8]; + fread(signature, 1, 8, fp); + if (!png_check_sig(signature, 8)) + { + return (KisImageBuilder_RESULT_BAD_FETCH); + } + + // Initialize the internal structures + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); + if (!KisImageBuilder_RESULT_FAILURE) + return (KisImageBuilder_RESULT_FAILURE); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return (KisImageBuilder_RESULT_FAILURE); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return (KisImageBuilder_RESULT_FAILURE); + } + + // Catch errors + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(fp); + return (KisImageBuilder_RESULT_FAILURE); + } + + png_init_io(png_ptr, fp); + png_set_sig_bytes(png_ptr, 8); + + // read all PNG info up to image data + png_read_info(png_ptr, info_ptr); + + // Read information about the png + png_uint_32 width, height; + int color_nb_bits, color_type, interlace_type; + png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, &interlace_type, NULL, NULL); + kdDebug(41008) << "it's an " << color_nb_bits << " depth image" << endl; + + // swap byteorder on little endian machines. + #ifndef WORDS_BIGENDIAN + if (color_nb_bits > 8 ) + png_set_swap(png_ptr); + #endif + + // Determine the colorspace + TQString csName = getColorSpaceForColorType(color_type, color_nb_bits); + if(csName.isEmpty()) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA); + + // Read image profile + png_charp profile_name, profile_data; + int compression_type; + png_uint_32 proflen; + int number_of_passes = 1; + + if (interlace_type == PNG_INTERLACE_ADAM7) + number_of_passes = png_set_interlace_handling(png_ptr); + + KisProfile* profile = 0; + if(png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) + { + TQByteArray profile_rawdata; + // XXX: Hardcoded for icc type -- is that correct for us? + if (TQString::compare(profile_name, "icc") == 0) { + profile_rawdata.resize(proflen); + memcpy(profile_rawdata.data(), profile_data, proflen); + profile = new KisProfile(profile_rawdata); + Q_CHECK_PTR(profile); + if (profile) { + kdDebug(41008) << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo() << endl; + if(!profile->isSuitableForOutput()) + { + kdDebug(41008) << "the profile is not suitable for output and therefore cannot be used in chalk, we need to convert the image to a standard profile" << endl; // TODO: in ko2 popup a selection menu to inform the user + } + } + } + } + + // Retrieve a pointer to the colorspace + KisColorSpace* cs; + if (profile && profile->isSuitableForOutput()) + { + kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n"; + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile); + } + else + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),""); + + if(cs == 0) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + + // Create the cmsTransform if needed + cmsHTRANSFORM transform = 0; + if(profile && !profile->isSuitableForOutput()) + { + transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(), + cs->getProfile()->profile() , cs->colorSpaceType(), + INTENT_PERCEPTUAL, 0); + } + + // Read comments/texts... + png_text* text_ptr; + int num_comments; + png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments); + KoDocumentInfo * info = m_doc->documentInfo(); + KoDocumentInfoAbout * aboutPage = static_cast(info->page( "about" )); + KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author")); + kdDebug(41008) << "There are " << num_comments << " comments in the text" << endl; + for(int i = 0; i < num_comments; i++) + { + kdDebug(41008) << "key is " << text_ptr[i].key << " containing " << text_ptr[i].text << endl; + if(TQString::compare(text_ptr[i].key, "title") == 0) + { + aboutPage->setTitle(text_ptr[i].text); + } else if(TQString::compare(text_ptr[i].key, "abstract") == 0) + { + aboutPage->setAbstract(text_ptr[i].text); + } else if(TQString::compare(text_ptr[i].key, "author") == 0) + { + authorPage->setFullName(text_ptr[i].text); + } + } + + // Read image data + png_bytep row_pointer = 0; + try + { + png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); + row_pointer = new png_byte[rowbytes]; + } + catch(std::bad_alloc& e) + { + // new png_byte[] may raise such an exception if the image + // is invalid / to large. + kdDebug(41008) << "bad alloc: " << e.what() << endl; + // Free only the already allocated png_byte instances. + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + return (KisImageBuilder_RESULT_FAILURE); + } + + // Read the palette if the file is indexed + png_colorp palette ; + int num_palette; + if(color_type == PNG_COLOR_TYPE_PALETTE) { + png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); + } +// png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL ); +// png_bytepp row_pointers = png_get_rows(png_ptr, info_ptr); // By using this function libpng will take care of freeing memory +// png_read_image(png_ptr, row_pointers); + + // Finish reading the file +// png_read_end(png_ptr, end_info); +// fclose(fp); + + // Creating the KisImageSP + if( ! m_img) { + m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image"); + m_img->blockSignals(true); // Don't send out signals while we're building the image + Q_CHECK_PTR(m_img); + if(profile && !profile->isSuitableForOutput()) + { + m_img -> addAnnotation( profile->annotation() ); + } + } + + KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX); + for (int i = 0; i < number_of_passes; i++) + { + for (png_uint_32 y = 0; y < height; y++) { + KisHLineIterator it = layer -> paintDevice() -> createHLineIterator(0, y, width, true); + png_read_rows(png_ptr, &row_pointer, NULL, 1); + + switch(color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + if(color_nb_bits == 16) + { + TQ_UINT16 *src = reinterpret_cast(row_pointer); + while (!it.isDone()) { + TQ_UINT16 *d = reinterpret_cast(it.rawData()); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + if(hasalpha) d[1] = *(src++); + else d[1] = TQ_UINT16_MAX; + ++it; + } + } else { + TQ_UINT8 *src = row_pointer; + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + if(hasalpha) d[1] = *(src++); + else d[1] = TQ_UINT8_MAX; + ++it; + } + } + //FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits + break; + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + if(color_nb_bits == 16) + { + TQ_UINT16 *src = reinterpret_cast(row_pointer); + while (!it.isDone()) { + TQ_UINT16 *d = reinterpret_cast(it.rawData()); + d[2] = *(src++); + d[1] = *(src++); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + if(hasalpha) d[3] = *(src++); + else d[3] = TQ_UINT16_MAX; + ++it; + } + } else { + TQ_UINT8 *src = row_pointer; + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + d[2] = *(src++); + d[1] = *(src++); + d[0] = *(src++); + if(transform) cmsDoTransform(transform, d, d, 1); + if(hasalpha) d[3] = *(src++); + else d[3] = TQ_UINT8_MAX; + ++it; + } + } + break; + case PNG_COLOR_TYPE_PALETTE: + { + KisPNGStream stream(row_pointer, color_nb_bits); + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + png_color c = palette[ stream.nextValue() ]; + d[2] = c.red; + d[1] = c.green; + d[0] = c.blue; + d[3] = TQ_UINT8_MAX; + ++it; + } + } + break; + default: + return KisImageBuilder_RESULT_UNSUPPORTED; + } + } + } + m_img->addLayer(layer, m_img->rootLayer(), 0); + + png_read_end(png_ptr, end_info); + fclose(fp); + + // Freeing memory + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + + delete [] row_pointer; + + return KisImageBuilder_RESULT_OK; + +} + +KisImageBuilder_Result KisPNGConverter::buildImage(const KURL& uri) +{ + kdDebug(41008) << TQFile::encodeName(uri.path()) << " " << uri.path() << " " << uri << endl; + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) { + return KisImageBuilder_RESULT_NOT_EXIST; + } + + // We're not set up to handle asynchronous loading at the moment. + KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE; + TQString tmpFile; + + if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) { + KURL uriTF; + uriTF.setPath( tmpFile ); + result = decode(uriTF); + KIO::NetAccess::removeTempFile(tmpFile); + } + + return result; +} + + +KisImageSP KisPNGConverter::image() +{ + return m_img; +} + +KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha) +{ + kdDebug(41008) << "Start writing PNG File" << endl; + if (!layer) + return KisImageBuilder_RESULT_INVALID_ARG; + + KisImageSP img = layer -> image(); + if (!img) + return KisImageBuilder_RESULT_EMPTY; + + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!uri.isLocalFile()) + return KisImageBuilder_RESULT_NOT_LOCAL; + // Open file for writing + FILE *fp = fopen(TQFile::encodeName(uri.path()), "wb"); + if (!fp) + { + return (KisImageBuilder_RESULT_FAILURE); + } + int height = img->height(); + int width = img->width(); + // Initialize structures + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL); + if (!png_ptr) + { + KIO::del(uri); + return (KisImageBuilder_RESULT_FAILURE); + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + KIO::del(uri); + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + return (KisImageBuilder_RESULT_FAILURE); + } + + // If an error occurs during writing, libpng will jump here + if (setjmp(png_jmpbuf(png_ptr))) + { + KIO::del(uri); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return (KisImageBuilder_RESULT_FAILURE); + } + // Initialize the writing + png_init_io(png_ptr, fp); + // Setup the progress function +// FIXME png_set_write_status_fn(png_ptr, progress); +// setProgressTotalSteps(100/*height*/); + + + /* set the zlib compression level */ + png_set_compression_level(png_ptr, compression); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels(); + int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha); + + if(color_type == -1) + { + return KisImageBuilder_RESULT_UNSUPPORTED; + } + + // Try to compute a table of color if the colorspace is RGB8f + png_colorp palette ; + int num_palette = 0; + if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") ) + { // png doesn't handle indexed images and alpha, and only have indexed for RGB8 + palette = new png_color[255]; + KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false); + bool toomuchcolor = false; + while( !it.isDone() ) + { + const TQ_UINT8* c = it.rawData(); + bool findit = false; + for(int i = 0; i < num_palette; i++) + { + if(palette[i].red == c[2] && + palette[i].green == c[1] && + palette[i].blue == c[0] ) + { + findit = true; + break; + } + } + if(!findit) + { + if( num_palette == 255) + { + toomuchcolor = true; + break; + } + palette[num_palette].red = c[2]; + palette[num_palette].green = c[1]; + palette[num_palette].blue = c[0]; + num_palette++; + } + ++it; + } + if(!toomuchcolor) + { + kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl; + color_type = PNG_COLOR_TYPE_PALETTE; + if( num_palette <= 2) + { + color_nb_bits = 1; + } else if( num_palette <= 4) + { + color_nb_bits = 2; + } else if( num_palette <= 16) + { + color_nb_bits = 4; + } else { + color_nb_bits = 8; + } + } else { + delete palette; + } + } + + int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; + + png_set_IHDR(png_ptr, info_ptr, + width, + height, + color_nb_bits, + color_type, interlacetype, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); + // set the palette + if( color_type == PNG_COLOR_TYPE_PALETTE) + { + png_set_PLTE(png_ptr, info_ptr, palette, num_palette); + } + // Save annotation + vKisAnnotationSP_it it = annotationsStart; + while(it != annotationsEnd) { + if (!(*it) || (*it) -> type() == TQString()) { + kdDebug(41008) << "Warning: empty annotation" << endl; + ++it; + continue; + } + + kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl; + + if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute + // FIXME: it should be possible to save chalk_attributes in the "CHUNKs" + kdDebug(41008) << "can't save this annotation : " << (*it) -> type() << endl; + } else { // Profile + char* name = new char[(*it)->type().length()+1]; + strcpy(name, (*it)->type().ascii()); + png_set_iCCP(png_ptr, info_ptr, name, PNG_COMPRESSION_TYPE_BASE, (char*)(*it)->annotation().data(), (*it) -> annotation() . size()); + } + ++it; + } + + // read comments from the document information + png_text texts[3]; + int nbtexts = 0; + KoDocumentInfo * info = m_doc->documentInfo(); + KoDocumentInfoAbout * aboutPage = static_cast(info->page( "about" )); + TQString title = aboutPage->title(); + if(!title.isEmpty()) + { + fillText(texts+nbtexts, "title", title); + nbtexts++; + } + TQString abstract = aboutPage->abstract(); + if(!abstract.isEmpty()) + { + fillText(texts+nbtexts, "abstract", abstract); + nbtexts++; + } + KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author" )); + TQString author = authorPage->fullName(); + if(!author.isEmpty()) + { + fillText(texts+nbtexts, "author", author); + nbtexts++; + } + + png_set_text(png_ptr, info_ptr, texts, nbtexts); + + // Save the information to the file + png_write_info(png_ptr, info_ptr); + png_write_flush(png_ptr); + + // swap byteorder on little endian machines. + #ifndef WORDS_BIGENDIAN + if (color_nb_bits > 8 ) + png_set_swap(png_ptr); + #endif + + // Write the PNG +// png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // Fill the data structure + png_byte** row_pointers= new png_byte*[height]; + + for (int y = 0; y < height; y++) { + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false); + row_pointers[y] = new png_byte[width*layer->paintDevice()->pixelSize()]; + switch(color_type) + { + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + if(color_nb_bits == 16) + { + TQ_UINT16 *dst = reinterpret_cast(row_pointers[y]); + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + *(dst++) = d[0]; + if(alpha) *(dst++) = d[1]; + ++it; + } + } else { + TQ_UINT8 *dst = row_pointers[y]; + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + *(dst++) = d[0]; + if(alpha) *(dst++) = d[1]; + ++it; + } + } + break; + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + if(color_nb_bits == 16) + { + TQ_UINT16 *dst = reinterpret_cast(row_pointers[y]); + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + *(dst++) = d[2]; + *(dst++) = d[1]; + *(dst++) = d[0]; + if(alpha) *(dst++) = d[3]; + ++it; + } + } else { + TQ_UINT8 *dst = row_pointers[y]; + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + *(dst++) = d[2]; + *(dst++) = d[1]; + *(dst++) = d[0]; + if(alpha) *(dst++) = d[3]; + ++it; + } + } + break; + case PNG_COLOR_TYPE_PALETTE: + { + TQ_UINT8 *dst = row_pointers[y]; + KisPNGStream writestream(dst, color_nb_bits); + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + int i; + for(i = 0; i < num_palette; i++) + { + if(palette[i].red == d[2] && + palette[i].green == d[1] && + palette[i].blue == d[0] ) + { + break; + } + } + writestream.setNextValue(i); + ++it; + } + } + break; + default: + kdDebug(41008) << "Unsupported color type for writting : " << color_type << endl; + KIO::del(uri); + return KisImageBuilder_RESULT_UNSUPPORTED; + } + } + + png_write_image(png_ptr, row_pointers); + + + // Writting is over + png_write_end(png_ptr, info_ptr); + + // Free memory + png_destroy_write_struct(&png_ptr, &info_ptr); + for (int y = 0; y < height; y++) { + delete[] row_pointers[y]; + } + delete[] row_pointers; + + if( color_type == PNG_COLOR_TYPE_PALETTE) + { + delete palette; + } + + fclose(fp); + + return KisImageBuilder_RESULT_OK; +} + + +void KisPNGConverter::cancel() +{ + m_stop = true; +} + +void KisPNGConverter::progress(png_structp png_ptr, png_uint_32 row_number, int pass) +{ + if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return; +// setProgress(row_number); +} + + +#include "kis_png_converter.moc" + diff --git a/filters/chalk/png/kis_png_converter.h b/filters/chalk/png/kis_png_converter.h new file mode 100644 index 00000000..a4f1140b --- /dev/null +++ b/filters/chalk/png/kis_png_converter.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_PNG_CONVERTER_H_ +#define _KIS_PNG_CONVERTER_H_ + +#include + +#include + +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_annotation.h" +class KisDoc; +class KisUndoAdapter; + +/** + * Image import/export plugins can use these results to report about success or failure. + */ +enum KisImageBuilder_Result { + KisImageBuilder_RESULT_FAILURE = -400, + KisImageBuilder_RESULT_NOT_EXIST = -300, + KisImageBuilder_RESULT_NOT_LOCAL = -200, + KisImageBuilder_RESULT_BAD_FETCH = -100, + KisImageBuilder_RESULT_INVALID_ARG = -50, + KisImageBuilder_RESULT_OK = 0, + KisImageBuilder_RESULT_PROGRESS = 1, + KisImageBuilder_RESULT_EMPTY = 100, + KisImageBuilder_RESULT_BUSY = 150, + KisImageBuilder_RESULT_NO_URI = 200, + KisImageBuilder_RESULT_UNSUPPORTED = 300, + KisImageBuilder_RESULT_INTR = 400, + KisImageBuilder_RESULT_PATH = 500, + KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600 +}; + +class KisPNGConverter : public KisProgressSubject { + Q_OBJECT + TQ_OBJECT + public: + KisPNGConverter(KisDoc *doc, KisUndoAdapter *adapter); + virtual ~KisPNGConverter(); + public: + KisImageBuilder_Result buildImage(const KURL& uri); + KisImageBuilder_Result buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha); + /** Retrieve the constructed image + */ + KisImageSP image(); + public slots: + virtual void cancel(); + private: + KisImageBuilder_Result decode(const KURL& uri); + void progress(png_structp png_ptr, png_uint_32 row_number, int pass); + private: + png_uint_32 m_max_row; + KisImageSP m_img; + KisDoc *m_doc; + KisUndoAdapter *m_adapter; + bool m_stop; +}; + +#endif diff --git a/filters/chalk/png/kis_png_export.cc b/filters/chalk/png/kis_png_export.cc new file mode 100644 index 00000000..8154866a --- /dev/null +++ b/filters/chalk/png/kis_png_export.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_png_export.h" + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_png_converter.h" +#include "kis_wdg_options_png.h" + +typedef KGenericFactory KisPNGExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkpngexport, KisPNGExportFactory("kofficefilters")) + +KisPNGExport::KisPNGExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisPNGExport::~KisPNGExport() +{ +} + +KoFilter::ConversiontqStatus KisPNGExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "Png export! From: " << from << ", To: " << to << "\n"; + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + + KDialogBase* kdb = new KDialogBase(0, "", false, i18n("PNG Export Options"), KDialogBase::Ok | KDialogBase::Cancel); + + KisImageSP img = output->currentImage(); + KisPaintDeviceSP pd = new KisPaintDevice(*img->projection()); + KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd); + + KisRectIteratorPixel it = l->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false); + KisColorSpace* cs = l->paintDevice()->colorSpace(); + bool isThereAlpha = false; + while( !it.isDone() ) + { + if(cs->getAlpha( it.rawData() ) != 255) + { + isThereAlpha = true; + break; + } + ++it; + } + + KisWdgOptionsPNG* wdg = new KisWdgOptionsPNG(kdb); + wdg->alpha->setChecked(isThereAlpha); + wdg->alpha->setEnabled(isThereAlpha); + kdb->setMainWidget(wdg); + kapp->restoreOverrideCursor(); + if(kdb->exec() == TQDialog::Rejected) + { + return KoFilter::OK; // FIXME Cancel doesn't exist :( + } + + bool alpha = wdg->alpha->isChecked(); + bool interlace = wdg->interlacing->isChecked(); + int compression = wdg->compressionLevel->value(); + + delete kdb; + + + KURL url; + url.setPath(filename); + + KisPNGConverter kpc(output, output->undoAdapter()); + + vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations(); + KisImageBuilder_Result res; + + + if ( (res = kpc.buildFile(url, l, beginIt, endIt, compression, interlace, alpha)) == KisImageBuilder_RESULT_OK) { + kdDebug(41008) << "success !" << endl; + return KoFilter::OK; + } + kdDebug(41008) << " Result = " << res << endl; + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/png/kis_png_export.h b/filters/chalk/png/kis_png_export.h new file mode 100644 index 00000000..d962523d --- /dev/null +++ b/filters/chalk/png/kis_png_export.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_PNG_EXPORT_H_ +#define _KIS_PNG_EXPORT_H_ + +#include + +class KisPNGExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisPNGExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisPNGExport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/png/kis_png_import.cc b/filters/chalk/png/kis_png_import.cc new file mode 100644 index 00000000..ccfe4388 --- /dev/null +++ b/filters/chalk/png/kis_png_import.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_png_import.h" + +#include + +#include + +#include +#include +#include +#include + +#include "kis_png_converter.h" + +typedef KGenericFactory PNGImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkpngimport, PNGImportFactory("kofficefilters")) + +KisPNGImport::KisPNGImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisPNGImport::~KisPNGImport() +{ +} + +KoFilter::ConversiontqStatus KisPNGImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using PNGImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url; + url.setPath(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisPNGConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/png/kis_png_import.h b/filters/chalk/png/kis_png_import.h new file mode 100644 index 00000000..d0b8502a --- /dev/null +++ b/filters/chalk/png/kis_png_import.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_PNG_IMPORT_H_ +#define _KIS_PNG_IMPORT_H_ + +#include + +class KisPNGImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisPNGImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisPNGImport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/png/kis_wdg_options_png.ui b/filters/chalk/png/kis_wdg_options_png.ui new file mode 100644 index 00000000..405db2fe --- /dev/null +++ b/filters/chalk/png/kis_wdg_options_png.ui @@ -0,0 +1,183 @@ + +KisWdgOptionsPNG + + + KisWdgOptionsPNG + + + + 0 + 0 + 286 + 106 + + + + Options of Your PNG + + + + unnamed + + + 0 + + + + tqlayout6 + + + + unnamed + + + + textLabel1 + + + Compress: + + + AlignTop + + + Note: the compression level does not change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level does not change the quality of the result.</p> + + + + + tqlayout5 + + + + unnamed + + + + compressionLevel + + + 1 + + + 9 + + + 1 + + + 9 + + + Horizontal + + + Below + + + Note: the compression level doesn't change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + tqlayout4 + + + + unnamed + + + + textLabel3 + + + Fast + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + textLabel4 + + + Small + + + AlignVCenter|AlignRight + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + + + + + + + spacer1 + + + Vertical + + + Expanding + + + + 20 + 5 + + + + + + interlacing + + + Interlacing + + + Use interlacing when publishing on the Internet + + + <p>Interlacing is useful if you intend to publish your image on the Internet.<br> +Enabling interlacing will cause the image to be displayed by the browser even while downloading.</p> + + + + + alpha + + + Store alpha channel (transparency) + + + true + + + Disable to get smaller files if your image has no transparency + + + <p>The Portable Network Graphics (PNG) file format allows transparency in your image to be stored by saving an alpha channel. +You can uncheck the box if you are not using transparency and you want to make the resulting file smaller .<br>Always saving the alpha channel is recommended.</p> + + + + + + diff --git a/filters/chalk/raw/Makefile.am b/filters/chalk/raw/Makefile.am new file mode 100644 index 00000000..2a814a56 --- /dev/null +++ b/filters/chalk/raw/Makefile.am @@ -0,0 +1,35 @@ +AM_CPPFLAGS= \ + -I$(srcdir) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + -I$(top_srcdir)/filters/chalk/magick \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = libchalk_raw_import.la + +libchalk_raw_import_la_LDFLAGS = $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalk_raw_import_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(raw_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + + +service_DATA = chalk_raw_import.desktop +servicedir = $(kde_servicesdir) + +kdelnk_DATA = chalk_raw.desktop +kdelnkdir = $(kde_appsdir)/.hidden + +libchalk_raw_import_la_SOURCES = kis_raw_import.cpp wdgrawimport.ui + +METASOURCES = AUTO + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + + diff --git a/filters/chalk/raw/chalk_raw.desktop b/filters/chalk/raw/chalk_raw.desktop new file mode 100644 index 00000000..d03d0b6f --- /dev/null +++ b/filters/chalk/raw/chalk_raw.desktop @@ -0,0 +1,57 @@ +[Desktop Entry] +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +MimeType=image/x-raw +Type=Application +Icon=chalk +Categories= +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi diff --git a/filters/chalk/raw/chalk_raw_import.desktop b/filters/chalk/raw/chalk_raw_import.desktop new file mode 100644 index 00000000..9c3a039d --- /dev/null +++ b/filters/chalk/raw/chalk_raw_import.desktop @@ -0,0 +1,51 @@ +[Desktop Entry] +Type=Service +Name=Chalk RAW Import Filter +Name[bg]=Филтър за импортиране на RAW в Chalk +Name[br]=Sil enporzh RAW evit Chalk +Name[ca]=Filtre d'importació RAW per a Chalk +Name[da]=Chalk RAW-importfilter +Name[de]=Chalk RAW-Importfilter +Name[el]=Φίλτρο εισαγωγής RAW του Chalk +Name[eo]=Chalk RAW-importfiltrilo +Name[es]=Filtro de importación a RAW de Chalk +Name[et]=Chalk toorpiltide impordifilter +Name[fa]=پالایۀ واردات Chalk RAW +Name[fi]=Chalk RAW -tuontisuodin +Name[fr]=Filtre d'importation RAW de Chalk +Name[fy]=Chalk RAW Ymportfilter +Name[ga]=Scagaire Iompórtála RAW Chalk +Name[gl]=Filtro de Importación RAW para Chalk +Name[he]=Chalk RAW מסנן יבוא +Name[hr]=Chalk RAW filtar uvoza +Name[hu]=Chalk RAW importszűrő +Name[is]=Chalk RAW innflutningssía +Name[it]=Filtro di importazione di formati grezzi per Chalk +Name[ja]=Chalk RAW インポートフィルタ +Name[km]=តម្រង​នាំចូល RAW សម្រាប់ Chalk +Name[lt]=Chalk RAW importavimo filtras +Name[lv]=Chalk RAW importa filtrs +Name[nb]=RAW importfilter for Chalk +Name[nds]=RAW-Importfilter för Chalk +Name[ne]=क्रिता RAW आयात फिल्टर +Name[nl]=Chalk RAW Importfilter +Name[pl]=Filtr importu formatu RAW dla Chalk +Name[pt]=Filtro de Importação RAW para o Chalk +Name[pt_BR]=Filtro de Importação RAW para o Chalk +Name[ru]=Фильтр импорта рисунков RAW в Chalk +Name[se]=Chalk RAW-sisafievrridansilli +Name[sk]=RAW filter pre import do Chalk +Name[sl]=Uvozni filter RAW za Krito +Name[sr]=Chalk-ин филтер за увоз из RAW-а +Name[sr@Latn]=Chalk-in filter za uvoz iz RAW-a +Name[sv]=Chalk RAW-importfilter +Name[uk]=Фільтр імпорту RAW для Chalk +Name[uz]=Chalk RAW import filteri +Name[uz@cyrillic]=Chalk RAW импорт филтери +Name[zh_CN]=Chalk RAW 导入过滤器 +Name[zh_TW]=Chalk RAW 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-raw +X-KDE-Weight=1 +X-KDE-Library=libchalk_raw_import +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/raw/dcraw.1 b/filters/chalk/raw/dcraw.1 new file mode 100644 index 00000000..10a690b8 --- /dev/null +++ b/filters/chalk/raw/dcraw.1 @@ -0,0 +1,182 @@ +.\" +.\" Man page for dcraw (Raw Photo Decoder) +.\" +.\" Copyright (c) 2005 by David Coffin +.\" +.\" You may distribute without restriction. +.\" +.\" David Coffin +.\" dcoffin a cybercom o net +.\" http://www.cybercom.net/~dcoffin +.\" +.TH dcraw 1 "September 29, 2005" +.LO 1 +.SH NAME +dcraw - convert raw digital photos to PPM format +.SH SYNOPSIS +.B dcraw +[\fIOPTION\fR]... [\fIFILE\fR]... +.SH DESCRIPTION +.B dcraw +converts raw digital photos to +.BR ppm (5) +format. +.SH OPTIONS +.TP +.B -v +Print verbose messages. The default is to print only warnings +and errors. +.TP +.B -z +Change the access and modification times of a JPEG or raw file to +when the photo was taken, assuming that the camera clock was set +to Universal Time. +.TP +.B -i +Identify files but don't decode them. +Exit status is 0 if +.B dcraw +can decode the last file, 1 if it can't. +.TP +.B "" +.B dcraw +cannot decode JPEG files!! +.TP +.B -c +Write binary image data to standard output. +By default, +.B dcraw +creates files with a ".ppm" extension. +.TP +.B -d +Show the raw data as a grayscale image with no interpolation. +Good for photographing black-and-white documents. +.TP +.B -q [0-3] +Set the interpolation quality (default is 3): + +.B \t0 +\ \ Bilinear (very fast, low quality) +.br +.B \t1 +\ \ Reserved +.br +.B \t2 +\ \ Variable Number of Gradients (VNG) +.br +.B \t3 +\ \ Adaptive Homogeneity-Directed (AHD) +.TP +.B -h +Output a half-size image. Twice as fast as +.BR -q\ 0 . +.TP +.B -f +Interpolate RGB as four colors. This blurs the image a little, +but it eliminates false 2x2 mesh patterns. +.TP +.B -B sigma_domain sigma_range +Use a bilateral filter to smooth noise while preserving edges. +.B sigma_domain +is in units of pixels, while +.B sigma_range +is in units of CIELab colorspace. +Try +.B -B\ 2\ 4 +to start. +.TP +.B -a +Automatic color balance. The default is to use a fixed +color balance based on a white card photographed in sunlight. +.TP +.B -w +Use the color balance specified by the camera. +If this can't be found, +.B dcraw +prints a warning and reverts to the default. +.TP +.B -r red_mul -l blue_mul +Further adjust the color balance by multiplying the red and +blue output channels by these values. Both default to 1.0. +.TP +.B -b brightness +Change the output brightness. Default is 1.0. +.TP +.B -k black +Set the black point. Default depends on the camera. +.TP +.B -n +By default, +.B dcraw +clips all colors to prevent pink hues in the highlights. +Combine this option with +.B -b 0.25 +to leave the image data completely unclipped. +.TP +.B -m +Write raw camera colors to the output file. By default, +.B dcraw +converts to sRGB colorspace. +.TP +.B -j +For Fuji\ Super\ CCD cameras, show the image tilted 45 degrees +so that each output pixel corresponds to one raw pixel. +.TP +.B -s +For Fuji\ Super\ CCD\ SR cameras, use the secondary sensors, in +effect underexposing the image by four stops to reveal detail +in the highlights. +.TP +.B "" +For all other cameras, +.B -j +and +.B -s +are silently ignored. +.TP +.B -t [0-7] +Flip the output image. The most common flips are 5 +(90 degrees CCW) and 6 (90 degrees clockwise). By default, +dcraw tries to use the flip specified by the camera. +.RB \^" -t\ 0 \^" +forces +.B dcraw +not to flip images. +.TP +.B -2 +Write eight bits per color value with a 99th-percentile white +point and the standard 0.45 gamma curve. Double the height if +necessary to correct the aspect ratio. This is the default. +.TP +.B -4 +Write sixteen bits per color value. Output is linear with +input -- no white point, no gamma, same aspect ratio. +.TP +.B -3 +Same image as +.BR -4 , +written in Adobe PhotoShop format. File extension is ".psd". +.SH "SEE ALSO" +.BR ppm (5), +.BR ppm2tiff (1), +.BR pnmtotiff (1), +.BR pnmtopng (1), +.BR gphoto2 (1), +.BR djpeg (1) +.SH BUGS +The +.B -w +option does not work with many cameras. +.P +No attempt is made to save camera settings or thumbnail images. +.P +The author stubbornly refuses to add more output formats. +.P +Don't expect +.B dcraw +to produce the same images as software provided by the camera +vendor. Sometimes +.B dcraw +gives better results! +.SH AUTHOR +Written by David Coffin, dcoffin a cybercom o net diff --git a/filters/chalk/raw/dcraw.c b/filters/chalk/raw/dcraw.c new file mode 100644 index 00000000..e92c1d3c --- /dev/null +++ b/filters/chalk/raw/dcraw.c @@ -0,0 +1,5999 @@ +/* + dcraw.c -- Dave Coffin's raw photo decoder + Copyright 1997-2005 by Dave Coffin, dcoffin a cybercom o net + + This is a command-line ANSI C program to convert raw photos from + any digital camera on any computer running any operating system. + + Attention! Some parts of this program are restricted under the + terms of the GNU General Public License. Such code is enclosed + in "BEGIN GPL BLOCK" and "END GPL BLOCK" declarations. + Any code not declared GPL is free for all uses. + + Starting in Revision 1.237, the code to support Foveon cameras + is under GPL. + + To lawfully redistribute dcraw.c, you must either (a) include + full source code for all executable files containing restricted + functions, (b) remove these functions, re-implement them, or + copy them from an earlier, non-GPL Revision of dcraw.c, or (c) + purchase a license from the author. + + $Revision: 1.296 $ + $Date: 2005/11/04 07:11:14 $ + */ + +#define _GNU_SOURCE +#define _USE_MATH_DEFINES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + By defining NO_JPEG, you lose only the ability to + decode compressed .KDC files from the Kodak DC120. + */ +#ifndef NO_JPEG +#include +#endif + +#ifdef __CYGWIN__ +#include +#endif +#ifdef WIN32 +#include +#include +#pragma comment(lib, "ws2_32.lib") +#define strcasecmp stricmp +typedef __int64 INT64; +typedef unsigned __int64 UINT64; +#else +#include +#include +#include +typedef long long INT64; +typedef unsigned long long UINT64; +#endif + +#ifdef LJPEG_DECODE +#error Please compile dcraw.c by itself. +#error Do not link it with ljpeg_decode. +#endif + +#ifndef LONG_BIT +#define LONG_BIT (8 * sizeof (long)) +#endif + +#define ushort UshORt +typedef unsigned char uchar; +typedef unsigned short ushort; + +/* + All global variables are defined here, and all functions that + access them are prefixed with "CLASS". Note that a thread-safe + C++ class cannot have non-const static local variables. + */ +FILE *ifp; +short order; +char *ifname, make[64], model[70], model2[64], *meta_data; +float flash_used, canon_5814; +time_t timestamp; +unsigned shot_order, kodak_cbpp; +int data_offset, meta_offset, meta_length, nikon_curve_offset; +int tiff_bps, tiff_data_compression, kodak_data_compression; +int raw_height, raw_width, top_margin, left_margin; +int height, width, fuji_width, colors, tiff_samples; +int black, maximum, clip_max, clip_color=1; +int iheight, iwidth, shrink; +int dng_version, is_foveon, raw_color, use_gamma; +int flip, xmag, ymag; +int zero_after_ff; +unsigned filters; +ushort (*image)[4], white[8][8], curve[0x1000]; +void (*load_raw)(); +float bright=1, red_scale=1, blue_scale=1, sigma_d=0, sigma_r=0; +int four_color_rgb=0, document_mode=0; +int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_rgb=0; +int fuji_layout, fuji_secondary, use_secondary=0; +float cam_mul[4], pre_mul[4], rgb_cam[3][4]; /* RGB from camera color */ +const double xyz_rgb[3][3] = { /* XYZ from RGB */ + { 0.412453, 0.357580, 0.180423 }, + { 0.212671, 0.715160, 0.072169 }, + { 0.019334, 0.119193, 0.950227 } }; +#define camera_red cam_mul[0] +#define camera_blue cam_mul[2] +int histogram[3][0x2000]; +void write_ppm(FILE *); +void (*write_fun)(FILE *) = write_ppm; +jmp_buf failure; + +#define USE_LCMS +#ifdef USE_LCMS +#include +int profile_offset, profile_length; +#endif + +struct decode { + struct decode *branch[2]; + int leaf; +} first_decode[2048], *second_decode, *free_decode; + +#define CLASS + +#define FORC3 for (c=0; c < 3; c++) +#define FORC4 for (c=0; c < 4; c++) +#define FORCC for (c=0; c < colors; c++) + +#define SQR(x) ((x)*(x)) +#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LIM(x,min,max) MAX(min,MIN(x,max)) +#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) +#define CLIP(x) LIM(x,0,clip_max) + +/* + In order to inline this calculation, I make the risky + assumption that all filter patterns can be described + by a repeating pattern of eight rows and two columns + + Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 + */ +#define FC(row,col) \ + (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) + +#define BAYER(row,col) \ + image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] + +/* + PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 + 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M + 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C + 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y + 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M + 4 C Y C Y C Y 4 Y C Y C Y C + PowerShot A5 5 G M G M G M 5 G M G M G M + 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y + 7 M G M G M G 7 M G M G M G + 0 1 2 3 4 5 + 0 C Y C Y C Y + 1 G M G M G M + 2 C Y C Y C Y + 3 M G M G M G + + All RGB cameras use one of these Bayer grids: + + 0x16161616: 0x61616161: 0x49494949: 0x94949494: + + 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 + 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G + 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B + 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G + 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B + */ + +#ifndef __GLIBC__ +char *memmem (char *haystack, size_t haystacklen, + char *needle, size_t needlelen) +{ + char *c; + for (c = haystack; c <= haystack + haystacklen - needlelen; c++) + if (!memcmp (c, needle, needlelen)) + return c; + return NULL; +} +#endif + +void CLASS merror (void *ptr, char *where) +{ + if (ptr) return; + fprintf (stderr, "%s: Out of memory in %s\n", ifname, where); + longjmp (failure, 1); +} + +ushort CLASS sget2 (uchar *s) +{ + if (order == 0x4949) /* "II" means little-endian */ + return s[0] | s[1] << 8; + else /* "MM" means big-endian */ + return s[0] << 8 | s[1]; +} + +ushort CLASS get2() +{ + uchar str[2] = { 0xff,0xff }; + fread (str, 1, 2, ifp); + return sget2(str); +} + +int CLASS sget4 (uchar *s) +{ + if (order == 0x4949) + return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; + else + return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; +} +#define sget4(s) sget4((uchar *)s) + +int CLASS get4() +{ + uchar str[4] = { 0xff,0xff,0xff,0xff }; + fread (str, 1, 4, ifp); + return sget4(str); +} + +double CLASS getrat() +{ + double num = get4(); + return num / get4(); +} + +float CLASS int_to_float (int i) +{ + union { int i; float f; } u; + u.i = i; + return u.f; +} + +void CLASS read_shorts (ushort *pixel, int count) +{ + fread (pixel, 2, count, ifp); + if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) + swab (pixel, pixel, count*2); +} + +void CLASS canon_600_fixed_wb (int temp) +{ + static const short mul[4][5] = { + { 667, 358,397,565,452 }, + { 731, 390,367,499,517 }, + { 1119, 396,348,448,537 }, + { 1399, 485,431,508,688 } }; + int lo, hi, i; + float frac=0; + + for (lo=4; --lo; ) + if (*mul[lo] <= temp) break; + for (hi=0; hi < 3; hi++) + if (*mul[hi] >= temp) break; + if (lo != hi) + frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); + for (i=1; i < 5; i++) + pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); +} + +/* Return values: 0 = white 1 = near white 2 = not white */ +int CLASS canon_600_color (int ratio[2], int mar) +{ + int clipped=0, target, miss; + + if (flash_used) { + if (ratio[1] < -104) + { ratio[1] = -104; clipped = 1; } + if (ratio[1] > 12) + { ratio[1] = 12; clipped = 1; } + } else { + if (ratio[1] < -264 || ratio[1] > 461) return 2; + if (ratio[1] < -50) + { ratio[1] = -50; clipped = 1; } + if (ratio[1] > 307) + { ratio[1] = 307; clipped = 1; } + } + target = flash_used || ratio[1] < 197 + ? -38 - (398 * ratio[1] >> 10) + : -123 + (48 * ratio[1] >> 10); + if (target - mar <= ratio[0] && + target + 20 >= ratio[0] && !clipped) return 0; + miss = target - ratio[0]; + if (abs(miss) >= mar*4) return 2; + if (miss < -20) miss = -20; + if (miss > mar) miss = mar; + ratio[0] = target - miss; + return 1; +} + +void CLASS canon_600_auto_wb () +{ + int mar, row, col, i, j, st, count[] = { 0,0 }; + int test[8], total[2][8], ratio[2][2], stat[2]; + + memset (&total, 0, sizeof total); + i = canon_5814 + 0.5; + if (i < 10) mar = 150; + else if (i > 12) mar = 20; + else mar = 280 - 20 * i; + if (flash_used) mar = 80; + for (row=14; row < height-14; row+=4) + for (col=10; col < width; col+=2) { + for (i=0; i < 8; i++) + test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = + BAYER(row+(i >> 1),col+(i & 1)); + for (i=0; i < 8; i++) + if (test[i] < 150 || test[i] > 1500) goto next; + for (i=0; i < 4; i++) + if (abs(test[i] - test[i+4]) > 50) goto next; + for (i=0; i < 2; i++) { + for (j=0; j < 4; j+=2) + ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; + stat[i] = canon_600_color (ratio[i], mar); + } + if ((st = stat[0] | stat[1]) > 1) goto next; + for (i=0; i < 2; i++) + if (stat[i]) + for (j=0; j < 2; j++) + test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; + for (i=0; i < 8; i++) + total[st][i] += test[i]; + count[st]++; +next: continue; + } + if (count[0] | count[1]) { + st = count[0]*200 < count[1]; + for (i=0; i < 4; i++) + pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); + } +} + +void CLASS canon_600_coeff () +{ + static const short table[6][12] = { + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, + { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, + { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, + { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, + { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; + int t=0, i, c; + float mc, yc; + + mc = pre_mul[1] / pre_mul[2]; + yc = pre_mul[3] / pre_mul[2]; + if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; + if (mc > 1.28 && mc <= 2) { + if (yc < 0.8789) t=3; + else if (yc <= 2) t=4; + } + if (flash_used) t=5; + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; +} + +void CLASS canon_600_load_raw() +{ + uchar data[1120], *dp; + ushort pixel[896], *pix; + int irow, row, col, val; + static const short mul[4][2] = + { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; + + for (irow=row=0; irow < height; irow++) + { + fread (data, 1120, 1, ifp); + for (dp=data, pix=pixel; dp < data+1120; dp+=10, pix+=8) + { + pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); + pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); + pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); + pix[3] = (dp[4] << 2) + (dp[1] & 3); + pix[4] = (dp[5] << 2) + (dp[9] & 3); + pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); + pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); + pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + for (col=width; col < 896; col++) + black += pixel[col]; + if ((row+=2) > height) row = 1; + } + black = black / ((896 - width) * height) - 4; + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + val = (BAYER(row,col) - black) * mul[row & 3][col & 1] >> 9; + if (val < 0) val = 0; + BAYER(row,col) = val; + } + canon_600_fixed_wb(1311); + canon_600_auto_wb(); + canon_600_coeff(); + maximum = (0x3ff - black) * 1109 >> 9; + black = 0; +} + +void CLASS canon_a5_load_raw() +{ + uchar data[1940], *dp; + ushort pixel[1552], *pix; + int row, col; + + for (row=0; row < height; row++) { + fread (data, raw_width * 10 / 8, 1, ifp); + for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=10, pix+=8) + { + pix[0] = (dp[1] << 2) + (dp[0] >> 6); + pix[1] = (dp[0] << 4) + (dp[3] >> 4); + pix[2] = (dp[3] << 6) + (dp[2] >> 2); + pix[3] = (dp[2] << 8) + (dp[5] ); + pix[4] = (dp[4] << 2) + (dp[7] >> 6); + pix[5] = (dp[7] << 4) + (dp[6] >> 4); + pix[6] = (dp[6] << 6) + (dp[9] >> 2); + pix[7] = (dp[9] << 8) + (dp[8] ); + } + for (col=0; col < width; col++) + BAYER(row,col) = (pixel[col] & 0x3ff); + for (col=width; col < raw_width; col++) + black += pixel[col] & 0x3ff; + } + if (raw_width > width) + black /= (raw_width - width) * height; + maximum = 0x3ff; +} + +/* + getbits(-1) initializes the buffer + getbits(n) where 0 <= n <= 25 returns an n-bit integer + */ +unsigned CLASS getbits (int nbits) +{ + static unsigned bitbuf=0; + static int vbits=0, reset=0; + unsigned c; + + if (nbits == -1) + return bitbuf = vbits = reset = 0; + if (nbits == 0 || reset) return 0; + while (vbits < nbits) { + c = fgetc(ifp); + if ((reset = zero_after_ff && c == 0xff && fgetc(ifp))) return 0; + bitbuf = (bitbuf << 8) + c; + vbits += 8; + } + vbits -= nbits; + return bitbuf << (32-nbits-vbits) >> (32-nbits); +} + +void CLASS init_decoder () +{ + memset (first_decode, 0, sizeof first_decode); + free_decode = first_decode; +} + +/* + Construct a decode tree according the specification in *source. + The first 16 bytes specify how many codes should be 1-bit, 2-bit + 3-bit, etc. Bytes after that are the leaf values. + + For example, if the source is + + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + + then the code is + + 00 0x04 + 010 0x03 + 011 0x05 + 100 0x06 + 101 0x02 + 1100 0x07 + 1101 0x01 + 11100 0x08 + 11101 0x09 + 11110 0x00 + 111110 0x0a + 1111110 0x0b + 1111111 0xff + */ +uchar * CLASS make_decoder (const uchar *source, int level) +{ + struct decode *cur; + static int leaf; + int i, next; + + if (level==0) leaf=0; + cur = free_decode++; + if (free_decode > first_decode+2048) { + fprintf (stderr, "%s: decoder table overflow\n", ifname); + longjmp (failure, 2); + } + for (i=next=0; i <= leaf && next < 16; ) + i += source[next++]; + if (i > leaf) { + if (level < next) { + cur->branch[0] = free_decode; + make_decoder (source, level+1); + cur->branch[1] = free_decode; + make_decoder (source, level+1); + } else + cur->leaf = source[16 + leaf++]; + } + return (uchar *) source + 16 + leaf; +} + +void CLASS crw_init_tables (unsigned table) +{ + static const uchar first_tree[3][29] = { + { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, + 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, + { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, + 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, + { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, + 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, + }; + static const uchar second_tree[3][180] = { + { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, + 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, + 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, + 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, + 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, + 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, + 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, + 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, + 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, + 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, + 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, + 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, + 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, + 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, + 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, + { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, + 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, + 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, + 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, + 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, + 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, + 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, + 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, + 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, + 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, + 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, + 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, + 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, + 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, + 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, + { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, + 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, + 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, + 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, + 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, + 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, + 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, + 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, + 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, + 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, + 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, + 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, + 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, + 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, + 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } + }; + if (table > 2) table = 2; + init_decoder(); + make_decoder ( first_tree[table], 0); + second_decode = free_decode; + make_decoder (second_tree[table], 0); +} + +/* + Return 0 if the image starts with compressed data, + 1 if it starts with uncompressed low-order bits. + + In Canon compressed data, 0xff is always followed by 0x00. + */ +int CLASS canon_has_lowbits() +{ + uchar test[0x4000]; + int ret=1, i; + + fseek (ifp, 0, SEEK_SET); + fread (test, 1, sizeof test, ifp); + for (i=540; i < sizeof test - 1; i++) + if (test[i] == 0xff) { + if (test[i+1]) return 1; + ret=0; + } + return ret; +} + +void CLASS canon_compressed_load_raw() +{ + ushort *pixel, *prow; + int lowbits, i, row, r, col, save, val; + unsigned irow, icol; + struct decode *decode, *dindex; + int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; + uchar c; + + pixel = calloc (raw_width*8, sizeof *pixel); + merror (pixel, "canon_compressed_load_raw()"); + lowbits = canon_has_lowbits(); + if (!lowbits) maximum = 0x3ff; + fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); + zero_after_ff = 1; + getbits(-1); + for (row = 0; row < raw_height; row += 8) { + for (block=0; block < raw_width >> 3; block++) { + memset (diffbuf, 0, sizeof diffbuf); + decode = first_decode; + for (i=0; i < 64; i++ ) { + for (dindex=decode; dindex->branch[0]; ) + dindex = dindex->branch[getbits(1)]; + leaf = dindex->leaf; + decode = second_decode; + if (leaf == 0 && i) break; + if (leaf == 0xff) continue; + i += leaf >> 4; + len = leaf & 15; + if (len == 0) continue; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + if (i < 64) diffbuf[i] = diff; + } + diffbuf[0] += carry; + carry = diffbuf[0]; + for (i=0; i < 64; i++ ) { + if (pnum++ % raw_width == 0) + base[0] = base[1] = 512; + pixel[(block << 6) + i] = ( base[i & 1] += diffbuf[i] ); + } + } + if (lowbits) { + save = ftell(ifp); + fseek (ifp, 26 + row*raw_width/4, SEEK_SET); + for (prow=pixel, i=0; i < raw_width*2; i++) { + c = fgetc(ifp); + for (r=0; r < 8; r+=2, prow++) { + val = (*prow << 2) + ((c >> r) & 3); + if (raw_width == 2672 && val < 512) val += 2; + *prow = val; + } + } + fseek (ifp, save, SEEK_SET); + } + for (r=0; r < 8; r++) { + irow = row - top_margin + r; + if (irow >= height) continue; + for (col = 0; col < raw_width; col++) { + icol = col - left_margin; + if (icol < width) + BAYER(irow,icol) = pixel[r*raw_width+col]; + else + black += pixel[r*raw_width+col]; + } + } + } + free (pixel); + if (raw_width > width) + black /= (raw_width - width) * height; +} + +/* + Not a full implementation of Lossless JPEG, just + enough to decode Canon, Kodak and Adobe DNG images. + */ +struct jhead { + int bits, high, wide, clrs, restart, vpred[4]; + struct decode *huff[4]; + ushort *row; +}; + +int CLASS ljpeg_start (struct jhead *jh) +{ + int i, tag, len; + uchar data[256], *dp; + + init_decoder(); + for (i=0; i < 4; i++) + jh->huff[i] = free_decode; + jh->restart = INT_MAX; + fread (data, 2, 1, ifp); + if (data[0] != 0xff || data[1] != 0xd8) return 0; + do { + fread (data, 2, 2, ifp); + tag = data[0] << 8 | data[1]; + len = (data[2] << 8 | data[3]) - 2; + if (tag <= 0xff00 || len > 255) return 0; + fread (data, 1, len, ifp); + switch (tag) { + case 0xffc3: + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; + jh->clrs = data[5]; + break; + case 0xffc4: + for (dp = data; dp < data+len && *dp < 4; ) { + jh->huff[*dp] = free_decode; + dp = make_decoder (++dp, 0); + } + break; + case 0xffdd: + jh->restart = data[0] << 8 | data[1]; + } + } while (tag != 0xffda); + jh->row = calloc (jh->wide*jh->clrs, 2); + merror (jh->row, " jpeg_start()"); + zero_after_ff = 1; + return 1; +} + +int CLASS ljpeg_diff (struct decode *dindex) +{ + int len, diff; + + while (dindex->branch[0]) + dindex = dindex->branch[getbits(1)]; + len = dindex->leaf; + if (len == 16 && (!dng_version || dng_version >= 0x1010000)) + return -32768; + diff = getbits(len); + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + return diff; +} + +void CLASS ljpeg_row (int jrow, struct jhead *jh) +{ + int col, c, diff; + ushort *outp=jh->row; + + if (jrow * jh->wide % jh->restart == 0) { + FORC4 jh->vpred[c] = 1 << (jh->bits-1); + if (jrow) get2(); /* Eat the FF Dx marker */ + getbits(-1); + } + for (col=0; col < jh->wide; col++) + for (c=0; c < jh->clrs; c++) { + diff = ljpeg_diff (jh->huff[c]); + *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff); + outp++; + } +} + +void CLASS lossless_jpeg_load_raw() +{ + int jwide, jrow, jcol, val, jidx, i, row, col; + struct jhead jh; + int min=INT_MAX; + + if (!ljpeg_start (&jh)) return; + jwide = jh.wide * jh.clrs; + + for (jrow=0; jrow < jh.high; jrow++) { + ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + val = jh.row[jcol]; + if (jh.bits <= 12) + val = curve[val]; + jidx = jrow*jwide + jcol; + if (raw_width == 5108) { + i = jidx / (1680*jh.high); + if (i < 2) { + row = jidx / 1680 % jh.high; + col = jidx % 1680 + i*1680; + } else { + jidx -= 2*1680*jh.high; + row = jidx / 1748; + col = jidx % 1748 + 2*1680; + } + } else if (raw_width == 4476 || raw_width == 3516) { + row = jidx / (raw_width/2); + col = jidx % (raw_width/2); + if (row >= raw_height) { + row -= raw_height; + col += raw_width/2; + } + } else { + row = jidx / raw_width; + col = jidx % raw_width; + } + if ((unsigned) (row-top_margin) >= height) continue; + if ((unsigned) (col-left_margin) < width) { + BAYER(row-top_margin,col-left_margin) = val; + if (min > val) min = val; + } else + black += val; + } + } + free (jh.row); + if (raw_width > width) + black /= (raw_width - width) * height; + if (!strcasecmp(make,"KODAK")) + black = min; +} + +void CLASS adobe_copy_pixel (int row, int col, ushort **rp) +{ + unsigned r, c; + + r = row -= top_margin; + c = col -= left_margin; + if (fuji_secondary && use_secondary) (*rp)++; + if (filters) { + if (fuji_width) { + r = row + fuji_width - 1 - (col >> 1); + c = row + ((col+1) >> 1); + } + if (r < height && c < width) + BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp; + *rp += 1 + fuji_secondary; + } else { + if (r < height && c < width) + for (c=0; c < tiff_samples; c++) + image[row*width+col][c] = (*rp)[c] < 0x1000 ? curve[(*rp)[c]]:(*rp)[c]; + *rp += tiff_samples; + } + if (fuji_secondary && use_secondary) (*rp)--; +} + +void CLASS adobe_dng_load_raw_lj() +{ + int save, twide, trow=0, tcol=0, jrow, jcol; + struct jhead jh; + ushort *rp; + + while (1) { + save = ftell(ifp); + fseek (ifp, get4(), SEEK_SET); + if (!ljpeg_start (&jh)) break; + if (trow >= raw_height) break; + if (jh.high > raw_height-trow) + jh.high = raw_height-trow; + twide = jh.wide; + if (filters) twide *= jh.clrs; + else colors = jh.clrs; + if (fuji_secondary) twide /= 2; + if (twide > raw_width-tcol) + twide = raw_width-tcol; + + for (jrow=0; jrow < jh.high; jrow++) { + ljpeg_row (jrow, &jh); + for (rp=jh.row, jcol=0; jcol < twide; jcol++) + adobe_copy_pixel (trow+jrow, tcol+jcol, &rp); + } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += twide) >= raw_width) { + tcol = 0; + trow += jh.high; + } + free (jh.row); + } +} + +void CLASS adobe_dng_load_raw_nc() +{ + ushort *pixel, *rp; + int row, col; + + pixel = calloc (raw_width * tiff_samples, sizeof *pixel); + merror (pixel, "adobe_dng_load_raw_nc()"); + for (row=0; row < raw_height; row++) { + if (tiff_bps == 16) + read_shorts (pixel, raw_width * tiff_samples); + else { + getbits(-1); + for (col=0; col < raw_width * tiff_samples; col++) + pixel[col] = getbits(tiff_bps); + } + for (rp=pixel, col=0; col < raw_width; col++) + adobe_copy_pixel (row, col, &rp); + } + free (pixel); +} + +void CLASS nikon_compressed_load_raw() +{ + static const uchar nikon_tree[] = { + 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, + 5,4,3,6,2,7,1,0,8,9,11,10,12 + }; + int csize, row, col, i, diff; + ushort vpred[4], hpred[2], *curve; + + init_decoder(); + make_decoder (nikon_tree, 0); + + fseek (ifp, nikon_curve_offset, SEEK_SET); + read_shorts (vpred, 4); + csize = get2(); + curve = calloc (csize, sizeof *curve); + merror (curve, "nikon_compressed_load_raw()"); + read_shorts (curve, csize); + + fseek (ifp, data_offset, SEEK_SET); + getbits(-1); + + for (row=0; row < height; row++) + for (col=0; col < raw_width; col++) + { + diff = ljpeg_diff (first_decode); + if (col < 2) { + i = 2*(row & 1) + (col & 1); + vpred[i] += diff; + hpred[col] = vpred[i]; + } else + hpred[col & 1] += diff; + if ((unsigned) (col-left_margin) >= width) continue; + diff = hpred[col & 1]; + if (diff >= csize) diff = csize-1; + BAYER(row,col-left_margin) = curve[diff]; + } + free (curve); +} + +void CLASS nikon_load_raw() +{ + int irow, row, col, i; + + getbits(-1); + for (irow=0; irow < height; irow++) { + row = irow; + if (model[0] == 'E') { + row = irow * 2 % height + irow / (height/2); + if (row == 1 && data_offset == 0) { + fseek (ifp, 0, SEEK_END); + fseek (ifp, ftell(ifp)/2, SEEK_SET); + getbits(-1); + } + } + for (col=0; col < raw_width; col++) { + i = getbits(12); + if ((unsigned) (col-left_margin) < width) + BAYER(row,col-left_margin) = i; + if (tiff_data_compression == 34713 && (col % 10) == 9) + getbits(8); + } + } +} + +/* + Figure out if a NEF file is compressed. These fancy heuristics + are only needed for the D100, thanks to a bug in some cameras + that tags all images as "compressed". + */ +int CLASS nikon_is_compressed() +{ + uchar test[256]; + int i; + + if (tiff_data_compression != 34713) + return 0; + if (strcmp(model,"D100")) + return 1; + fseek (ifp, data_offset, SEEK_SET); + fread (test, 1, 256, ifp); + for (i=15; i < 256; i+=16) + if (test[i]) return 1; + return 0; +} + +/* + Returns 1 for a Coolpix 990, 0 for a Coolpix 995. + */ +int CLASS nikon_e990() +{ + int i, histo[256]; + const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; + + memset (histo, 0, sizeof histo); + fseek (ifp, 2064*1540*3/4, SEEK_SET); + for (i=0; i < 2000; i++) + histo[fgetc(ifp)]++; + for (i=0; i < 4; i++) + if (histo[often[i]] > 400) + return 1; + return 0; +} + +/* + Returns 1 for a Coolpix 2100, 0 for anything else. + */ +int CLASS nikon_e2100() +{ + uchar t[12]; + int i; + + fseek (ifp, 0, SEEK_SET); + for (i=0; i < 1024; i++) { + fread (t, 1, 12, ifp); + if (((t[2] & t[4] & t[7] & t[9]) >> 4 + & t[1] & t[6] & t[8] & t[11] & 3) != 3) + return 0; + } + return 1; +} + +/* + Returns 0 for a Pentax Optio 33WR, + 1 for a Nikon E3700, + 2 for an Olympus C740UZ. + */ +int CLASS nikon_3700() +{ + int i, sum[] = { 0, 0 }; + uchar tail[952]; + + fseek (ifp, -sizeof tail, SEEK_END); + fread (tail, 1, sizeof tail, ifp); + for (i=0; i < sizeof tail; i++) + sum[(i>>2) & 1] += tail[i]; + if (sum[1] > 4*sum[0]) return 2; + return sum[0] > 4*sum[1]; +} + +/* + Separates a Minolta DiMAGE Z2 from a Nikon E4300. + */ +int CLASS minolta_z2() +{ + int i; + char tail[424]; + + fseek (ifp, -sizeof tail, SEEK_END); + fread (tail, 1, sizeof tail, ifp); + for (i=0; i < sizeof tail; i++) + if (tail[i]) return 1; + return 0; +} + +/* Here raw_width is in bytes, not pixels. */ +void CLASS nikon_e900_load_raw() +{ + int offset=0, irow, row, col; + + for (irow=0; irow < height; irow++) { + row = irow * 2 % height; + if (row == 1) + offset = - (-offset & -4096); + fseek (ifp, offset, SEEK_SET); + offset += raw_width; + getbits(-1); + for (col=0; col < width; col++) + BAYER(row,col) = getbits(10); + } +} + +void CLASS nikon_e2100_load_raw() +{ + uchar data[3456], *dp; + ushort pixel[2304], *pix; + int row, col; + + for (row=0; row <= height; row+=2) { + if (row == height) { + fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET); + row = 1; + } + fread (data, 1, width*3/2, ifp); + for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) { + pix[0] = (dp[2] >> 4) + (dp[ 3] << 4); + pix[1] = (dp[2] << 8) + dp[ 1]; + pix[2] = (dp[7] >> 4) + (dp[ 0] << 4); + pix[3] = (dp[7] << 8) + dp[ 6]; + pix[4] = (dp[4] >> 4) + (dp[ 5] << 4); + pix[5] = (dp[4] << 8) + dp[11]; + pix[6] = (dp[9] >> 4) + (dp[10] << 4); + pix[7] = (dp[9] << 8) + dp[ 8]; + } + for (col=0; col < width; col++) + BAYER(row,col) = (pixel[col] & 0xfff); + } +} + +/* + The Fuji Super CCD is just a Bayer grid rotated 45 degrees. + */ +void CLASS fuji_load_raw() +{ + ushort *pixel; + int row, col, r, c; + + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "fuji_load_raw()"); + for (row=0; row < raw_height; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < fuji_width << !fuji_layout; col++) { + if (fuji_layout) { + r = fuji_width - 1 - col + (row >> 1); + c = col + ((row+1) >> 1); + } else { + r = fuji_width - 1 + row - (col >> 1); + c = row + ((col+1) >> 1); + } + BAYER(r,c) = pixel[col]; + } + } + free (pixel); +} + +void CLASS rollei_load_raw() +{ + uchar pixel[10]; + unsigned iten=0, isix, i, buffer=0, row, col, todo[16]; + + isix = raw_width * raw_height * 5 / 8; + while (fread (pixel, 1, 10, ifp) == 10) { + for (i=0; i < 10; i+=2) { + todo[i] = iten++; + todo[i+1] = pixel[i] << 8 | pixel[i+1]; + buffer = pixel[i] >> 2 | buffer << 6; + } + for ( ; i < 16; i+=2) { + todo[i] = isix++; + todo[i+1] = buffer >> (14-i)*5; + } + for (i=0; i < 16; i+=2) { + row = todo[i] / raw_width - top_margin; + col = todo[i] % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = (todo[i+1] & 0x3ff); + } + } + maximum = 0x3ff; +} + +void CLASS phase_one_load_raw() +{ + int row, col, a, b; + ushort *pixel, akey, bkey, tqmask; + + fseek (ifp, nikon_curve_offset, SEEK_SET); + akey = get2(); + bkey = get2(); + tqmask = tiff_data_compression == 1 ? 0x5555:0x1354; + fseek (ifp, data_offset + top_margin*raw_width*2, SEEK_SET); + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "phase_one_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < raw_width; col+=2) { + a = pixel[col+0] ^ akey; + b = pixel[col+1] ^ bkey; + pixel[col+0] = (a & tqmask) | (b & ~tqmask); + pixel[col+1] = (b & tqmask) | (a & ~tqmask); + } + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col+left_margin]; + } + free (pixel); + maximum = 0xffff; +} + +unsigned CLASS ph1_bits (int nbits) +{ + static UINT64 bitbuf=0; + static int vbits=0; + + if (nbits == 0) + return bitbuf = vbits = 0; + if (vbits < nbits) { + bitbuf = bitbuf << 32 | (unsigned) get4(); + vbits += 32; + } + vbits -= nbits; + return bitbuf << (64 - nbits - vbits) >> (64 - nbits); +} + +void CLASS phase_one_load_raw_c() +{ + static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; + int len[2], pred[2], row, col, ncols, i, j; + ushort *pixel; + + ncols = (raw_width + 7) & -8; + pixel = calloc (ncols, sizeof *pixel); + merror (pixel, "phase_one_load_raw_c()"); + for (row=0; row < raw_height; row++) { + ph1_bits(0); + pred[0] = pred[1] = 0; + for (col=0; col < ncols; col++) { + if (col >= (raw_width & -8)) + len[0] = len[1] = 14; + else if ((col & 7) == 0) + for (i=0; i < 2; i++) { + for (j=0; j < 5 && !ph1_bits(1); j++); + if (j--) len[i] = length[j*2 + ph1_bits(1)]; + } + if ((i = len[col & 1]) == 14) + pixel[col] = pred[col & 1] = ph1_bits(16); + else + pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); + } + if ((unsigned) (row-top_margin) < height) + for (col=0; col < width; col++) + BAYER(row-top_margin,col) = pixel[col+left_margin]; + } + free (pixel); + maximum = 0x3fff; +} + +void CLASS leaf_load_raw() +{ + ushort *pixel; + int r, c, row, col; + + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "leaf_load_raw()"); + for (r=0; r < height-32; r+=32) + FORC3 for (row=r; row < r+32; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < width; col++) + image[row*width+col][c] = pixel[col]; + } + free (pixel); +} + +/* Here raw_width is in bytes, not pixels. */ +void CLASS packed_12_load_raw() +{ + int row, col; + + getbits(-1); + for (row=0; row < height; row++) { + for (col=0; col < width; col++) + BAYER(row,col) = getbits(12); + for (col = width*3/2; col < raw_width; col++) + getbits(8); + } +} + +void CLASS unpacked_load_raw() +{ + ushort *pixel; + int row, col; + + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "unpacked_load_raw()"); + for (row=0; row < height; row++) { + read_shorts (pixel, raw_width); + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + } + free (pixel); +} + +void CLASS olympus_e300_load_raw() +{ + uchar *data, *dp; + ushort *pixel, *pix; + int dwide, row, col; + + dwide = raw_width * 16 / 10; + data = malloc (dwide + raw_width*2); + merror (data, "olympus_e300_load_raw()"); + pixel = (ushort *) (data + dwide); + for (row=0; row < height; row++) { + fread (data, 1, dwide, ifp); + for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) { + if (((dp-data) & 15) == 15) dp++; + pix[0] = dp[1] << 8 | dp[0]; + pix[1] = dp[2] << 4 | dp[1] >> 4; + } + for (col=0; col < width; col++) + BAYER(row,col) = (pixel[col] & 0xfff); + for (col=width+4; col < raw_width; col++) + black += pixel[col] & 0xfff; + } + black /= (raw_width - width - 4) * height; + free (data); +} + +void CLASS olympus_cseries_load_raw() +{ + int irow, row, col; + + for (irow=0; irow < height; irow++) { + row = irow * 2 % height + irow / (height/2); + if (row < 2) { + fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET); + getbits(-1); + } + for (col=0; col < width; col++) + BAYER(row,col) = getbits(12); + } +} + +void CLASS minolta_rd175_load_raw() +{ + uchar pixel[768]; + unsigned irow, box, row, col; + + for (irow=0; irow < 1481; irow++) { + fread (pixel, 1, 768, ifp); + box = irow / 82; + row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); + switch (irow) { + case 1477: case 1479: continue; + case 1476: row = 984; break; + case 1480: row = 985; break; + case 1478: row = 985; box = 1; + } + if ((box < 12) && (box & 1)) { + for (col=0; col < 1533; col++, row ^= 1) + if (col != 1) BAYER(row,col) = (col+1) & 2 ? + pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; + BAYER(row,1) = pixel[1] << 1; + BAYER(row,1533) = pixel[765] << 1; + } else + for (col=row & 1; col < 1534; col+=2) + BAYER(row,col) = pixel[col/2] << 1; + } + maximum = 0xff << 1; +} + +void CLASS eight_bit_load_raw() +{ + uchar *pixel; + int row, col; + + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "eight_bit_load_raw()"); + for (row=0; row < height; row++) { + fread (pixel, 1, raw_width, ifp); + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + } + free (pixel); + maximum = 0xff; +} + +void CLASS casio_qv5700_load_raw() +{ + uchar data[3232], *dp; + ushort pixel[2576], *pix; + int row, col; + + for (row=0; row < height; row++) { + fread (data, 1, 3232, ifp); + for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) { + pix[0] = (dp[0] << 2) + (dp[1] >> 6); + pix[1] = (dp[1] << 4) + (dp[2] >> 4); + pix[2] = (dp[2] << 6) + (dp[3] >> 2); + pix[3] = (dp[3] << 8) + (dp[4] ); + } + for (col=0; col < width; col++) + BAYER(row,col) = (pixel[col] & 0x3ff); + } + maximum = 0x3fc; +} + +void CLASS nucore_load_raw() +{ + ushort *pixel; + int irow, row, col; + + pixel = calloc (width, 2); + merror (pixel, "nucore_load_raw()"); + for (irow=0; irow < height; irow++) { + read_shorts (pixel, width); + row = irow/2 + height/2 * (irow & 1); + for (col=0; col < width; col++) + BAYER(row,col) = pixel[col]; + } + free (pixel); +} + +const int * CLASS make_decoder_int (const int *source, int level) +{ + struct decode *cur; + + cur = free_decode++; + if (level < source[0]) { + cur->branch[0] = free_decode; + source = make_decoder_int (source, level+1); + cur->branch[1] = free_decode; + source = make_decoder_int (source, level+1); + } else { + cur->leaf = source[1]; + source += 2; + } + return source; +} + +int CLASS radc_token (int tree) +{ + int t; + static struct decode *dstart[18], *dindex; + static const int *s, source[] = { + 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, + 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, + 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, + 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, + 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, + 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, + 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, + 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, + 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, + 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, + 1,0, 2,2, 2,-2, + 1,-3, 1,3, + 2,-17, 2,-5, 2,5, 2,17, + 2,-7, 2,2, 2,9, 2,18, + 2,-18, 2,-9, 2,-2, 2,7, + 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, + 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, + 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 + }; + + if (free_decode == first_decode) + for (s=source, t=0; t < 18; t++) { + dstart[t] = free_decode; + s = make_decoder_int (s, 0); + } + if (tree == 18) { + if (kodak_cbpp == 243) + return (getbits(6) << 2) + 2; /* most DC50 photos */ + else + return (getbits(5) << 3) + 4; /* DC40, Fotoman Pixtura */ + } + for (dindex = dstart[tree]; dindex->branch[0]; ) + dindex = dindex->branch[getbits(1)]; + return dindex->leaf; +} + +#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) + +#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ +: (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) + +void CLASS kodak_radc_load_raw() +{ + int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; + short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; + + init_decoder(); + getbits(-1); + for (i=0; i < sizeof(buf)/sizeof(short); i++) + buf[0][0][i] = 2048; + for (row=0; row < height; row+=4) { + FORC3 mul[c] = getbits(6); + FORC3 { + val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; + s = val > 65564 ? 10:12; + x = ~(-1 << (s-1)); + val <<= 12-s; + for (i=0; i < sizeof(buf[0])/sizeof(short); i++) + buf[c][0][i] = (buf[c][0][i] * val + x) >> s; + last[c] = mul[c]; + for (r=0; r <= !c; r++) { + buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; + for (tree=1, col=width/2; col > 0; ) { + if ((tree = radc_token(tree))) { + col -= 2; + if (tree == 8) + FORYX buf[c][y][x] = radc_token(tree+10) * mul[c]; + else + FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; + } else + do { + nreps = (col > 2) ? radc_token(9) + 1 : 1; + for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { + col -= 2; + FORYX buf[c][y][x] = PREDICTOR; + if (rep & 1) { + step = radc_token(10) << 4; + FORYX buf[c][y][x] += step; + } + } + } while (nreps == 9); + } + for (y=0; y < 2; y++) + for (x=0; x < width/2; x++) { + val = (buf[c][y+1][x] << 4) / mul[c]; + if (val < 0) val = 0; + if (c) + BAYER(row+y*2+c-1,x*2+2-c) = val; + else + BAYER(row+r*2+y,x*2+y) = val; + } + memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); + } + } + for (y=row; y < row+4; y++) + for (x=0; x < width; x++) + if ((x+y) & 1) { + val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2; + if (val < 0) val = 0; + BAYER(y,x) = val; + } + } + maximum = 10000; +} + +#undef FORYX +#undef PREDICTOR + +#ifdef NO_JPEG +void CLASS kodak_jpeg_load_raw() {} +#else + +METHODDEF(boolean) +fill_input_buffer (j_decompress_ptr cinfo) +{ + static uchar jpeg_buffer[4096]; + size_t nbytes; + + nbytes = fread (jpeg_buffer, 1, 4096, ifp); + swab (jpeg_buffer, jpeg_buffer, nbytes); + cinfo->src->next_input_byte = jpeg_buffer; + cinfo->src->bytes_in_buffer = nbytes; + return TRUE; +} + +void CLASS kodak_jpeg_load_raw() +{ + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPARRAY buf; + JSAMPLE (*pixel)[3]; + int row, col; + + cinfo.err = jpeg_std_error (&jerr); + jpeg_create_decompress (&cinfo); + jpeg_stdio_src (&cinfo, ifp); + cinfo.src->fill_input_buffer = fill_input_buffer; + jpeg_read_header (&cinfo, TRUE); + jpeg_start_decompress (&cinfo); + if ((cinfo.output_width != width ) || + (cinfo.output_height*2 != height ) || + (cinfo.output_components != 3 )) { + fprintf (stderr, "%s: incorrect JPEG dimensions\n", ifname); + jpeg_destroy_decompress (&cinfo); + longjmp (failure, 3); + } + buf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); + + while (cinfo.output_scanline < cinfo.output_height) { + row = cinfo.output_scanline * 2; + jpeg_read_scanlines (&cinfo, buf, 1); + pixel = (void *) buf[0]; + for (col=0; col < width; col+=2) { + BAYER(row+0,col+0) = pixel[col+0][1] << 1; + BAYER(row+1,col+1) = pixel[col+1][1] << 1; + BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; + BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; + } + } + jpeg_finish_decompress (&cinfo); + jpeg_destroy_decompress (&cinfo); + maximum = 0xff << 1; +} + +#endif + +void CLASS kodak_dc120_load_raw() +{ + static const int mul[4] = { 162, 192, 187, 92 }; + static const int add[4] = { 0, 636, 424, 212 }; + uchar pixel[848]; + int row, shift, col; + + for (row=0; row < height; row++) { + fread (pixel, 848, 1, ifp); + shift = row * mul[row & 3] + add[row & 3]; + for (col=0; col < width; col++) + BAYER(row,col) = (ushort) pixel[(col + shift) % 848]; + } + maximum = 0xff; +} + +void CLASS kodak_easy_load_raw() +{ + uchar *pixel; + unsigned row, col, icol; + + if (raw_width > width) + black = 0; + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "kodak_easy_load_raw()"); + for (row=0; row < height; row++) { + fread (pixel, 1, raw_width, ifp); + for (col=0; col < raw_width; col++) { + icol = col - left_margin; + if (icol < width) + BAYER(row,icol) = (ushort) curve[pixel[col]]; + else + black += curve[pixel[col]]; + } + } + free (pixel); + if (raw_width > width) + black /= (raw_width - width) * height; + if (!strncmp(model,"DC2",3)) + black = 0; + maximum = curve[0xff]; +} + +void CLASS kodak_compressed_load_raw() +{ + uchar c, blen[256]; + ushort raw[6]; + unsigned row, col, len, save, i, israw=0, bits=0, pred[2]; + INT64 bitbuf=0; + int diff; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) + { + if ((col & 255) == 0) { /* Get the bit-lengths of the */ + len = width - col; /* next 256 pixel values */ + if (len > 256) len = 256; + save = ftell(ifp); + for (israw=i=0; i < len; i+=2) { + c = fgetc(ifp); + if ((blen[i+0] = c & 15) > 12 || + (blen[i+1] = c >> 4) > 12 ) + israw = 1; + } + bitbuf = bits = pred[0] = pred[1] = 0; + if (len % 8 == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + if (israw) + fseek (ifp, save, SEEK_SET); + } + if (israw) { /* If the data is not compressed */ + switch (col & 7) { + case 0: + read_shorts (raw, 6); + diff = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; + break; + case 1: + diff = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; + break; + default: + diff = raw[(col & 7) - 2] & 0xfff; + } + } else { /* If the data is compressed */ + len = blen[col & 255]; /* Number of bits for this pixel */ + if (bits < len) { /* Got enough bits in the buffer? */ + for (i=0; i < 32; i+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(i^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); /* Pull bits from buffer */ + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + pred[col & 1] += diff; + diff = pred[col & 1]; + } + BAYER(row,col) = curve[diff]; + } +} + +void CLASS kodak_yuv_load_raw() +{ + uchar c, blen[384]; + unsigned row, col, len, bits=0; + INT64 bitbuf=0; + int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3]; + ushort *ip; + + for (row=0; row < height; row+=2) + for (col=0; col < width; col+=2) { + if ((col & 127) == 0) { + len = (width - col + 1) * 3 & -4; + if (len > 384) len = 384; + for (i=0; i < len; ) { + c = fgetc(ifp); + blen[i++] = c & 15; + blen[i++] = c >> 4; + } + li = bitbuf = bits = y[1] = y[3] = cb = cr = 0; + if (len % 8 == 4) { + bitbuf = fgetc(ifp) << 8; + bitbuf += fgetc(ifp); + bits = 16; + } + } + for (si=0; si < 6; si++) { + len = blen[li++]; + if (bits < len) { + for (i=0; i < 32; i+=8) + bitbuf += (INT64) fgetc(ifp) << (bits+(i^8)); + bits += 32; + } + diff = bitbuf & (0xffff >> (16-len)); + bitbuf >>= len; + bits -= len; + if ((diff & (1 << (len-1))) == 0) + diff -= (1 << len) - 1; + six[si] = diff; + } + y[0] = six[0] + y[1]; + y[1] = six[1] + y[0]; + y[2] = six[2] + y[3]; + y[3] = six[3] + y[2]; + cb += six[4]; + cr += six[5]; + for (i=0; i < 4; i++) { + ip = image[(row+(i >> 1))*width + col+(i & 1)]; + rgb[0] = y[i] + cr; + rgb[1] = y[i]; + rgb[2] = y[i] + cb; + FORC3 if (rgb[c] > 0) ip[c] = curve[rgb[c]]; + } + } +} + +void CLASS sony_decrypt (unsigned *data, int len, int start, int key) +{ + static unsigned pad[128], p; + + if (start) { + for (p=0; p < 4; p++) + pad[p] = key = key * 48828125 + 1; + pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; + for (p=4; p < 127; p++) + pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; + for (p=0; p < 127; p++) + pad[p] = htonl(pad[p]); + } + while (len--) + *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; +} + +void CLASS sony_load_raw() +{ + uchar head[40]; + ushort *pixel; + unsigned i, key, row, col; + + fseek (ifp, 200896, SEEK_SET); + fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); + order = 0x4d4d; + key = get4(); + fseek (ifp, 164600, SEEK_SET); + fread (head, 1, 40, ifp); + sony_decrypt ((void *) head, 10, 1, key); + for (i=26; i-- > 22; ) + key = key << 8 | head[i]; + fseek (ifp, data_offset, SEEK_SET); + pixel = calloc (raw_width, sizeof *pixel); + merror (pixel, "sony_load_raw()"); + for (row=0; row < height; row++) { + fread (pixel, 2, raw_width, ifp); + sony_decrypt ((void *) pixel, raw_width/2, !row, key); + for (col=9; col < left_margin; col++) + black += ntohs(pixel[col]); + for (col=0; col < width; col++) + BAYER(row,col) = ntohs(pixel[col+left_margin]); + } + free (pixel); + if (left_margin > 9) + black /= (left_margin-9) * height; + maximum = 0x3ff0; +} + +#define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) + +/* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ +void CLASS smal_decode_segment (unsigned seg[2][2], int holes) +{ + uchar hist[3][13] = { + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, + { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; + int low, high=0xff, carry=0, nbits=8; + int s, count, bin, next, i, sym[3]; + uchar diff, pred[]={0,0}; + ushort data=0, range=0; + unsigned pix, row, col; + + fseek (ifp, seg[0][1]+1, SEEK_SET); + getbits(-1); + for (pix=seg[0][0]; pix < seg[1][0]; pix++) { + for (s=0; s < 3; s++) { + data = data << nbits | getbits(nbits); + if (carry < 0) + carry = (nbits += carry+1) < 1 ? nbits-1 : 0; + while (--nbits >= 0) + if ((data >> nbits & 0xff) == 0xff) break; + if (nbits > 0) + data = ((data & ((1 << (nbits-1)) - 1)) << 1) | + ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); + if (nbits >= 0) { + data += getbits(1); + carry = nbits - 8; + } + count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); + for (bin=0; hist[s][bin+5] > count; bin++); + low = hist[s][bin+5] * (high >> 4) >> 2; + if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; + high -= low; + for (nbits=0; high << nbits < 128; nbits++); + range = (range+low) << nbits; + high <<= nbits; + next = hist[s][1]; + if (++hist[s][2] > hist[s][3]) { + next = (next+1) & hist[s][0]; + hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; + hist[s][2] = 1; + } + if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { + if (bin < hist[s][1]) + for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; + else if (next <= bin) + for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; + } + hist[s][1] = next; + sym[s] = bin; + } + diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); + if (sym[0] & 4) + diff = diff ? -diff : 0x80; + if (ftell(ifp) + 12 >= seg[1][1]) + diff = 0; + pred[pix & 1] += diff; + row = pix / raw_width - top_margin; + col = pix % raw_width - left_margin; + if (row < height && col < width) + BAYER(row,col) = pred[pix & 1]; + if (!(pix & 1) && HOLE(row)) pix += 2; + } + maximum = 0xff; +} + +void CLASS smal_v6_load_raw() +{ + unsigned seg[2][2]; + + fseek (ifp, 16, SEEK_SET); + seg[0][0] = 0; + seg[0][1] = get2(); + seg[1][0] = raw_width * raw_height; + seg[1][1] = INT_MAX; + smal_decode_segment (seg, 0); + use_gamma = 0; +} + +int CLASS median4 (int *p) +{ + int min, max, sum, i; + + min = max = sum = p[0]; + for (i=1; i < 4; i++) { + sum += p[i]; + if (min > p[i]) min = p[i]; + if (max < p[i]) max = p[i]; + } + return (sum - min - max) >> 1; +} + +void CLASS fill_holes (int holes) +{ + int row, col, val[4]; + + for (row=2; row < height-2; row++) { + if (!HOLE(row)) continue; + for (col=1; col < width-1; col+=4) { + val[0] = BAYER(row-1,col-1); + val[1] = BAYER(row-1,col+1); + val[2] = BAYER(row+1,col-1); + val[3] = BAYER(row+1,col+1); + BAYER(row,col) = median4(val); + } + for (col=2; col < width-2; col+=4) + if (HOLE(row-2) || HOLE(row+2)) + BAYER(row,col) = (BAYER(row,col-2) + BAYER(row,col+2)) >> 1; + else { + val[0] = BAYER(row,col-2); + val[1] = BAYER(row,col+2); + val[2] = BAYER(row-2,col); + val[3] = BAYER(row+2,col); + BAYER(row,col) = median4(val); + } + } +} + +void CLASS smal_v9_load_raw() +{ + unsigned seg[256][2], offset, nseg, holes, i; + + fseek (ifp, 67, SEEK_SET); + offset = get4(); + nseg = fgetc(ifp); + fseek (ifp, offset, SEEK_SET); + for (i=0; i < nseg*2; i++) + seg[0][i] = get4() + data_offset*(i & 1); + fseek (ifp, 78, SEEK_SET); + holes = fgetc(ifp); + fseek (ifp, 88, SEEK_SET); + seg[nseg][0] = raw_height * raw_width; + seg[nseg][1] = get4() + data_offset; + for (i=0; i < nseg; i++) + smal_decode_segment (seg+i, holes); + if (holes) fill_holes (holes); +} + +/* BEGIN GPL BLOCK */ + +void CLASS foveon_decoder (unsigned huff[1024], unsigned code) +{ + struct decode *cur; + int i, len; + + cur = free_decode++; + if (free_decode > first_decode+2048) { + fprintf (stderr, "%s: decoder table overflow\n", ifname); + longjmp (failure, 2); + } + if (code) + for (i=0; i < 1024; i++) + if (huff[i] == code) { + cur->leaf = i; + return; + } + if ((len = code >> 27) > 26) return; + code = (len+1) << 27 | (code & 0x3ffffff) << 1; + + cur->branch[0] = free_decode; + foveon_decoder (huff, code); + cur->branch[1] = free_decode; + foveon_decoder (huff, code+1); +} + +void CLASS foveon_load_camf() +{ + unsigned key, i, val; + + fseek (ifp, meta_offset, SEEK_SET); + key = get4(); + fread (meta_data, 1, meta_length, ifp); + for (i=0; i < meta_length; i++) { + key = (key * 1597 + 51749) % 244944; + val = key * (INT64) 301593171 >> 24; + meta_data[i] ^= ((((key << 8) - val) >> 1) + val) >> 17; + } +} + +void CLASS foveon_load_raw() +{ + struct decode *dindex; + short diff[1024], pred[3]; + unsigned huff[1024], bitbuf=0; + int fixed, row, col, bit=-1, c, i; + + fixed = get4(); + read_shorts ((ushort *) diff, 1024); + if (!fixed) { + for (i=0; i < 1024; i++) + huff[i] = get4(); + init_decoder(); + foveon_decoder (huff, 0); + } + for (row=0; row < height; row++) { + memset (pred, 0, sizeof pred); + if (!bit && !fixed) get4(); + for (col=bit=0; col < width; col++) { + if (fixed) { + bitbuf = get4(); + FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; + } + else FORC3 { + for (dindex=first_decode; dindex->branch[0]; ) { + if ((bit = (bit-1) & 31) == 31) + for (i=0; i < 4; i++) + bitbuf = (bitbuf << 8) + fgetc(ifp); + dindex = dindex->branch[bitbuf >> bit & 1]; + } + pred[c] += diff[dindex->leaf]; + } + FORC3 image[row*width+col][c] = pred[c]; + } + } + foveon_load_camf(); + maximum = clip_max = 0xffff; +} + +char * CLASS foveon_camf_param (char *block, char *param) +{ + unsigned idx, num; + char *pos, *cp, *dp; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'P') continue; + if (strcmp (block, pos+sget4(pos+12))) continue; + cp = pos + sget4(pos+16); + num = sget4(cp); + dp = pos + sget4(cp+4); + while (num--) { + cp += 8; + if (!strcmp (param, dp+sget4(cp))) + return dp+sget4(cp+4); + } + } + return NULL; +} + +void * CLASS foveon_camf_matrix (int dim[3], char *name) +{ + unsigned i, idx, type, ndim, size, *mat; + char *pos, *cp, *dp; + + for (idx=0; idx < meta_length; idx += sget4(pos+8)) { + pos = meta_data + idx; + if (strncmp (pos, "CMb", 3)) break; + if (pos[3] != 'M') continue; + if (strcmp (name, pos+sget4(pos+12))) continue; + dim[0] = dim[1] = dim[2] = 1; + cp = pos + sget4(pos+16); + type = sget4(cp); + if ((ndim = sget4(cp+4)) > 3) break; + dp = pos + sget4(cp+8); + for (i=ndim; i--; ) { + cp += 12; + dim[i] = sget4(cp); + } + if ((size = dim[0]*dim[1]*dim[2]) > meta_length/4) break; + mat = malloc (size * 4); + merror (mat, "foveon_camf_matrix()"); + for (i=0; i < size; i++) + if (type && type != 6) + mat[i] = sget4(dp + i*4); + else + mat[i] = sget4(dp + i*2) & 0xffff; + return mat; + } + fprintf (stderr, "%s: \"%s\" matrix not found!\n", ifname, name); + return NULL; +} + +int CLASS foveon_fixed (void *ptr, int size, char *name) +{ + void *dp; + int dim[3]; + + dp = foveon_camf_matrix (dim, name); + if (!dp) return 0; + memcpy (ptr, dp, size*4); + free (dp); + return 1; +} + +float CLASS foveon_avg (short *pix, int range[2], float cfilt) +{ + int i; + float val, min=FLT_MAX, max=-FLT_MAX, sum=0; + + for (i=range[0]; i <= range[1]; i++) { + sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; + if (min > val) min = val; + if (max < val) max = val; + } + return (sum - min - max) / (range[1] - range[0] - 1); +} + +short * CLASS foveon_make_curve (double max, double mul, double filt) +{ + short *curve; + int i, size; + double x; + + if (!filt) filt = 0.8; + size = 4*M_PI*max / filt; + curve = calloc (size+1, sizeof *curve); + merror (curve, "foveon_make_curve()"); + curve[0] = size; + for (i=0; i < size; i++) { + x = i*filt/max/4; + curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; + } + return curve; +} + +void CLASS foveon_make_curves + (short **curvep, float dq[3], float div[3], float filt) +{ + double mul[3], max=0; + int c; + + FORC3 mul[c] = dq[c]/div[c]; + FORC3 if (max < mul[c]) max = mul[c]; + FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); +} + +int CLASS foveon_apply_curve (short *curve, int i) +{ + if (abs(i) >= curve[0]) return 0; + return i < 0 ? -curve[1-i] : curve[1+i]; +} + +#define image ((short (*)[4]) image) + +void CLASS foveon_interpolate() +{ + static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; + short *pix, prev[3], *curve[8], (*shrink)[3]; + float cfilt=0, ddft[3][3][2], ppm[3][3][3]; + float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; + float chroma_dq[3], color_dq[3], diag[3][3], div[3]; + float (*black)[3], (*sgain)[3], (*sgrow)[3]; + float fsum[3], val, frow, num; + int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; + int dim[3], dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; + int work[3][3], smlast, smred, smred_p=0, dev[3]; + int satlev[3], keep[4], active[4]; + unsigned *badpix; + double dsum=0, trsum[3]; + char str[128], *cp; + + if (verbose) + fprintf (stderr, "Foveon interpolation...\n"); + + foveon_fixed (dscr, 4, "DarkShieldColRange"); + foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); + foveon_fixed (satlev, 3, "SaturationLevel"); + foveon_fixed (keep, 4, "KeepImageArea"); + foveon_fixed (active, 4, "ActiveImageArea"); + foveon_fixed (chroma_dq, 3, "ChromaDQ"); + foveon_fixed (color_dq, 3, + foveon_camf_param ("IncludeBlocks", "ColorDQ") ? + "ColorDQ" : "ColorDTQCamRGB"); + if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) + foveon_fixed (&cfilt, 1, "ColumnFilter"); + + memset (ddft, 0, sizeof ddft); + if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") + || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) + for (i=0; i < 2; i++) { + foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); + for (row = dstb[1]; row <= dstb[3]; row++) + for (col = dstb[0]; col <= dstb[2]; col++) + FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; + FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); + } + + if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) + { fprintf (stderr, "%s: Invalid white balance \"%s\"\n", ifname, model2); + return; } + foveon_fixed (cam_xyz, 9, cp); + foveon_fixed (correct, 9, + foveon_camf_param ("WhiteBalanceCorrections", model2)); + memset (last, 0, sizeof last); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; + + sprintf (str, "%sRGBNeutral", model2); + if (foveon_camf_param ("IncludeBlocks", str)) + foveon_fixed (div, 3, str); + else { + #define LAST(x,y) last[(i+x)%3][(c+y)%3] + for (i=0; i < 3; i++) + FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); + #undef LAST + FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; + } + num = 0; + FORC3 if (num < div[c]) num = div[c]; + FORC3 div[c] /= num; + + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; + FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; + dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; + for (i=0; i < 3; i++) + FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; + memset (trans, 0, sizeof trans); + for (i=0; i < 3; i++) + for (j=0; j < 3; j++) + FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; + + foveon_make_curves (curve, color_dq, div, cfilt); + FORC3 chroma_dq[c] /= 3; + foveon_make_curves (curve+3, chroma_dq, div, cfilt); + FORC3 dsum += chroma_dq[c] / div[c]; + curve[6] = foveon_make_curve (dsum, dsum, cfilt); + curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); + + sgain = foveon_camf_matrix (dim, "SpatialGain"); + if (!sgain) return; + sgrow = calloc (dim[1], sizeof *sgrow); + sgx = (width + dim[1]-2) / (dim[1]-1); + + black = calloc (height, sizeof *black); + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + FORC3 black[row][c] = + ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 + - ddft[0][c][0] ) / 4 - ddft[0][c][1]; + } + memcpy (black, black+8, sizeof *black*8); + memcpy (black+height-11, black+height-22, 11*sizeof *black); + memcpy (last, black, sizeof last); + + for (row=1; row < height-1; row++) { + FORC3 if (last[1][c] > last[0][c]) { + if (last[1][c] > last[2][c]) + black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; + } else + if (last[1][c] < last[2][c]) + black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; + memmove (last, last+1, 2*sizeof last[0]); + memcpy (last[2], black[row+1], sizeof last[2]); + } + FORC3 black[row][c] = (last[0][c] + last[1][c])/2; + FORC3 black[0][c] = (black[1][c] + black[3][c])/2; + + val = 1 - exp(-1/24.0); + memcpy (fsum, black, sizeof fsum); + for (row=1; row < height; row++) + FORC3 fsum[c] += black[row][c] = + (black[row][c] - black[row-1][c])*val + black[row-1][c]; + memcpy (last[0], black[height-1], sizeof last[0]); + FORC3 fsum[c] /= height; + for (row = height; row--; ) + FORC3 last[0][c] = black[row][c] = + (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; + + memset (total, 0, sizeof total); + for (row=2; row < height; row+=4) + for (col=2; col < width; col+=4) { + FORC3 total[c] += (short) image[row*width+col][c]; + total[3]++; + } + for (row=0; row < height; row++) + FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); + + for (row=0; row < height; row++) { + for (i=0; i < 6; i++) + ddft[0][0][i] = ddft[1][0][i] + + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); + pix = image[row*width]; + memcpy (prev, pix, sizeof prev); + frow = row / (height-1.0) * (dim[2]-1); + if ((irow = frow) == dim[2]-1) irow--; + frow -= irow; + for (i=0; i < dim[1]; i++) + FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + + sgain[(irow+1)*dim[1]+i][c] * frow; + for (col=0; col < width; col++) { + FORC3 { + diff = pix[c] - prev[c]; + prev[c] = pix[c]; + ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt + - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) + - black[row][c] ); + } + FORC3 { + work[0][c] = ipix[c] * ipix[c] >> 14; + work[2][c] = ipix[c] * work[0][c] >> 14; + work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; + } + FORC3 { + for (val=i=0; i < 3; i++) + for ( j=0; j < 3; j++) + val += ppm[c][i][j] * work[i][j]; + ipix[c] = floor ((ipix[c] + floor(val)) * + ( sgrow[col/sgx ][c] * (sgx - col%sgx) + + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); + if (ipix[c] > 32000) ipix[c] = 32000; + pix[c] = ipix[c]; + } + pix += 4; + } + } + free (black); + free (sgrow); + free (sgain); + + if ((badpix = foveon_camf_matrix (dim, "BadPixels"))) { + for (i=0; i < dim[0]; i++) { + col = (badpix[i] >> 8 & 0xfff) - keep[0]; + row = (badpix[i] >> 20 ) - keep[1]; + if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) + continue; + memset (fsum, 0, sizeof fsum); + for (sum=j=0; j < 8; j++) + if (badpix[i] & (1 << j)) { + FORC3 fsum[c] += (short) + image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; + sum++; + } + if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; + } + free (badpix); + } + + /* Array for 5x5 Gaussian averaging of red values */ + smrow[6] = calloc (width*5, sizeof **smrow); + merror (smrow[6], "foveon_interpolate()"); + for (i=0; i < 5; i++) + smrow[i] = smrow[6] + i*width; + + /* Sharpen the reds against these Gaussian averages */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + smrow[4][col][0] = + (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + smred = ( 6 * smrow[2][col][0] + + 4 * (smrow[1][col][0] + smrow[3][col][0]) + + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; + if (col == 2) + smred_p = smred; + i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); + if (i > 32000) i = 32000; + pix[0] = i; + smred_p = smred; + pix += 4; + } + } + + /* Adjust the brighter pixels for better linearity */ + min = 0xffff; + FORC3 { + i = satlev[c] / div[c]; + if (min > i) min = i; + } + limit = min * 9 >> 4; + for (pix=image[0]; pix < image[height*width]; pix+=4) { + if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) + continue; + min = max = pix[0]; + for (c=1; c < 3; c++) { + if (min > pix[c]) min = pix[c]; + if (max < pix[c]) max = pix[c]; + } + if (min >= limit*2) { + pix[0] = pix[1] = pix[2] = max; + } else { + i = 0x4000 - ((min - limit) << 14) / limit; + i = 0x4000 - (i*i >> 14); + i = i*i >> 14; + FORC3 pix[c] += (max - pix[c]) * i >> 14; + } + } +/* + Because photons that miss one detector often hit another, + the sum R+G+B is much less noisy than the individual colors. + So smooth the hues without smoothing the total. + */ + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - + ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); + sum = (dev[0] + dev[1] + dev[2]) >> 3; + FORC3 pix[c] += dev[c] - sum; + pix += 4; + } + } + for (smlast=-1, row=2; row < height-2; row++) { + while (smlast < row+2) { + for (i=0; i < 6; i++) + smrow[(i+5) % 6] = smrow[i]; + pix = image[++smlast*width+2]; + for (col=2; col < width-2; col++) { + FORC3 smrow[4][col][c] = + (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; + pix += 4; + } + } + pix = image[row*width+2]; + for (col=2; col < width-2; col++) { + for (total[3]=375, sum=60, c=0; c < 3; c++) { + for (total[c]=i=0; i < 5; i++) + total[c] += smrow[i][col][c]; + total[3] += total[c]; + sum += pix[c]; + } + if (sum < 0) sum = 0; + j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; + FORC3 pix[c] += foveon_apply_curve (curve[6], + ((j*total[c] + 0x8000) >> 16) - pix[c]); + pix += 4; + } + } + + /* Transform the image to a different colorspace */ + for (pix=image[0]; pix < image[height*width]; pix+=4) { + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); + sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; + FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); + FORC3 { + for (dsum=i=0; i < 3; i++) + dsum += trans[c][i] * pix[i]; + if (dsum < 0) dsum = 0; + if (dsum > 24000) dsum = 24000; + ipix[c] = dsum + 0.5; + } + FORC3 pix[c] = ipix[c]; + } + + /* Smooth the image bottom-to-top and save at 1/4 scale */ + shrink = calloc ((width/4) * (height/4), sizeof *shrink); + merror (shrink, "foveon_interpolate()"); + for (row = height/4; row--; ) + for (col=0; col < width/4; col++) { + ipix[0] = ipix[1] = ipix[2] = 0; + for (i=0; i < 4; i++) + for (j=0; j < 4; j++) + FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; + FORC3 + if (row+2 > height/4) + shrink[row*(width/4)+col][c] = ipix[c] >> 4; + else + shrink[row*(width/4)+col][c] = + (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; + } + /* From the 1/4-scale image, smooth right-to-left */ + for (row=0; row < (height & ~3); row++) { + ipix[0] = ipix[1] = ipix[2] = 0; + if ((row & 3) == 0) + for (col = width & ~3 ; col--; ) + FORC3 smrow[0][col][c] = ipix[c] = + (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Then smooth left-to-right */ + ipix[0] = ipix[1] = ipix[2] = 0; + for (col=0; col < (width & ~3); col++) + FORC3 smrow[1][col][c] = ipix[c] = + (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; + + /* Smooth top-to-bottom */ + if (row == 0) + memcpy (smrow[2], smrow[1], sizeof **smrow * width); + else + for (col=0; col < (width & ~3); col++) + FORC3 smrow[2][col][c] = + (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; + + /* Adjust the chroma toward the smooth values */ + for (col=0; col < (width & ~3); col++) { + for (i=j=30, c=0; c < 3; c++) { + i += smrow[2][col][c]; + j += image[row*width+col][c]; + } + j = (j << 16) / i; + for (sum=c=0; c < 3; c++) { + ipix[c] = foveon_apply_curve (curve[c+3], + ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); + sum += ipix[c]; + } + sum >>= 3; + FORC3 { + i = image[row*width+col][c] + ipix[c] - sum; + if (i < 0) i = 0; + image[row*width+col][c] = i; + } + } + } + free (shrink); + free (smrow[6]); + for (i=0; i < 8; i++) + free (curve[i]); + + /* Trim off the black border */ + active[1] -= keep[1]; + active[3] -= 2; + i = active[2] - active[0]; + for (row = 0; row < active[3]-active[1]; row++) + memcpy (image[row*i], image[(row+active[1])*width+active[0]], + i * sizeof *image); + width = i; + height = row; +} +#undef image + +/* END GPL BLOCK */ + +/* + Seach from the current directory up to the root looking for + a ".badpixels" file, and fix those pixels now. + */ +void CLASS bad_pixels() +{ + FILE *fp=NULL; + char *fname, *cp, line[128]; + int len, time, row, col, r, c, rad, tot, n, fixed=0; + + if (!filters) return; + for (len=16 ; ; len *= 2) { + fname = malloc (len); + if (!fname) return; + if (getcwd (fname, len-12)) break; + free (fname); + if (errno != ERANGE) return; + } +#ifdef WIN32 + if (fname[1] == ':') + memmove (fname, fname+2, len-2); + for (cp=fname; *cp; cp++) + if (*cp == '\\') *cp = '/'; +#endif + cp = fname + strlen(fname); + if (cp[-1] == '/') cp--; + while (*fname == '/') { + strcpy (cp, "/.badpixels"); + if ((fp = fopen (fname, "r"))) break; + if (cp == fname) break; + while (*--cp != '/'); + } + free (fname); + if (!fp) return; + while (fgets (line, 128, fp)) { + cp = strchr (line, '#'); + if (cp) *cp = 0; + if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; + if ((unsigned) col >= width || (unsigned) row >= height) continue; + if (time > timestamp) continue; + for (tot=n=0, rad=1; rad < 3 && n==0; rad++) + for (r = row-rad; r <= row+rad; r++) + for (c = col-rad; c <= col+rad; c++) + if ((unsigned) r < height && (unsigned) c < width && + (r != row || c != col) && FC(r,c) == FC(row,col)) { + tot += BAYER(r,c); + n++; + } + BAYER(row,col) = tot/n; + if (verbose) { + if (!fixed++) + fprintf (stderr, "Fixed bad pixels at:"); + fprintf (stderr, " %d,%d", col, row); + } + } + if (fixed) fputc ('\n', stderr); + fclose (fp); +} + +void CLASS pseudoinverse (const double (*in)[3], double (*out)[3], int size) +{ + double work[3][6], num; + int i, j, k; + + for (i=0; i < 3; i++) { + for (j=0; j < 6; j++) + work[i][j] = j == i+3; + for (j=0; j < 3; j++) + for (k=0; k < size; k++) + work[i][j] += in[k][i] * in[k][j]; + } + for (i=0; i < 3; i++) { + num = work[i][i]; + for (j=0; j < 6; j++) + work[i][j] /= num; + for (k=0; k < 3; k++) { + if (k==i) continue; + num = work[k][i]; + for (j=0; j < 6; j++) + work[k][j] -= work[i][j] * num; + } + } + for (i=0; i < size; i++) + for (j=0; j < 3; j++) + for (out[i][j]=k=0; k < 3; k++) + out[i][j] += work[j][k+3] * in[i][k]; +} + +void CLASS cam_xyz_coeff (double cam_xyz[4][3]) +{ + double cam_rgb[4][3], inverse[4][3], num; + int i, j, k; + + for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ + for (j=0; j < 3; j++) + for (cam_rgb[i][j] = k=0; k < 3; k++) + cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; + + for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ + for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ + num += cam_rgb[i][j]; + for (j=0; j < 3; j++) + cam_rgb[i][j] /= num; + pre_mul[i] = 1 / num; + } + pseudoinverse ((const double (*)[3]) cam_rgb, inverse, colors); + for (raw_color = i=0; i < 3; i++) + for (j=0; j < colors; j++) + rgb_cam[i][j] = inverse[j][i]; +} + +#ifdef COLORCHECK +void CLASS colorcheck() +{ +#define NSQ 24 +// Coordinates of the GretagMacbeth ColorChecker squares +// width, height, 1st_column, 1st_row + static const int cut[NSQ][4] = { + { 241, 231, 234, 274 }, + { 251, 235, 534, 274 }, + { 255, 239, 838, 272 }, + { 255, 240, 1146, 274 }, + { 251, 237, 1452, 278 }, + { 243, 238, 1758, 288 }, + { 253, 253, 218, 558 }, + { 255, 249, 524, 562 }, + { 261, 253, 830, 562 }, + { 260, 255, 1144, 564 }, + { 261, 255, 1450, 566 }, + { 247, 247, 1764, 576 }, + { 255, 251, 212, 862 }, + { 259, 259, 518, 862 }, + { 263, 261, 826, 864 }, + { 265, 263, 1138, 866 }, + { 265, 257, 1450, 872 }, + { 257, 255, 1762, 874 }, + { 257, 253, 212, 1164 }, + { 262, 251, 516, 1172 }, + { 263, 257, 826, 1172 }, + { 263, 255, 1136, 1176 }, + { 255, 252, 1452, 1182 }, + { 257, 253, 1760, 1180 } }; +// ColorChecker Chart under 6500-kelvin illumination + static const double gmb_xyz[NSQ][3] = { + { 11.078, 9.870, 6.738 }, // Dark Skin + { 37.471, 35.004, 26.057 }, // Light Skin + { 18.187, 19.306, 35.425 }, // Blue Sky + { 10.825, 13.827, 7.600 }, // Foliage + { 24.769, 23.304, 43.943 }, // Blue Flower + { 31.174, 42.684, 45.277 }, // Bluish Green + { 36.238, 29.188, 6.222 }, // Orange + { 13.661, 11.845, 38.929 }, // Purplish Blue + { 27.999, 19.272, 14.265 }, // Moderate Red + { 8.398, 6.309, 14.211 }, // Purple + { 33.692, 44.346, 11.288 }, // Yellow Green + { 45.000, 42.144, 8.429 }, // Orange Yellow + { 8.721, 6.130, 31.181 }, // Blue + { 14.743, 24.049, 9.778 }, // Green + { 19.777, 11.530, 5.101 }, // Red + { 55.978, 59.599, 10.047 }, // Yellow + { 29.421, 19.271, 31.167 }, // Magenta + { 13.972, 18.952, 37.646 }, // Cyan + { 82.819, 87.727, 94.479 }, // White + { 55.950, 58.959, 64.375 }, // Neutral 8 + { 32.877, 34.536, 38.097 }, // Neutral 6.5 + { 18.556, 19.701, 21.487 }, // Neutral 5 + { 8.353, 8.849, 9.812 }, // Neutral 3.5 + { 2.841, 2.980, 3.332 } }; // Black + double inverse[NSQ][3], gmb_cam[NSQ][4], cam_xyz[4][3]; + double num, error, minerr=DBL_MAX, best[4][3]; + int b, c, i, j, k, sq, row, col, count[4]; + + memset (gmb_cam, 0, sizeof gmb_cam); + for (sq=0; sq < NSQ; sq++) { + FORCC count[c] = 0; + for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) + for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { + c = FC(row,col); + if (c >= colors) c -= 2; + gmb_cam[sq][c] += BAYER(row,col); + count[c]++; + } + FORCC gmb_cam[sq][c] /= count[c]; + } + for (b=0; b < 2000; b++) { + pseudoinverse (gmb_xyz, inverse, NSQ); + for (i=0; i < colors; i++) + for (j=0; j < 3; j++) + for (cam_xyz[i][j] = k=0; k < NSQ; k++) + cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; + + for (error=sq=0; sq < NSQ; sq++) + FORCC { + for (num=j=0; j < 3; j++) + num += cam_xyz[c][j] * gmb_xyz[sq][j]; + if (num < 0) num=0; + error += pow (num - gmb_cam[sq][c], 2); + gmb_cam[sq][c]--; // for the next black value + } + if (error < minerr) { + black = b; + minerr = error; + memcpy (best, cam_xyz, sizeof best); + } + } + cam_xyz_coeff (best); + if (verbose) { + fprintf (stderr, " { \"%s %s\",\n\t{ ", make, model); + num = 10000 / (best[1][0] + best[1][1] + best[1][2]); + FORCC for (j=0; j < 3; j++) + fprintf (stderr, "%d,", (int) (best[c][j] * num + 0.5)); + fprintf (stderr, "\b } },\n"); + } +#undef NSQ +} +#endif + +void CLASS scale_colors() +{ + int row, col, c, val, shift=0; + int min[4], max[4], count[4]; + double sum[4], dmin; + + maximum -= black; + if (use_auto_wb || (use_camera_wb && camera_red == -1)) { + FORC4 min[c] = INT_MAX; + FORC4 max[c] = count[c] = sum[c] = 0; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + FORC4 { + val = image[row*width+col][c]; + if (!val) continue; + if (min[c] > val) min[c] = val; + if (max[c] < val) max[c] = val; + val -= black; + if (val > maximum-25) continue; + if (val < 0) val = 0; + sum[c] += val; + count[c]++; + } + FORC4 if (sum[c]) pre_mul[c] = count[c] / sum[c]; + } + if (use_camera_wb && camera_red != -1) { + FORC4 count[c] = sum[c] = 0; + for (row=0; row < 8; row++) + for (col=0; col < 8; col++) { + c = FC(row,col); + if ((val = white[row][col] - black) > 0) + sum[c] += val; + count[c]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + FORC4 pre_mul[c] = count[c] / sum[c]; + else if (camera_red && camera_blue) + memcpy (pre_mul, cam_mul, sizeof pre_mul); + else + fprintf (stderr, "%s: Cannot use camera white balance.\n", ifname); + } + if (raw_color) { + pre_mul[0] *= red_scale; + pre_mul[2] *= blue_scale; + } + if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; + dmin = DBL_MAX; + FORC4 if (dmin > pre_mul[c]) + dmin = pre_mul[c]; + FORC4 pre_mul[c] /= dmin; + + while (maximum << shift < 0x8000) shift++; + FORC4 pre_mul[c] *= 1 << shift; + maximum <<= shift; + + if (write_fun != write_ppm || bright < 1) { + maximum *= bright; + if (maximum > 0xffff) + maximum = 0xffff; + FORC4 pre_mul[c] *= bright; + } + if (verbose) { + fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black); + FORC4 fprintf (stderr, " %f", pre_mul[c]); + fputc ('\n', stderr); + } + clip_max = clip_color ? maximum : 0xffff; + for (row=0; row < height; row++) + for (col=0; col < width; col++) + FORC4 { + val = image[row*width+col][c]; + if (!val) continue; + val -= black; + val *= pre_mul[c]; + image[row*width+col][c] = CLIP(val); + } + if (filters && colors == 3) { + if (four_color_rgb) { + colors++; + FORC3 rgb_cam[c][3] = rgb_cam[c][1] /= 2; + } else { + for (row = FC(1,0) >> 1; row < height; row+=2) + for (col = FC(row,1) & 1; col < width; col+=2) + image[row*width+col][1] = image[row*width+col][3]; + filters &= ~((filters & 0x55555555) << 1); + } + } +} + +void CLASS border_interpolate (int border) +{ + unsigned row, col, y, x, c, sum[8]; + + for (row=0; row < height; row++) + for (col=0; col < width; col++) { + if (col==border && row >= border && row < height-border) + col = width-border; + memset (sum, 0, sizeof sum); + for (y=row-1; y != row+2; y++) + for (x=col-1; x != col+2; x++) + if (y < height && x < width) { + sum[FC(y,x)] += BAYER(y,x); + sum[FC(y,x)+4]++; + } + FORCC if (c != FC(row,col)) + image[row*width+col][c] = sum[c] / sum[c+4]; + } +} + +void CLASS lin_interpolate() +{ + int code[8][2][32], *ip, sum[4]; + int c, i, x, y, row, col, shift, color; + ushort *pix; + + if (verbose) fprintf (stderr, "Bilinear interpolation...\n"); + + border_interpolate(1); + for (row=0; row < 8; row++) + for (col=0; col < 2; col++) { + ip = code[row][col]; + memset (sum, 0, sizeof sum); + for (y=-1; y <= 1; y++) + for (x=-1; x <= 1; x++) { + shift = (y==0) + (x==0); + if (shift == 2) continue; + color = FC(row+y,col+x); + *ip++ = (width*y + x)*4 + color; + *ip++ = shift; + *ip++ = color; + sum[color] += 1 << shift; + } + FORCC + if (c != FC(row,col)) { + *ip++ = c; + *ip++ = sum[c]; + } + } + for (row=1; row < height-1; row++) + for (col=1; col < width-1; col++) { + pix = image[row*width+col]; + ip = code[row & 7][col & 1]; + memset (sum, 0, sizeof sum); + for (i=8; i--; ip+=3) + sum[ip[2]] += pix[ip[0]] << ip[1]; + for (i=colors; --i; ip+=2) + pix[ip[0]] = sum[ip[0]] / ip[1]; + } +} + +/* + This algorithm is officially called: + + "Interpolation using a Threshold-based variable number of gradients" + + described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html + + I've extended the basic idea to work with non-Bayer filter arrays. + Gradients are numbered clockwise from NW=0 to W=7. + */ +void CLASS vng_interpolate() +{ + static const signed char *cp, terms[] = { + -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, + -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, + -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, + -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, + -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, + -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, + -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, + -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, + -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, + -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, + -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, + -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, + -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, + +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, + +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, + +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, + +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, + +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, + +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, + +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, + +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, + +1,+0,+2,+1,0,0x10 + }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; + ushort (*brow[5])[4], *pix; + int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4]; + int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; + int g, diff, thold, num, c; + + lin_interpolate(); + if (verbose) fprintf (stderr, "VNG interpolation...\n"); + + for (row=0; row < 8; row++) { /* Precalculate for VNG */ + for (col=0; col < 2; col++) { + ip = code[row][col]; + for (cp=terms, t=0; t < 64; t++) { + y1 = *cp++; x1 = *cp++; + y2 = *cp++; x2 = *cp++; + weight = *cp++; + grads = *cp++; + color = FC(row+y1,col+x1); + if (FC(row+y2,col+x2) != color) continue; + diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1; + if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; + *ip++ = (y1*width + x1)*4 + color; + *ip++ = (y2*width + x2)*4 + color; + *ip++ = weight; + for (g=0; g < 8; g++) + if (grads & 1< gval[g]) gmin = gval[g]; + if (gmax < gval[g]) gmax = gval[g]; + } + if (gmax == 0) { + memcpy (brow[2][col], pix, sizeof *image); + continue; + } + thold = gmin + (gmax >> 1); + memset (sum, 0, sizeof sum); + color = FC(row,col); + for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ + if (gval[g] <= thold) { + FORCC + if (c == color && ip[1]) + sum[c] += (pix[c] + pix[ip[1]]) >> 1; + else + sum[c] += pix[ip[0] + c]; + num++; + } + } + FORCC { /* Save to buffer */ + t = pix[color]; + if (c != color) + t += (sum[c] - sum[color]) / num; + brow[2][col][c] = CLIP(t); + } + } + if (row > 3) /* Write buffer to image */ + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + for (g=0; g < 4; g++) + brow[(g-1) & 3] = brow[g]; + } + memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); + memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); + free (brow[4]); +} + +void CLASS cam_to_cielab (ushort cam[4], float lab[3]) +{ + int c, i, j, k; + float r, xyz[3]; + static const float d65[3] = { 0.950456, 1, 1.088754 }; + static float cbrt[0x10000], xyz_cam[3][4]; + + if (cam == NULL) { + for (i=0; i < 0x10000; i++) { + r = (float) i / maximum; + cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; + } + for (i=0; i < 3; i++) + for (j=0; j < colors; j++) + for (xyz_cam[i][j] = k=0; k < 3; k++) + xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65[i]; + } else { + for (i=0; i < 3; i++) { + for (xyz[i]=0.5, c=0; c < colors; c++) + xyz[i] += xyz_cam[i][c] * cam[c]; + xyz[i] = cbrt[CLIP((int) xyz[i])]; + } + lab[0] = 116 * xyz[1] - 16; + lab[1] = 500 * (xyz[0] - xyz[1]); + lab[2] = 200 * (xyz[1] - xyz[2]); + } +} + +/* + Adaptive Homogeneity-Directed interpolation is based on + the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. + */ +#define TS 256 /* Tile Size */ + +void CLASS ahd_interpolate() +{ + int i, j, top, left, row, col, tr, tc, fc, c, d, val, hm[2]; + ushort (*pix)[4], (*rix)[3]; + static const int dir[4] = { -1, 1, -TS, TS }; + unsigned ldiff[2][4], abdiff[2][4], leps, abeps; + float flab[3]; + ushort (*rgb)[TS][TS][3]; + short (*lab)[TS][TS][3]; + char (*homo)[TS][TS], *buffer; + + if (verbose) fprintf (stderr, "AHD interpolation...\n"); + + border_interpolate(3); + buffer = malloc (26*TS*TS); /* 1664 kB */ + merror (buffer, "ahd_interpolate()"); + rgb = (void *) buffer; + lab = (void *) (buffer + 12*TS*TS); + homo = (void *) (buffer + 24*TS*TS); + + for (top=0; top < height; top += TS-6) + for (left=0; left < width; left += TS-6) { + memset (rgb, 0, 12*TS*TS); + +/* Interpolate green horizontally and vertically: */ + for (row = top < 2 ? 2:top; row < top+TS && row < height-2; row++) { + col = left + (FC(row,left) == 1); + if (col < 2) col += 2; + for (fc = FC(row,col); col < left+TS && col < width-2; col+=2) { + pix = image + row*width+col; + val = ((pix[-1][1] + pix[0][fc] + pix[1][1]) * 2 + - pix[-2][fc] - pix[2][fc]) >> 2; + rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); + val = ((pix[-width][1] + pix[0][fc] + pix[width][1]) * 2 + - pix[-2*width][fc] - pix[2*width][fc]) >> 2; + rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); + } + } +/* Interpolate red and blue, and convert to CIELab: */ + for (d=0; d < 2; d++) + for (row=top+1; row < top+TS-1 && row < height-1; row++) + for (col=left+1; col < left+TS-1 && col < width-1; col++) { + pix = image + row*width+col; + rix = &rgb[d][row-top][col-left]; + if ((c = 2 - FC(row,col)) == 1) { + c = FC(row+1,col); + val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] + - rix[-1][1] - rix[1][1] ) >> 1); + rix[0][2-c] = CLIP(val); + val = pix[0][1] + (( pix[-width][c] + pix[width][c] + - rix[-TS][1] - rix[TS][1] ) >> 1); + } else + val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + + pix[+width-1][c] + pix[+width+1][c] + - rix[-TS-1][1] - rix[-TS+1][1] + - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); + rix[0][c] = CLIP(val); + c = FC(row,col); + rix[0][c] = pix[0][c]; + cam_to_cielab (rix[0], flab); + FORC3 lab[d][row-top][col-left][c] = 64*flab[c]; + } +/* Build homogeneity maps from the CIELab images: */ + memset (homo, 0, 2*TS*TS); + for (row=top+2; row < top+TS-2 && row < height; row++) { + tr = row-top; + for (col=left+2; col < left+TS-2 && col < width; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + ldiff[d][i] = ABS(lab[d][tr][tc][0]-lab[d][tr][tc+dir[i]][0]); + leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), + MAX(ldiff[1][2],ldiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (i >> 1 == d || ldiff[d][i] <= leps) + abdiff[d][i] = SQR(lab[d][tr][tc][1]-lab[d][tr][tc+dir[i]][1]) + + SQR(lab[d][tr][tc][2]-lab[d][tr][tc+dir[i]][2]); + abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), + MAX(abdiff[1][2],abdiff[1][3])); + for (d=0; d < 2; d++) + for (i=0; i < 4; i++) + if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) + homo[d][tr][tc]++; + } + } +/* Combine the most homogenous pixels for the final result: */ + for (row=top+3; row < top+TS-3 && row < height-3; row++) { + tr = row-top; + for (col=left+3; col < left+TS-3 && col < width-3; col++) { + tc = col-left; + for (d=0; d < 2; d++) + for (hm[d]=0, i=tr-1; i <= tr+1; i++) + for (j=tc-1; j <= tc+1; j++) + hm[d] += homo[d][i][j]; + if (hm[0] != hm[1]) + FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; + else + FORC3 image[row*width+col][c] = + (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; + } + } + } + free (buffer); +} +#undef TS + +/* + Bilateral Filtering was developed by C. Tomasi and R. Manduchi. + */ +void CLASS bilateral_filter() +{ + float (**window)[7], *kernel, scale_r, elut[1024], sum[5]; + int c, i, wr, ws, wlast, row, col, y, x; + unsigned sep; + + if (verbose) fprintf (stderr, "Bilateral filtering...\n"); + + wr = ceil(sigma_d*2); /* window radius */ + ws = 2*wr + 1; /* window size */ + window = calloc ((ws+1)*sizeof *window + + ws*width*sizeof **window + ws*sizeof *kernel, 1); + merror (window, "bilateral_filter()"); + for (i=0; i <= ws; i++) + window[i] = (float(*)[7]) (window+ws+1) + i*width; + kernel = (float *) window[ws] + wr; + for (i=-wr; i <= wr; i++) + kernel[i] = 256 / (2*SQR(sigma_d)) * i*i + 0.25; + scale_r = 256 / (2*SQR(sigma_r)); + for (i=0; i < 1024; i++) + elut[i] = exp (-i/256.0); + + for (wlast=-1, row=0; row < height; row++) { + while (wlast < row+wr) { + wlast++; + for (i=0; i <= ws; i++) /* rotate window rows */ + window[(ws+i) % (ws+1)] = window[i]; + if (wlast < height) + for (col=0; col < width; col++) { + FORCC window[ws-1][col][c] = image[wlast*width+col][c]; + cam_to_cielab (image[wlast*width+col], window[ws-1][col]+4); + } + } + for (col=0; col < width; col++) { + memset (sum, 0, sizeof sum); + for (y=-wr; y <= wr; y++) + if ((unsigned)(row+y) < height) + for (x=-wr; x <= wr; x++) + if ((unsigned)(col+x) < width) { + sep = ( SQR(window[wr+y][col+x][4] - window[wr][col][4]) + + SQR(window[wr+y][col+x][5] - window[wr][col][5]) + + SQR(window[wr+y][col+x][6] - window[wr][col][6]) ) + * scale_r + kernel[y] + kernel[x]; + if (sep < 1024) { + FORCC sum[c] += elut[sep] * window[wr+y][col+x][c]; + sum[4] += elut[sep]; + } + } + FORCC image[row*width+col][c] = sum[c]/sum[4]; + } + } + free (window); +} + +void CLASS parse_makernote() +{ + static const uchar xlat[2][256] = { + { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, + 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, + 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, + 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, + 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, + 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, + 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, + 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, + 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, + 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, + 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, + 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, + 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, + 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, + 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, + 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, + { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, + 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, + 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, + 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, + 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, + 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, + 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, + 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, + 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, + 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, + 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, + 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, + 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, + 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, + 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, + 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; + unsigned base=0, offset=0, entries, tag, type, len, save, c; + unsigned ver97=0, serial=0, i; + uchar buf97[324], ci, cj, ck; + static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; + short sorder; + char buf[10]; +/* + The MakerNote might have its own TIFF header (possibly with + its own byte-order!), or it might just be a table. + */ + sorder = order; + fread (buf, 1, 10, ifp); + if (!strncmp (buf,"KC" ,2) || /* these aren't TIFF format */ + !strncmp (buf,"MLY",3)) return; + if (!strcmp (buf,"Nikon")) { + base = ftell(ifp); + order = get2(); + if (get2() != 42) goto quit; + offset = get4(); + fseek (ifp, offset-8, SEEK_CUR); + } else if (!strncmp (buf,"FUJIFILM",8) || + !strcmp (buf,"Panasonic")) { + order = 0x4949; + fseek (ifp, 2, SEEK_CUR); + } else if (!strcmp (buf,"OLYMP") || + !strcmp (buf,"LEICA") || + !strcmp (buf,"EPSON")) + fseek (ifp, -2, SEEK_CUR); + else if (!strcmp (buf,"AOC") || + !strcmp (buf,"TQVC")) + fseek (ifp, -4, SEEK_CUR); + else fseek (ifp, -10, SEEK_CUR); + + entries = get2(); + while (entries--) { + tag = get2(); + type = get2(); + len = get4(); + save = ftell(ifp); + if (len * size[type < 13 ? type:0] > 4) + fseek (ifp, get4()+base, SEEK_SET); + + if (tag == 8 && type == 4) + shot_order = get4(); + if (tag == 0xc && len == 4) { + camera_red = getrat(); + camera_blue = getrat(); + } + if (tag == 0x14 && len == 2560 && type == 7) { + fseek (ifp, 1248, SEEK_CUR); + goto get2_256; + } + if (strstr(make,"PENTAX")) { + if (tag == 0x1b) tag = 0x1018; + if (tag == 0x1c) tag = 0x1017; + } + if (tag == 0x1d) + while ((c = fgetc(ifp))) + serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); + if (tag == 0x8c) + nikon_curve_offset = ftell(ifp) + 2112; + if (tag == 0x96) + nikon_curve_offset = ftell(ifp) + 2; + if (tag == 0x97) { + for (i=0; i < 4; i++) + ver97 = (ver97 << 4) + fgetc(ifp)-'0'; + switch (ver97) { + case 0x100: + fseek (ifp, 68, SEEK_CUR); + FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); + break; + case 0x102: + fseek (ifp, 6, SEEK_CUR); + goto get2_rggb; + case 0x103: + fseek (ifp, 16, SEEK_CUR); + FORC4 cam_mul[c] = get2(); + } + if (ver97 >> 8 == 2) { + if (ver97 != 0x205) fseek (ifp, 280, SEEK_CUR); + fread (buf97, 324, 1, ifp); + } + } + if (tag == 0xa7 && ver97 >> 8 == 2) { + ci = xlat[0][serial & 0xff]; + cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; + ck = 0x60; + for (i=0; i < 324; i++) + buf97[i] ^= (cj += ci * ck++); + FORC4 cam_mul[c ^ (c >> 1)] = + sget2 (buf97 + (ver97 == 0x205 ? 14:6) + c*2); + } + if (tag == 0xe0 && len == 17) { + get2(); + raw_width = get2(); + raw_height = get2(); + } + if (tag == 0x200 && len == 4) + black = (get2()+get2()+get2()+get2())/4; + if (tag == 0x201 && len == 4) + goto get2_rggb; + if (tag == 0x401 && len == 4) { + black = (get4()+get4()+get4()+get4())/4; + } + if (tag == 0xe01) { /* Nikon Capture Note */ + type = order; + order = 0x4949; + fseek (ifp, 22, SEEK_CUR); + for (offset=22; offset+22 < len; offset += 22+i) { + tag = get4(); + fseek (ifp, 14, SEEK_CUR); + i = get4()-4; + if (tag == 0x76a43207) flip = get2(); + else fseek (ifp, i, SEEK_CUR); + } + order = type; + } + if (tag == 0xe80 && len == 256 && type == 7) { + fseek (ifp, 48, SEEK_CUR); + camera_red = get2() * 508 * 1.078 / 0x10000; + camera_blue = get2() * 382 * 1.173 / 0x10000; + } + if (tag == 0xf00 && len == 614 && type == 7) { + fseek (ifp, 188, SEEK_CUR); + goto get2_256; + } + if (tag == 0x1017) + camera_red = get2() / 256.0; + if (tag == 0x1018) + camera_blue = get2() / 256.0; + if (tag == 0x2011 && len == 2) { +get2_256: + order = 0x4d4d; + camera_red = get2() / 256.0; + camera_blue = get2() / 256.0; + } + if (tag == 0x4001) { + fseek (ifp, strstr(model,"EOS-1D") ? 68 : + strstr(model,"EOS 5D") ? 126 : 50, SEEK_CUR); +get2_rggb: + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + } + fseek (ifp, save+4, SEEK_SET); + } +quit: + order = sorder; +} + +/* + Since the TIFF DateTime string has no timezone information, + assume that the camera's clock was set to Universal Time. + */ +void CLASS get_timestamp (int reversed) +{ + struct tm t; + char str[20]; + int i; + + if (timestamp) return; + str[19] = 0; + if (reversed) + for (i=19; i--; ) str[i] = fgetc(ifp); + else + fread (str, 19, 1, ifp); + if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, + &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) + return; + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); +} + +void CLASS parse_exif (int base) +{ + int entries, tag, type, len, val, save; + + entries = get2(); + while (entries--) { + tag = get2(); + type = get2(); + len = get4(); + val = get4(); + save = ftell(ifp); + fseek (ifp, base+val, SEEK_SET); + if (tag == 0x9003 || tag == 0x9004) + get_timestamp(0); + if (tag == 0x927c) + parse_makernote(); + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_mos (int offset); +void CLASS sony_decrypt (unsigned *data, int len, int start, int key); + +int CLASS parse_tiff_ifd (int base, int level) +{ + unsigned entries, tag, type, len, plen=16, save; + int done=0, use_cm=0, cfa, i, j, c; + static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 }; + char software[64], *cbuf, *cp; + static const int flip_map[] = { 0,1,3,2,4,6,7,5 }; + uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; + double dblack, cc[4][4], cm[4][3], cam_xyz[4][3]; + double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; + unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; + FILE *sfp; + + for (j=0; j < 4; j++) + for (i=0; i < 4; i++) + cc[j][i] = i == j; + entries = get2(); + if (entries > 512) return 1; + while (entries--) { + tag = get2(); + type = get2(); + len = get4(); + save = ftell(ifp); + if (tag > 50700 && tag < 50800) done = 1; + if (len * size[type < 13 ? type:0] > 4) + fseek (ifp, get4()+base, SEEK_SET); + switch (tag) { + case 0x11: + case 0x12: + if (type == 3 && len == 1) + cam_mul[(tag-0x11)*2] = get2() / 256.0; + break; + case 0x27: + if (len < 50) break; + fseek (ifp, 12, SEEK_CUR); + FORC3 cam_mul[c] = get2(); + break; + case 0x2: + case 0x100: /* ImageWidth */ + if ((strcmp(make,"Canon") || level) && len == 1) + raw_width = type==3 ? get2() : get4(); + break; + case 0x3: + case 0x101: /* ImageHeight */ + if ((strcmp(make,"Canon") || level) && len == 1) + raw_height = type==3 ? get2() : get4(); + break; + case 0x102: /* Bits per sample */ + fuji_secondary = len == 2; + maximum = (1 << (tiff_bps = get2())) - 1; + break; + case 0x103: /* Compression */ + tiff_data_compression = get2(); + break; + case 0x106: /* Kodak color format */ + kodak_data_compression = get2(); + break; + case 0x10f: /* Make */ + fgets (make, 64, ifp); + break; + case 0x110: /* Model */ + fgets (model, 64, ifp); + break; + case 0x111: /* StripOffset */ + data_offset = get4(); + break; + case 0x112: /* Qt::Orientation */ + flip = flip_map[(get2()-1) & 7]; + break; + case 0x115: /* SamplesPerPixel */ + tiff_samples = get2(); + break; + case 0x131: /* Software tag */ + fgets (software, 64, ifp); + if (!strncmp(software,"Adobe",5) || + !strncmp(software,"Bibble",6) || + !strcmp (software,"Digital Photo Professional")) + make[0] = 0; + break; + case 0x132: /* DateTime tag */ + get_timestamp(0); + break; + case 0x144: /* TileOffsets */ + if (level) { + data_offset = ftell(ifp); + } else { + data_offset = get4(); + done = 1; + } + break; + case 0x14a: /* SubIFD tag */ + if (len > 2 && !dng_version && !strcmp(make,"Kodak")) + len = 2; + while (len--) { + i = ftell(ifp); + fseek (ifp, get4()+base, SEEK_SET); + if (parse_tiff_ifd (base, level+1)) break; + fseek (ifp, i+4, SEEK_SET); + } + break; + case 29184: sony_offset = get4(); break; + case 29185: sony_length = get4(); break; + case 29217: sony_key = get4(); break; + case 29443: + FORC4 cam_mul[c ^ (c < 2)] = get2(); + break; + case 33405: /* Model2 */ + fgets (model2, 64, ifp); + break; + case 33422: /* CFAPattern */ + if ((plen=len) > 16) plen = 16; + fread (cfa_pat, 1, plen, ifp); + for (colors=cfa=i=0; i < plen; i++) { + colors += !(cfa & (1 << cfa_pat[i])); + cfa |= 1 << cfa_pat[i]; + } + if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ + if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ + goto guess_cfa_pc; + case 34310: + parse_mos (ftell(ifp)); + break; + case 34665: /* EXIF tag */ + fseek (ifp, get4()+base, SEEK_SET); + parse_exif (base); + break; + case 37122: /* CompressedBitsPerPixel */ + kodak_cbpp = get4(); + break; + case 37400: + for (raw_color = i=0; i < 3; i++) { + getrat(); + FORC3 rgb_cam[i][c] = getrat(); + } + break; + case 46275: + strcpy (make, "Imacon"); + data_offset = ftell(ifp); + raw_width = 4090; + raw_height = len / raw_width / 2; + done = 1; + break; + case 50454: /* Sinar tag */ + case 50455: + if (!(cbuf = malloc(len))) break; + fread (cbuf, 1, len, ifp); + for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) + if (!strncmp (++cp,"Neutral ",8)) + sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); + free (cbuf); + break; + case 50706: /* DNGVersion */ + FORC4 dng_version = (dng_version << 8) + fgetc(ifp); + break; + case 50710: /* CFAPlaneColor */ + if (len > 4) len = 4; + colors = len; + fread (cfa_pc, 1, colors, ifp); +guess_cfa_pc: + FORCC tab[cfa_pc[c]] = c; + for (i=16; i--; ) + filters = filters << 2 | tab[cfa_pat[i % plen]]; + break; + case 50711: /* CFALayout */ + if (get2() == 2) { + fuji_width = (raw_width+1)/2; + filters = 0x49494949; + } + break; + case 0x123: + case 0x90d: + case 50712: /* LinearizationTable */ + if (len > 0x1000) + len = 0x1000; + read_shorts (curve, len); + for (i=len; i < 0x1000; i++) + maximum = curve[i] = curve[i-1]; + break; + case 50714: /* BlackLevel */ + case 50715: /* BlackLevelDeltaH */ + case 50716: /* BlackLevelDeltaV */ + for (dblack=i=0; i < len; i++) + dblack += getrat(); + black += dblack/len + 0.5; + break; + case 50717: /* WhiteLevel */ + maximum = get2(); + break; + case 50718: /* DefaultScale */ + i = get4(); + j = get4() * get4(); + i *= get4(); + if (i > j) xmag = i / j; + else ymag = j / i; + break; + case 50721: /* ColorMatrix1 */ + case 50722: /* ColorMatrix2 */ + FORCC for (j=0; j < 3; j++) + cm[c][j] = getrat(); + use_cm = 1; + break; + case 50723: /* CameraCalibration1 */ + case 50724: /* CameraCalibration2 */ + for (i=0; i < colors; i++) + FORCC cc[i][c] = getrat(); + case 50727: /* AnalogBalance */ + FORCC ab[c] = getrat(); + break; + case 50728: /* AsShotNeutral */ + FORCC asn[c] = getrat(); + break; + case 50729: /* AsShotWhiteXY */ + xyz[0] = getrat(); + xyz[1] = getrat(); + xyz[2] = 1 - xyz[0] - xyz[1]; + break; + case 50740: /* DNGPrivateData */ + if (dng_version) break; + fseek (ifp, get4()+base, SEEK_SET); + parse_tiff_ifd (base, level+1); + break; + case 50829: /* ActiveArea */ + top_margin = get4(); + left_margin = get4(); + height = get4() - top_margin; + width = get4() - left_margin; + } + fseek (ifp, save+4, SEEK_SET); + } + if (sony_length && (buf = malloc(sony_length))) { + fseek (ifp, sony_offset, SEEK_SET); + fread (buf, sony_length, 1, ifp); + sony_decrypt (buf, sony_length/4, 1, sony_key); + sfp = ifp; + if ((ifp = tmpfile())) { + fwrite (buf, sony_length, 1, ifp); + fseek (ifp, 0, SEEK_SET); + parse_tiff_ifd (-sony_offset, level); + fclose (ifp); + } + ifp = sfp; + free (buf); + } + if (!(base | level | dng_version) && + (strstr(make,"Minolta") || strstr(make,"MINOLTA"))) make[0] = 0; + for (i=0; i < colors; i++) + FORCC cc[i][c] *= ab[i]; + if (use_cm) { + FORCC for (i=0; i < 3; i++) + for (cam_xyz[c][i]=j=0; j < colors; j++) + cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; + cam_xyz_coeff (cam_xyz); + } + if (asn[0]) + FORCC pre_mul[c] = 1 / asn[c]; + if (!use_cm) + FORCC pre_mul[c] /= cc[c][c]; + return done; +} + +void CLASS parse_tiff (int base) +{ + int doff, maxifd=1000; + + fseek (ifp, base, SEEK_SET); + order = get2(); + if (order != 0x4949 && order != 0x4d4d) return; + get2(); + while ((doff = get4()) && maxifd--) { + fseek (ifp, doff+base, SEEK_SET); + if (parse_tiff_ifd (base, 0)) break; + if (!dng_version && data_offset == 8) make[0] = 0; + } + if (!dng_version && !strncmp(make,"Kodak",5)) { + fseek (ifp, 12+base, SEEK_SET); + parse_tiff_ifd (base, 2); + } +} + +void CLASS parse_minolta() +{ + int save, tag, len, offset, high=0, wide=0, i, c; + + fseek (ifp, 4, SEEK_SET); + offset = get4() + 8; + while ((save=ftell(ifp)) < offset) { + tag = get4(); + len = get4(); + switch (tag) { + case 0x505244: /* PRD */ + fseek (ifp, 8, SEEK_CUR); + high = get2(); + wide = get2(); + break; + case 0x574247: /* WBG */ + get4(); + i = strstr(model,"A200") ? 3:0; + FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); + break; + case 0x545457: /* TTW */ + parse_tiff (ftell(ifp)); + } + fseek (ifp, save+len+8, SEEK_SET); + } + raw_height = high; + raw_width = wide; + data_offset = offset; +} + +/* + Many cameras have a "debug mode" that writes JPEG and raw + at the same time. The raw file has no header, so try to + to open the matching JPEG file and read its metadata. + */ +void CLASS parse_external_jpeg() +{ + char *file, *ext, *jname, *jfile, *jext; + FILE *save=ifp; + + ext = strrchr (ifname, '.'); + file = strrchr (ifname, '/'); + if (!file) file = strrchr (ifname, '\\'); + if (!file) file = ifname-1; + file++; + if (strlen(ext) != 4 || ext-file != 8) return; + jname = malloc (strlen(ifname) + 1); + merror (jname, "parse_external()"); + strcpy (jname, ifname); + jfile = file - ifname + jname; + jext = ext - ifname + jname; + if (strcasecmp (ext, ".jpg")) { + strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); + memcpy (jfile, file+4, 4); + memcpy (jfile+4, file, 4); + } else + while (isdigit(*--jext)) { + if (*jext != '9') { + (*jext)++; + break; + } + *jext = '0'; + } + if (strcmp (jname, ifname)) { + if ((ifp = fopen (jname, "rb"))) { + if (verbose) + fprintf (stderr, "Reading metadata from %s...\n", jname); + parse_tiff (12); + fclose (ifp); + } + } + if (!timestamp) + fprintf (stderr, "Failed to read metadata from %s\n", jname); + free (jname); + ifp = save; +} + +/* + CIFF block 0x1030 contains an 8x8 white sample. + Load this into white[][] for use in scale_colors(). + */ +void CLASS ciff_block_1030() +{ + static const ushort key[] = { 0x410, 0x45f3 }; + int i, bpp, row, col, vbits=0; + unsigned long bitbuf=0; + + get2(); + if (get4() != 0x80008) return; + if (get4() == 0) return; + bpp = get2(); + if (bpp != 10 && bpp != 12) return; + for (i=row=0; row < 8; row++) + for (col=0; col < 8; col++) { + if (vbits < bpp) { + bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); + vbits += 16; + } + white[row][col] = + bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); + vbits -= bpp; + } +} + +/* + Parse a CIFF file, better known as Canon CRW format. + */ +void CLASS parse_ciff (int offset, int length) +{ + int tboff, nrecs, i, c, type, len, roff, aoff, save, wbi=-1; + static const int remap[] = { 1,2,3,4,5,1 }; + static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 }; + static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 }; + ushort key[] = { 0x410, 0x45f3 }; + + if (strcmp(model,"Canon PowerShot G6") && + strcmp(model,"Canon PowerShot S60") && + strcmp(model,"Canon PowerShot S70") && + strcmp(model,"Canon PowerShot Pro1")) + key[0] = key[1] = 0; + fseek (ifp, offset+length-4, SEEK_SET); + tboff = get4() + offset; + fseek (ifp, tboff, SEEK_SET); + nrecs = get2(); + if (nrecs > 100) return; + for (i = 0; i < nrecs; i++) { + type = get2(); + len = get4(); + roff = get4(); + aoff = offset + roff; + save = ftell(ifp); + if (type == 0x080a) { /* Get the camera make and model */ + fseek (ifp, aoff, SEEK_SET); + fread (make, 64, 1, ifp); + fseek (ifp, aoff+strlen(make)+1, SEEK_SET); + fread (model, 64, 1, ifp); + } + if (type == 0x102a) { /* Find the White Balance index */ + fseek (ifp, aoff+14, SEEK_SET); /* 0=auto, 1=daylight, 2=cloudy ... */ + wbi = get2(); + if (((!strcmp(model,"Canon EOS DIGITAL REBEL") || + !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6) + wbi++; + } + if (type == 0x102c) { /* Get white balance (G2) */ + if (!strcmp(model,"Canon PowerShot G1") || + !strcmp(model,"Canon PowerShot Pro90 IS")) { + fseek (ifp, aoff+120, SEEK_SET); + FORC4 cam_mul[c ^ 2] = get2(); + } else { + fseek (ifp, aoff+100, SEEK_SET); + goto common; + } + } + if (type == 0x0032) { /* Get white balance (D30 & G3) */ + if (!strcmp(model,"Canon EOS D30")) { + fseek (ifp, aoff+72, SEEK_SET); +common: + camera_red = get2() ^ key[0]; + camera_red =(get2() ^ key[1]) / camera_red; + camera_blue = get2() ^ key[0]; + camera_blue /= get2() ^ key[1]; + if (!wbi) camera_red = -1; /* Use my auto WB for this photo */ + } else if (!strcmp(model,"Canon PowerShot G6") || + !strcmp(model,"Canon PowerShot S60") || + !strcmp(model,"Canon PowerShot S70")) { + fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET); + goto common; + } else if (!strcmp(model,"Canon PowerShot Pro1")) { + fseek (ifp, aoff+96 + wbi*8, SEEK_SET); + goto common; + } else { + fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET); + if (!camera_red) + goto common; + } + } + if (type == 0x10a9) { /* Get white balance (D60) */ + if (!strcmp(model,"Canon EOS 10D")) + wbi = remap_10d[wbi]; + fseek (ifp, aoff+2 + wbi*8, SEEK_SET); + camera_red = get2(); + camera_red /= get2(); + camera_blue = get2(); + camera_blue = get2() / camera_blue; + } + if (type == 0x1030 && (wbi == 6 || wbi == 15)) { + fseek (ifp, aoff, SEEK_SET); /* Get white sample */ + ciff_block_1030(); + } + if (type == 0x1031) { /* Get the raw width and height */ + fseek (ifp, aoff+2, SEEK_SET); + raw_width = get2(); + raw_height = get2(); + } + if (type == 0x180e) { /* Get the timestamp */ + fseek (ifp, aoff, SEEK_SET); + timestamp = get4(); + } + if (type == 0x5817) + shot_order = len; + if (type == 0x580e) + timestamp = len; +#ifdef LOCALTIME + if ((type | 0x4000) == 0x580e) + timestamp = mktime (gmtime (×tamp)); +#endif + if (type == 0x5813) + flash_used = int_to_float(len); + if (type == 0x5814) + canon_5814 = int_to_float(len); + if (type == 0x1810) { /* Get the rotation */ + fseek (ifp, aoff+12, SEEK_SET); + flip = get4(); + } + if (type == 0x1835) { /* Get the decoder table */ + fseek (ifp, aoff, SEEK_SET); + crw_init_tables (get4()); + } + if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */ + parse_ciff(aoff, len); + fseek (ifp, save, SEEK_SET); + } +} + +void CLASS parse_rollei() +{ + char line[128], *val; + int tx=0, ty=0; + struct tm t; + + fseek (ifp, 0, SEEK_SET); + do { + fgets (line, 128, ifp); + if ((val = strchr(line,'='))) + *val++ = 0; + else + val = line + strlen(line); + if (!strcmp(line,"DAT")) + sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); + if (!strcmp(line,"TIM")) + sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); + if (!strcmp(line,"HDR")) + data_offset = atoi(val); + if (!strcmp(line,"X ")) + raw_width = atoi(val); + if (!strcmp(line,"Y ")) + raw_height = atoi(val); + if (!strcmp(line,"TX ")) + tx = atoi(val); + if (!strcmp(line,"TY ")) + ty = atoi(val); + } while (strncmp(line,"EOHD",4)); + t.tm_year -= 1900; + t.tm_mon -= 1; + if (mktime(&t) > 0) + timestamp = mktime(&t); + data_offset += tx * ty * 2; + strcpy (make, "Rollei"); + strcpy (model,"d530flex"); +} + +void CLASS parse_mos (int offset) +{ + char data[40]; + int skip, from, i, c, neut[4]; + static const unsigned bayer[] = + { 0x94949494, 0x61616161, 0x16161616, 0x49494949 }; + + fseek (ifp, offset, SEEK_SET); + while (1) { + fread (data, 1, 8, ifp); + if (strcmp(data,"PKTS")) break; + if (!make[0]) strcpy(make,"Leaf"); + fread (data, 1, 40, ifp); + skip = get4(); + from = ftell(ifp); +#ifdef USE_LCMS + if (!strcmp(data,"icc_camera_profile")) { + profile_length = skip; + profile_offset = from; + } +#endif + if (!strcmp(data,"CaptProf_number_of_planes")) { + fscanf (ifp, "%d", &i); + if (i > 1) filters = 0; + } + if (!strcmp(data,"CaptProf_raw_data_rotation") && filters) { + fscanf (ifp, "%d", &i); + filters = bayer[i/90]; + } + if (!strcmp(data,"NeutObj_neutrals")) { + for (i=0; i < 4; i++) + fscanf (ifp, "%d", neut+i); + FORC3 cam_mul[c] = 1.0 / neut[c+1]; + } + parse_mos (from); + fseek (ifp, skip+from, SEEK_SET); + } +} + +void CLASS parse_phase_one (int base) +{ + unsigned entries, tag, type, len, data, save, i, c; + char *cp; + + fseek (ifp, base, SEEK_SET); + order = get4() & 0xffff; + if (get4() >> 8 != 0x526177) return; /* "Raw" */ + fseek (ifp, base+get4(), SEEK_SET); + entries = get4(); + get4(); + while (entries--) { + tag = get4(); + type = get4(); + len = get4(); + data = get4(); + save = ftell(ifp); + fseek (ifp, base+data, SEEK_SET); + switch (tag) { + case 0x106: + for (raw_color = i=0; i < 3; i++) + FORC3 rgb_cam[i][c] = int_to_float(get4()); + break; + case 0x107: + FORC3 cam_mul[c] = pre_mul[c] = int_to_float(get4()); + break; + case 0x108: raw_width = data; break; + case 0x109: raw_height = data; break; + case 0x10a: left_margin = data; break; + case 0x10b: top_margin = data; break; + case 0x10c: width = data; break; + case 0x10d: height = data; break; + case 0x10e: tiff_data_compression = data; break; + case 0x10f: data_offset = data+base; break; + case 0x112: + nikon_curve_offset = save - 4; break; + case 0x301: + fread (model, 64, 1, ifp); + cp = strstr(model," camera"); + if (cp && cp < model+64) *cp = 0; + } + fseek (ifp, save, SEEK_SET); + } + load_raw = tiff_data_compression < 3 ? + phase_one_load_raw:phase_one_load_raw_c; + strcpy (make, "Phase One"); + if (model[0]) return; + sprintf (model, "%dx%d", width, height); + switch (raw_height) { + case 2060: strcpy (model,"LightPhase"); break; + case 2682: strcpy (model,"H 10"); break; + case 4128: strcpy (model,"H 20"); break; + case 5488: strcpy (model,"H 25"); break; + } +} + +void CLASS parse_fuji (int offset) +{ + int entries, tag, len, save, c; + + fseek (ifp, offset, SEEK_SET); + entries = get4(); + if (entries > 255) return; + while (entries--) { + tag = get2(); + len = get2(); + save = ftell(ifp); + if (tag == 0x100) { + raw_height = get2(); + raw_width = get2(); + } else if (tag == 0x121) { + height = get2(); + if ((width = get2()) == 4284) width += 3; + } else if (tag == 0x130) + fuji_layout = fgetc(ifp) >> 7; + if (tag == 0x2ff0) + FORC4 cam_mul[c ^ 1] = get2(); + fseek (ifp, save+len, SEEK_SET); + } + if (fuji_layout) { + height *= 2; + width /= 2; + } +} + +int CLASS parse_jpeg (int offset) +{ + int len, save, hlen; + + fseek (ifp, offset, SEEK_SET); + if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; + + while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) { + order = 0x4d4d; + len = get2() - 2; + save = ftell(ifp); + order = get2(); + hlen = get4(); + if (get4() == 0x48454150) /* "HEAP" */ + parse_ciff (save+hlen, len-hlen); + parse_tiff (save+6); + fseek (ifp, save+len, SEEK_SET); + } + return 1; +} + +void CLASS parse_riff() +{ + unsigned i, size, end; + char tag[4], date[64], month[64]; + static const char mon[12][4] = + { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; + struct tm t; + + order = 0x4949; + fread (tag, 4, 1, ifp); + size = get4(); + if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { + end = ftell(ifp) + size; + get4(); + while (ftell(ifp) < end) + parse_riff(); + } else if (!memcmp(tag,"IDIT",4) && size < 64) { + fread (date, 64, 1, ifp); + date[size] = 0; + if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, + &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { + for (i=0; i < 12 && strcmp(mon[i],month); i++); + t.tm_mon = i; + t.tm_year -= 1900; + if (mktime(&t) > 0) + timestamp = mktime(&t); + } + } else + fseek (ifp, size, SEEK_CUR); +} + +void CLASS parse_smal (int offset, int fsize) +{ + int ver; + + fseek (ifp, offset+2, SEEK_SET); + order = 0x4949; + ver = fgetc(ifp); + if (ver == 6) + fseek (ifp, 5, SEEK_CUR); + if (get4() != fsize) return; + if (ver > 6) data_offset = get4(); + raw_height = height = get2(); + raw_width = width = get2(); + strcpy (make, "SMaL"); + sprintf (model, "v%d %dx%d", ver, width, height); + if (ver == 6) load_raw = smal_v6_load_raw; + if (ver == 9) load_raw = smal_v9_load_raw; +} + +char * CLASS foveon_gets (int offset, char *str, int len) +{ + int i; + fseek (ifp, offset, SEEK_SET); + for (i=0; i < len-1; i++) + if ((str[i] = get2()) == 0) break; + str[i] = 0; + return str; +} + +void CLASS parse_foveon() +{ + int entries, off, len, tag, save, i, wide, high, pent, poff[256][2]; + char name[64]; + + order = 0x4949; /* Little-endian */ + fseek (ifp, 36, SEEK_SET); + flip = get4(); + fseek (ifp, -4, SEEK_END); + fseek (ifp, get4(), SEEK_SET); + if (get4() != 0x64434553) return; /* SECd */ + get4(); + entries = get4(); + while (entries--) { + off = get4(); + len = get4(); + tag = get4(); + save = ftell(ifp); + fseek (ifp, off, SEEK_SET); + if (get4() != (0x20434553 | (tag << 24))) return; + switch (tag) { + case 0x47414d49: /* IMAG */ + case 0x32414d49: /* IMA2 */ + fseek (ifp, 12, SEEK_CUR); + wide = get4(); + high = get4(); + if (wide > raw_width && high > raw_height) { + raw_width = wide; + raw_height = high; + data_offset = off + 24; + } + break; + case 0x464d4143: /* CAMF */ + meta_offset = off + 24; + meta_length = len - 28; + if (meta_length > 0x20000) + meta_length = 0x20000; + break; + case 0x504f5250: /* PROP */ + get4(); + pent = get4(); + fseek (ifp, 12, SEEK_CUR); + off += pent*8 + 24; + if (pent > 256) pent=256; + for (i=0; i < pent*2; i++) + poff[0][i] = off + get4()*2; + for (i=0; i < pent; i++) { + foveon_gets (poff[i][0], name, 64); + if (!strcmp (name, "CAMMANUF")) + foveon_gets (poff[i][1], make, 64); + if (!strcmp (name, "CAMMODEL")) + foveon_gets (poff[i][1], model, 64); + if (!strcmp (name, "WB_DESC")) + foveon_gets (poff[i][1], model2, 64); + if (!strcmp (name, "TIME")) + timestamp = atoi (foveon_gets (poff[i][1], name, 64)); + } +#ifdef LOCALTIME + timestamp = mktime (gmtime (×tamp)); +#endif + } + fseek (ifp, save, SEEK_SET); + } + is_foveon = 1; +} + +/* + Thanks to Adobe for providing these excellent CAM -> XYZ matrices! + */ +void CLASS adobe_coeff() +{ + static const struct { + const char *prefix; + short trans[12]; + } table[] = { + { "Canon EOS D2000", + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Canon EOS D6000", + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Canon EOS D30", + { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, + { "Canon EOS D60", + { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, + { "Canon EOS 5D", + { 6228,-404,-967,-8314,16108,2312,-1923,2179,7499 } }, + { "Canon EOS 20D", + { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, + { "Canon EOS 350D", + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { "Canon EOS DIGITAL REBEL XT", + { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, + { "Canon EOS-1Ds Mark II", + { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, + { "Canon EOS-1D Mark II", + { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, + { "Canon EOS-1DS", + { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, + { "Canon EOS-1D", + { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, + { "Canon EOS", + { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, + { "Canon PowerShot A50", + { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, + { "Canon PowerShot A5", + { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, + { "Canon PowerShot G1", + { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, + { "Canon PowerShot G2", + { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3", + { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5", + { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, + { "Canon PowerShot G6", + { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, + { "Canon PowerShot Pro1", + { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, + { "Canon PowerShot Pro70", + { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, + { "Canon PowerShot Pro90", + { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, + { "Canon PowerShot S30", + { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, + { "Canon PowerShot S40", + { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, + { "Canon PowerShot S45", + { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, + { "Canon PowerShot S50", + { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, + { "Canon PowerShot S60", + { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, + { "Canon PowerShot S70", + { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, + { "Contax N Digital", + { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "EPSON R-D1", + { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, + { "FUJIFILM FinePix E550", + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix F8", + { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, + { "FUJIFILM FinePix F7", + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S20Pro", + { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, + { "FUJIFILM FinePix S2Pro", + { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, + { "FUJIFILM FinePix S3Pro", + { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, + { "FUJIFILM FinePix S5000", + { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, + { "FUJIFILM FinePix S5100", + { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, + { "FUJIFILM FinePix S7000", + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "FUJIFILM FinePix S9", /* copied from S7000 */ + { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, + { "KODAK NC2000F", /* DJC */ + { 16475,-6903,-1218,-851,10375,477,2505,-7,1020 } }, + { "Kodak DCS315C", + { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, + { "Kodak DCS330C", + { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, + { "KODAK DCS420", + { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, + { "KODAK DCS460", + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS1", + { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, + { "KODAK EOSDCS3B", + { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, + { "Kodak DCS520C", + { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, + { "Kodak DCS560C", + { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, + { "Kodak DCS620C", + { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, + { "Kodak DCS620X", + { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, + { "Kodak DCS660C", + { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, + { "Kodak DCS720X", + { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, + { "Kodak DCS760C", + { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, + { "Kodak DCS Pro SLR", + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14nx", + { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, + { "Kodak DCS Pro 14", + { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, + { "Kodak ProBack645", + { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, + { "Kodak ProBack", + { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, + { "LEICA DIGILUX 2", + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Leaf Valeo", + { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, + { "Minolta DiMAGE 5", + { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, + { "Minolta DiMAGE 7Hi", + { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, + { "Minolta DiMAGE 7", + { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, + { "Minolta DiMAGE A1", + { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, + { "MINOLTA DiMAGE A200", + { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, + { "Minolta DiMAGE A2", + { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, + { "Minolta DiMAGE Z2", + { 11428,-3512,-1706,-5895,13815,2266,-2382,2719,5651 } }, + { "MINOLTA DYNAX 5", + { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, + { "MINOLTA DYNAX 7", + { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, + { "NIKON D100", + { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, + { "NIKON D1H", + { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, + { "NIKON D1X", + { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, + { "NIKON D1", + { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } }, + { "NIKON D2H", + { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, + { "NIKON D2X", + { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, + { "NIKON D50", + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON D70", + { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "NIKON E995", /* copied from E5000 */ + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E2500", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E4500", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5000", + { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, + { "NIKON E5400", + { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, + { "NIKON E5700", + { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, + { "NIKON E8400", + { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, + { "NIKON E8700", + { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, + { "NIKON E8800", + { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, + { "OLYMPUS C5050", + { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, + { "OLYMPUS C5060", + { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, + { "OLYMPUS C70", + { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, + { "OLYMPUS C80", + { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, + { "OLYMPUS E-10", + { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, + { "OLYMPUS E-1", + { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, + { "OLYMPUS E-20", + { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, + { "OLYMPUS E-300", + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "OLYMPUS E-500", /* copied from E-300 */ + { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, + { "PENTAX *ist DS", + { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, + { "PENTAX *ist D", + { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, + { "Panasonic DMC-FZ30", + { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, + { "Panasonic DMC-LC1", + { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, + { "Panasonic DMC-LX1", + { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, + { "SONY DSC-F828", + { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, + { "SONY DSC-R1", /* DJC */ + { 10528,-3695,-517,-2822,10699,2124,406,1240,5342 } }, + { "SONY DSC-V3", + { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } } + }; + double cam_xyz[4][3]; + char name[130]; + int i, j; + + sprintf (name, "%s %s", make, model); + for (i=0; i < sizeof table / sizeof *table; i++) + if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { + for (j=0; j < 12; j++) + cam_xyz[0][j] = table[i].trans[j]; + cam_xyz_coeff (cam_xyz); + break; + } +} + +void CLASS simple_coeff (int index) +{ + static const float table[][12] = { + /* index 0 -- all Foveon cameras */ + { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, + /* index 1 -- Kodak DC20 and DC25 */ + { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, + /* index 2 -- Logitech Fotoman Pixtura */ + { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, + /* index 3 -- Nikon E700, E800, and E950 */ + { -1.936280, 1.800443, -1.448486, 2.584324, + 1.405365, -0.524955, -0.289090, 0.408680, + -1.204965, 1.082304, 2.941367, -1.818705 } + }; + int i, c; + + for (raw_color = i=0; i < 3; i++) + FORCC rgb_cam[i][c] = table[index][i*colors+c]; +} + +short CLASS guess_byte_order (int words) +{ + uchar test[4][2]; + int t=2, msb; + double diff, sum[2] = {0,0}; + + fread (test[0], 2, 2, ifp); + for (words-=2; words--; ) { + fread (test[t], 2, 1, ifp); + for (msb=0; msb < 2; msb++) { + diff = (test[t^2][msb] << 8 | test[t^2][!msb]) + - (test[t ][msb] << 8 | test[t ][!msb]); + sum[msb] += diff*diff; + } + t = (t+1) & 3; + } + return sum[0] < sum[1] ? 0x4d4d : 0x4949; +} + +/* + Identify which camera created this file, and set global variables + accordingly. Return nonzero if the file cannot be decoded. + */ +int CLASS identify (int no_decode) +{ + char head[32], *cp; + unsigned hlen, fsize, i, c, is_jpeg=0, is_canon; + static const struct { + int fsize; + char make[12], model[15], withjpeg; + } table[] = { + { 62464, "Kodak", "DC20" ,0 }, + { 124928, "Kodak", "DC20" ,0 }, + { 311696, "ST Micro", "STV680 VGA" ,0 }, /* SPYz */ + { 787456, "Creative", "PC-CAM 600" ,0 }, + { 1138688, "Minolta", "RD175" ,0 }, + { 3840000, "Foculus", "531C" ,0 }, + { 1920000, "AVT", "F-201C" ,0 }, + { 5067304, "AVT", "F-510C" ,0 }, + { 10134608, "AVT", "F-510C" ,0 }, + { 16157136, "AVT", "F-810C" ,0 }, + { 6624000, "Pixelink", "A782" ,0 }, + { 13248000, "Pixelink", "A782" ,0 }, + { 6291456, "RoverShot","3320AF" ,0 }, + { 5939200, "OLYMPUS", "C770UZ" ,0 }, + { 1581060, "NIKON", "E900" ,1 }, /* or E900s,E910 */ + { 2465792, "NIKON", "E950" ,1 }, /* or E800,E700 */ + { 2940928, "NIKON", "E2100" ,1 }, /* or E2500 */ + { 4771840, "NIKON", "E990" ,1 }, /* or E995 */ + { 4775936, "NIKON", "E3700" ,1 }, /* or Optio 33WR */ + { 5869568, "NIKON", "E4300" ,1 }, /* or DiMAGE Z2 */ + { 5865472, "NIKON", "E4500" ,1 }, + { 7438336, "NIKON", "E5000" ,1 }, /* or E5700 */ + { 1976352, "CASIO", "QV-2000UX" ,1 }, + { 3217760, "CASIO", "QV-3*00EX" ,1 }, + { 6218368, "CASIO", "QV-5700" ,1 }, + { 7530816, "CASIO", "QV-R51" ,1 }, + { 7684000, "CASIO", "QV-4000" ,1 }, + { 4948608, "CASIO", "EX-S100" ,1 }, + { 7542528, "CASIO", "EX-Z50" ,1 }, + { 7753344, "CASIO", "EX-Z55" ,1 }, + { 7426656, "CASIO", "EX-P505" ,1 }, + { 9313536, "CASIO", "EX-P600" ,1 }, + { 10979200, "CASIO", "EX-P700" ,1 }, + { 3178560, "PENTAX", "Optio S" ,1 }, /* 8-bit */ + { 4841984, "PENTAX", "Optio S" ,1 }, /* 12-bit */ + { 6114240, "PENTAX", "Optio S4" ,1 }, /* or S4i */ + { 12582980, "Sinar", "" ,0 } }; + static const char *corp[] = + { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX", + "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar" }; + +/* What format is this file? Set make[] if we recognize it. */ + + load_raw = NULL; + raw_height = raw_width = fuji_width = flip = 0; + height = width = top_margin = left_margin = 0; + make[0] = model[0] = model2[0] = 0; + memset (white, 0, sizeof white); + data_offset = meta_length = tiff_bps = tiff_data_compression = 0; + kodak_cbpp = zero_after_ff = dng_version = fuji_secondary = 0; + timestamp = shot_order = tiff_samples = black = is_foveon = 0; + raw_color = use_gamma = xmag = ymag = 1; + filters = UINT_MAX; /* 0 = no filters, UINT_MAX = unknown */ + for (i=0; i < 4; i++) { + cam_mul[i] = i == 1; + pre_mul[i] = i < 3; + FORC3 rgb_cam[c][i] = c == i; + } + colors = 3; + for (i=0; i < 0x1000; i++) curve[i] = i; + maximum = 0xfff; +#ifdef USE_LCMS + profile_length = 0; +#endif + + order = get2(); + hlen = get4(); + fseek (ifp, 0, SEEK_SET); + fread (head, 1, 32, ifp); + fseek (ifp, 0, SEEK_END); + fsize = ftell(ifp); + if ((cp = memmem (head, 32, "MMMM", 4)) || + (cp = memmem (head, 32, "IIII", 4))) + parse_phase_one (cp-head); + else if (order == 0x4949 || order == 0x4d4d) { + if (!memcmp (head+6,"HEAPCCDR",8)) { + data_offset = hlen; + parse_ciff (hlen, fsize - hlen); + } else { + parse_tiff(0); + if (!dng_version && !strncmp(make,"NIKON",5) && filters == UINT_MAX) + make[0] = 0; + } + } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && + !memcmp (head+6,"Exif",4)) { + fseek (ifp, 4, SEEK_SET); + fseek (ifp, 4 + get2(), SEEK_SET); + if (fgetc(ifp) != 0xff) + parse_tiff(12); + } else if (!memcmp (head,"BM",2) && + head[26] == 1 && head[28] == 16 && head[30] == 0) { + data_offset = 0x1000; + order = 0x4949; + fseek (ifp, 38, SEEK_SET); + if (get4() == 2834 && get4() == 2834 && get4() == 0 && get4() == 4096) { + strcpy (model, "BMQ"); + flip = 3; + goto nucore; + } + } else if (!memcmp (head,"BR",2)) { + strcpy (model, "RAW"); +nucore: + strcpy (make, "Nucore"); + order = 0x4949; + fseek (ifp, 10, SEEK_SET); + data_offset += get4(); + get4(); + raw_width = get4(); + raw_height = get4(); + if (model[0] == 'B' && raw_width == 2597) { + raw_width++; + data_offset -= 0x1000; + } + } else if (!memcmp (head+25,"ARECOYK",7)) { + strcpy (make, "Contax"); + strcpy (model,"N Digital"); + fseek (ifp, 33, SEEK_SET); + get_timestamp(1); + fseek (ifp, 60, SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = get4(); + } else if (!strcmp (head, "PXN")) { + strcpy (make, "Logitech"); + strcpy (model,"Fotoman Pixtura"); + } else if (!memcmp (head,"FUJIFILM",8)) { + fseek (ifp, 92, SEEK_SET); + parse_fuji (get4()); + fseek (ifp, 84, SEEK_SET); + if ((hlen = get4()) > 120) { + fseek (ifp, 120, SEEK_SET); + fuji_secondary = (i = get4()) && 1; + if (fuji_secondary && use_secondary) + parse_fuji (i); + } + fseek (ifp, 100, SEEK_SET); + i = get4(); + parse_tiff (hlen+12); + data_offset = i; + } else if (!memcmp (head,"RIFF",4)) { + fseek (ifp, 0, SEEK_SET); + parse_riff(); + } else if (!memcmp (head,"DSC-Image",9)) + parse_rollei(); + else if (!memcmp (head,"\0MRM",4)) + parse_minolta(); + else if (!memcmp (head,"FOVb",4)) + parse_foveon(); + else + for (i=0; i < sizeof table / sizeof *table; i++) + if (fsize == table[i].fsize) { + strcpy (make, table[i].make ); + strcpy (model, table[i].model); + if (table[i].withjpeg) + parse_external_jpeg(); + } + parse_mos(8); + parse_mos(3472); + if (make[0] == 0) parse_smal (0, fsize); + if (make[0] == 0) is_jpeg = parse_jpeg(0); + if (no_decode) return !timestamp; + + for (i=0; i < sizeof corp / sizeof *corp; i++) + if (strstr (make, corp[i])) /* Simplify company names */ + strcpy (make, corp[i]); + if (!strncmp (make,"KODAK",5)) + make[16] = model[16] = 0; + cp = make + strlen(make); /* Remove trailing spaces */ + while (*--cp == ' ') *cp = 0; + cp = model + strlen(model); + while (*--cp == ' ') *cp = 0; + i = strlen(make); /* Remove make from model */ + if (!strncmp (model, make, i) && model[i++] == ' ') + memmove (model, model+i, 64-i); + make[63] = model[63] = model2[63] = 0; + + if (make[0] == 0) { + fprintf (stderr, "%s: unsupported file format.\n", ifname); + return 1; + } + if ((raw_height | raw_width) < 0) + raw_height = raw_width = 0; + if (!height) height = raw_height; + if (!width) width = raw_width; + if (fuji_width) { + width = height + fuji_width; + height = width - 1; + xmag = ymag = 1; + } + if (dng_version) { + strcat (model," DNG"); + if (filters == UINT_MAX) filters = 0; + if (!filters) + colors = tiff_samples; + if (tiff_data_compression == 1) + load_raw = adobe_dng_load_raw_nc; + if (tiff_data_compression == 7) + load_raw = adobe_dng_load_raw_lj; + FORC4 cam_mul[c] = pre_mul[c]; + goto dng_skip; + } + +/* We'll try to decode anything from Canon or Nikon. */ + + if (filters == UINT_MAX) filters = 0x94949494; + if ((is_canon = !strcmp(make,"Canon"))) { + load_raw = memcmp (head+6,"HEAPCCDR",8) ? + lossless_jpeg_load_raw : canon_compressed_load_raw; + maximum = 0xfff; + } + if (!strcmp(make,"NIKON")) + load_raw = nikon_is_compressed() ? + nikon_compressed_load_raw : nikon_load_raw; + if (!strncmp (make,"OLYMPUS",7)) + height += height & 1; + +/* Set parameters based on camera name (for non-DNG files). */ + + if (is_foveon) { + if (height*2 < width) ymag = 2; + if (height > width) xmag = 2; + filters = 0; + load_raw = foveon_load_raw; + simple_coeff(0); + } else if (!strcmp(model,"PowerShot 600")) { + height = 613; + width = 854; + colors = 4; + filters = 0xe1e4e1e4; + load_raw = canon_600_load_raw; + } else if (!strcmp(model,"PowerShot A5") || + !strcmp(model,"PowerShot A5 Zoom")) { + height = 773; + width = 960; + raw_width = 992; + colors = 4; + filters = 0x1e4e1e4e; + load_raw = canon_a5_load_raw; + } else if (!strcmp(model,"PowerShot A50")) { + height = 968; + width = 1290; + raw_width = 1320; + colors = 4; + filters = 0x1b4e4b1e; + load_raw = canon_a5_load_raw; + } else if (!strcmp(model,"PowerShot Pro70")) { + height = 1024; + width = 1552; + colors = 4; + filters = 0x1e4b4e1b; + load_raw = canon_a5_load_raw; + black = 34; + } else if (!strcmp(model,"PowerShot Pro90 IS")) { + width = 1896; + colors = 4; + filters = 0xb4b4b4b4; + } else if (is_canon && raw_width == 2144) { + height = 1550; + width = 2088; + top_margin = 8; + left_margin = 4; + if (!strcmp(model,"PowerShot G1")) { + colors = 4; + filters = 0xb4b4b4b4; + } + } else if (is_canon && raw_width == 2224) { + height = 1448; + width = 2176; + top_margin = 6; + left_margin = 48; + } else if (is_canon && raw_width == 2376) { + height = 1720; + width = 2312; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 2672) { + height = 1960; + width = 2616; + top_margin = 6; + left_margin = 12; + } else if (is_canon && raw_width == 3152) { + height = 2056; + width = 3088; + top_margin = 12; + left_margin = 64; + maximum = 0xfa0; + } else if (is_canon && raw_width == 3160) { + height = 2328; + width = 3112; + top_margin = 12; + left_margin = 44; + } else if (is_canon && raw_width == 3344) { + height = 2472; + width = 3288; + top_margin = 6; + left_margin = 4; + } else if (!strcmp(model,"EOS D2000C")) { + filters = 0x61616161; + black = curve[200]; + } else if (!strcmp(model,"EOS-1D")) { + raw_height = height = 1662; + raw_width = width = 2496; + data_offset = 288912; + filters = 0x61616161; + } else if (!strcmp(model,"EOS-1DS")) { + raw_height = height = 2718; + raw_width = width = 4082; + data_offset = 289168; + filters = 0x61616161; + } else if (is_canon && raw_width == 3516) { + top_margin = 14; + left_margin = 42; + goto canon_cr2; + } else if (is_canon && raw_width == 3596) { + top_margin = 12; + left_margin = 74; + goto canon_cr2; + } else if (is_canon && raw_width == 4476) { + top_margin = 34; + left_margin = 90; + goto canon_cr2; + } else if (is_canon && raw_width == 5108) { + top_margin = 13; + left_margin = 98; + maximum = 0xe80; +canon_cr2: + height = raw_height - top_margin; + width = raw_width - left_margin; + } else if (!strcmp(model,"D1")) { + camera_red *= 256/527.0; + camera_blue *= 256/317.0; + } else if (!strcmp(model,"D1X")) { + width = 4024; + ymag = 2; + } else if (!strcmp(model,"D70")) { + maximum = 0xf53; + } else if (!strcmp(model,"D100")) { + if (tiff_data_compression == 34713 && load_raw == nikon_load_raw) + raw_width = (width += 3) + 3; + maximum = 0xf44; + } else if (!strcmp(model,"D2H")) { + width = 2482; + left_margin = 6; + } else if (!strcmp(model,"D2X")) { + width = 4312; + } else if (fsize == 1581060) { + height = 963; + width = 1287; + raw_width = 1632; + load_raw = nikon_e900_load_raw; + maximum = 0x3f4; + colors = 4; + filters = 0x1e1e1e1e; + simple_coeff(3); + pre_mul[0] = 1.2085; + pre_mul[1] = 1.0943; + pre_mul[3] = 1.1103; + } else if (fsize == 2465792) { + height = 1203; + width = 1616; + raw_width = 2048; + load_raw = nikon_e900_load_raw; + maximum = 0x3dd; + colors = 4; + filters = 0x4b4b4b4b; + simple_coeff(3); + pre_mul[0] = 1.18193; + pre_mul[2] = 1.16452; + pre_mul[3] = 1.17250; + } else if (!strcmp(model,"E880") || + !strcmp(model,"E990")) { + if (!timestamp && !nikon_e990()) goto cp_e995; + height = 1540; + width = 2064; + colors = 4; + filters = 0xb4b4b4b4; + simple_coeff(3); + pre_mul[0] = 1.196; + pre_mul[1] = 1.246; + pre_mul[2] = 1.018; + } else if (!strcmp(model,"E995")) { +cp_e995: + strcpy (model, "E995"); + height = 1540; + width = 2064; + colors = 4; + filters = 0xe1e1e1e1; + } else if (!strcmp(model,"E2100")) { + if (!timestamp && !nikon_e2100()) goto cp_e2500; + height = 1206; + width = 1616; + load_raw = nikon_e2100_load_raw; + pre_mul[0] = 1.945; + pre_mul[2] = 1.040; + } else if (!strcmp(model,"E2500")) { +cp_e2500: + strcpy (model, "E2500"); + height = 1204; + width = 1616; + colors = 4; + filters = 0x4b4b4b4b; + } else if (fsize == 4775936) { + height = 1542; + width = 2064; + load_raw = nikon_e2100_load_raw; + pre_mul[0] = 1.818; + pre_mul[2] = 1.618; + if ((i = nikon_3700()) == 2) { + strcpy (make, "OLYMPUS"); + strcpy (model, "C740UZ"); + } else if (i == 0) { + strcpy (make, "PENTAX"); + strcpy (model,"Optio 33WR"); + flip = 1; + filters = 0x16161616; + pre_mul[0] = 1.331; + pre_mul[2] = 1.820; + } + } else if (!strcmp(model,"E4300")) { + if (!timestamp && minolta_z2()) goto dimage_z2; + height = 1710; + width = 2288; + filters = 0x16161616; + pre_mul[0] = 508; + pre_mul[1] = 256; + pre_mul[2] = 322; + } else if (!strcmp(model,"DiMAGE Z2")) { +dimage_z2: + strcpy (make, "MINOLTA"); + strcpy (model,"DiMAGE Z2"); + height = 1710; + width = 2288; + filters = 0x16161616; + load_raw = nikon_e2100_load_raw; + black = 68; + } else if (!strcmp(model,"E4500")) { + height = 1708; + width = 2288; + colors = 4; + filters = 0xb4b4b4b4; + } else if (fsize == 7438336) { + height = 1924; + width = 2576; + colors = 4; + filters = 0xb4b4b4b4; + } else if (!strcmp(model,"R-D1")) { + tiff_data_compression = 34713; + load_raw = nikon_load_raw; + } else if (!strcmp(model,"FinePix S5100") || + !strcmp(model,"FinePix S5500")) { + load_raw = unpacked_load_raw; + maximum = 0xffff; + } else if (!strncmp(model,"FinePix",7)) { + if (!strcmp(model+7,"S2Pro")) { + strcpy (model+7," S2Pro"); + height = 2144; + width = 2880; + black = 128; + flip = 6; + } else + maximum = 0x3e00; + top_margin = (raw_height - height)/2; + left_margin = (raw_width - width )/2; + data_offset += (top_margin*raw_width + left_margin) * 2; + if (fuji_secondary) + data_offset += use_secondary * ( strcmp(model+7," S3Pro") + ? (raw_width *= 2) : raw_height*raw_width*2 ); + fuji_width = width >> !fuji_layout; + width = (height >> fuji_layout) + fuji_width; + raw_height = height; + height = width - 1; + load_raw = fuji_load_raw; + if (!(fuji_width & 1)) filters = 0x49494949; + } else if (!strcmp(model,"RD175")) { + height = 986; + width = 1534; + data_offset = 513; + filters = 0x61616161; + load_raw = minolta_rd175_load_raw; + } else if (!strcmp(model,"Digital Camera KD-400Z")) { + height = 1712; + width = 2312; + raw_width = 2336; + data_offset = 4034; + fseek (ifp, 2032, SEEK_SET); + goto konica_400z; + } else if (!strcmp(model,"Digital Camera KD-510Z")) { + data_offset = 4032; + pre_mul[0] = 1.297; + pre_mul[2] = 1.438; + fseek (ifp, 2032, SEEK_SET); + goto konica_510z; + } else if (!strcasecmp(make,"MINOLTA")) { + load_raw = unpacked_load_raw; + maximum = 0xf7d; + if (!strncmp(model,"DiMAGE A",8)) { + if (!strcmp(model,"DiMAGE A200")) + filters = 0x49494949; + load_raw = packed_12_load_raw; + maximum = model[8] == '1' ? 0xf8b : 0xfff; + } else if (!strncmp(model,"ALPHA",5) || + !strncmp(model,"DYNAX",5) || + !strncmp(model,"MAXXUM",6)) { + sprintf (model, "DYNAX %s", model+6 + (model[0]=='M')); + load_raw = packed_12_load_raw; + maximum = 0xffb; + } else if (!strncmp(model,"DiMAGE G",8)) { + if (model[8] == '4') { + data_offset = 5056; + pre_mul[0] = 1.602; + pre_mul[2] = 1.441; + fseek (ifp, 2078, SEEK_SET); + height = 1716; + width = 2304; + } else if (model[8] == '5') { + data_offset = 4016; + fseek (ifp, 1936, SEEK_SET); +konica_510z: + height = 1956; + width = 2607; + raw_width = 2624; + } else if (model[8] == '6') { + data_offset = 4032; + fseek (ifp, 2030, SEEK_SET); + height = 2136; + width = 2848; + } + filters = 0x61616161; +konica_400z: + load_raw = unpacked_load_raw; + maximum = 0x3df; + order = 0x4d4d; + FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); + } + if (pre_mul[0] == 1 && pre_mul[2] == 1) { + pre_mul[0] = 1.42; + pre_mul[2] = 1.25; + } + } else if (!strncmp(model,"*ist D",6)) { + load_raw = model[6] ? packed_12_load_raw : unpacked_load_raw; + if (model[6] == 'S') height -= 2; + } else if (!strcmp(model,"Optio S")) { + if (fsize == 3178560) { + height = 1540; + width = 2064; + load_raw = eight_bit_load_raw; + camera_red *= 4; + camera_blue *= 4; + pre_mul[0] = 1.391; + pre_mul[2] = 1.188; + } else { + height = 1544; + width = 2068; + raw_width = 3136; + load_raw = packed_12_load_raw; + maximum = 0xf7c; + pre_mul[0] = 1.137; + pre_mul[2] = 1.453; + } + } else if (!strncmp(model,"Optio S4",8)) { + height = 1737; + width = 2324; + raw_width = 3520; + load_raw = packed_12_load_raw; + maximum = 0xf7a; + pre_mul[0] = 1.980; + pre_mul[2] = 1.570; + } else if (!strcmp(model,"STV680 VGA")) { + height = 484; + width = 644; + load_raw = eight_bit_load_raw; + flip = 2; + filters = 0x16161616; + black = 16; + pre_mul[0] = 1.097; + pre_mul[2] = 1.128; + } else if (!strcmp(model,"531C")) { + height = 1200; + width = 1600; + load_raw = unpacked_load_raw; + filters = 0x49494949; + pre_mul[1] = 1.218; + } else if (!strcmp(model,"F-201C")) { + height = 1200; + width = 1600; + load_raw = eight_bit_load_raw; + } else if (!strcmp(model,"F-510C")) { + height = 1958; + width = 2588; + load_raw = (fsize < 7500000) ? eight_bit_load_raw : unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"F-810C")) { + height = 2469; + width = 3272; + load_raw = unpacked_load_raw; + maximum = 0xfff0; + } else if (!strcmp(model,"A782")) { + height = 3000; + width = 2208; + filters = 0x61616161; + load_raw = (fsize < 10000000) ? eight_bit_load_raw : unpacked_load_raw; + maximum = 0xffc0; + } else if (!strcmp(model,"3320AF")) { + height = 1536; + raw_width = width = 2048; + filters = 0x61616161; + load_raw = unpacked_load_raw; + maximum = 0x3ff; + pre_mul[0] = 1.717; + pre_mul[2] = 1.138; + fseek (ifp, 0x300000, SEEK_SET); + if ((order = guess_byte_order(0x10000)) == 0x4d4d) { + data_offset = (2048 * 16 + 28) * 2; + height -= 16; + width -= 28; + maximum = 0xf5c0; + strcpy (make, "ISG"); + sprintf (model, "%dx%d", width, height); + } + } else if (!strcmp(make,"Imacon")) { + height = raw_height - 6; + width = raw_width - 10; + data_offset += 6 + raw_width*12; + flip = height > width+10 ? 5:3; + sprintf (model, "Ixpress %d-Mp", height*width/1000000); + filters = 0x61616161; + load_raw = unpacked_load_raw; + maximum = 0xffff; + pre_mul[0] = 1.963; + pre_mul[2] = 1.430; + } else if (!strcmp(make,"Sinar")) { + if (!memcmp(head,"8BPS",4)) { + fseek (ifp, 14, SEEK_SET); + height = get4(); + width = get4(); + filters = 0x61616161; + data_offset = 68; + } + load_raw = unpacked_load_raw; + maximum = 0x3fff; + } else if (!strcmp(make,"Leaf")) { + load_raw = unpacked_load_raw; + if (tiff_data_compression == 99) + load_raw = lossless_jpeg_load_raw; + maximum = 0x3fff; + strcpy (model, "Valeo"); + if (filters == 0) { + load_raw = leaf_load_raw; + maximum = 0xffff; + strcpy (model, "Volare"); + } + } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) { + if (width == 3880) { + data_offset += 12; + maximum = 0xf7f0; + width -= 22; + } else if (width == 3304) { + maximum = 0xf94c; + width -= 16; + } else maximum = 0xfff0; + load_raw = unpacked_load_raw; + } else if (!strcmp(model,"E-1")) { + filters = 0x61616161; + load_raw = unpacked_load_raw; + maximum = 0xfff0; + black = 1024; + } else if (!strcmp(model,"E-10")) { + load_raw = unpacked_load_raw; + maximum = 0xfff0; + black = 2048; + } else if (!strncmp(model,"E-20",4)) { + load_raw = unpacked_load_raw; + maximum = 0xffc0; + black = 2560; + } else if (!strcmp(model,"E-300") || + !strcmp(model,"E-500")) { + width -= 20; + load_raw = olympus_e300_load_raw; + maximum = 0xfff; + if (fsize > 15728640) { + load_raw = unpacked_load_raw; + maximum = 0xfc30; + } + } else if (!strcmp(model,"C770UZ")) { + height = 1718; + width = 2304; + filters = 0x16161616; + load_raw = nikon_e2100_load_raw; + } else if (!strcmp(make,"OLYMPUS")) { + load_raw = olympus_cseries_load_raw; + if (!strcmp(model,"C5050Z") || + !strcmp(model,"C8080WZ")) + filters = 0x16161616; + } else if (!strcmp(model,"N Digital")) { + height = 2047; + width = 3072; + filters = 0x61616161; + data_offset = 0x1a00; + load_raw = packed_12_load_raw; + maximum = 0xf1e; + } else if (!strcmp(model,"DSC-F828")) { + width = 3288; + left_margin = 5; + data_offset = 862144; + load_raw = sony_load_raw; + filters = 0x9c9c9c9c; + colors = 4; + black = 491; + } else if (!strcmp(model,"DSC-V3")) { + width = 3109; + left_margin = 59; + data_offset = 787392; + load_raw = sony_load_raw; + } else if (!strcmp(model,"DSC-R1")) { + width = 3925; + order = 0x4d4d; + load_raw = unpacked_load_raw; + black = 512; + } else if (!strncmp(model,"P850",4)) { + height = 1950; + width = 2608; + data_offset = 76456; + filters = 0x16161616; + load_raw = packed_12_load_raw; + } else if (!strcasecmp(make,"KODAK")) { + filters = 0x61616161; + if (!strcmp(model,"NC2000F")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS3B")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"EOSDCS1")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS315C")) { + black = 8; + } else if (!strcmp(model,"DCS330C")) { + black = 8; + } else if (!strcmp(model,"DCS420")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460")) { + width -= 4; + left_margin = 2; + } else if (!strcmp(model,"DCS460A")) { + width -= 4; + left_margin = 2; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS520C")) { + black = 180; + } else if (!strcmp(model,"DCS560C")) { + black = 188; + } else if (!strcmp(model,"DCS620C")) { + black = 180; + } else if (!strcmp(model,"DCS620X")) { + black = 185; + } else if (!strcmp(model,"DCS660C")) { + black = 214; + } else if (!strcmp(model,"DCS660M")) { + black = 214; + colors = 1; + filters = 0; + } else if (!strcmp(model,"DCS760M")) { + colors = 1; + filters = 0; + } + switch (tiff_data_compression) { + case 0: /* No compression */ + case 1: + load_raw = kodak_easy_load_raw; + break; + case 7: /* Lossless JPEG */ + load_raw = lossless_jpeg_load_raw; + case 32867: + break; + case 65000: /* Kodak DCR compression */ + if (kodak_data_compression == 32803) + load_raw = kodak_compressed_load_raw; + else { + load_raw = kodak_yuv_load_raw; + height = (height+1) & -2; + width = (width +1) & -2; + filters = 0; + } + break; + default: + fprintf (stderr, "%s: %s %s uses unsupported compression method %d.\n", + ifname, make, model, tiff_data_compression); + return 1; + } + if (strstr(model,"DC25")) { + strcpy (model, "DC25"); + data_offset = 15424; + } + if (!strncmp(model,"DC2",3)) { + height = 242; + if (fsize < 100000) { + raw_width = 256; width = 249; + } else { + raw_width = 512; width = 501; + } + data_offset += raw_width + 1; + colors = 4; + filters = 0x8d8d8d8d; + simple_coeff(1); + pre_mul[1] = 1.179; + pre_mul[2] = 1.209; + pre_mul[3] = 1.036; + load_raw = kodak_easy_load_raw; + } else if (!strcmp(model,"Digital Camera 40")) { + strcpy (model, "DC40"); + height = 512; + width = 768; + data_offset = 1152; + load_raw = kodak_radc_load_raw; + } else if (strstr(model,"DC50")) { + strcpy (model, "DC50"); + height = 512; + width = 768; + data_offset = 19712; + load_raw = kodak_radc_load_raw; + } else if (strstr(model,"DC120")) { + strcpy (model, "DC120"); + height = 976; + width = 848; + if (tiff_data_compression == 7) + load_raw = kodak_jpeg_load_raw; + else + load_raw = kodak_dc120_load_raw; + } + } else if (!strcmp(model,"Fotoman Pixtura")) { + height = 512; + width = 768; + data_offset = 3632; + load_raw = kodak_radc_load_raw; + filters = 0x61616161; + simple_coeff(2); + } else if (!strcmp(make,"Rollei")) { + switch (raw_width) { + case 1316: + height = 1030; + width = 1300; + top_margin = 1; + left_margin = 6; + break; + case 2568: + height = 1960; + width = 2560; + top_margin = 2; + left_margin = 8; + } + filters = 0x16161616; + load_raw = rollei_load_raw; + pre_mul[0] = 1.8; + pre_mul[2] = 1.3; + } else if (!strcmp(model,"PC-CAM 600")) { + height = 768; + data_offset = width = 1024; + filters = 0x49494949; + load_raw = eight_bit_load_raw; + pre_mul[0] = 1.14; + pre_mul[2] = 2.73; + } else if (!strcmp(model,"QV-2000UX")) { + height = 1208; + width = 1632; + data_offset = width * 2; + load_raw = eight_bit_load_raw; + } else if (fsize == 3217760) { + height = 1546; + width = 2070; + raw_width = 2080; + load_raw = eight_bit_load_raw; + } else if (!strcmp(model,"QV-4000")) { + height = 1700; + width = 2260; + load_raw = unpacked_load_raw; + maximum = 0xffff; + } else if (!strcmp(model,"QV-5700")) { + height = 1924; + width = 2576; + load_raw = casio_qv5700_load_raw; + } else if (!strcmp(model,"QV-R51")) { + height = 1926; + width = 2576; + raw_width = 3904; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.340; + pre_mul[2] = 1.672; + } else if (!strcmp(model,"EX-S100")) { + height = 1544; + width = 2058; + raw_width = 3136; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.631; + pre_mul[2] = 1.106; + } else if (!strcmp(model,"EX-Z50")) { + height = 1931; + width = 2570; + raw_width = 3904; + load_raw = packed_12_load_raw; + pre_mul[0] = 2.529; + pre_mul[2] = 1.185; + } else if (!strcmp(model,"EX-Z55")) { + height = 1960; + width = 2570; + raw_width = 3904; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.520; + pre_mul[2] = 1.316; + } else if (!strcmp(model,"EX-P505")) { + height = 1928; + width = 2568; + raw_width = 3852; + load_raw = packed_12_load_raw; + pre_mul[0] = 2.07; + pre_mul[2] = 1.88; + } else if (!strcmp(model,"EX-P600")) { + height = 2142; + width = 2844; + raw_width = 4288; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.797; + pre_mul[2] = 1.219; + } else if (!strcmp(model,"EX-P700")) { + height = 2318; + width = 3082; + raw_width = 4672; + load_raw = packed_12_load_raw; + pre_mul[0] = 1.758; + pre_mul[2] = 1.504; + } else if (!strcmp(make,"Nucore")) { + filters = 0x61616161; + load_raw = unpacked_load_raw; + if (width == 2598) { + filters = 0x16161616; + load_raw = nucore_load_raw; + flip = 2; + } + } + if (raw_color) adobe_coeff(); +dng_skip: + if (!load_raw || !height || is_jpeg) { + fprintf (stderr, "%s: Cannot decode %s %s%s images.\n", + ifname, make, model, is_jpeg ? " JPEG":""); + return 1; + } +#ifdef NO_JPEG + if (load_raw == kodak_jpeg_load_raw) { + fprintf (stderr, "%s: decoder was not linked with libjpeg.\n", ifname); + return 1; + } +#endif + if (!raw_height) raw_height = height; + if (!raw_width ) raw_width = width; + raw_color |= use_camera_rgb && colors == 3; + FORCC { /* Apply user-selected color balance */ + rgb_cam[0][c] *= red_scale; + rgb_cam[2][c] *= blue_scale; + } + if (filters && colors == 3) + for (i=0; i < 32; i+=4) { + if ((filters >> i & 15) == 9) + filters |= 2 << i; + if ((filters >> i & 15) == 6) + filters |= 8 << i; + } + fseek (ifp, data_offset, SEEK_SET); + return 0; +} + +#ifdef USE_LCMS +void CLASS apply_profile (char *pfname) +{ + char *prof; + cmsHPROFILE hInProfile=NULL, hOutProfile; + cmsHTRANSFORM hTransform; + + if (pfname) + hInProfile = cmsOpenProfileFromFile (pfname, "r"); + else if (profile_length) { + prof = malloc (profile_length); + merror (prof, "apply_profile()"); + fseek (ifp, profile_offset, SEEK_SET); + fread (prof, 1, profile_length, ifp); + hInProfile = cmsOpenProfileFromMem (prof, profile_length); + free (prof); + } + if (!hInProfile) return; + if (verbose) + fprintf (stderr, "Applying color profile...\n"); + maximum = 0xffff; + use_gamma = 0; + raw_color = 1; /* Don't use rgb_cam with a profile */ + + hOutProfile = cmsCreate_sRGBProfile(); + hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, + hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); + cmsDoTransform (hTransform, image, image, width*height); + + cmsDeleteTransform (hTransform); + cmsCloseProfile (hInProfile); + cmsCloseProfile (hOutProfile); +} +#endif + +/* + Convert the entire image to RGB colorspace and build a histogram. + */ +void CLASS convert_to_rgb() +{ + int row, col, c, i, fc=0; + ushort *img; + float rgb[3]; + + if (verbose) + fprintf (stderr, raw_color ? + "Building histograms...\n" : "Converting to sRGB colorspace...\n"); + + if (document_mode) + colors = 1; + memset (histogram, 0, sizeof histogram); + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) { + img = image[row*width+col]; + if (document_mode) + fc = FC(row,col); + if (colors == 4 && raw_color) /* Recombine the greens */ + img[1] = (img[1] + img[3]) >> 1; + if (colors == 1) /* RGB from grayscale */ + FORC3 rgb[c] = img[fc]; + else if (raw_color) /* RGB from RGB (easy) */ + goto norgb; + else FORC3 /* RGB via rgb_cam */ + for (rgb[c]=i=0; i < colors; i++) + rgb[c] += img[i] * rgb_cam[c][i]; + FORC3 img[c] = CLIP((int) rgb[c]); +norgb: + FORC3 histogram[c][img[c] >> 3]++; + } +} + +void CLASS fuji_rotate() +{ + int i, wide, high, row, col; + double step; + float r, c, fr, fc; + unsigned ur, uc; + ushort (*img)[4], (*pix)[4]; + + if (!fuji_width) return; + if (verbose) + fprintf (stderr, "Rotating image 45 degrees...\n"); + fuji_width = (fuji_width - 1 + shrink) >> shrink; + step = sqrt(0.5); + wide = fuji_width / step; + high = (height - fuji_width) / step; + img = calloc (wide*high, sizeof *img); + merror (img, "fuji_rotate()"); + + for (row=0; row < high; row++) + for (col=0; col < wide; col++) { + ur = r = fuji_width + (row-col)*step; + uc = c = (row+col)*step; + if (ur > height-2 || uc > width-2) continue; + fr = r - ur; + fc = c - uc; + pix = image + ur*width + uc; + for (i=0; i < colors; i++) + img[row*wide+col][i] = + (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; + } + free (image); + width = wide; + height = high; + image = img; + fuji_width = 0; +} + +void CLASS flip_image() +{ + unsigned *flag; + int size, base, dest, next, row, col, temp; + INT64 *img, hold; + + if (verbose) + fprintf (stderr, "Flipping image %c:%c:%c...\n", + flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', flip & 4 ? 'T':'0'); + + img = (INT64 *) image; + size = height * width; + flag = calloc ((size+31) >> 5, sizeof *flag); + merror (flag, "flip_image()"); + for (base = 0; base < size; base++) { + if (flag[base >> 5] & (1 << (base & 31))) + continue; + dest = base; + hold = img[base]; + while (1) { + if (flip & 4) { + row = dest % height; + col = dest / height; + } else { + row = dest / width; + col = dest % width; + } + if (flip & 2) + row = height - 1 - row; + if (flip & 1) + col = width - 1 - col; + next = row * width + col; + if (next == base) break; + flag[next >> 5] |= 1 << (next & 31); + img[dest] = img[next]; + dest = next; + } + img[dest] = hold; + } + free (flag); + if (flip & 4) { + temp = height; + height = width; + width = temp; + temp = ymag; + ymag = xmag; + xmag = temp; + } +} + +/* + Write the image to an 8-bit PPM file. + */ +void CLASS write_ppm (FILE *ofp) +{ + uchar (*ppm)[3], lut[0x10000]; + int perc, c, val, total, i, row, col; + float white=0, r; + + fprintf (ofp, "P6\n%d %d\n255\n", xmag*width, ymag*height); + ppm = calloc (width, 3*xmag); + merror (ppm, "write_ppm()"); + + perc = width * height * 0.01; /* 99th percentile white point */ + if (fuji_width) perc /= 2; + FORC3 { + for (val=0x2000, total=0; --val > 32; ) + if ((total += histogram[c][val]) > perc) break; + if (white < val) white = val; + } + white *= 8 / bright; + for (i=0; i < 0x10000; i++) { + r = i / white; + val = 256 * ( !use_gamma ? r : +#ifdef SRGB_GAMMA + r <= 0.00304 ? r*12.92 : pow(r,2.5/6)*1.055-0.055 ); +#else + r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 ); +#endif + if (val > 255) val = 255; + lut[i] = val; + } + for (row=0; row < height; row++) { + for (col=0; col < width; col++) + FORC3 for (i=0; i < xmag; i++) + ppm[xmag*col+i][c] = lut[image[row*width+col][c]]; + for (i=0; i < ymag; i++) + fwrite (ppm, width, 3*xmag, ofp); + } + free (ppm); +} + +/* + Write the image to a 16-bit Photoshop file. + */ +void CLASS write_psd (FILE *ofp) +{ + char head[] = { + '8','B','P','S', /* signature */ + 0,1,0,0,0,0,0,0, /* version and reserved */ + 0,3, /* number of channels */ + 0,0,0,0, /* height, big-endian */ + 0,0,0,0, /* width, big-endian */ + 0,16, /* 16-bit color */ + 0,3, /* mode (1=grey, 3=rgb) */ + 0,0,0,0, /* color mode data */ + 0,0,0,0, /* image resources */ + 0,0,0,0, /* layer/tqmask info */ + 0,0 /* no compression */ + }; + int hw[2], psize, row, col, c; + ushort *buffer, *pred; + + hw[0] = htonl(height); /* write the header */ + hw[1] = htonl(width); + memcpy (head+14, hw, sizeof hw); + fwrite (head, 40, 1, ofp); + + psize = height*width; + buffer = calloc (6, psize); + merror (buffer, "write_psd()"); + pred = buffer; + + for (row = 0; row < height; row++) + for (col = 0; col < width; col++) { + FORC3 pred[c*psize] = htons(image[row*width+col][c]); + pred++; + } + fwrite(buffer, psize, 6, ofp); + free (buffer); +} + +/* + Write the image to a 16-bit PPM file. + */ +void CLASS write_ppm16 (FILE *ofp) +{ + int row, col, c; + ushort (*ppm)[3]; + + if (maximum < 256) maximum = 256; + fprintf (ofp, "P6\n%d %d\n%d\n", width, height, maximum); + + ppm = calloc (width, 6); + merror (ppm, "write_ppm16()"); + + for (row = 0; row < height; row++) { + for (col = 0; col < width; col++) + FORC3 ppm[col][c] = htons(image[row*width+col][c]); + fwrite (ppm, width, 6, ofp); + } + free (ppm); +} + +int CLASS main (int argc, char **argv) +{ + int arg, status=0, user_flip=-1, user_black=-1, user_qual=-1; + int timestamp_only=0, identify_only=0, write_to_stdout=0; + int half_size=0, use_fuji_rotate=1, quality; + char opt, *ofname, *cp; + struct utimbuf ut; + const char *write_ext = ".ppm"; + FILE *ofp = stdout; +#ifdef USE_LCMS + char *profile = NULL; +#endif + +#ifndef LOCALTIME + putenv ("TZ=UTC"); +#endif + if (argc == 1) + { + fprintf (stderr, + "\nRaw Photo Decoder \"dcraw\" v7.82" + "\nby Dave Coffin, dcoffin a cybercom o net" + "\n\nUsage: %s [options] file1 file2 ...\n" + "\nValid options:" + "\n-v Print verbose messages" + "\n-z Change file dates to camera timestamp" + "\n-i Identify files without decoding them" + "\n-c Write to standard output" + "\n-a Use automatic white balance" + "\n-w Use camera white balance, if possible" + "\n-r Set red multiplier (default = 1.0)" + "\n-l Set blue multiplier (default = 1.0)" + "\n-b Set brightness (default = 1.0)" + "\n-k Set black point" + "\n-n Don't clip colors" + "\n-m Don't convert camera RGB to sRGB" +#ifdef USE_LCMS + "\n-p Apply color profile from file" +#endif + "\n-d Document Mode (no color, no interpolation)" + "\n-q [0-3] Set the interpolation quality" + "\n-h Half-size color image (twice as fast as \"-q 0\")" + "\n-f Interpolate RGGB as four colors" + "\n-B Apply bilateral filter to reduce noise" + "\n-j Show Fuji Super CCD images tilted 45 degrees" + "\n-s Use secondary pixels (Fuji Super CCD SR only)" + "\n-t [0-7] Flip image (0 = none, 3 = 180, 5 = 90CCW, 6 = 90CW)" + "\n-2 Write 8-bit PPM with 0.45 gamma (default)" + "\n-3 Write 16-bit linear PSD (Adobe Photoshop)" + "\n-4 Write 16-bit linear PPM" + "\n\n", argv[0]); + return 1; + } + + argv[argc] = ""; + for (arg=1; argv[arg][0] == '-'; ) { + opt = argv[arg++][1]; + if ((strchr("Bbrlktq", opt) && !isdigit(argv[arg][0])) || + (opt == 'B' && !isdigit(argv[arg+1][0]))) { + fprintf (stderr, "Non-numeric argument to \"-%c\"\n", opt); + return 1; + } + switch (opt) + { + case 'B': sigma_d = atof(argv[arg++]); + sigma_r = atof(argv[arg++]); break; + case 'b': bright = atof(argv[arg++]); break; + case 'r': red_scale = atof(argv[arg++]); break; + case 'l': blue_scale = atof(argv[arg++]); break; + case 'k': user_black = atoi(argv[arg++]); break; + case 't': user_flip = atoi(argv[arg++]); break; + case 'q': user_qual = atoi(argv[arg++]); break; +#ifdef USE_LCMS + case 'p': profile = argv[arg++] ; break; +#endif + case 'z': timestamp_only = 1; break; + case 'i': identify_only = 1; break; + case 'c': write_to_stdout = 1; break; + case 'v': verbose = 1; break; + case 'h': half_size = 1; /* "-h" implies "-f" */ + case 'f': four_color_rgb = 1; break; + case 'd': document_mode = 1; break; + case 'a': use_auto_wb = 1; break; + case 'w': use_camera_wb = 1; break; + case 'j': use_fuji_rotate = 0; break; + case 's': use_secondary = 1; break; + case 'n': clip_color = 0; break; + case 'm': use_camera_rgb = 1; break; + + case '2': write_fun = write_ppm; write_ext = ".ppm"; break; + case '3': write_fun = write_psd; write_ext = ".psd"; break; + case '4': write_fun = write_ppm16; write_ext = ".ppm"; break; + + default: + fprintf (stderr, "Unknown option \"-%c\".\n", opt); + return 1; + } + } + if (arg == argc) { + fprintf (stderr, "No files to process.\n"); + return 1; + } + if (write_to_stdout) { + if (isatty(1)) { + fprintf (stderr, "Will not write an image to the terminal!\n"); + return 1; + } +#if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) + if (setmode(1,O_BINARY) < 0) { + perror("setmode()"); + return 1; + } +#endif + } + for ( ; arg < argc; arg++) { + status = 1; + image = NULL; + if (setjmp (failure)) { + if (fileno(ifp) > 2) fclose(ifp); + if (fileno(ofp) > 2) fclose(ofp); + if (image) free (image); + status = 1; + continue; + } + ifname = argv[arg]; + if (!(ifp = fopen (ifname, "rb"))) { + perror (ifname); + continue; + } + if (timestamp_only) { + if ((status = identify(1))) + fprintf (stderr, "%s has no timestamp.\n", ifname); + else if (identify_only) + printf ("%10ld%10d %s\n", timestamp, shot_order, ifname); + else { + if (verbose) + fprintf (stderr, "%s time set to %d.\n", ifname, (int) timestamp); + ut.actime = ut.modtime = timestamp; + utime (ifname, &ut); + } + goto next; + } + if ((status = identify(0))) goto next; + if (user_flip >= 0) + flip = user_flip; + switch ((flip+3600) % 360) { + case 270: flip = 5; break; + case 180: flip = 3; break; + case 90: flip = 6; + } + if (identify_only) { + fprintf (stderr, "%s is a %s %s image.\n", ifname, make, model); +next: + fclose(ifp); + continue; + } + shrink = half_size && filters; + iheight = (height + shrink) >> shrink; + iwidth = (width + shrink) >> shrink; + image = calloc (iheight*iwidth*sizeof *image + meta_length, 1); + merror (image, "main()"); + meta_data = (char *) (image + iheight*iwidth); + if (verbose) + fprintf (stderr, + "Loading %s %s image from %s...\n", make, model, ifname); + (*load_raw)(); + bad_pixels(); + height = iheight; + width = iwidth; +#ifdef COLORCHECK + colorcheck(); +#endif + quality = 2 + !fuji_width; + if (user_qual >= 0) quality = user_qual; + if (user_black >= 0) black = user_black; + if (is_foveon) foveon_interpolate(); + else scale_colors(); + if (shrink) filters = 0; + cam_to_cielab (NULL,NULL); + if (filters && !document_mode) { + if (quality == 0) + lin_interpolate(); + else if (quality < 3 || colors > 3) + vng_interpolate(); + else ahd_interpolate(); + } + if (sigma_d > 0 && sigma_r > 0) bilateral_filter(); + if (use_fuji_rotate) fuji_rotate(); +#ifdef USE_LCMS + apply_profile (profile); +#endif + convert_to_rgb(); + if (flip) flip_image(); + fclose(ifp); + ofname = malloc (strlen(ifname) + 16); + merror (ofname, "main()"); + if (write_to_stdout) + strcpy (ofname, "standard output"); + else { + strcpy (ofname, ifname); + if ((cp = strrchr (ofname, '.'))) *cp = 0; + strcat (ofname, write_ext); + ofp = fopen (ofname, "wb"); + if (!ofp) { + status = 1; + perror(ofname); + goto cleanup; + } + } + if (verbose) + fprintf (stderr, "Writing data to %s...\n", ofname); + (*write_fun)(ofp); + if (ofp != stdout) + fclose(ofp); +cleanup: + free (ofname); + free (image); + } + return status; +} diff --git a/filters/chalk/raw/kis_raw_import.cpp b/filters/chalk/raw/kis_raw_import.cpp new file mode 100644 index 00000000..adfd14f6 --- /dev/null +++ b/filters/chalk/raw/kis_raw_import.cpp @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "config.h" + +#ifdef HAVE_SYS_TYPES_H + #include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "imageviewer.h" +#include "kis_config.h" +#include "kis_cmb_idlist.h" +#include "kis_types.h" +#include "kis_raw_import.h" +#include "kis_doc.h" +#include "kis_image.h" +#include "kis_meta_registry.h" +#include "kis_layer.h" +#include "kis_annotation.h" +#include "kis_profile.h" +#include "kis_colorspace_factory_registry.h" +#include "kis_iterators_pixel.h" +#include "kis_abstract_colorspace.h" +#include "kis_paint_device.h" +#include "kis_paint_layer.h" +#include "wdgrawimport.h" + +typedef KGenericFactory KisRawImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalk_raw_import, KisRawImportFactory("kofficefilters")) + +KisRawImport::KisRawImport(KoFilter *, const char *, const TQStringList&) + : KoFilter() + , m_data(0) + , m_process(0) + , m_progress(0) + , m_err(false) +{ + m_dialog = new KDialogBase(); + m_dialog->enableButtonApply(false); + m_page = new WdgRawImport(m_dialog); + m_dialog -> setMainWidget(m_page); + + connect(m_page->bnPreview, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUpdatePreview())); + connect(m_page->grpColorSpace, TQT_SIGNAL(clicked( int )), this, TQT_SLOT(slotFillCmbProfiles())); + connect(m_page->grpChannelDepth, TQT_SIGNAL(clicked( int )), this, TQT_SLOT(slotFillCmbProfiles())); + + KisConfig cfg; + TQString monitorProfileName = cfg.monitorProfile(); + m_monitorProfile = KisMetaRegistry::instance()->csRegistry()->getProfileByName(monitorProfileName); + + slotFillCmbProfiles(); +} + +KisRawImport::~KisRawImport() +{ + delete m_dialog; + delete m_process; +} + +KoFilter::ConversiontqStatus KisRawImport::convert(const TQCString& from, const TQCString& to) +{ + if (from != "image/x-raw" || to != "application/x-chalk") { + return KoFilter::NotImplemented; + } + + if (m_err) { + return KoFilter::CreationError; + } + + kdDebug(41008) << "Chalk importing from Raw\n"; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + if (!doc) { + return KoFilter::CreationError; + } + + doc -> prepareForImport(); + + TQString filename = m_chain -> inputFile(); + + if (filename.isEmpty()) { + return KoFilter::FileNotFound; + } + + slotUpdatePreview(); + + // Show dialog + m_dialog->setCursor(TQt::ArrowCursor); + TQApplication::setOverrideCursor(TQt::ArrowCursor); + + KConfig * cfg = KGlobal::config(); + cfg->setGroup("rawimport"); + + m_page->radioGray->setChecked(cfg->readBoolEntry("gray", false)); + m_page->radioRGB->setChecked(cfg->readBoolEntry("rgb", true)); + m_page->radio8->setChecked(cfg->readBoolEntry("8bit", false)); + m_page->radio16->setChecked(cfg->readBoolEntry("16bit", true)); + m_page->chkFourColorRGB->setChecked( cfg->readBoolEntry("four_color_rgb", false)); + m_page->chkCameraColors->setChecked( cfg->readBoolEntry("camera_colors", false)); + m_page->chkBrightness->setChecked( cfg->readBoolEntry("do_brightness", false)); + m_page->chkBlackpoint->setChecked( cfg->readBoolEntry("do_blackpoint", false)); + m_page->chkRed->setChecked( cfg->readBoolEntry("do_red", false)); + m_page->chkBlue->setChecked( cfg->readBoolEntry("do_blue", false)); + m_page->radioFixed->setChecked( cfg->readBoolEntry("fixed_wb", true)); + m_page->radioAutomatic->setChecked( cfg->readBoolEntry("automatic_wb", false)); + m_page->radioCamera->setChecked( cfg->readBoolEntry("camera_wb", false)); + m_page->chkClip->setChecked( cfg->readBoolEntry("clip", true)); + m_page->chkProfile->setChecked(cfg->readBoolEntry("useprofile", false)); + m_page->dblBrightness->setValue(cfg->readDoubleNumEntry("brightness", 1.0)); + m_page->dblBlackpoint->setValue(cfg->readDoubleNumEntry("blackpoint", 0)); + m_page->dblRed->setValue(cfg->readDoubleNumEntry("red", 1.0)); + m_page->dblBlue->setValue(cfg->readDoubleNumEntry("blue", 1.0)); + + if (m_dialog->exec() == TQDialog::Accepted) { + + cfg->writeEntry("gray", m_page->radioGray->isChecked()); + cfg->writeEntry("rgb", m_page->radioRGB->isChecked()); + cfg->writeEntry("8bit", m_page->radio8->isChecked()); + cfg->writeEntry("16bit", m_page->radio16->isChecked()); + cfg->writeEntry("four_color_rgb", m_page->chkFourColorRGB -> isChecked()); + cfg->writeEntry("camera_colors", m_page->chkCameraColors -> isChecked()); + cfg->writeEntry("do_brightness", m_page->chkBrightness -> isChecked()); + cfg->writeEntry("do_blackpoint", m_page->chkBlackpoint -> isChecked()); + cfg->writeEntry("do_red", m_page->chkRed -> isChecked()); + cfg->writeEntry("do_blue", m_page->chkBlue -> isChecked()); + cfg->writeEntry("fixed_wb", m_page->radioFixed -> isChecked()); + cfg->writeEntry("automatic_wb", m_page->radioAutomatic -> isChecked()); + cfg->writeEntry("camera_wb", m_page->radioCamera -> isChecked()); + cfg->writeEntry("clip", m_page->chkClip->isChecked()); + cfg->writeEntry("useprofile", m_page->chkProfile->isChecked()); + cfg->writeEntry("brightness", m_page->dblBrightness->value()); + cfg->writeEntry("blackpoint", m_page->dblBlackpoint->value()); + cfg->writeEntry("red", m_page->dblRed->value()); + cfg->writeEntry("blue", m_page->dblBlue->value()); + + TQApplication::setOverrideCursor(TQt::waitCursor); + // Create a busy indicator to show that we didn't die or so + m_progress = new TQProgressDialog(); + m_progress -> setTotalSteps(0); + m_progress -> setCancelButton(0); + TQTimer timer; + connect(&timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(incrementProgress())); + timer.start(200); + + doc -> undoAdapter() -> setUndo(false); + + getImageData(createArgumentList(false)); + + KisImageSP image = 0; + KisPaintLayerSP layer = 0; + KisPaintDeviceSP device = 0; + + TQApplication::restoreOverrideCursor(); + + delete m_progress; + m_progress = 0; + + if (m_page->radio8->isChecked()) { + // 8 bits + + TQImage img; + img.loadFromData(*m_data); + + KisColorSpace * cs = 0; + if (m_page->radioGray->isChecked()) { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA"), profile() ); + } + else { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA"), profile() ); + } + if (cs == 0) { kdDebug() << "No CS\n"; return KoFilter::InternalError; } + + image = new KisImage(doc->undoAdapter(), img.width(), img.height(), cs, filename); + if (image == 0) return KoFilter::CreationError; + image->blockSignals(true); // Don't send out signals while we're building the image + + layer = dynamic_cast( image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data() ); + if (layer == 0) return KoFilter::CreationError; + + device = layer->paintDevice(); + if (device == 0) return KoFilter::CreationError; + + device->convertFromTQImage(img, ""); + + } else { + // 16 bits + + TQ_UINT32 startOfImagedata = 0; + TQSize sz = determineSize(startOfImagedata); + + kdDebug(41008) << "Total bytes: " << m_data->size() + << "\n start of image data: " << startOfImagedata + << "\n bytes for pixels left: " << m_data->size() - startOfImagedata + << "\n total pixels: " << sz.width() * sz.height() + << "\n total pixel bytes: " << sz.width() * sz.height() * 6 + << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata + << "\n"; + + + char * data = m_data->data() + startOfImagedata; + + KisColorSpace * cs = 0; + if (m_page->radioGray->isChecked()) { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() ); + } + else { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() ); + } + if (cs == 0) return KoFilter::InternalError; + + image = new KisImage( doc->undoAdapter(), sz.width(), sz.height(), cs, filename); + if (image == 0)return KoFilter::CreationError; + + layer = dynamic_cast (image->newLayer(image -> nextLayerName(), OPACITY_OPAQUE).data()); + if (layer == 0) return KoFilter::CreationError; + + device = layer->paintDevice(); + if (device == 0) return KoFilter::CreationError; + + // Copy the colordata to the pixels + int pos = 0; + + for (int line = 0; line < sz.height(); ++line) { + KisHLineIterator it = device->createHLineIterator(0, line, sz.width(), true); + + while (!it.isDone()) { + if (m_page->radioGray->isChecked()) { + TQ_UINT16 d = (TQ_INT16)*(data + pos); + d = ntohs(d); + memcpy(it.rawData(), &d, 2); + pos += 2; + } + else { + // Red + TQ_UINT16 d = (TQ_INT16)*(data + pos); + d = ntohs(d); + memcpy(it.rawData() + 4, &d, 2); + + // Green + pos += 2; + d = (TQ_INT16)*(data + pos ); + d = ntohs(d); + memcpy(it.rawData() + 2, &d, 2); + + // Blue + pos += 2; + d = (TQ_INT16)*(data + pos ); + d = ntohs(d); + memcpy(it.rawData(), &d, 2); + + pos += 2; + } + cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1); + ++it; + } + } + } + layer->setDirty(); + kdDebug() << "going to set image\n"; + doc -> setCurrentImage(image); + doc -> undoAdapter() -> setUndo(true); + doc -> setModified(false); + kdDebug() << "everything ok\n"; + + TQApplication::restoreOverrideCursor(); + return KoFilter::OK; + } + + TQApplication::restoreOverrideCursor(); + return KoFilter::UserCancelled; +} + +void KisRawImport::incrementProgress() +{ + m_progress -> setProgress(m_progress -> progress() + 10); +} + + +void KisRawImport::slotUpdatePreview() +{ + TQApplication::setOverrideCursor(TQt::waitCursor); + getImageData(createArgumentList(true)); + + kdDebug(41008) << "Retrieved " << m_data->size() << " bytes of image data\n"; + + if (m_data->isNull()) return; + + TQImage img; + + if (m_page->radio8->isChecked()) { + // 8 bits + img.loadFromData(*m_data); + + } else { + // 16 bits + + TQ_UINT32 startOfImagedata = 0; + TQSize sz = determineSize(startOfImagedata); + + kdDebug(41008) << "Total bytes: " << m_data->size() + << "\n start of image data: " << startOfImagedata + << "\n bytes for pixels left: " << m_data->size() - startOfImagedata + << "\n total pixels: " << sz.width() * sz.height() + << "\n total pixel bytes: " << sz.width() * sz.height() * 6 + << "\n total necessary bytes: " << (sz.width() * sz.height() * 6) + startOfImagedata + << "\n"; + + char * data = m_data->data() + startOfImagedata; + + KisColorSpace * cs = 0; + if (m_page->radioGray->isChecked()) { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("GRAYA16"), profile() ); + } + else { + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace( KisID("RGBA16"), profile() ); + } + KisPaintDevice * dev = new KisPaintDevice(cs, "preview"); + // Copy the colordata to the pixels + int pos = 0; + + for (int line = 0; line < sz.height(); ++line) { + KisHLineIterator it = dev->createHLineIterator(0, line, sz.width(), true); + + while (!it.isDone()) { + if (m_page->radioGray->isChecked()) { + TQ_UINT16 d = (TQ_INT16)*(data + pos); + d = ntohs(d); + memcpy(it.rawData(), &d, 2); + pos += 2; + } + else { + // Red + TQ_UINT16 d = (TQ_INT16)*(data + pos); + d = ntohs(d); + memcpy(it.rawData() + 4, &d, 2); + + // Green + pos += 2; + d = (TQ_INT16)*(data + pos ); + d = ntohs(d); + memcpy(it.rawData() + 2, &d, 2); + + // Blue + pos += 2; + d = (TQ_INT16)*(data + pos ); + d = ntohs(d); + memcpy(it.rawData(), &d, 2); + + pos += 2; + } + cs->setAlpha(it.rawData(), OPACITY_OPAQUE, 1); + ++it; + } + } + + img = dev->convertToTQImage(m_monitorProfile); + } + + m_page->lblPreview->setImage(img); + TQApplication::restoreOverrideCursor(); +} + + +void KisRawImport::getImageData( TQStringList arguments ) +{ + // delete m_process; + delete m_data; + + kdDebug(41008) << "getImageData " << arguments.join(" ") << "\n"; + KProcess process (this); + m_data = new TQByteArray(0); + + for (TQStringList::iterator it = arguments.begin(); it != arguments.end(); ++it) { + process << *it; + } + + process.setUseShell(true); + connect(&process, TQT_SIGNAL(receivedStdout(KProcess *, char *, int)), this, TQT_SLOT(slotReceivedStdout(KProcess *, char *, int))); + connect(&process, TQT_SIGNAL(receivedStderr(KProcess *, char *, int)), this, TQT_SLOT(slotReceivedStderr(KProcess *, char *, int))); + connect(&process, TQT_SIGNAL(processExited(KProcess *)), this, TQT_SLOT(slotProcessDone())); + + + kdDebug(41008) << "Starting process\n"; + + if (!process.start(KProcess::NotifyOnExit, KProcess::AllOutput)) { + KMessageBox::error( 0, i18n("Cannot convert RAW files because the dcraw executable could not be started.")); + } + while (process.isRunning()) { + //kdDebug(41008) << "Waiting...\n"; + tqApp->eventLoop()->processEvents(TQEventLoop::ExcludeUserInput); + //process.wait(2); + } + + if (process.normalExit()) { + kdDebug(41008) << "Return value of process: " << process.exitStatus() << "\n"; + } + else { + kdDebug(41008) << "Process did not exit normally. Exit signal: " << process.exitSignal() << "\n"; + m_err = true; + } + +} + + +void KisRawImport::slotProcessDone() +{ + kdDebug(41008) << "process done!\n"; +} + +void KisRawImport::slotReceivedStdout(KProcess *, char *buffer, int buflen) +{ + //kdDebug(41008) << "stdout received " << buflen << " bytes on stdout.\n"; + //kdDebug(41008) << TQString::fromAscii(buffer, buflen) << "\n"; + int oldSize = m_data->size(); + m_data->resize(oldSize + buflen, TQGArray::SpeedOptim); + memcpy(m_data->data() + oldSize, buffer, buflen); +} + +void KisRawImport::slotReceivedStderr(KProcess *, char *buffer, int buflen) +{ + TQByteArray b(buflen); + memcpy(b.data(), buffer, buflen); + kdDebug(41008) << TQString(b) << "\n"; + KMessageBox::error(0, i18n("Error: Dcraw cannot load this image. Message: ") + TQString(b)); + m_err = true; +} + + +TQStringList KisRawImport::createArgumentList(bool forPreview) +{ + TQStringList args; + + args.append("dcraw"); // XXX: Create a chalkdcraw so we can count on it being available + + //args.append("-v"); // Verbose + + args.append("-c"); // Write to stdout + + if (forPreview) { + args.append("-h"); // Fast, half size image + } + + if (m_page->radio8->isChecked()) { + args.append("-2"); // 8 bits + } + else { + args.append("-4"); // 16 bits + } + + if (m_page->radioGray->isChecked()) { + args.append("-d"); // Create grayscale image + } + + if (m_page->chkCameraColors->isChecked()) { + args.append("-m"); // Use camera raw colors instead of sRGB + } + + if (m_page->radioAutomatic->isChecked()) { + args.append("-a"); // Automatic white balancing + } + + if (m_page->radioCamera->isChecked()) { + args.append("-w"); // Use camera white balance, if present + } + + if (m_page->chkFourColorRGB->isChecked()) { + args.append("-f"); // Interpolate RGB as four colors + } + + if (!m_page->chkClip->isChecked()) { + args.append("-n"); // Do not clip colors + } + + if (m_page->chkBrightness->isChecked()) { + args.append("-b " + TQString::number(m_page->dblBrightness->value())); + } + + if (m_page->chkBlackpoint->isChecked()) { + args.append("-k " + TQString::number(m_page->dblBlackpoint->value())); + } + + if (m_page->chkRed->isChecked()) { + args.append("-r " + TQString::number(m_page->dblRed->value())); + } + + if (m_page->chkBlue->isChecked()) { + args.append("-l " + TQString::number(m_page->dblBlue->value())); + } + + + KisProfile * pf = profile(); + if (m_page->chkProfile->isChecked()) { + if (!pf->filename().isNull()) { + // Use the user-set profile, if it's not an lcms internal + // profile. This does not add the profile to the image, we + // need to do that later. + args.append("-p \"" + pf->filename() + "\""); + } + } + + // Don't forget the filename + args.append("\"" + m_chain -> inputFile() + "\""); + + return args; +} + +TQSize KisRawImport::determineSize(TQ_UINT32& startOfImageData) +{ + if (m_data->isNull() || m_data->size() < 2048) { + startOfImageData = 0; + return TQSize(0,0); + } + + TQString magick = TQString::fromAscii(m_data->data(), 2); + if (magick != "P6") { + kdDebug(41008) << " Bad magick! " << magick << "\n"; + startOfImageData = 0; + return TQSize(0,0); + } + + // Find the third newline that marks the header end in a dcraw generated ppm. + TQ_UINT32 i = 0; + TQ_UINT32 counter = 0; + + while (true) { + if (counter == 3) break; + if (m_data->data()[i] == '\n') { + counter++; + } + ++i; + } + + TQString size = TQStringList::split("\n", TQString::fromAscii(m_data->data(), i))[1]; + kdDebug(41008) << "Header: " << TQString::fromAscii(m_data->data(), i) << "\n"; + TQStringList sizelist = TQStringList::split(" ", size); + TQ_INT32 w = sizelist[0].toInt(); + TQ_INT32 h = sizelist[1].toInt(); + + startOfImageData = i; + return TQSize(w, h); + +} + +KisProfile * KisRawImport::profile() +{ + if (m_page->chkProfile->isChecked()) { + return KisMetaRegistry::instance()->csRegistry()->getProfileByName(m_page->cmbProfile->currentText()); + } + else + return 0; +} + +void KisRawImport::slotFillCmbProfiles() +{ + KisID s = getColorSpace(); + + KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s); + m_page -> cmbProfile -> clear(); + TQValueVector profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf ); + TQValueVector ::iterator it; + for ( it = profileList.begin(); it != profileList.end(); ++it ) { + m_page -> cmbProfile -> insertItem((*it) -> productName()); + } +} + +KisID KisRawImport::getColorSpace() +{ + if (m_page->radioRGB->isChecked()) { + if (m_page->radio16->isChecked()) { + return KisID( "RGBA16" ); + } + } + else { + if (m_page->radio16->isChecked()) { + return KisID( "GRAYA16" ); + } + else { + return KisID( "GRAYA" ); + } + } + return KisID("RGBA"); +} + +#include "kis_raw_import.moc" diff --git a/filters/chalk/raw/kis_raw_import.h b/filters/chalk/raw/kis_raw_import.h new file mode 100644 index 00000000..35adb6e1 --- /dev/null +++ b/filters/chalk/raw/kis_raw_import.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_RAW_IMPORT_H_ +#define KIS_RAW_IMPORT_H_ + +#include + +class KProcess; +class KDialogBase; +class WdgRawImport; +class KisProfile; +class TQProgressDialog; + +class KisRawImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + KisRawImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisRawImport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); + + +private slots: + + void slotUpdatePreview(); + void slotFillCmbProfiles(); + void slotProcessDone(); + void slotReceivedStdout(KProcess *proc, char *buffer, int buflen); + void slotReceivedStderr(KProcess *proc, char *buffer, int buflen); + void incrementProgress(); + +private: + + TQStringList createArgumentList(bool forPreview = false); + TQSize determineSize(TQ_UINT32& startOfImageData); + void getImageData(TQStringList arguments); + KisProfile * profile(); + KisID getColorSpace(); + +private: + TQByteArray * m_data; + KDialogBase * m_dialog; + WdgRawImport * m_page; + KisProfile * m_monitorProfile; + KProcess * m_process; + TQProgressDialog* m_progress; + bool m_err; // Set to true when slotReceivedStderr is called +}; + +#endif // KIS_RAW_IMPORT_H_ + diff --git a/filters/chalk/raw/wdgrawimport.ui b/filters/chalk/raw/wdgrawimport.ui new file mode 100644 index 00000000..d6080a01 --- /dev/null +++ b/filters/chalk/raw/wdgrawimport.ui @@ -0,0 +1,496 @@ + +WdgRawImport + + + WdgRawImport + + + + 0 + 0 + 835 + 596 + + + + + unnamed + + + + bnPreview + + + &Update Preview + + + + + lblPreview + + + + 7 + 7 + 0 + 0 + + + + + 200 + 150 + + + + + + tqlayout2 + + + + unnamed + + + + grpColorSettings + + + Color Settings + + + + unnamed + + + + chkBlackpoint + + + Blackpoint: + + + + + chkRed + + + Red multiplier: + + + + + dblRed + + + 0.1 + + + 1 + + + + + chkBlue + + + Blue multiplier: + + + + + dblBlue + + + 0.1 + + + 1 + + + + + dblBlackpoint + + + + + dblBrightness + + + 0.1 + + + 2 + + + Brightness. 1.0 is default + + + + + grpWhiteBalance + + + &White Balance + + + true + + + + unnamed + + + + radioFixed + + + White card in sunlight + + + true + + + + + radioAutomatic + + + Automatic + + + + + + false + + + Automatic color balance. The default is to use a fixed color balance based on a white card photographed in sunlight. + + + + + radioCamera + + + From camera + + + + + + + Use the color balance specified by the camera. If this cannot be found, dcraw prints a warning and reverts to the default. + + + + + + + chkBrightness + + + Brightness: + + + + + + + grpColorSpace + + + Colorspace + + + true + + + + unnamed + + + + radioGray + + + &Document mode + + + + + radioRGB + + + &RGB + + + true + + + + + + + grpChannelDepth + + + Channel Depth + + + false + + + true + + + 0 + + + + unnamed + + + + radio16 + + + &16 bits per channel + + + Alt+1 + + + true + + + + + radio8 + + + &8 bits per channel + + + Alt+8 + + + false + + + + + + + chkFourColorRGB + + + &Interpolate RGB as four colors + + + Interpolate RGB as four colors. This blurs the image a little, but it eliminates false 2x2 mesh patterns. + + + + + + + spacer3 + + + Horizontal + + + Expanding + + + + 500 + 20 + + + + + + spacer3_2 + + + Vertical + + + Expanding + + + + 20 + 120 + + + + + + tqlayout4 + + + + unnamed + + + + chkClip + + + Clip colors to prevent pink highlights + + + + + + true + + + By default, dcraw clips all colors to prevent pink hues in the highlights. Combine this option with -b 0.25 to leave the image data completely unclipped. + + + + + tqlayout10 + + + + unnamed + + + + chkProfile + + + + + + + + + + + cmbProfile + + + true + + + + 3 + 0 + 0 + 0 + + + + + + + + chkCameraColors + + + Use camera raw colors, not sRGB + + + + + spacer4 + + + Horizontal + + + Expanding + + + + 41 + 20 + + + + + + + + + + KisCmbIDList +
kis_cmb_idlist.h
+ + 1 + 24 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+ + ImageViewer +
imageviewer.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image1 + moved(QPoint) + moving(QPoint) + startMoving(QPoint) + zoomIn() + slot() + zoomOut() + slot() + slot() + slotMoving(QPoint) + slotMoved(QPoint) + slot() + slotStartMoving(QPoint) +
+
+ + + 89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b000003b149444154388dad945f4c5b551cc73fe7dc4b7b4bcba0762d45c43114323599ee6192609c51d883892ce083f1718b3ebb185f8dc91e972cf39d2d2a2f1af664b6f1e0fe3863a0718969700eb0c52142da0242a1bd6d696f7bcff101585203ceb8fd9ece39f99dcff9fe7edf939f88c562ec465f5f9fe609442c161362173c3e3eae7b7a7ac8e7f36432196cdbfe4f907c3e4f2291201e8fe338cec3737357e9e8e828aded1e229d650e1f2d51754b082110124c13a4dc5ea341eb9dc284c0558a853f3ce8cb0677ef500fde7d39d2596679e326597b8e9abb85d7a770ab16ab6983ec5a05b487a70e36f0f4e10afe408d6a558310980108478dba4a1e8233990c5d474b64ed39aa3a8fe5f3317fbf81dbd70bccfeb205947632fd74f6589c1c6ea2f70d03a58ba0c1f2c9bdc1b66de3b8256a6e11cbe7e3ee1d181b590124fe2693aeee08d223c82c3a2c24b7b874bec8f26288774f7bd054504aef0dde6e99c0eb83f9fb266323cb80a27fb0958141836044605a2ee5523393371cc646fee2da37195aa35d0c0c5b4859ac03d7e91712dcaac5adab3650a3ff9d08ef7dd8404bb48869e5d958b5b87dadc4c9a1464e9f0d0326df7ebd86bd2e310cb1bf62d384d59441f2d70a070e1c60e09489929b988681bdd9cc97170bcc4c65595f71f8e0e3301337fc24a7732467831875a47f289652b0be5e4151e6d07316c1b0c0340d8ab92023e76d66a6b2840e36d2fb7a13fee632475e6edc367ea98a90fb98b7dd6310ca0328a44761582e1bab41befabcc0ec940d28bc5e93b68e064cab84e1d9beaeb48934eac1f53b01c1b000fca496aa54b61a99fcde61662a4b4b4b23d1680be9d426173e4df3602a48ea411989a4fd590f52a8fd156b05ed9d350e3defe3cfdf4b4c7ce770ea7d3fb9f520afbe1620daeee5c26735d20b9b9cfb6811a754a439e4e5c5639a4caa1e5caf586bfc0197b78702005cb9b4cae4cd3267ce8638fe964bd72b393e39d74928d242617303a756a37f284447770dcdbffc6384a05a85de1306e9a52057c7527c7131c3c42d3f475eb2303c82d4fc3276d6811db37efeb148723082d9b08f79f97c1e5729109a9a28307cc622d2d6cdf52b2b24efe548dedb00142009862cfa879ee1a71f6cec928353511472fbf4389148b0b0e0c108081412458dfe21c9f11351e67e7358595468246d1d1e5e38a6e9e851bc39d84ab502a669331dafec0d8ec7e3e8cb06e1a881d727d1ae40180a434a8c9db129a54126ad48a7358c2b4c5352c8c374bcccdab2bb37d8719cba79fab8211f9df218e0582c261e95f8bfc04f1a1e8bc5c4dfe0a190172af6a9690000000049454e44ae426082 + + + 789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f + + + + radioRGB + radio16 + chkBrightness + dblBrightness + chkBlackpoint + dblBlackpoint + chkRed + dblRed + chkBlue + dblBlue + radioFixed + chkFourColorRGB + chkClip + chkProfile + chkCameraColors + bnPreview + radioAutomatic + + +
diff --git a/filters/chalk/tiff/Makefile.am b/filters/chalk/tiff/Makefile.am new file mode 100644 index 00000000..2e120576 --- /dev/null +++ b/filters/chalk/tiff/Makefile.am @@ -0,0 +1,55 @@ +kde_module_LTLIBRARIES = libchalktiffimport.la libchalktiffexport.la + +libchalktiffexport_la_LDFLAGS = -avoid-version -module -no-undefined \ + $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalktiffexport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \ + libchalktiffconverter.la $(KOFFICE_LIBS) -ltiff + +libchalktiffimport_la_LDFLAGS = -avoid-version -module -no-undefined \ + $(KDE_PLUGIN) $(KDE_RPATH) $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalktiffimport_la_LIBADD = $(top_builddir)/chalk/libchalkcommon.la \ + libchalktiffconverter.la $(KOFFICE_LIBS) -ltiff + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + + +servicedir = $(kde_servicesdir) + + +kdelnkdir = $(kde_appsdir)/.hidden + + + + +METASOURCES = AUTO + + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) +libchalktiffimport_la_SOURCES = kis_tiff_import.cc +libchalktiffexport_la_SOURCES = kis_tiff_export.cc kis_wdg_options_tiff.ui \ + kis_dlg_options_tiff.cpp +service_DATA = chalk_tiff_export.desktop chalk_tiff_import.desktop +kdelnk_DATA = chalk_tiff.desktop +noinst_HEADERS = kis_dlg_options_tiff.h kis_tiff_writer_visitor.h \ + kis_tiff_ycbcr_reader.h +libchalktiffconverter_la_LDFLAGS = -no-undefined $(all_libraries) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +noinst_LTLIBRARIES = libchalktiffconverter.la +libchalktiffconverter_la_SOURCES = kis_tiff_converter.cc kis_tiff_stream.cc \ + kis_tiff_writer_visitor.cpp kis_tiff_reader.cc kis_tiff_ycbcr_reader.cc diff --git a/filters/chalk/tiff/chalk_tiff.desktop b/filters/chalk/tiff/chalk_tiff.desktop new file mode 100644 index 00000000..55cd1033 --- /dev/null +++ b/filters/chalk/tiff/chalk_tiff.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +Categories= +Exec=chalk %u +GenericName=Painting and Image Editing Application +GenericName[bg]=Редактор на графични изображения +GenericName[ca]=Programa de dibuix i manipulació d'imatges +GenericName[cs]=Malování a úpravy obrázků +GenericName[cy]=Cymhwysiad Peintio Golygu Delweddau +GenericName[da]=Male- og billedredigeringsprogram +GenericName[de]=Mal- und Bildbearbeitungsprogramm +GenericName[el]=Εφαρμογή επεξεργασίας εικόνων +GenericName[eo]=Aplikaĵo por Pentrado kaj Bildredaktado +GenericName[es]=Aplicación de pintura y de edición de imágenes +GenericName[et]=Joonistamise ja pilditöötluse rakendus +GenericName[eu]=Irudien marrazketa eta ediziorako aplikazioa +GenericName[fa]=کاربرد ویرایش تصویر و نقاشی +GenericName[fi]=Maalaus- ja kuvankäsitelyohjelma +GenericName[fr]=Application de dessin et de manipulation d'images +GenericName[fy]=Ofbyldingsmanipulaasje +GenericName[gl]=Aplicación de Pintura e Manipulación de Imaxes +GenericName[he]=יישום לציור ועריכת תמונות +GenericName[hr]=Aplikacija za obradu slika i fotografija +GenericName[hu]=Képszerkesztő +GenericName[is]=Málun og myndritill +GenericName[it]=Applicazione di disegno e di modifica delle immagini +GenericName[ja]=描画と画像編集のためのアプリケーション +GenericName[km]=កម្មវិធី​គូរ​គំនូរ និង​កែសម្រួល​រូបភាព +GenericName[lv]=Zīmēšanas un attēlu apstrādes programma +GenericName[nb]=Program for tegning og bilderedigering +GenericName[nds]=Programm för't Malen un Bildbewerken +GenericName[ne]=पेन्टीङ्ग र छवि सम्पादन अनुप्रयोग +GenericName[nl]=Afbeeldingsmanipulatie +GenericName[pl]=Program do edycji zdjęć oraz rysunków +GenericName[pt]=Aplicação de Pintura e Edição de Imagens +GenericName[pt_BR]=Aplicação de Pintura e Edição de Imagens +GenericName[ru]=Растровые изображения +GenericName[se]=Málen- ja govvagieđahallanprográmma +GenericName[sk]=Program pre tvorbu a úpravu obrázkov +GenericName[sl]=Program za risanje in obdelavo slik +GenericName[sr]=Програм за цртање и уређивање слика +GenericName[sr@Latn]=Program za crtanje i uređivanje slika +GenericName[sv]=Målnings- och bildredigeringsprogram +GenericName[uk]=Програма для малювання і редагування зображень +GenericName[uz]=Rasmlar bilan ishlaydigan dastur +GenericName[uz@cyrillic]=Расмлар билан ишлайдиган дастур +GenericName[zh_CN]=绘图和图像编辑应用程序 +GenericName[zh_TW]=繪圖與影像處理程式 +Icon=chalk +MimeType=image/tiff +Name=Chalk +Name[hi]=के-रिता +Name[km]= Chalk +Name[lo]=ກຣິຕາ +Name[ne]=क्रिता +Path= +StartupNotify=true +Terminal=false +TerminalOptions= +Type=Application +X-DCOP-ServiceType=multi +X-KDE-StartupNotify=true +X-KDE-SubstituteUID=false +X-KDE-Username= diff --git a/filters/chalk/tiff/chalk_tiff_export.desktop b/filters/chalk/tiff/chalk_tiff_export.desktop new file mode 100644 index 00000000..3f174827 --- /dev/null +++ b/filters/chalk/tiff/chalk_tiff_export.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Icon= +Name=Chalk TIFF Export Filter +Name[bg]=Филтър за експортиране от Chalk в TIFF +Name[br]=Sil ezporzh TIFF evit Chalk +Name[ca]=Filtre d'exportació TIFF per a Chalk +Name[da]=Chalk TIFF-eksportfilter +Name[de]=Chalk TIFF-Exportfilter +Name[el]=Φίλτρο εξαγωγής TIFF του Chalk +Name[eo]=Chalk TIFF-eksportfiltrilo +Name[es]=Filtro de exportación a TIFF de Chalk +Name[et]=Chalk TIFF-i ekspordifilter +Name[fa]=پالایۀ صادرات Chalk TIFF +Name[fi]=Chalk TIFF -vientisuodin +Name[fr]=Filtre d'exportation TIFF de Chalk +Name[fy]=Chalk TIFF Eksportfilter +Name[ga]=Scagaire Easpórtála TIFF Chalk +Name[gl]=Filtro de Exportación de TIFF para Chalk +Name[he]=Chalk TIFF מסנן יצוא +Name[hr]=Chalk TIFF filtar izvoza +Name[hu]=Chalk TIFF exportszűrő +Name[is]=Chalk TIFF útflutningssía +Name[it]=Filtro di esportazione TIFF per Chalk +Name[ja]=Chalk TIFF エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ TIFF សម្រាប់ Chalk +Name[lt]=Chalk TIFF eksportavimo filtras +Name[lv]=Chalk TIFF eksporta filtrs +Name[nb]=TIFF-eksportfilter for Chalk +Name[nds]=TIFF-Exportfilter för Chalk +Name[ne]=क्रिता TIFF निर्यात फिल्टर +Name[nl]=Chalk TIFF Exportfilter +Name[pl]=Filtr eksportu do formatu TIFF dla Chalk +Name[pt]=Filtro de Exportação de TIFF para o Chalk +Name[pt_BR]=Filtro de Exportação de TIFF para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в TIFF +Name[se]=Chalk Tiff-olggosfievrridansilli +Name[sk]=Exportný filter Chalk TIFF +Name[sl]=Izvozni filter TIFF za Krito +Name[sr]=Chalk-ин филтер за извоз у TIFF +Name[sr@Latn]=Chalk-in filter za izvoz u TIFF +Name[sv]=Chalk TIFF-exportfilter +Name[uk]=Фільтр експорту TIFF для Chalk +Name[uz]=Chalk TIFF eksport filteri +Name[uz@cyrillic]=Chalk TIFF экспорт филтери +Name[zh_CN]=Chalk TIFF 导出过滤器 +Name[zh_TW]=Chalk TIFF 匯出過濾程式 +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Export=image/tiff +X-KDE-Import=application/x-chalk +X-KDE-Library=libchalktiffexport +X-KDE-Weight=1 diff --git a/filters/chalk/tiff/chalk_tiff_import.desktop b/filters/chalk/tiff/chalk_tiff_import.desktop new file mode 100644 index 00000000..593b0eee --- /dev/null +++ b/filters/chalk/tiff/chalk_tiff_import.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Icon= +Name=Chalk TIFF Import Filter +Name[bg]=Филтър за импортиране от TIFF в Chalk +Name[br]=Sil enporzh TIFF evit Chalk +Name[ca]=Filtre d'importació TIFF per a Chalk +Name[da]=Chalk TIFF-importfilter +Name[de]=Chalk TIFF-Importfilter +Name[el]=Φίλτρο εισαγωγής TIFF του Chalk +Name[eo]=Chalk TIFF-importfiltrilo +Name[es]=Filtro de importación desde TIFF de Chalk +Name[et]=Chalk TIFF-i impordifilter +Name[fa]=پالایۀ واردات Chalk TIFF +Name[fi]=Chalk TIFF -tuontisuodin +Name[fr]=Filtre d'importation TIFF de Chalk +Name[fy]=Chalk TIFF Ymportfilter +Name[ga]=Scagaire Iompórtála TIFF Chalk +Name[gl]=Filtro de Importación de TIFF para Chalk +Name[he]=Chalk TIFF מסנן יבוא +Name[hr]=Chalk TIFF filtar uvoza +Name[hu]=Chalk TIFF importszűrő +Name[is]=Chalk TIFF innflutningssía +Name[it]=Filtro di importazione TIFF per Chalk +Name[ja]=Chalk TIFF インポートフィルタ +Name[km]=តម្រង​នាំចូល TIFF សម្រាប់ Chalk +Name[lt]=Chalk TIFF importavimo filtras +Name[lv]=Chalk TIFF importa filtrs +Name[nb]=TIFF-importfilter for Chalk +Name[nds]=TIFF-Importfilter för Chalk +Name[ne]=क्रिता TIFF आयात फिल्टर +Name[nl]=Chalk TIFF Importfilter +Name[pl]=Filtr importu formatu TIFF dla Chalk +Name[pt]=Filtro de Importação de TIFF para o Chalk +Name[pt_BR]=Filtro de Importação de TIFF para o Chalk +Name[ru]=Фильтр импорта рисунков TIFF в Chalk +Name[se]=Chalk TIFF-sisafievrridansilli +Name[sk]=TIFF filter pre import do Chalk +Name[sl]=Uvozni filter TIFF za Krito +Name[sr]=Chalk-ин филтер за увоз из TIFF-а +Name[sr@Latn]=Chalk-in filter za uvoz iz TIFF-a +Name[sv]=Chalk TIFF-importfilter +Name[uk]=Фільтр імпорту TIFF для Chalk +Name[uz]=Chalk TIFF import filteri +Name[uz@cyrillic]=Chalk TIFF импорт филтери +Name[zh_CN]=Chalk TIFF 导入过滤器 +Name[zh_TW]=Chalk TIFF 匯入過濾程式 +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Export=application/x-chalk +X-KDE-Import=image/tiff +X-KDE-Library=libchalktiffimport +X-KDE-Weight=1 diff --git a/filters/chalk/tiff/configure.in.bot b/filters/chalk/tiff/configure.in.bot new file mode 100644 index 00000000..8458154d --- /dev/null +++ b/filters/chalk/tiff/configure.in.bot @@ -0,0 +1,7 @@ +if test -z "$LIBTIFF"; then + echo "" + echo "You're missing libtiff (binaries and/or headers), chalk won't be able" + echo "to import/export tiff" + echo "" + all_tests=bad +fi diff --git a/filters/chalk/tiff/kis_dlg_options_tiff.cpp b/filters/chalk/tiff/kis_dlg_options_tiff.cpp new file mode 100644 index 00000000..345f7e7e --- /dev/null +++ b/filters/chalk/tiff/kis_dlg_options_tiff.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_dlg_options_tiff.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "kis_wdg_options_tiff.h" + +KisDlgOptionsTIFF::KisDlgOptionsTIFF(TQWidget *tqparent, const char *name) + : KDialogBase(tqparent, name, false, i18n("TIFF Export Options"), KDialogBase::Ok | KDialogBase::Cancel) +{ + optionswdg = new KisWdgOptionsTIFF(this); + activated(0); + connect(optionswdg->kComboBoxCompressionType, TQT_SIGNAL(activated ( int )), this, TQT_SLOT(activated ( int ) )); + connect(optionswdg->flatten, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(flattenToggled( bool) ) ); + setMainWidget(optionswdg); + kapp->restoreOverrideCursor(); + tqsetSizePolicy(TQSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::Minimum) ); +} + +KisDlgOptionsTIFF::~KisDlgOptionsTIFF() +{ +} + +void KisDlgOptionsTIFF::activated ( int index ) +{ +/* optionswdg->groupBoxJPEG->hide(); + optionswdg->groupBoxDeflate->hide(); + optionswdg->groupBoxCCITGroupCCITG3->hide(); + optionswdg->groupBoxPixarLog->hide();*/ + switch(index) + { + case 1: + optionswdg->codecsOptionsStack->raiseWidget(1); +// optionswdg->groupBoxJPEG->show(); + break; + case 2: + optionswdg->codecsOptionsStack->raiseWidget(2); +// optionswdg->groupBoxDeflate->show(); + break; + case 6: + optionswdg->codecsOptionsStack->raiseWidget(3); +// optionswdg->groupBoxCCITGroupCCITG3->show(); + break; + case 8: + optionswdg->codecsOptionsStack->raiseWidget(4); +// optionswdg->groupBoxPixarLog->show(); + break; + default: + optionswdg->codecsOptionsStack->raiseWidget(0); + } +} + +void KisDlgOptionsTIFF::flattenToggled(bool t) +{ + optionswdg->alpha->setEnabled(t); + if(!t) + { + optionswdg->alpha->setChecked(true); + } +} + + +KisTIFFOptions KisDlgOptionsTIFF::options() +{ + KisTIFFOptions options; + switch(optionswdg->kComboBoxCompressionType->currentItem ()) + { + case 0: + options.compressionType = COMPRESSION_NONE; + break; + case 1: + options.compressionType = COMPRESSION_JPEG; + break; + case 2: + options.compressionType = COMPRESSION_DEFLATE; + break; + case 3: + options.compressionType = COMPRESSION_LZW; + break; +#ifdef COMPRESSION_JP2000 + case 4: + options.compressionType = COMPRESSION_JP2000; + break; +#endif + case 5: + options.compressionType = COMPRESSION_CCITTRLE; + break; + case 6: + options.compressionType = COMPRESSION_CCITTFAX3; + break; + case 7: + options.compressionType = COMPRESSION_CCITTFAX4; + break; + case 8: + options.compressionType = COMPRESSION_PIXARLOG; + break; + } + options.predictor = optionswdg->kComboBoxPredictor->currentItem() + 1; + options.alpha = optionswdg->alpha->isChecked(); + options.flatten = optionswdg->flatten->isChecked(); + options.jpegQuality = optionswdg->qualityLevel->value(); + options.deflateCompress = optionswdg->compressionLevelDeflate->value(); + options.faxMode = optionswdg->kComboBoxFaxMode->currentItem() + 1; + options.pixarLogCompress = optionswdg->compressionLevelPixarLog->value(); + + return options; +} + +#include "kis_dlg_options_tiff.moc" diff --git a/filters/chalk/tiff/kis_dlg_options_tiff.h b/filters/chalk/tiff/kis_dlg_options_tiff.h new file mode 100644 index 00000000..5fd1e48e --- /dev/null +++ b/filters/chalk/tiff/kis_dlg_options_tiff.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_DLG_OPTIONS_TIFF_H +#define KIS_DLG_OPTIONS_TIFF_H + +#include +#include + +class KisWdgOptionsTIFF; +/** + @author Cyrille Berger +*/ +class KisDlgOptionsTIFF : public KDialogBase +{ + Q_OBJECT + TQ_OBJECT + public: + KisDlgOptionsTIFF(TQWidget *tqparent=0, const char *name=0); + ~KisDlgOptionsTIFF(); + public slots: + void activated ( int index ); + void flattenToggled(bool); + KisTIFFOptions options(); + public: + KisWdgOptionsTIFF* optionswdg; +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_converter.cc b/filters/chalk/tiff/kis_tiff_converter.cc new file mode 100644 index 00000000..09a0ba99 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_converter.cc @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_converter.h" + +#include + +#include +#include LCMS_HEADER + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kis_tiff_reader.h" +#include "kis_tiff_ycbcr_reader.h" +#include "kis_tiff_stream.h" +#include "kis_tiff_writer_visitor.h" + +namespace { + + TQString getColorSpaceForColorType(uint16 color_type, uint16 color_nb_bits, TIFF *image, uint16 &nbchannels, uint16 &extrasamplescount, uint8 &destDepth, uint16 sampletype) { + if(color_type == PHOTOMETRIC_MINISWHITE || color_type == PHOTOMETRIC_MINISBLACK) + { + if(nbchannels == 0) nbchannels = 1; + extrasamplescount = nbchannels - 1; // FIX the extrasamples count in case of + if(color_nb_bits <= 8) + { + destDepth = 8; + return "GRAYA"; + } else { + destDepth = 16; + return "GRAYA16"; + } + } else if(color_type == PHOTOMETRIC_RGB /*|| color_type == */ ) { + if(nbchannels == 0) nbchannels = 3; + extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of + if(sampletype == SAMPLEFORMAT_IEEEFP) + { + if(color_nb_bits == 16) + { + destDepth = 16; + return "RGBAF16HALF"; + } else if( color_nb_bits == 32) { + destDepth = 32; + return "RGBAF32"; + } + return ""; + } else { + if(color_nb_bits <= 8) + { + destDepth = 8; + return "RGBA"; + } else { + destDepth = 16; + return "RGBA16"; + } + } + } else if(color_type == PHOTOMETRIC_YCBCR ) { + if(nbchannels == 0) nbchannels = 3; + extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of + if(color_nb_bits <= 8) + { + destDepth = 8; + return "YCbCrAU8"; + } else { + destDepth = 16; + return "YCbCrAU16"; + } + } else if(color_type == PHOTOMETRIC_SEPARATED ) { + if(nbchannels == 0) nbchannels = 4; + // SEPARATED is in general CMYK but not allways, so we check + uint16 inkset; + if((TIFFGetField(image, TIFFTAG_INKSET, &inkset) == 0)){ + kdDebug(41008) << "Image does not define the inkset." << endl; + inkset = 2; + } + if(inkset != INKSET_CMYK) + { + kdDebug(41008) << "Unsupported inkset (right now, only CMYK is supported)" << endl; + char** ink_names; + uint16 numberofinks; + if( TIFFGetField(image, TIFFTAG_INKNAMES, &ink_names) && TIFFGetField(image, TIFFTAG_NUMBEROFINKS, &numberofinks) ) + { + kdDebug(41008) << "Inks are : " << endl; + for(uint i = 0; i < numberofinks; i++) + { + kdDebug(41008) << ink_names[i] << endl; + } + } else { + kdDebug(41008) << "inknames aren't defined !" << endl; + // To be able to read stupid adobe files, if there are no information about inks and four channels, then it's a CMYK file : + if( nbchannels - extrasamplescount != 4) + { + return ""; + } + } + } + if(color_nb_bits <= 8) + { + destDepth = 8; + return "CMYK"; + } else { + destDepth = 16; + return "CMYKA16"; + } + } else if(color_type == PHOTOMETRIC_CIELAB +#ifdef PHOTOMETRIC_ICCLAB + || color_type == PHOTOMETRIC_ICCLAB +#endif + ) { + destDepth = 16; + if(nbchannels == 0) nbchannels = 3; + extrasamplescount = nbchannels - 3; // FIX the extrasamples count in case of + return "LABA"; // TODO add support for a 8bit LAB colorspace when it is written + } else if(color_type == PHOTOMETRIC_PALETTE) { + destDepth = 16; + if(nbchannels == 0) nbchannels = 2; + extrasamplescount = nbchannels - 2; // FIX the extrasamples count in case of + // <-- we will convert the index image to RGBA16 as the palette is allways on 16bits colors + return "RGBA16"; + } + return ""; + } +} + +KisTIFFConverter::KisTIFFConverter(KisDoc *doc, KisUndoAdapter *adapter) +{ + m_doc = doc; + m_adapter = adapter; + m_job = 0; + m_stop = false; +} + +KisTIFFConverter::~KisTIFFConverter() +{ +} + +KisImageBuilder_Result KisTIFFConverter::decode(const KURL& uri) +{ + kdDebug(41008) << "Start decoding TIFF File" << endl; + // Opent the TIFF file + TIFF *image = 0; + if((image = TIFFOpen(TQFile::encodeName(uri.path()), "r")) == NULL){ + kdDebug(41008) << "Could not open the file, either it doesn't exist, either it is not a TIFF : " << uri.path() << endl; + + return (KisImageBuilder_RESULT_BAD_FETCH); + } + do { + kdDebug(41008) << "Read new sub-image" << endl; + KisImageBuilder_Result result = readTIFFDirectory(image); + if(result != KisImageBuilder_RESULT_OK){ + return result; + } + } while (TIFFReadDirectory(image)); + // Freeing memory + TIFFClose(image); + return KisImageBuilder_RESULT_OK; +} + +KisImageBuilder_Result KisTIFFConverter::readTIFFDirectory( TIFF* image) +{ + // Read information about the tiff + uint32 width, height; + if(TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width) == 0){ + kdDebug(41008) << "Image does not define its width" << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_INVALID_ARG; + } + if(TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height) == 0){ + kdDebug(41008) << "Image does not define its height" << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_INVALID_ARG; + } + uint16 depth; + if((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &depth) == 0)){ + kdDebug(41008) << "Image does not define its depth" << endl; + depth = 1; + } + uint16 sampletype; + if((TIFFGetField(image, TIFFTAG_SAMPLEFORMAT, &sampletype) == 0)){ + kdDebug(41008) << "Image does not define its sample type" << endl; + sampletype = SAMPLEFORMAT_UINT; + } + // Determine the number of channels (usefull to know if a file has an alpha or not + uint16 nbchannels; + if(TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &nbchannels) == 0){ + kdDebug(41008) << "Image has an undefined number of samples per pixel" << endl; + nbchannels = 0; + } + // Get the number of extrasamples and information about them + uint16 *sampleinfo, extrasamplescount; + if(TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extrasamplescount, &sampleinfo) == 0) + { + extrasamplescount = 0; + } + // Determine the colorspace + uint16 color_type; + if(TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &color_type) == 0){ + kdDebug(41008) << "Image has an undefined photometric interpretation" << endl; + color_type = PHOTOMETRIC_MINISWHITE; + } + uint8 dstDepth; + TQString csName = getColorSpaceForColorType(color_type, depth, image, nbchannels, extrasamplescount, dstDepth,sampletype); + if(csName.isEmpty()) { + kdDebug(41008) << "Image has an unsupported colorspace : " << color_type << " for this depth : "<< depth << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + kdDebug(41008) << "Colorspace is : " << csName << " with a depth of " << depth << " and with a nb of channels of " << nbchannels << endl; + + // Read image profile + kdDebug() << "Reading profile" << endl; + KisProfile* profile = 0; + DWORD EmbedLen; + LPBYTE EmbedBuffer; + + if (TIFFGetField(image, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer)) { + kdDebug(41008) << "Profile found" << endl; + TQByteArray rawdata; + rawdata.resize(EmbedLen); + memcpy(rawdata.data(), EmbedBuffer, EmbedLen); + profile = new KisProfile(rawdata); + } else { + kdDebug(41008) << "No Profile found" << endl; + } + + // Retrieve a pointer to the colorspace + KisColorSpace* cs = 0; + if (profile && profile->isSuitableForOutput()) + { + kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n"; + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile); + } + else + cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),""); + + if(cs == 0) { + kdDebug(41008) << "Colorspace " << csName << " is not available, please check your installation." << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; + } + + // Create the cmsTransform if needed + cmsHTRANSFORM transform = 0; + if(profile && !profile->isSuitableForOutput()) + { + kdDebug(41008) << "The profile can't be used in chalk, need conversion" << endl; + transform = cmsCreateTransform(profile->profile(), cs->colorSpaceType(), + cs->getProfile()->profile() , cs->colorSpaceType(), + INTENT_PERCEPTUAL, 0); + } + + + // Check if there is an alpha channel + int8 alphapos = -1; // <- no alpha + // Check which extra is alpha if any + kdDebug(41008) << "There are " << nbchannels << " channels and " << extrasamplescount << " extra channels" << endl; + if(sampleinfo) // index images don't have any sampleinfo, and therefor sampleinfo == 0 + { + for(int i = 0; i < extrasamplescount; i ++) + { + kdDebug(41008) << i << " " << extrasamplescount << " " << (cs->nColorChannels()) << nbchannels << " " << sampleinfo[i] << endl; + if(sampleinfo[i] == EXTRASAMPLE_ASSOCALPHA) + { + // XXX: dangelo: the color values are already multiplied with + // the alpha value. This needs to be reversed later (postprocessor?) + alphapos = i; + } + + if (sampleinfo[i] == EXTRASAMPLE_UNASSALPHA) + { + // color values are not premultiplied with alpha, and can be used as they are. + alphapos = i; + } + } + } + + // Read META Information + KoDocumentInfo * info = m_doc->documentInfo(); + KoDocumentInfoAbout * aboutPage = static_cast(info->page( "about" )); + KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author")); + char* text; + if (TIFFGetField(image, TIFFTAG_ARTIST, &text)) { + authorPage->setFullName(text); + } + if (TIFFGetField(image, TIFFTAG_DOCUMENTNAME, &text)) { + aboutPage->setTitle(text); + } + if (TIFFGetField(image,TIFFTAG_IMAGEDESCRIPTION,&text) ) { + aboutPage->setAbstract( text ); + } + + + // Get the planar configuration + uint16 planarconfig; + if(TIFFGetField(image, TIFFTAG_PLANARCONFIG, &planarconfig) == 0) + { + kdDebug(41008) << "Plannar configuration is not define" << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_INVALID_ARG; + } + // Creating the KisImageSP + if( ! m_img ) { + m_img = new KisImage(m_doc->undoAdapter(), width, height, cs, "built image"); + Q_CHECK_PTR(m_img); + m_img->blockSignals(true); // Don't send out signals while we're building the image + if(profile) + { + m_img -> addAnnotation( profile->annotation() ); + } + } else { + if( m_img->width() < (TQ_INT32)width || m_img->height() < (TQ_INT32)height) + { + TQ_UINT32 newwidth = (m_img->width() < (TQ_INT32)width) ? width : m_img->width(); + TQ_UINT32 newheight = (m_img->height() < (TQ_INT32)height) ? height : m_img->height(); + m_img->resize(newwidth, newheight, false); + } + } + KisPaintLayer* layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), TQ_UINT8_MAX); + tdata_t buf = 0; + tdata_t* ps_buf = 0; // used only for planar configuration seperated + TIFFStreamBase* tiffstream; + + KisTIFFReaderBase* tiffReader = 0; + + TQ_UINT8 poses[5]; + KisTIFFPostProcessor* postprocessor = 0; + + // Configure poses + uint8 nbcolorsamples = nbchannels - extrasamplescount; + switch(color_type) + { + case PHOTOMETRIC_MINISWHITE: + { + poses[0] = 0; poses[1] = 1; + postprocessor = new KisTIFFPostProcessorInvert(nbcolorsamples); + } + break; + case PHOTOMETRIC_MINISBLACK: + { + poses[0] = 0; poses[1] = 1; + postprocessor = new KisTIFFPostProcessor(nbcolorsamples); + } + break; + case PHOTOMETRIC_CIELAB: + { + poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3; + postprocessor = new KisTIFFPostProcessorICCLABtoCIELAB(nbcolorsamples); + } + break; +#ifdef PHOTOMETRIC_ICCLAB + case PHOTOMETRIC_ICCLAB: + { + poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3; + postprocessor = new KisTIFFPostProcessor(nbcolorsamples); + } + break; +#endif + case PHOTOMETRIC_RGB: + { + poses[0] = 2; poses[1] = 1; poses[2] = 0; poses[3] = 3; + postprocessor = new KisTIFFPostProcessor(nbcolorsamples); + } + break; + case PHOTOMETRIC_SEPARATED: + { + poses[0] = 0; poses[1] = 1; poses[2] = 2; poses[3] = 3; poses[4] = 4; + postprocessor = new KisTIFFPostProcessor(nbcolorsamples); + } + break; + default: + break; + } + + + // Initisalize tiffReader + uint16 * lineSizeCoeffs = new uint16[nbchannels]; + uint16 vsubsampling = 1; + uint16 hsubsampling = 1; + for(uint i = 0; i < nbchannels; i++) + { + lineSizeCoeffs[i] = 1; + } + if( color_type == PHOTOMETRIC_PALETTE) + { + uint16 *red; // No need to free them they are free by libtiff + uint16 *green; + uint16 *blue; + if ((TIFFGetField(image, TIFFTAG_COLORMAP, &red, &green, &blue)) == 0) + { + kdDebug(41008) << "Indexed image does not define a palette" << endl; + TIFFClose(image); + return KisImageBuilder_RESULT_INVALID_ARG; + } + + tiffReader = new KisTIFFReaderFromPalette( layer->paintDevice(), red, green, blue, poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor); + } else if(color_type == PHOTOMETRIC_YCBCR ) { + TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRSUBSAMPLING, &hsubsampling, &vsubsampling ); + lineSizeCoeffs[1] = hsubsampling; + lineSizeCoeffs[2] = hsubsampling; + uint16 position; + TIFFGetFieldDefaulted( image, TIFFTAG_YCBCRPOSITIONING, &position ); + if( dstDepth == 8 ) + { + tiffReader = new KisTIFFYCbCrReaderTarget8Bit(layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position); + } else if( dstDepth == 16 ) + { + tiffReader = new KisTIFFYCbCrReaderTarget16Bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor, hsubsampling, vsubsampling, (KisTIFFYCbCr::Position)position); + } + } else if(dstDepth == 8) + { + tiffReader = new KisTIFFReaderTarget8bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor); + } else if(dstDepth == 16) { + tiffReader = new KisTIFFReaderTarget16bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor); + } else if(dstDepth == 32) { + tiffReader = new KisTIFFReaderTarget32bit( layer->paintDevice(), poses, alphapos, depth, nbcolorsamples, extrasamplescount, transform, postprocessor); + } + + if(TIFFIsTiled(image)) + { + kdDebug(41008) << "tiled image" << endl; + uint32 tileWidth, tileHeight; + uint32 x, y; + TIFFGetField(image, TIFFTAG_TILEWIDTH, &tileWidth); + TIFFGetField(image, TIFFTAG_TILELENGTH, &tileHeight); + uint32 linewidth = (tileWidth * depth * nbchannels) / 8; + if(planarconfig == PLANARCONFIG_CONTIG) + { + buf = _TIFFmalloc(TIFFTileSize(image)); + if(depth < 16) + { + tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, linewidth); + } else if(depth < 32) + { + tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, linewidth); + } else { + tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, linewidth); + } + } else { + ps_buf = new tdata_t[nbchannels]; + uint32 * lineSizes = new uint32[nbchannels]; + uint16 baseSize = TIFFTileSize(image)/nbchannels; + for(uint i = 0; i < nbchannels; i++) + { + ps_buf[i] = _TIFFmalloc(baseSize); + lineSizes[i] = baseSize / lineSizeCoeffs[i]; + } + tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes); + delete [] lineSizes; + } + kdDebug(41008) << linewidth << " " << nbchannels << " " << layer->paintDevice()->colorSpace()->nColorChannels() << endl; + for (y = 0; y < height; y+= tileHeight) + { + for (x = 0; x < width; x += tileWidth) + { + kdDebug(41008) << "Reading tile x = " << x << " y = " << y << endl; + if( planarconfig == PLANARCONFIG_CONTIG ) + { + TIFFReadTile(image, buf, x, y, 0, (tsample_t) -1); + } else { + for(uint i = 0; i < nbchannels; i++) + { + TIFFReadTile(image, ps_buf[i], x, y, 0, i); + } + } + uint32 realTileWidth = (x + tileWidth) < width ? tileWidth : width - x; + for (uint yintile = 0; y + yintile < height && yintile < tileHeight/vsubsampling; ) { + tiffReader->copyDataToChannels( x, y + yintile , realTileWidth, tiffstream); + yintile += 1; + tiffstream->moveToLine( yintile ); + } + tiffstream->restart(); + } + } + } else { + kdDebug(41008) << "striped image" << endl; + tsize_t stripsize = TIFFStripSize(image); + uint32 rowsPerStrip; + TIFFGetFieldDefaulted(image, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip); + kdDebug() << rowsPerStrip << " " << height << endl; + rowsPerStrip = TQMIN(rowsPerStrip, height); // when TIFFNumberOfStrips(image) == 1 it might happen that rowsPerStrip is incorrectly set + if(planarconfig == PLANARCONFIG_CONTIG) + { + buf = _TIFFmalloc(stripsize); + if(depth < 16) + { + tiffstream = new TIFFStreamContigBelow16((uint8*)buf, depth, stripsize/rowsPerStrip); + } else if(depth < 32) + { + tiffstream = new TIFFStreamContigBelow32((uint8*)buf, depth, stripsize/rowsPerStrip); + } else { + tiffstream = new TIFFStreamContigAbove32((uint8*)buf, depth, stripsize/rowsPerStrip); + } + } else { + ps_buf = new tdata_t[nbchannels]; + uint32 scanLineSize = stripsize/rowsPerStrip; + kdDebug(41008) << " scanLineSize for each plan = " << scanLineSize << endl; + uint32 * lineSizes = new uint32[nbchannels]; + for(uint i = 0; i < nbchannels; i++) + { + ps_buf[i] = _TIFFmalloc(stripsize); + lineSizes[i] = scanLineSize / lineSizeCoeffs[i]; + } + tiffstream = new TIFFStreamSeperate( (uint8**) ps_buf, nbchannels, depth, lineSizes); + delete [] lineSizes; + } + + kdDebug(41008) << "Scanline size = " << TIFFRasterScanlineSize(image) << " / strip size = " << TIFFStripSize(image) << " / rowsPerStrip = " << rowsPerStrip << " stripsize/rowsPerStrip = " << stripsize/rowsPerStrip << endl; + uint32 y = 0; + kdDebug(41008) << " NbOfStrips = " << TIFFNumberOfStrips(image) << " rowsPerStrip = " << rowsPerStrip << " stripsize = " << stripsize << endl; + for (uint32 strip = 0; y < height; strip++) + { + if( planarconfig == PLANARCONFIG_CONTIG ) + { + TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, 0 ) , buf, (tsize_t) -1); + } else { + for(uint i = 0; i < nbchannels; i++) + { + TIFFReadEncodedStrip(image, TIFFComputeStrip( image, y, i ), ps_buf[i], (tsize_t) -1); + } + } + for( uint32 yinstrip = 0 ; yinstrip < rowsPerStrip && y < height ; ) + { + uint linesread = tiffReader->copyDataToChannels( 0, y, width, tiffstream); + y += linesread; + yinstrip += linesread; + tiffstream->moveToLine( yinstrip ); + } + tiffstream->restart(); + } + } + tiffReader->finalize(); + delete lineSizeCoeffs; + delete tiffReader; + delete tiffstream; + if( planarconfig == PLANARCONFIG_CONTIG ) + { + _TIFFfree(buf); + } else { + for(uint i = 0; i < nbchannels; i++) + { + _TIFFfree(ps_buf[i]); + } + delete[] ps_buf; + } + + m_img->addLayer(layer, m_img->rootLayer(), 0); + return KisImageBuilder_RESULT_OK; +} + +KisImageBuilder_Result KisTIFFConverter::buildImage(const KURL& uri) +{ + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!KIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) { + return KisImageBuilder_RESULT_NOT_EXIST; + } + + // We're not set up to handle asynchronous loading at the moment. + KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE; + TQString tmpFile; + + if (KIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) { + KURL uriTF; + uriTF.setPath( tmpFile ); + result = decode(uriTF); + KIO::NetAccess::removeTempFile(tmpFile); + } + + return result; +} + + +KisImageSP KisTIFFConverter::image() +{ + return m_img; +} + + +KisImageBuilder_Result KisTIFFConverter::buildFile(const KURL& uri, KisImageSP img, KisTIFFOptions options) +{ + kdDebug(41008) << "Start writing TIFF File" << endl; + if (!img) + return KisImageBuilder_RESULT_EMPTY; + + if (uri.isEmpty()) + return KisImageBuilder_RESULT_NO_URI; + + if (!uri.isLocalFile()) + return KisImageBuilder_RESULT_NOT_LOCAL; + + // Open file for writing + TIFF *image; + if((image = TIFFOpen(TQFile::encodeName(uri.path()), "w")) == NULL){ + kdDebug(41008) << "Could not open the file for writting " << uri.path() << endl; + TIFFClose(image); + return (KisImageBuilder_RESULT_FAILURE); + } + + // Set the document informations + KoDocumentInfo * info = m_doc->documentInfo(); + KoDocumentInfoAbout * aboutPage = static_cast(info->page( "about" )); + TQString title = aboutPage->title(); + if(!title.isEmpty()) + { + TIFFSetField(image, TIFFTAG_DOCUMENTNAME, title.ascii()); + } + TQString abstract = aboutPage->abstract(); + if(!abstract.isEmpty()) + { + TIFFSetField(image, TIFFTAG_IMAGEDESCRIPTION, abstract.ascii()); + } + KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author" )); + TQString author = authorPage->fullName(); + if(!author.isEmpty()) + { + TIFFSetField(image, TIFFTAG_ARTIST, author.ascii()); + } + + KisTIFFWriterVisitor* visitor = new KisTIFFWriterVisitor(image, &options); + KisGroupLayer* root = dynamic_cast(img->rootLayer().data()); + if(root == 0) + { + KIO::del(uri); + TIFFClose(image); + return KisImageBuilder_RESULT_FAILURE; + } + if(!visitor->visit( root )) + { + KIO::del(uri); + TIFFClose(image); + return KisImageBuilder_RESULT_FAILURE; + } + + TIFFClose(image); + return KisImageBuilder_RESULT_OK; +} + + +void KisTIFFConverter::cancel() +{ + m_stop = true; +} + +#include "kis_tiff_converter.moc" diff --git a/filters/chalk/tiff/kis_tiff_converter.h b/filters/chalk/tiff/kis_tiff_converter.h new file mode 100644 index 00000000..7d7176b7 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_converter.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TIFF_CONVERTER_H_ +#define _KIS_TIFF_CONVERTER_H_ + +#include +#include + +#include + +#include + +#include + +#include "kis_types.h" +#include "kis_global.h" +#include "kis_annotation.h" +class KisDoc; +class KisUndoAdapter; + +/** + * Image import/export plugins can use these results to report about success or failure. + */ +enum KisImageBuilder_Result { + KisImageBuilder_RESULT_FAILURE = -400, + KisImageBuilder_RESULT_NOT_EXIST = -300, + KisImageBuilder_RESULT_NOT_LOCAL = -200, + KisImageBuilder_RESULT_BAD_FETCH = -100, + KisImageBuilder_RESULT_INVALID_ARG = -50, + KisImageBuilder_RESULT_OK = 0, + KisImageBuilder_RESULT_PROGRESS = 1, + KisImageBuilder_RESULT_EMPTY = 100, + KisImageBuilder_RESULT_BUSY = 150, + KisImageBuilder_RESULT_NO_URI = 200, + KisImageBuilder_RESULT_UNSUPPORTED = 300, + KisImageBuilder_RESULT_INTR = 400, + KisImageBuilder_RESULT_PATH = 500, + KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE = 600 +}; + +struct KisTIFFOptions { + TQ_UINT16 compressionType; + TQ_UINT16 predictor; + bool alpha; + bool flatten; + TQ_UINT16 jpegQuality; + TQ_UINT16 deflateCompress; + TQ_UINT16 faxMode; + TQ_UINT16 pixarLogCompress; +}; + +class KisTIFFConverter : public KisProgressSubject { + Q_OBJECT + TQ_OBJECT + public: + KisTIFFConverter(KisDoc *doc, KisUndoAdapter *adapter); + virtual ~KisTIFFConverter(); + public: + KisImageBuilder_Result buildImage(const KURL& uri); + KisImageBuilder_Result buildFile(const KURL& uri, KisImageSP layer, KisTIFFOptions); + /** Retrieve the constructed image + */ + KisImageSP image(); + public slots: + virtual void cancel(); + private: + KisImageBuilder_Result decode(const KURL& uri); + KisImageBuilder_Result readTIFFDirectory( TIFF* image); + private: + KisImageSP m_img; + KisDoc *m_doc; + KisUndoAdapter *m_adapter; + bool m_stop; + KIO::TransferJob *m_job; +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_export.cc b/filters/chalk/tiff/kis_tiff_export.cc new file mode 100644 index 00000000..bcd3f22e --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_export.cc @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_export.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "kis_tiff_converter.h" +#include "kis_dlg_options_tiff.h" +#include "kis_wdg_options_tiff.h" + +typedef KGenericFactory KisTIFFExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalktiffexport, KisTIFFExportFactory("kofficefilters")) + +KisTIFFExport::KisTIFFExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisTIFFExport::~KisTIFFExport() +{ +} + +KoFilter::ConversiontqStatus KisTIFFExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "Tiff export! From: " << from << ", To: " << to << "\n"; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + + KisDlgOptionsTIFF* kdb = new KisDlgOptionsTIFF(0, "options dialog for tiff"); + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + + KisColorSpace* cs = output->currentImage()->colorSpace(); + KisChannelInfo::enumChannelValueType type = cs->channels()[0]->channelValueType(); + if( type == KisChannelInfo::FLOAT16 || type == KisChannelInfo::FLOAT32) + { + kdb->optionswdg->kComboBoxPredictor->removeItem(1); + } else { + kdb->optionswdg->kComboBoxPredictor->removeItem(2); + } + + if(kdb->exec() == TQDialog::Rejected) + { + return KoFilter::OK; // FIXME Cancel doesn't exist :( + } + + KisTIFFOptions options = kdb->options(); + + if( ( type == KisChannelInfo::FLOAT16 || type == KisChannelInfo::FLOAT32) && options.predictor == 2 ) + { // FIXME THIS IS AN HACK FIX THAT IN 2.0 !! + options.predictor = 3; + } + delete kdb; + + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + KURL url; + url.setPath(filename); + + KisImageSP img; + + if(options.flatten) + { + img = new KisImage(0, output->currentImage()->width(), output->currentImage()->height(), output->currentImage()->colorSpace(), ""); + KisPaintDeviceSP pd = new KisPaintDevice(*output->currentImage()->projection()); + KisPaintLayerSP l = new KisPaintLayer(img, "projection", OPACITY_OPAQUE, pd); + img->addLayer(l.data(), img->rootLayer(), 0); + } else { + img = output->currentImage(); + } + + + KisTIFFConverter ktc(output, output->undoAdapter()); +/* vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations();*/ + KisImageBuilder_Result res; + if ( (res = ktc.buildFile(url, img, options)) == KisImageBuilder_RESULT_OK) { + kdDebug(41008) << "success !" << endl; + return KoFilter::OK; + } + kdDebug(41008) << " Result = " << res << endl; + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/tiff/kis_tiff_export.h b/filters/chalk/tiff/kis_tiff_export.h new file mode 100644 index 00000000..113747c7 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_export.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TIFF_EXPORT_H_ +#define _KIS_TIFF_EXPORT_H_ + +#include + +class KisTIFFExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisTIFFExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisTIFFExport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_import.cc b/filters/chalk/tiff/kis_tiff_import.cc new file mode 100644 index 00000000..89d1763f --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_import.cc @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_import.h" + +#include + +#include + +#include +#include +#include +#include + +#include "kis_tiff_converter.h" + +typedef KGenericFactory TIFFImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalktiffimport, TIFFImportFactory("kofficefilters")) + +KisTIFFImport::KisTIFFImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +KisTIFFImport::~KisTIFFImport() +{ +} + +KoFilter::ConversiontqStatus KisTIFFImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using TIFFImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url; + url.setPath(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisTIFFConverter ib(doc, doc -> undoAdapter()); + + if (view != 0) + view -> canvasSubject() -> progressDisplay() -> setSubject(&ib, false, true); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/tiff/kis_tiff_import.h b/filters/chalk/tiff/kis_tiff_import.h new file mode 100644 index 00000000..9fef7755 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_import.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_TIFF_IMPORT_H_ +#define _KIS_TIFF_IMPORT_H_ + +#include + +class KisTIFFImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + public: + KisTIFFImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~KisTIFFImport(); + public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_reader.cc b/filters/chalk/tiff/kis_tiff_reader.cc new file mode 100644 index 00000000..f2eabd87 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_reader.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_reader.h" + +#include + +#include +#include + +#include "kis_tiff_stream.h" + + uint KisTIFFReaderTarget8bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true); + double coeff = TQ_UINT8_MAX / (double)( pow(2, sourceDepth() ) - 1 ); +// kdDebug(41008) << " depth expension coefficient : " << coeff << endl; + while (!it.isDone()) { + TQ_UINT8 *d = it.rawData(); + TQ_UINT8 i; + for(i = 0; i < nbColorsSamples() ; i++) + { + d[poses()[i]] = (TQ_UINT8)( tiffstream->nextValue() * coeff ); + } + postProcessor()->postProcess8bit( d); + if(transform()) cmsDoTransform(transform(), d, d, 1); + d[poses()[i]] = TQ_UINT8_MAX; + for(int k = 0; k < nbExtraSamples(); k++) + { + if(k == alphaPos()) + d[poses()[i]] = (TQ_UINT32) ( tiffstream->nextValue() * coeff ); + else + tiffstream->nextValue(); + } + ++it; + } + return 1; + } + uint KisTIFFReaderTarget16bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true); + double coeff = TQ_UINT16_MAX / (double)( pow(2, sourceDepth() ) - 1 ); +// kdDebug(41008) << " depth expension coefficient : " << coeff << endl; + while (!it.isDone()) { + TQ_UINT16 *d = reinterpret_cast(it.rawData()); + TQ_UINT8 i; + for(i = 0; i < nbColorsSamples(); i++) + { + d[poses()[i]] = (TQ_UINT16)( tiffstream->nextValue() * coeff ); + } + postProcessor()->postProcess16bit( d); + if(transform()) cmsDoTransform(transform(), d, d, 1); + d[poses()[i]] = TQ_UINT16_MAX; + for(int k = 0; k < nbExtraSamples(); k++) + { + if(k == alphaPos()) + d[poses()[i]] = (TQ_UINT16) ( tiffstream->nextValue() * coeff ); + else + tiffstream->nextValue(); + } + ++it; + } + return 1; + } + + uint KisTIFFReaderTarget32bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true); + double coeff = TQ_UINT32_MAX / (double)( pow(2, sourceDepth() ) - 1 ); +// kdDebug(41008) << " depth expension coefficient : " << coeff << endl; + while (!it.isDone()) { + TQ_UINT32 *d = reinterpret_cast(it.rawData()); + TQ_UINT8 i; + for(i = 0; i < nbColorsSamples(); i++) + { + d[poses()[i]] = (TQ_UINT32)( tiffstream->nextValue() * coeff ); + } + postProcessor()->postProcess32bit( d); + if(transform()) cmsDoTransform(transform(), d, d, 1); + d[poses()[i]] = TQ_UINT32_MAX; + for(int k = 0; k < nbExtraSamples(); k++) + { + if(k == alphaPos()) + d[poses()[i]] = (TQ_UINT32) ( tiffstream->nextValue() * coeff ); + else + tiffstream->nextValue(); + } + ++it; + } + return 1; + } + uint KisTIFFReaderFromPalette::copyDataToChannels(TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x, y, dataWidth, true); + while (!it.isDone()) { + TQ_UINT16* d = reinterpret_cast(it.rawData()); + uint32 index = tiffstream->nextValue(); + d[2] = m_red[index]; + d[1] = m_green[index]; + d[0] = m_blue[index]; + d[3] = TQ_UINT16_MAX; + ++it; + } + return 1; + } diff --git a/filters/chalk/tiff/kis_tiff_reader.h b/filters/chalk/tiff/kis_tiff_reader.h new file mode 100644 index 00000000..2ab573dd --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_reader.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TIFF_READER_H_ +#define _KIS_TIFF_READER_H_ + +// On some platforms, tiffio.h #defines NULL in a bad +// way for C++, as (void *)0 instead of using the correct +// C++ value 0. Include stdio.h first to get the right one. +#include +#include + +// #include +// #include +// #include + +#include + +#include "kis_types.h" +#include "kis_global.h" +// #include "kis_annotation.h" + +#include +#include + +#define TQ_UINT32_MAX 4294967295u + +class TIFFStreamBase; + +class KisTIFFPostProcessor { + public: + KisTIFFPostProcessor(uint8 nbcolorssamples) : m_nbcolorssamples(nbcolorssamples) { } + public: + virtual void postProcess8bit( TQ_UINT8* ) { }; + virtual void postProcess16bit( TQ_UINT16* ) { }; + virtual void postProcess32bit( TQ_UINT32* ) { }; + protected: + inline uint8 nbColorsSamples() { return m_nbcolorssamples; } + private: + uint8 m_nbcolorssamples; +}; + +class KisTIFFPostProcessorInvert : public KisTIFFPostProcessor { + public: + KisTIFFPostProcessorInvert(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {} + public: + virtual void postProcess8bit( TQ_UINT8* data ) + { + for(int i = 0; i < nbColorsSamples(); i++) + { + data[i] = TQ_UINT8_MAX - data[i]; + } + } + virtual void postProcess16bit( TQ_UINT16* data ) + { + TQ_UINT16* d = (TQ_UINT16*) data; + for(int i = 0; i < nbColorsSamples(); i++) + { + d[i] = TQ_UINT16_MAX - d[i]; + } + } + virtual void postProcess32bit( TQ_UINT32* data ) + { + TQ_UINT32* d = (TQ_UINT32*) data; + for(int i = 0; i < nbColorsSamples(); i++) + { + d[i] = TQ_UINT32_MAX - d[i]; + } + } +}; + +class KisTIFFPostProcessorICCLABtoCIELAB : public KisTIFFPostProcessor { + public: + KisTIFFPostProcessorICCLABtoCIELAB(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {} + public: + void postProcess8bit(TQ_UINT8* data) + { + TQ_INT8* ds = (TQ_INT8*) data; + for(int i = 1; i < nbColorsSamples(); i++) + { + ds[i] = data[i] - TQ_UINT8_MAX/2; + } + } + void postProcess16bit(TQ_UINT16* data) + { + TQ_UINT16* d = (TQ_UINT16*) data; + TQ_INT16* ds = (TQ_INT16*) data; + for(int i = 1; i < nbColorsSamples(); i++) + { + ds[i] = d[i] - TQ_UINT16_MAX /2; + } + } + void postProcess32bit(TQ_UINT32* data) + { + TQ_UINT32* d = (TQ_UINT32*) data; + TQ_INT32* ds = (TQ_INT32*) data; + for(int i = 1; i < nbColorsSamples(); i++) + { + ds[i] = d[i] - TQ_UINT32_MAX /2; + } + } +}; + + +class KisTIFFReaderBase { + public: + KisTIFFReaderBase( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : m_device(device), m_alphapos(alphapos), m_sourceDepth(sourceDepth), m_nbcolorssamples(nbcolorssamples), m_nbextrasamples(extrasamplescount), m_poses(poses), m_transformProfile(transformProfile), m_postprocess(postprocessor) + { + + } + public: + /** + * This function copy data from the tiff stream to the paint device starting at the given position. + * @param x horizontal start position + * @param y vertical start position + * @param dataWidth width of the data to copy + * @param tiffstream source of data + * + * @return the number of line which were copied + */ + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) =0; + /** + * This function is called when all data has been read and should be used for any postprocessing. + */ + virtual void finalize() { }; + protected: + inline KisPaintDeviceSP paintDevice() { return m_device; } + inline TQ_UINT8 alphaPos() { return m_alphapos; } + inline TQ_UINT8 sourceDepth() { return m_sourceDepth; } + inline TQ_UINT8 nbColorsSamples() { return m_nbcolorssamples; } + inline TQ_UINT8 nbExtraSamples() { return m_nbextrasamples; } + inline TQ_UINT8* poses() { return m_poses; } + inline cmsHTRANSFORM transform() { return m_transformProfile; } + inline KisTIFFPostProcessor* postProcessor() { return m_postprocess; } + private: + KisPaintDeviceSP m_device; + TQ_UINT8 m_alphapos; + TQ_UINT8 m_sourceDepth; + TQ_UINT8 m_nbcolorssamples; + TQ_UINT8 m_nbextrasamples; + TQ_UINT8* m_poses; + cmsHTRANSFORM m_transformProfile; + KisTIFFPostProcessor* m_postprocess; + TQ_UINT32 m_tiffDataWidth; +}; + +class KisTIFFReaderTarget8bit : public KisTIFFReaderBase { + public: + KisTIFFReaderTarget8bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor ) + { + + } + public: + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream); +}; + + +class KisTIFFReaderTarget16bit : public KisTIFFReaderBase { + public: + KisTIFFReaderTarget16bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor ) + { + + } + public: + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ; +}; + +class KisTIFFReaderTarget32bit : public KisTIFFReaderBase { + public: + KisTIFFReaderTarget32bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor ) + { + + } + public: + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ; +}; + +class KisTIFFReaderFromPalette : public KisTIFFReaderBase { + public: + KisTIFFReaderFromPalette( KisPaintDeviceSP device, uint16 *red, uint16 *green, uint16 *blue, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor ), m_red(red), m_green(green), m_blue(blue) + { + + } + public: + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ; + private: + uint16 *m_red, *m_green, *m_blue; +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_stream.cc b/filters/chalk/tiff/kis_tiff_stream.cc new file mode 100644 index 00000000..3d52d4dc --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_stream.cc @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_stream.h" + +TIFFStreamContigBase::TIFFStreamContigBase( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamBase(depth), m_src(src), m_lineSize(lineSize) { restart(); } + +void TIFFStreamContigBase::restart() +{ + m_srcit = m_src; + m_posinc = 8; +} + +void TIFFStreamContigBase::moveToLine(uint32 lineNumber) +{ + m_srcit = m_src + lineNumber * m_lineSize; + m_posinc = 8; +} + +uint32 TIFFStreamContigBelow16::nextValue() +{ + register uint8 remain; + register uint32 value; + remain = m_depth; + value = 0; + while (remain > 0) + { + register uint8 toread; + toread = remain; + if (toread > m_posinc) toread = m_posinc; + remain -= toread; + m_posinc -= toread; + value = (value << toread) | (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) ); + if (m_posinc == 0) + { + m_srcit++; + m_posinc=8; + } + } + return value; +} + +uint32 TIFFStreamContigBelow32::nextValue() +{ + register uint8 remain; + register uint32 value; + remain = m_depth; + value = 0; + while (remain > 0) + { + register uint8 toread; + toread = remain; + if (toread > m_posinc) toread = m_posinc; + remain -= toread; + m_posinc -= toread; + value = (value) | ( (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) ) << ( m_depth - 8 - remain ) ); + if (m_posinc == 0) + { + m_srcit++; + m_posinc=8; + } + } + return value; +} + +uint32 TIFFStreamContigAbove32::nextValue() +{ + register uint8 remain; + register uint32 value; + remain = m_depth; + value = 0; + while (remain > 0) + { + register uint8 toread; + toread = remain; + if (toread > m_posinc) toread = m_posinc; + remain -= toread; + m_posinc -= toread; + if(remain < 32 ) + { + value = (value) | ( (( (*m_srcit) >> (m_posinc) ) & ( ( 1 << toread ) - 1 ) ) << ( 24 - remain ) ); + } + if (m_posinc == 0) + { + m_srcit++; + m_posinc=8; + } + } + return value; +} + +TIFFStreamSeperate::TIFFStreamSeperate( uint8** srcs, uint8 nb_samples ,uint16 depth, uint32* lineSize) : TIFFStreamBase(depth), m_nb_samples(nb_samples) +{ + streams = new TIFFStreamContigBase*[nb_samples]; + if(depth < 16) + { + for(uint8 i = 0; i < m_nb_samples; i++) + { + streams[i] = new TIFFStreamContigBelow16(srcs[i], depth, lineSize[i]); + } + } else if( depth < 32 ) + { + for(uint8 i = 0; i < m_nb_samples; i++) + { + streams[i] = new TIFFStreamContigBelow32(srcs[i], depth, lineSize[i]); + } + } else { + for(uint8 i = 0; i < m_nb_samples; i++) + { + streams[i] = new TIFFStreamContigAbove32(srcs[i], depth, lineSize[i]); + } + } + restart(); +} + +TIFFStreamSeperate::~TIFFStreamSeperate() +{ + for(uint8 i = 0; i < m_nb_samples; i++) + { + delete streams[i]; + } + delete[] streams; +} + +uint32 TIFFStreamSeperate::nextValue() +{ + uint32 value = streams[ m_current_sample ]->nextValue(); + if( (++m_current_sample) >= m_nb_samples) + m_current_sample = 0; + return value; +} + +void TIFFStreamSeperate::restart() +{ + m_current_sample = 0; + for(uint8 i = 0; i < m_nb_samples; i++) + { + streams[i]->restart(); + } +} + +void TIFFStreamSeperate::moveToLine(uint32 lineNumber) +{ + for(uint8 i = 0; i < m_nb_samples; i++) + { + streams[i]->moveToLine(lineNumber); + } +} diff --git a/filters/chalk/tiff/kis_tiff_stream.h b/filters/chalk/tiff/kis_tiff_stream.h new file mode 100644 index 00000000..f203568e --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_stream.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005-2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef TIFFSTREAM_H_ +#define TIFFSTREAM_H_ + +#include + +class TIFFStreamBase { + public: + TIFFStreamBase( uint16 depth ) : m_depth(depth) {}; + virtual uint32 nextValue() =0; + virtual void restart() =0; + virtual void moveToLine(uint32 lineNumber) =0; + protected: + uint16 m_depth; +}; + +class TIFFStreamContigBase : public TIFFStreamBase { + public: + TIFFStreamContigBase( uint8* src, uint16 depth, uint32 lineSize ); + virtual void restart(); + virtual void moveToLine(uint32 lineNumber); + protected: + uint8* m_src; + uint8* m_srcit; + uint8 m_posinc; + uint32 m_lineSize; +}; + +class TIFFStreamContigBelow16 : public TIFFStreamContigBase { + public: + TIFFStreamContigBelow16( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { } + public: + virtual uint32 nextValue(); +}; + +class TIFFStreamContigBelow32 : public TIFFStreamContigBase { + public: + TIFFStreamContigBelow32( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { } + public: + virtual uint32 nextValue(); +}; + +class TIFFStreamContigAbove32 : public TIFFStreamContigBase { + public: + TIFFStreamContigAbove32( uint8* src, uint16 depth, uint32 lineSize ) : TIFFStreamContigBase(src, depth, lineSize) { } + public: + virtual uint32 nextValue(); +}; + + +class TIFFStreamSeperate : public TIFFStreamBase { + public: + TIFFStreamSeperate( uint8** srcs, uint8 nb_samples ,uint16 depth, uint32* lineSize); + ~TIFFStreamSeperate(); + virtual uint32 nextValue(); + virtual void restart(); + virtual void moveToLine(uint32 lineNumber); + private: + TIFFStreamContigBase** streams; + uint8 m_current_sample, m_nb_samples; +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_writer_visitor.cpp b/filters/chalk/tiff/kis_tiff_writer_visitor.cpp new file mode 100644 index 00000000..681e66b7 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_writer_visitor.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_writer_visitor.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kis_tiff_converter.h" + +namespace { + bool writeColorSpaceInformation( TIFF* image, KisColorSpace * cs, uint16& color_type, uint16& sample_format ) + { + sample_format = SAMPLEFORMAT_UINT; + if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) + { + color_type = PHOTOMETRIC_MINISBLACK; + return true; + } + if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) + { + color_type = PHOTOMETRIC_RGB; + return true; + } + if ( cs->id() == KisID("RGBAF16HALF") || cs->id() == KisID("RGBAF32") ) + { + color_type = PHOTOMETRIC_RGB; + sample_format = SAMPLEFORMAT_IEEEFP; + return true; + } + if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYKA16") ) + { + color_type = PHOTOMETRIC_SEPARATED; + TIFFSetField(image, TIFFTAG_INKSET, INKSET_CMYK); + return true; + } + if ( cs->id() == KisID("LABA") ) + { + color_type = PHOTOMETRIC_CIELAB; + return true; + } + + KMessageBox::error(0, i18n("Cannot export images in %1.\n").tqarg(cs->id().name()) ) ; + return false; + + } +} + +KisTIFFWriterVisitor::KisTIFFWriterVisitor(TIFF*img, KisTIFFOptions* options) : m_image(img), m_options(options) +{ +} + +KisTIFFWriterVisitor::~KisTIFFWriterVisitor() +{ +} + +bool KisTIFFWriterVisitor::saveAlpha() { return m_options->alpha; } + +bool KisTIFFWriterVisitor::copyDataToStrips( KisHLineIterator it, tdata_t buff, uint8 depth, uint8 nbcolorssamples, TQ_UINT8* poses) +{ + if(depth == 32) + { + TQ_UINT32 *dst = reinterpret_cast(buff); + while (!it.isDone()) { + const TQ_UINT32 *d = reinterpret_cast(it.rawData()); + int i; + for(i = 0; i < nbcolorssamples; i++) + { + *(dst++) = d[poses[i]]; + } + if(saveAlpha()) *(dst++) = d[poses[i]]; + ++it; + } + return true; + } else if(depth == 16) + { + TQ_UINT16 *dst = reinterpret_cast(buff); + while (!it.isDone()) { + const TQ_UINT16 *d = reinterpret_cast(it.rawData()); + int i; + for(i = 0; i < nbcolorssamples; i++) + { + *(dst++) = d[poses[i]]; + } + if(saveAlpha()) *(dst++) = d[poses[i]]; + ++it; + } + return true; + } else if(depth == 8) { + TQ_UINT8 *dst = reinterpret_cast(buff); + while (!it.isDone()) { + const TQ_UINT8 *d = it.rawData(); + int i; + for(i = 0; i < nbcolorssamples; i++) + { + *(dst++) = d[poses[i]]; + } + if(saveAlpha()) *(dst++) = d[poses[i]]; + ++it; + } + return true; + } + return false; +} + + +bool KisTIFFWriterVisitor::visit(KisPaintLayer *layer) +{ + kdDebug(41008) << "visiting on paint layer " << layer->name() << "\n"; + KisPaintDeviceSP pd = layer->paintDevice(); + // Save depth + int depth = 8 * pd->pixelSize() / pd->nChannels(); + TIFFSetField(image(), TIFFTAG_BITSPERSAMPLE, depth); + // Save number of samples + if(saveAlpha()) + { + TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels()); + uint16 sampleinfo[1] = { EXTRASAMPLE_UNASSALPHA }; + TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 1, sampleinfo); + } else { + TIFFSetField(image(), TIFFTAG_SAMPLESPERPIXEL, pd->nChannels() - 1); + TIFFSetField(image(), TIFFTAG_EXTRASAMPLES, 0); + } + // Save colorspace information + uint16 color_type; + uint16 sample_format; + if(!writeColorSpaceInformation(image(), pd->colorSpace(), color_type, sample_format)) + { // unsupported colorspace + return false; + } + TIFFSetField(image(), TIFFTAG_PHOTOMETRIC, color_type); + TIFFSetField(image(), TIFFTAG_SAMPLEFORMAT, sample_format); + TIFFSetField(image(), TIFFTAG_IMAGEWIDTH, layer->image()->width()); + TIFFSetField(image(), TIFFTAG_IMAGELENGTH, layer->image()->height()); + + // Set the compression options + TIFFSetField(image(), TIFFTAG_COMPRESSION, m_options->compressionType); + TIFFSetField(image(), TIFFTAG_FAXMODE, m_options->faxMode); + TIFFSetField(image(), TIFFTAG_JPEGQUALITY, m_options->jpegQuality); + TIFFSetField(image(), TIFFTAG_ZIPQUALITY, m_options->deflateCompress); + TIFFSetField(image(), TIFFTAG_PIXARLOGQUALITY, m_options->pixarLogCompress); + + // Set the predictor + TIFFSetField(image(), TIFFTAG_PREDICTOR, m_options->predictor); + + // Use contiguous configuration + TIFFSetField(image(), TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + // Use 8 rows per strip + TIFFSetField(image(), TIFFTAG_ROWSPERSTRIP, 8); + + // Save profile + KisProfile* profile = pd->colorSpace()->getProfile(); + if(profile) + { + TQByteArray ba = profile->annotation()->annotation(); + TIFFSetField(image(), TIFFTAG_ICCPROFILE, ba.size(),ba.data()); + } + tsize_t stripsize = TIFFStripSize(image()); + tdata_t buff = _TIFFmalloc(stripsize); + TQ_INT32 height = layer->image()->height(); + TQ_INT32 width = layer->image()->width(); + bool r = true; + for (int y = 0; y < height; y++) { + KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false); + switch(color_type) + { + case PHOTOMETRIC_MINISBLACK: + { + TQ_UINT8 poses[]={ 0,1 }; + r = copyDataToStrips(it, buff, depth, 1, poses); + } + break; + case PHOTOMETRIC_RGB: + { + TQ_UINT8 poses[]={ 2, 1, 0, 3}; + r = copyDataToStrips(it, buff, depth, 3, poses); + } + break; + case PHOTOMETRIC_SEPARATED: + { + TQ_UINT8 poses[]={ 0, 1, 2, 3, 4 }; + r = copyDataToStrips(it, buff, depth, 4, poses); + } + break; + case PHOTOMETRIC_CIELAB: + { + TQ_UINT8 poses[]={ 0, 1, 2, 3 }; + r = copyDataToStrips(it, buff, depth, 3, poses); + } + break; + return false; + } + if(!r) return false; + TIFFWriteScanline(image(), buff, y, (tsample_t) -1); + } + _TIFFfree(buff); + TIFFWriteDirectory(image()); + return true; +} +bool KisTIFFWriterVisitor::visit(KisGroupLayer *layer) +{ + kdDebug(41008) << "Visiting on grouplayer " << layer->name() << "\n"; + KisLayerSP child = layer->firstChild(); + while (child) { + child->accept(*this); + child = child->nextSibling(); + } + return true; +} + +bool KisTIFFWriterVisitor::visit(KisPartLayer *) +{ + return true; +} diff --git a/filters/chalk/tiff/kis_tiff_writer_visitor.h b/filters/chalk/tiff/kis_tiff_writer_visitor.h new file mode 100644 index 00000000..abd1aec7 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_writer_visitor.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_TIFF_WRITER_VISITOR_H +#define KIS_TIFF_WRITER_VISITOR_H + +#include + +#include + +#include + +class KisTIFFOptions; + +/** + @author Cyrille Berger +*/ +class KisTIFFWriterVisitor : public KisLayerVisitor +{ + public: + KisTIFFWriterVisitor(TIFF*img, KisTIFFOptions* options); + ~KisTIFFWriterVisitor(); + public: + virtual bool visit(KisPaintLayer *layer); + virtual bool visit(KisGroupLayer *layer); + virtual bool visit(KisPartLayer *layer); + virtual bool visit(KisAdjustmentLayer* ) { return true; } + private: + inline TIFF* image() { return m_image; } + inline bool saveAlpha(); + bool copyDataToStrips( KisHLineIterator it, tdata_t buff, uint8 depth, uint8 nbcolorssamples, TQ_UINT8* poses); + private: + TIFF* m_image; + KisTIFFOptions* m_options; +}; + +#endif diff --git a/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc b/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc new file mode 100644 index 00000000..ce5e4ae9 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_ycbcr_reader.cc @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "kis_tiff_ycbcr_reader.h" + +#include +#include + +#include "kis_tiff_stream.h" + + +KisTIFFYCbCrReaderTarget8Bit::KisTIFFYCbCrReaderTarget8Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor), m_hsub(hsub), m_vsub(vsub), m_position(position) +{ + // Initialize the buffer + TQ_INT32 imagewidth = device->image()->width(); + if(2*(imagewidth / 2) != imagewidth) imagewidth++; + m_bufferWidth = imagewidth / m_hsub; + TQ_INT32 imageheight = device->image()->height(); + if(2*(imageheight / 2) != imageheight) imageheight++; + m_bufferHeight = imageheight / m_vsub; + m_bufferCb = new TQ_UINT8[ m_bufferWidth * m_bufferHeight ]; + m_bufferCr = new TQ_UINT8[ m_bufferWidth * m_bufferHeight ]; +} + +KisTIFFYCbCrReaderTarget8Bit::~KisTIFFYCbCrReaderTarget8Bit() +{ + delete[] m_bufferCb; + delete[] m_bufferCr; +} + +uint KisTIFFYCbCrReaderTarget8Bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) +{ + int numcols = dataWidth / m_hsub; + double coeff = TQ_UINT8_MAX / (double)( pow(2, sourceDepth() ) - 1 ); +// kdDebug(41008) << " depth expension coefficient : " << coeff << endl; +// kdDebug(41008) << " y = " << y << endl; + uint buffPos = y / m_vsub * m_bufferWidth + x / m_hsub ; + for(int index = 0; index < numcols; index++) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x + m_hsub * index, y, m_hsub, true); + for( int vindex = 0; vindex < m_vsub; vindex++) + { + while( !it.isDone() ) + { + TQ_UINT8 *d = it.rawData(); + d[0] = (TQ_UINT8)( tiffstream->nextValue() * coeff ); + d[3] = TQ_UINT8_MAX; + for(int k = 0; k < nbExtraSamples(); k++) + { + if(k == alphaPos()) + d[3] = (TQ_UINT32) ( tiffstream->nextValue() * coeff ); + else + tiffstream->nextValue(); + } + ++it; + } + it.nextRow(); + } + m_bufferCb[ buffPos ] = (TQ_UINT8)(tiffstream->nextValue() * coeff); + m_bufferCr[ buffPos ] = (TQ_UINT8)(tiffstream->nextValue() * coeff); + buffPos ++; + } + return m_vsub; +} + +void KisTIFFYCbCrReaderTarget8Bit::finalize() +{ + KisHLineIterator it = paintDevice() -> createHLineIterator(0, 0, paintDevice()->image()->width(), true); + for(int y = 0; y < paintDevice()->image()->height(); y++) + { + int x = 0; + while(!it.isDone()) + { + TQ_UINT8 *d = it.rawData(); + int index = x/m_hsub + y/m_vsub * m_bufferWidth; + d[1] = m_bufferCb[ index ]; + d[2] = m_bufferCr[ index ]; + ++it; ++x; + } + it.nextRow(); + } +} + +KisTIFFYCbCrReaderTarget16Bit::KisTIFFYCbCrReaderTarget16Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth, nbcolorssamples, extrasamplescount, transformProfile, postprocessor), m_hsub(hsub), m_vsub(vsub), m_position(position) +{ + // Initialize the buffer + TQ_INT32 imagewidth = device->image()->width(); + if(2*(imagewidth / 2) != imagewidth) imagewidth++; + m_bufferWidth = imagewidth / m_hsub; + TQ_INT32 imageheight = device->image()->height(); + if(2*(imageheight / 2) != imageheight) imageheight++; + m_bufferHeight = imageheight / m_vsub; + m_bufferCb = new TQ_UINT16[ m_bufferWidth * m_bufferHeight ]; + m_bufferCr = new TQ_UINT16[ m_bufferWidth * m_bufferHeight ]; +} + +KisTIFFYCbCrReaderTarget16Bit::~KisTIFFYCbCrReaderTarget16Bit() +{ + delete[] m_bufferCb; + delete[] m_bufferCr; +} + +uint KisTIFFYCbCrReaderTarget16Bit::copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) +{ + int numcols = dataWidth / m_hsub; + double coeff = TQ_UINT16_MAX / (double)( pow(2, sourceDepth() ) - 1 ); +// kdDebug(41008) << " depth expension coefficient : " << coeff << endl; +// kdDebug(41008) << " y = " << y << endl; + uint buffPos = y / m_vsub * m_bufferWidth + x / m_hsub ; + for(int index = 0; index < numcols; index++) + { + KisHLineIterator it = paintDevice() -> createHLineIterator(x + m_hsub * index, y, m_hsub, true); + for( int vindex = 0; vindex < m_vsub; vindex++) + { + while( !it.isDone() ) + { + TQ_UINT16 *d = reinterpret_cast(it.rawData()); + d[0] = (TQ_UINT16)( tiffstream->nextValue() * coeff ); + d[3] = TQ_UINT16_MAX; + for(int k = 0; k < nbExtraSamples(); k++) + { + if(k == alphaPos()) + d[3] = (TQ_UINT32) ( tiffstream->nextValue() * coeff ); + else + tiffstream->nextValue(); + } + ++it; + } + it.nextRow(); + } + m_bufferCb[ buffPos ] = (TQ_UINT16)(tiffstream->nextValue() * coeff); + m_bufferCr[ buffPos ] = (TQ_UINT16)(tiffstream->nextValue() * coeff); + buffPos ++; + } + return m_vsub; +} + +void KisTIFFYCbCrReaderTarget16Bit::finalize() +{ + KisHLineIterator it = paintDevice() -> createHLineIterator(0, 0, paintDevice()->image()->width(), true); + for(int y = 0; y < paintDevice()->image()->height(); y++) + { + int x = 0; + while(!it.isDone()) + { + TQ_UINT16 *d = reinterpret_cast(it.rawData()); + int index = x/m_hsub + y/m_vsub * m_bufferWidth; + d[1] = m_bufferCb[ index ]; + d[2] = m_bufferCr[ index ]; + ++it; ++x; + } + it.nextRow(); + } +} diff --git a/filters/chalk/tiff/kis_tiff_ycbcr_reader.h b/filters/chalk/tiff/kis_tiff_ycbcr_reader.h new file mode 100644 index 00000000..e81e8893 --- /dev/null +++ b/filters/chalk/tiff/kis_tiff_ycbcr_reader.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_TIFF_YCBCR_READER_H_ +#define _KIS_TIFF_YCBCR_READER_H_ + +#include "kis_tiff_reader.h" + +namespace KisTIFFYCbCr { + enum Position { + POSITION_CENTERED = 1, + POSITION_COSITED = 2 + }; +} + +class KisTIFFYCbCrReaderTarget8Bit : public KisTIFFReaderBase { + public: + /** + * @param hsub horizontal subsampling of Cb and Cr + * @param hsub vertical subsampling of Cb and Cr + */ + KisTIFFYCbCrReaderTarget8Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ); + ~KisTIFFYCbCrReaderTarget8Bit(); + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream); + virtual void finalize(); + private: + TQ_UINT8* m_bufferCb; + TQ_UINT8* m_bufferCr; + TQ_UINT32 m_bufferWidth, m_bufferHeight; + uint16 m_hsub; + uint16 m_vsub; + KisTIFFYCbCr::Position m_position; + +}; + +class KisTIFFYCbCrReaderTarget16Bit : public KisTIFFReaderBase { + public: + /** + * @param hsub horizontal subsampling of Cb and Cr + * @param hsub vertical subsampling of Cb and Cr + */ + KisTIFFYCbCrReaderTarget16Bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor, uint16 hsub, uint16 vsub, KisTIFFYCbCr::Position position ); + ~KisTIFFYCbCrReaderTarget16Bit(); + virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream); + virtual void finalize(); + private: + TQ_UINT16* m_bufferCb; + TQ_UINT16* m_bufferCr; + TQ_UINT32 m_bufferWidth, m_bufferHeight; + uint16 m_hsub; + uint16 m_vsub; + KisTIFFYCbCr::Position m_position; + +}; + + +#endif diff --git a/filters/chalk/tiff/kis_wdg_options_tiff.ui b/filters/chalk/tiff/kis_wdg_options_tiff.ui new file mode 100644 index 00000000..3ffc1bd4 --- /dev/null +++ b/filters/chalk/tiff/kis_wdg_options_tiff.ui @@ -0,0 +1,741 @@ + +KisWdgOptionsTIFF + + + KisWdgOptionsTIFF + + + + 0 + 0 + 452 + 267 + + + + + 1 + 1 + 0 + 0 + + + + Options of Your TIFF + + + + unnamed + + + 0 + + + + groupBox1 + + + + 1 + 1 + 0 + 0 + + + + TIFF Options + + + + unnamed + + + + tqlayout10 + + + + unnamed + + + + textLabel1 + + + Compression type: + + + + + + None + + + + + JPEG DCT Compression + + + + + Deflate (ZIP) + + + + + Lempel-Ziv & Welch (LZW) + + + + + Leadtools JPEG2000 + + + + + CCITT Modified Huffman RLE + + + + + CCITT Group 3 Fax Encoding + + + + + CCITT Group 4 Fax Encoding + + + + + Pixar Log + + + + kComboBoxCompressionType + + + + + + + tqlayout7 + + + + unnamed + + + + textLabel1_3 + + + Predictor: + + + + + + None + + + + + Horizontal Differencing + + + + + Floating PointQt::Horizontal Differencing + + + + kComboBoxPredictor + + + 0 + + + Using a predictor can improve the compression (mostly for LZW and deflate) + + + + + + + alpha + + + Store alpha &channel (transparency) + + + true + + + Disable to get smaller files if your image has no transparancy + + + <p>The Portable Network Graphics (PNG) file format allows transparancy in your image to be stored by saving an alpha channel. +You can uncheck the box if you are not using transparancy and you want to make the resulting file smaller .<br>Always saving the alpha channel is recommended.</p> + + + + + flatten + + + + 3 + 3 + 0 + 0 + + + + Flatten the &image + + + true + + + This option will merge all layers. It is advisable to check this option, otherwise other applications might not be able to read your file correctly. + + + + + + + codecsOptionsStack + + + NoFrame + + + + WStackPage + + + 0 + + + + unnamed + + + 0 + + + 0 + + + + frame4 + + + NoFrame + + + Plain + + + + + + + WStackPage + + + 1 + + + + unnamed + + + 0 + + + 0 + + + + groupBoxJPEG + + + + 1 + 1 + 0 + 0 + + + + JPEG Compression Options + + + + unnamed + + + + textLabel1_2 + + + Quality: + + + AlignTop + + + + + tqlayout5 + + + + unnamed + + + + qualityLevel + + + 0 + + + 100 + + + 1 + + + 1 + + + 80 + + + Horizontal + + + Both + + + 10 + + + These settings determine how much information is lost during compression + + + + + tqlayout4_2 + + + + unnamed + + + + textLabel3 + + + Smallest + + + + + textLabel4 + + + Best + + + AlignVCenter|AlignRight + + + + + + + + + + + + + WStackPage + + + 2 + + + + unnamed + + + 0 + + + 0 + + + + groupBoxDeflate + + + + 1 + 1 + 0 + 0 + + + + Deflate Compression Options + + + + unnamed + + + + textLabel1_4 + + + Compress: + + + AlignTop + + + Note: the compression level does not change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level does not change the quality of the result.</p> + + + + + tqlayout5_2 + + + + unnamed + + + + compressionLevelDeflate + + + 1 + + + 9 + + + 1 + + + 6 + + + Horizontal + + + Both + + + Note: the compression level doesn't change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + tqlayout4 + + + + unnamed + + + + textLabel3_2 + + + Fast + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + textLabel4_2 + + + Small + + + AlignVCenter|AlignRight + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + + + + + + + + + WStackPage + + + 3 + + + + unnamed + + + 0 + + + 0 + + + + groupBoxCCITGroupCCITG3 + + + + 1 + 1 + 0 + 0 + + + + CCITT Group 3 fax encoding Options + + + + unnamed + + + + textLabel2 + + + Fax mode: + + + + + + Classic + + + + + No RTC + + + + + No EOL + + + + kComboBoxFaxMode + + + + + + + + + WStackPage + + + 4 + + + + unnamed + + + 0 + + + 0 + + + + groupBoxPixarLog + + + + 1 + 1 + 0 + 0 + + + + Pixar Log Compression Options + + + + unnamed + + + + textLabel1_4_2 + + + Compress: + + + AlignTop + + + Note: the compression level does not change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level does not change the quality of the result.</p> + + + + + tqlayout5_2_2 + + + + unnamed + + + + compressionLevelPixarLog + + + 1 + + + 9 + + + 1 + + + 6 + + + Horizontal + + + Both + + + Note: the compression level doesn't change the quality of the result + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + tqlayout4_3 + + + + unnamed + + + + textLabel3_2_2 + + + Fast + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + textLabel4_2_2 + + + Small + + + AlignVCenter|AlignRight + + + <p>Adjust the compression time. Better compression takes longer. +<br>Note: the compression level doesn't change the quality of the result.</p> + + + + + + + + + + + + + + spacer3 + + + Vertical + + + Expanding + + + + 20 + 16 + + + + + + + + + kComboBoxCompressionType + kComboBoxPredictor + alpha + flatten + qualityLevel + compressionLevelDeflate + kComboBoxFaxMode + compressionLevelPixarLog + + + + kcombobox.h + kcombobox.h + kcombobox.h + + diff --git a/filters/chalk/tiff/kis_ycbcr_colorspace.h b/filters/chalk/tiff/kis_ycbcr_colorspace.h new file mode 100644 index 00000000..05220127 --- /dev/null +++ b/filters/chalk/tiff/kis_ycbcr_colorspace.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006 Cyrille Berger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_YCBCR_COLORSPACE_H +#define KIS_YCBCR_COLORSPACE_H +namespace { + const TQ_INT32 MAX_CHANNEL_YCbCr = 3; + const TQ_INT32 MAX_CHANNEL_YCbCrA = 4; +} +#endif + diff --git a/filters/chalk/xcf/Makefile.am b/filters/chalk/xcf/Makefile.am new file mode 100644 index 00000000..88822a23 --- /dev/null +++ b/filters/chalk/xcf/Makefile.am @@ -0,0 +1,42 @@ +kde_module_LTLIBRARIES = libchalkxcfimport.la libchalkxcfexport.la + +libchalkxcfexport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkxcfexport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +libchalkxcfimport_la_LDFLAGS = $(KDE_PLUGIN) $(LIBMAGICK_LDFLAGS) $(KDE_RPATH) $(LIBMAGICK_RPATH) $(all_libraries) -module -avoid-version -no-undefined -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts \ + -L../../../lib/kofficecore/.libs/ -lkofficecore -llcms \ + -L../../../lib/kofficeui/.libs/ -lkofficeui -L../../../lib/store/.libs/ -lkstore -L../../../chalk/core/.libs/ -lchalkimage -L../../../chalk/ui/.libs/ -lchalkui -L../../../chalk/chalkcolor/.libs/ -lchalkcolor +libchalkxcfimport_la_LIBADD = \ + $(KOFFICE_LIBS) \ + $(LIBMAGICK_LIBS) \ + $(top_builddir)/chalk/libchalkcommon.la + +INCLUDES= \ + -I$(srcdir) \ + $(KOFFICE_INCLUDES) \ + -I$(top_srcdir)/chalk \ + -I$(top_srcdir)/chalk/core \ + -I$(top_srcdir)/chalk/sdk \ + -I$(top_srcdir)/chalk/core/tiles \ + -I$(top_srcdir)/chalk/chalkcolor \ + -I$(top_srcdir)/chalk/ui \ + $(KOFFICE_INCLUDES) -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) $(LIBMAGICK_CPPFLAGS) \ + $(all_includes) + +service_DATA = chalk_xcf_import.desktop chalk_xcf_export.desktop +servicedir = $(kde_servicesdir) + +libchalkxcfimport_la_SOURCES = xcfimport.cpp +libchalkxcfexport_la_SOURCES = xcfexport.cpp + +METASOURCES = AUTO + +SUBDIRS=xcf + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) diff --git a/filters/chalk/xcf/chalk_xcf_export.desktop b/filters/chalk/xcf/chalk_xcf_export.desktop new file mode 100644 index 00000000..b88afaed --- /dev/null +++ b/filters/chalk/xcf/chalk_xcf_export.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Name=Chalk XCF Export Filter +Name[bg]=Филтър за експортиране от Chalk в XCF +Name[br]=Sil ezporzh XCF evit Chalk +Name[ca]=Filtre d'exportació XCF per a Chalk +Name[cy]=Hidl Allforio XCF Chalk +Name[da]=Chalk XCF-eksportfilter +Name[de]=Chalk XCF-Exportfilter +Name[el]=Φίλτρο εξαγωγής XCF του Chalk +Name[eo]=Chalk XCF-importfiltrilo +Name[es]=Filtro de exportación a XCF de Chalk +Name[et]=Chalk XCF-i ekspordifilter +Name[fa]=پالایۀ صادرات Chalk XCF +Name[fi]=Chalk XCF -vientisuodin +Name[fr]=Filtre d'exportation XCF de Chalk +Name[fy]=Chalk XCF Eksportfilter +Name[ga]=Scagaire Easpórtála XCF Chalk +Name[gl]=Filtro de Exportación de XCF para Chalk +Name[he]=Chalk XCF מסנן יצוא +Name[hr]=Chalk XCF filtar izvoza +Name[hu]=Chalk XCF exportszűrő +Name[is]=Chalk XCF útflutningssía +Name[it]=Filtro di esportazione XCF per Chalk +Name[ja]=Chalk XCF エクスポートフィルタ +Name[km]=តម្រង​នាំចេញ XCF សម្រាប់ Chalk +Name[lt]=Chalk XCF eksportavimo filtras +Name[lv]=Chalk XCF eksporta filtrs +Name[nb]=XCF-eksportfilter for Chalk +Name[nds]=XCF-Exportfilter för Chalk +Name[ne]=क्रिता XFC निर्यात फिल्टर +Name[nl]=Chalk XCF Exportfilter +Name[pl]=Filtr eksportu do formatu XCF dla Chalk +Name[pt]=Filtro de Exportação de XCF para o Chalk +Name[pt_BR]=Filtro de Exportação de XCF para o Chalk +Name[ru]=Фильтр экспорта рисунков Chalk в XCF +Name[se]=Chalk XCF-olggosfievrridansilli +Name[sk]=Exportný filter Chalk XCF +Name[sl]=Izvozni filter XCF za Krito +Name[sr]=Chalk-ин филтер за извоз у XCF +Name[sr@Latn]=Chalk-in filter za izvoz u XCF +Name[sv]=Chalk XCF-exportfilter +Name[uk]=Фільтр експорту XCF для Chalk +Name[uz]=Chalk XCF eksport filteri +Name[uz@cyrillic]=Chalk XCF экспорт филтери +Name[zh_CN]=Chalk XCF 导出过滤器 +Name[zh_TW]=Chalk XCF 匯出過濾程式 +X-KDE-Export=image/x-xcf-gimp +ServiceTypes=KOfficeFilter +Type=Service +X-KDE-Import=application/x-chalk +X-KDE-Weight=1 +X-KDE-Library=libchalkxcfexport diff --git a/filters/chalk/xcf/chalk_xcf_import.desktop b/filters/chalk/xcf/chalk_xcf_import.desktop new file mode 100644 index 00000000..b2e68d13 --- /dev/null +++ b/filters/chalk/xcf/chalk_xcf_import.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Type=Service +Name=Chalk XCF Import Filter +Name[bg]=Филтър за импортиране от XCF в Chalk +Name[br]=Sil enporzh XCF evit Chalk +Name[ca]=Filtre d'importació XCF per a Chalk +Name[cy]=Hidl Mewnforio XCF Chalk +Name[da]=Chalk XCF-importfilter +Name[de]=Chalk XCF-Importfilter +Name[el]=Φίλτρο εισαγωγής XCF του Chalk +Name[eo]=Chalk XCF-importfiltrilo +Name[es]=Filtro de importación a XCF de Chalk +Name[et]=Chalk XCF-i impordifilter +Name[fa]=پالایۀ واردات Chalk XCF +Name[fi]=Chalk XCF -tuontisuodin +Name[fr]=Filtre d'importation XCF de Chalk +Name[fy]=Chalk XCF Ymportfilter +Name[ga]=Scagaire Iompórtála XCF Chalk +Name[gl]=Filtro de Importación de XCF para Chalk +Name[he]=Chalk XCF מסנן יבוא +Name[hr]=Chalk XCF filtar uvoza +Name[hu]=Chalk XCF importszűrő +Name[is]=Chalk XCF innflutningssía +Name[it]=Filtro di importazione XCF per Chalk +Name[ja]=Chalk XCF インポートフィルタ +Name[km]=តម្រង​នាំចូល XCF សម្រាប់ Chalk +Name[lt]=Chalk XCF importavimo filtras +Name[lv]=Chalk XCF importa filtrs +Name[nb]=XCF-importfilter for Chalk +Name[nds]=XCF-Importfilter för Chalk +Name[ne]=क्रिता XCF आयात फिल्टर +Name[nl]=Chalk XCF Importfilter +Name[pl]=Filtr importu formatu XCF dla Chalk +Name[pt]=Filtro de Importação de XCF para o Chalk +Name[pt_BR]=Filtro de Importação de XCF para o Chalk +Name[ru]=Фильтр импорта рисунков XCF в Chalk +Name[se]=Chalk XCF-sisafievrridansilli +Name[sk]=XCF filter pre import do Chalk +Name[sl]=Uvozni filter XCF za Krito +Name[sr]=Chalk-ин филтер за увоз из XCF-а +Name[sr@Latn]=Chalk-in filter za uvoz iz XCF-a +Name[sv]=Chalk XCF-importfilter +Name[uk]=Фільтр імпорту XCF для Chalk +Name[uz]=Chalk XCF import filteri +Name[uz@cyrillic]=Chalk XCF импорт филтери +Name[zh_CN]=Chalk XCF 导入过滤器 +Name[zh_TW]=Chalk XCF 匯入過濾程式 +X-KDE-Export=application/x-chalk +X-KDE-Import=image/x-xcf-gimp +X-KDE-Weight=1 +X-KDE-Library=libchalkxcfimport +ServiceTypes=KOfficeFilter diff --git a/filters/chalk/xcf/xcf/README b/filters/chalk/xcf/xcf/README new file mode 100644 index 00000000..567d2ab1 --- /dev/null +++ b/filters/chalk/xcf/xcf/README @@ -0,0 +1,2 @@ +Note: this is source copy of 6 feb. 2006; when updated, use a diff from the gimp cvs +to check for changes in their file format. diff --git a/filters/chalk/xcf/xcf/xcf-load.cc b/filters/chalk/xcf/xcf/xcf-load.cc new file mode 100644 index 00000000..07b6a145 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-load.cc @@ -0,0 +1,1740 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include /* strcmp, memcmp */ + +//#include + +//#include "libgimpbase/gimpbase.h" +//#include "libgimpcolor/gimpcolor.h" + +//#include "core/core-types.h" + +//#include "base/tile.h" +//#include "base/tile-manager.h" +//#include "base/tile-manager-private.h" + +//#include "config/gimpcoreconfig.h" + +//#include "core/gimp.h" +//#include "core/gimpcontainer.h" +//#include "core/gimpdrawable.h" +//#include "core/gimpgrid.h" +//#include "core/gimpimage.h" +//#include "core/gimpimage-grid.h" +//#include "core/gimpimage-guides.h" +//#include "core/gimplayer.h" +//#include "core/gimplayer-floating-sel.h" +//#include "core/gimplayertqmask.h" +//#include "core/gimpparasitelist.h" +//#include "core/gimpselection.h" +//#include "core/gimptemplate.h" +//#include "core/gimpunit.h" + +//#include "text/gimptextlayer.h" +//#include "text/gimptextlayer-xcf.h" + +//#include "vectors/gimpanchor.h" +//#include "vectors/gimpstroke.h" +//#include "vectors/gimpbezierstroke.h" +//#include "vectors/gimpvectors.h" +//#include "vectors/gimpvectors-compat.h" + +#include "xcf-private.h" +#include "xcf-load.h" +#include "xcf-read.h" +#include "xcf-seek.h" + +//#include "gimp-intl.h" + +static bool xcf_load_image_props (XcfInfo * info, KisImage * gimage); +static bool xcf_load_layer_props (XcfInfo * info, + KisImage * gimage, + KisLayer * layer, + bool * apply_tqmask, + bool * edit_tqmask, + bool * show_tqmask, + TQ_INT32 * text_layer_flags); +static bool xcf_load_channel_props (XcfInfo * info, + KisImage * gimage, + GimpChannel ** channel); +static bool xcf_load_prop (XcfInfo * info, + PropType * prop_type, TQ_INT32 * prop_size); +static KisLayer *xcf_load_layer (XcfInfo * info, KisImage * gimage); +//static GimpChannel * xcf_load_channel (XcfInfo *info, +// KisImage *gimage); +//static GimpLayerMask * xcf_load_layer_tqmask (XcfInfo *info, +// KisImage *gimage); +static bool xcf_load_hierarchy (XcfInfo * info, TileManager * tiles); +static bool xcf_load_level (XcfInfo * info, TileManager * tiles); +static bool xcf_load_tile (XcfInfo * info, Tile * tile); +static bool xcf_load_tile_rle (XcfInfo * info, + Tile * tile, TQ_INT32 data_length); +//static GimpParasite * xcf_load_parasite (XcfInfo *info); +static bool xcf_load_old_paths (XcfInfo * info, KisImage * gimage); +static bool xcf_load_old_path (XcfInfo * info, KisImage * gimage); +static bool xcf_load_vectors (XcfInfo * info, KisImage * gimage); +static bool xcf_load_vector (XcfInfo * info, KisImage * gimage); + +#ifdef SWAP_FROM_FILE +static bool xcf_swap_func (TQ_INT32 fd, + Tile * tile, TQ_INT32 cmd, gpointer user_data); +#endif + + +KisImage * +xcf_load_image (XcfInfo * info) +{ + KisImage *gimage; + KisLayer *layer; + //GimpChannel *channel; + //KisAnnotation *parasite; + TQ_INT32 saved_pos; + TQ_INT32 offset; + TQ_INT32 width; + TQ_INT32 height; + TQ_INT32 image_type; + TQ_INT32 num_successful_elements = 0; + + /* read in the image width, height and type */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & image_type, 1); + + gimage = gimp_create_image (gimp, width, height, image_type, FALSE); + + gimp_image_undo_disable (gimage); + + /* read the image properties */ + if (!xcf_load_image_props (info, gimage)) + goto hard_error; + + /* check for a GimpGrid parasite */ + parasite = gimp_image_parasite_tqfind (GIMP_IMAGE (gimage), + gimp_grid_parasite_name ()); + if (parasite) + { + GimpGrid *grid = gimp_grid_from_parasite (parasite); + + if (grid) + { + gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites, + gimp_parasite_name (parasite)); + + gimp_image_set_grid (GIMP_IMAGE (gimage), grid, FALSE); + } + } + + while (TRUE) + { + /* read in the offset of the next layer */ + info->cp += xcf_read_int32 (info->fp, &offset, 1); + + /* if the offset is 0 then we are at the end + * of the layer list. + */ + if (offset == 0) + break; + + /* save the current position as it is where the + * next layer offset is stored. + */ + saved_pos = info->cp; + + /* seek to the layer offset */ + if (!xcf_seek_pos (info, offset, NULL)) + goto error; + + /* read in the layer */ + layer = xcf_load_layer (info, gimage); + if (!layer) + goto error; + + num_successful_elements++; + + /* add the layer to the image if its not the floating selection */ + if (layer != info->floating_sel) + gimp_image_add_layer (gimage, layer, + gimp_container_num_tqchildren (gimage->layers)); + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + if (!xcf_seek_pos (info, saved_pos, NULL)) + goto error; + } + + while (TRUE) + { + /* read in the offset of the next channel */ + info->cp += xcf_read_int32 (info->fp, &offset, 1); + + /* if the offset is 0 then we are at the end + * of the channel list. + */ + if (offset == 0) + break; + + /* save the current position as it is where the + * next channel offset is stored. + */ + saved_pos = info->cp; + + /* seek to the channel offset */ + if (!xcf_seek_pos (info, offset, NULL)) + goto error; + + /* read in the layer */ + channel = xcf_load_channel (info, gimage); + if (!channel) + goto error; + + num_successful_elements++; + + /* add the channel to the image if its not the selection */ + if (channel != gimage->selection_tqmask) + gimp_image_add_channel (gimage, channel, -1); + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + if (!xcf_seek_pos (info, saved_pos, NULL)) + goto error; + } + + if (info->floating_sel && info->floating_sel_drawable) + floating_sel_attach (info->floating_sel, info->floating_sel_drawable); + + if (info->active_layer) + gimp_image_set_active_layer (gimage, info->active_layer); + + if (info->active_channel) + gimp_image_set_active_channel (gimage, info->active_channel); + + gimp_image_set_filename (gimage, info->filename); + + if (info->tattoo_state > 0) + gimp_image_set_tattoo_state (gimage, info->tattoo_state); + + gimp_image_undo_enable (gimage); + + return gimage; + +error: + if (num_successful_elements == 0) + goto hard_error; + + g_message ("XCF: This file is corrupt! I have loaded as much\n" + "of it as I can, but it is incomplete."); + + gimp_image_undo_enable (gimage); + + return gimage; + +hard_error: + g_message ("XCF: This file is corrupt! I could not even\n" + "salvage any partial image data from it."); + + g_object_unref (gimage); + + return NULL; +} + +static bool +xcf_load_image_props (XcfInfo * info, KisImage * gimage) +{ + PropType prop_type; + TQ_INT32 prop_size; + + while (TRUE) + { + if (!xcf_load_prop (info, &prop_type, &prop_size)) + return FALSE; + + switch (prop_type) + { + case PROP_END: + return TRUE; + + case PROP_COLORMAP: + if (info->file_version == 0) + { + TQ_INT32 i; + + g_message (_("XCF warning: version 0 of XCF file format\n" + "did not save indexed colormaps correctly.\n" + "Substituting grayscale map.")); + info->cp += + xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1); + gimage->cmap = g_new (guchar, gimage->num_cols * 3); + if (!xcf_seek_pos (info, info->cp + gimage->num_cols, NULL)) + return FALSE; + + for (i = 0; i < gimage->num_cols; i++) + { + gimage->cmap[i * 3 + 0] = i; + gimage->cmap[i * 3 + 1] = i; + gimage->cmap[i * 3 + 2] = i; + } + } + else + { + info->cp += + xcf_read_int32 (info->fp, (TQ_INT32 *) & gimage->num_cols, 1); + gimage->cmap = g_new (guchar, gimage->num_cols * 3); + info->cp += + xcf_read_int8 (info->fp, + (TQ_UINT8 *) gimage->cmap, + gimage->num_cols * 3); + } + + /* discard color map, if image is not indexed, this is just + * sanity checking to make sure gimp doesn't end up with an + * image state that is impossible. + */ + if (gimp_image_base_type (gimage) != GIMP_INDEXED) + { + g_free (gimage->cmap); + gimage->cmap = NULL; + gimage->num_cols = 0; + } + break; + + case PROP_COMPRESSION: + { + TQ_UINT8 compression; + + info->cp += + xcf_read_int8 (info->fp, (TQ_UINT8 *) & compression, 1); + + if ((compression != COMPRESS_NONE) && + (compression != COMPRESS_RLE) && + (compression != COMPRESS_ZLIB) && + (compression != COMPRESS_FRACTAL)) + { + g_message ("unknown compression type: %d", (int) compression); + return FALSE; + } + + info->compression = compression; + } + break; + + case PROP_GUIDES: + { + TQ_INT3232 position; + TQ_INT328 orientation; + TQ_INT32 i, nguides; + + nguides = prop_size / (4 + 1); + for (i = 0; i < nguides; i++) + { + info->cp += + xcf_read_int32 (info->fp, (TQ_INT32 *) & position, 1); + info->cp += + xcf_read_int8 (info->fp, (TQ_UINT8 *) & orientation, 1); + + /* skip -1 guides from old XCFs */ + if (position < 0) + continue; + + switch (orientation) + { + case XCF_ORIENTATION_HORIZONTAL: + gimp_image_add_hguide (gimage, position, FALSE); + break; + + case XCF_ORIENTATION_VERTICAL: + gimp_image_add_vguide (gimage, position, FALSE); + break; + + default: + g_message ("guide orientation out of range in XCF file"); + continue; + } + } + + /* this is silly as the order of guides doesn't really matter, + * but it restores the list to it's original order, which + * cannot be wrong --Mitch + */ + gimage->guides = g_list_reverse (gimage->guides); + } + break; + + case PROP_RESOLUTION: + { + float xres, yres; + + info->cp += xcf_read_float (info->fp, &xres, 1); + info->cp += xcf_read_float (info->fp, &yres, 1); + if (xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION || + yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION) + { + g_message ("Warning, resolution out of range in XCF file"); + xres = gimage->gimp->config->default_image->xresolution; + yres = gimage->gimp->config->default_image->yresolution; + } + gimage->xresolution = xres; + gimage->yresolution = yres; + } + break; + + case PROP_TATTOO: + { + info->cp += xcf_read_int32 (info->fp, &info->tattoo_state, 1); + } + break; + + case PROP_PARASITES: + { + glong base = info->cp; + KisAnnotation *p; + + while (info->cp - base < prop_size) + { + p = xcf_load_parasite (info); + gimp_image_parasite_attach (gimage, p); + gimp_parasite_free (p); + } + if (info->cp - base != prop_size) + g_message ("Error while loading an image's parasites"); + } + break; + + case PROP_UNIT: + { + TQ_INT32 unit; + + info->cp += xcf_read_int32 (info->fp, &unit, 1); + + if ((unit <= GIMP_UNIT_PIXEL) || + (unit >= + _gimp_unit_get_number_of_built_in_units (gimage->gimp))) + { + g_message ("Warning, unit out of range in XCF file, " + "falling back to inches"); + unit = GIMP_UNIT_INCH; + } + + gimage->resolution_unit = unit; + } + break; + + case PROP_PATHS: + xcf_load_old_paths (info, gimage); + break; + + case PROP_USER_UNIT: + { + TQCString *unit_strings[5]; + float factor; + TQ_INT32 digits; + GimpUnit unit; + TQ_INT32 num_units; + TQ_INT32 i; + + info->cp += xcf_read_float (info->fp, &factor, 1); + info->cp += xcf_read_int32 (info->fp, &digits, 1); + info->cp += xcf_read_string (info->fp, unit_strings, 5); + + for (i = 0; i < 5; i++) + if (unit_strings[i] == NULL) + unit_strings[i] = g_strdup (""); + + num_units = _gimp_unit_get_number_of_units (gimage->gimp); + + for (unit = + _gimp_unit_get_number_of_built_in_units (gimage->gimp); + unit < num_units; unit++) + { + /* if the factor and the identifier match some unit + * in unitrc, use the unitrc unit + */ + if ((ABS (_gimp_unit_get_factor (gimage->gimp, + unit) - factor) < 1e-5) && + (strcmp (unit_strings[0], + _gimp_unit_get_identifier (gimage->gimp, + unit)) == 0)) + { + break; + } + } + + /* no match */ + if (unit == num_units) + unit = _gimp_unit_new (gimage->gimp, + unit_strings[0], + factor, + digits, + unit_strings[1], + unit_strings[2], + unit_strings[3], unit_strings[4]); + + gimage->resolution_unit = unit; + + for (i = 0; i < 5; i++) + g_free (unit_strings[i]); + } + break; + + case PROP_VECTORS: + { + TQ_INT32 base = info->cp; + + if (xcf_load_vectors (info, gimage)) + { + if (base + prop_size != info->cp) + { + g_warning + ("Mismatch in PROP_VECTORS size: skipping %d bytes.", + base + prop_size - info->cp); + xcf_seek_pos (info, base + prop_size, NULL); + } + } + else + { + /* skip silently since we don't understand the format and + * xcf_load_vectors already explained what was wrong + */ + xcf_seek_pos (info, base + prop_size, NULL); + } + } + break; + + default: +#ifdef GIMP_UNSTABLE + g_printerr ("unexpected/unknown image property: %d (skipping)", + prop_type); +#endif + { + TQ_UINT8 buf[16]; + TQ_UINT32 amount; + + while (prop_size > 0) + { + amount = MIN (16, prop_size); + info->cp += xcf_read_int8 (info->fp, buf, amount); + prop_size -= MIN (16, amount); + } + } + break; + } + } + + return FALSE; +} + +static bool +xcf_load_layer_props (XcfInfo * info, + KisImage * gimage, + KisLayer * layer, + bool * apply_tqmask, + bool * edit_tqmask, + bool * show_tqmask, TQ_INT32 * text_layer_flags) +{ + PropType prop_type; + TQ_INT32 prop_size; + + while (TRUE) + { + if (!xcf_load_prop (info, &prop_type, &prop_size)) + return FALSE; + + switch (prop_type) + { + case PROP_END: + return TRUE; + + case PROP_ACTIVE_LAYER: + info->active_layer = layer; + break; + + case PROP_FLOATING_SELECTION: + info->floating_sel = layer; + info->cp += + xcf_read_int32 (info->fp, + (TQ_INT32 *) & info->floating_sel_offset, 1); + break; + + case PROP_OPACITY: + { + TQ_INT32 opacity; + + info->cp += xcf_read_int32 (info->fp, &opacity, 1); + layer->opacity = CLAMP ((gdouble) opacity / 255.0, + GIMP_OPACITY_TRANSPARENT, + GIMP_OPACITY_OPAQUE); + } + break; + + case PROP_VISIBLE: + { + bool visible; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1); + gimp_item_set_visible (GIMP_ITEM (layer), + visible ? TRUE : FALSE, FALSE); + } + break; + + case PROP_LINKED: + { + bool linked; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1); + gimp_item_set_linked (GIMP_ITEM (layer), + linked ? TRUE : FALSE, FALSE); + } + break; + + case PROP_LOCK_ALPHA: + info->cp += + xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->lock_alpha, 1); + break; + + case PROP_APPLY_MASK: + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) apply_tqmask, 1); + break; + + case PROP_EDIT_MASK: + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) edit_tqmask, 1); + break; + + case PROP_SHOW_MASK: + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) show_tqmask, 1); + break; + + case PROP_OFFSETS: + info->cp += + xcf_read_int32 (info->fp, + (TQ_INT32 *) & GIMP_ITEM (layer)->offset_x, 1); + info->cp += + xcf_read_int32 (info->fp, + (TQ_INT32 *) & GIMP_ITEM (layer)->offset_y, 1); + break; + + case PROP_MODE: + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & layer->mode, 1); + break; + + case PROP_TATTOO: + info->cp += xcf_read_int32 (info->fp, + (TQ_INT32 *) & GIMP_ITEM (layer)->tattoo, + 1); + break; + + case PROP_PARASITES: + { + glong base = info->cp; + KisAnnotation *p; + + while (info->cp - base < prop_size) + { + p = xcf_load_parasite (info); + gimp_item_parasite_attach (GIMP_ITEM (layer), p); + gimp_parasite_free (p); + } + if (info->cp - base != prop_size) + g_message ("Error while loading a layer's parasites"); + } + break; + + case PROP_TEXT_LAYER_FLAGS: + info->cp += xcf_read_int32 (info->fp, text_layer_flags, 1); + break; + + default: + { + TQ_UINT8 buf[16]; + TQ_UINT32 amount; + +#ifdef GIMP_UNSTABLE + g_printerr ("unexpected/unknown layer property: %d (skipping)", + prop_type); +#endif + while (prop_size > 0) + { + amount = MIN (16, prop_size); + info->cp += xcf_read_int8 (info->fp, buf, amount); + prop_size -= MIN (16, amount); + } + } + break; + } + } + + return FALSE; +} + +static bool +xcf_load_channel_props (XcfInfo * info, + KisImage * gimage, GimpChannel ** channel) +{ + PropType prop_type; + TQ_INT32 prop_size; + + while (TRUE) + { + if (!xcf_load_prop (info, &prop_type, &prop_size)) + return FALSE; + + switch (prop_type) + { + case PROP_END: + return TRUE; + + case PROP_ACTIVE_CHANNEL: + info->active_channel = *channel; + break; + + case PROP_SELECTION: + g_object_unref (gimage->selection_tqmask); + gimage->selection_tqmask = + gimp_selection_new (gimage, + gimp_item_width (GIMP_ITEM (*channel)), + gimp_item_height (GIMP_ITEM (*channel))); + g_object_ref (gimage->selection_tqmask); + gimp_item_sink (GIMP_ITEM (gimage->selection_tqmask)); + + tile_manager_unref (GIMP_DRAWABLE (gimage->selection_tqmask)->tiles); + GIMP_DRAWABLE (gimage->selection_tqmask)->tiles = + GIMP_DRAWABLE (*channel)->tiles; + GIMP_DRAWABLE (*channel)->tiles = NULL; + g_object_unref (*channel); + *channel = gimage->selection_tqmask; + (*channel)->boundary_known = FALSE; + (*channel)->bounds_known = FALSE; + break; + + case PROP_OPACITY: + { + TQ_INT32 opacity; + + info->cp += xcf_read_int32 (info->fp, &opacity, 1); + (*channel)->color.a = opacity / 255.0; + } + break; + + case PROP_VISIBLE: + { + bool visible; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & visible, 1); + gimp_item_set_visible (GIMP_ITEM (*channel), + visible ? TRUE : FALSE, FALSE); + } + break; + + case PROP_LINKED: + { + bool linked; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & linked, 1); + gimp_item_set_linked (GIMP_ITEM (*channel), + linked ? TRUE : FALSE, FALSE); + } + break; + + case PROP_SHOW_MASKED: + { + bool show_tqmasked; + + info->cp += + xcf_read_int32 (info->fp, (TQ_INT32 *) & show_tqmasked, 1); + gimp_channel_set_show_tqmasked (*channel, show_tqmasked); + } + break; + + case PROP_COLOR: + { + guchar col[3]; + + info->cp += xcf_read_int8 (info->fp, (TQ_UINT8 *) col, 3); + + gimp_rgb_set_uchar (&(*channel)->color, col[0], col[1], col[2]); + } + break; + + case PROP_TATTOO: + info->cp += + xcf_read_int32 (info->fp, &GIMP_ITEM (*channel)->tattoo, 1); + break; + + case PROP_PARASITES: + { + glong base = info->cp; + KisAnnotation *p; + + while ((info->cp - base) < prop_size) + { + p = xcf_load_parasite (info); + gimp_item_parasite_attach (GIMP_ITEM (*channel), p); + gimp_parasite_free (p); + } + if (info->cp - base != prop_size) + g_message ("Error while loading a channel's parasites"); + } + break; + + default: +#ifdef GIMP_UNSTABLE + g_printerr ("unexpected/unknown channel property: %d (skipping)", + prop_type); +#endif + + { + TQ_UINT8 buf[16]; + TQ_UINT32 amount; + + while (prop_size > 0) + { + amount = MIN (16, prop_size); + info->cp += xcf_read_int8 (info->fp, buf, amount); + prop_size -= MIN (16, amount); + } + } + break; + } + } + + return FALSE; +} + +static bool +xcf_load_prop (XcfInfo * info, PropType * prop_type, TQ_INT32 * prop_size) +{ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_type, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) prop_size, 1); + return TRUE; +} + +static KisLayer * +xcf_load_layer (XcfInfo * info, KisImage * gimage) +{ + KisLayer *layer; + GimpLayerMask *layer_tqmask; + TQ_INT32 hierarchy_offset; + TQ_INT32 layer_tqmask_offset; + bool apply_tqmask = TRUE; + bool edit_tqmask = FALSE; + bool show_tqmask = FALSE; + bool active; + bool floating; + TQ_INT32 text_layer_flags = 0; + TQ_INT32 width; + TQ_INT32 height; + TQ_INT32 type; + bool is_fs_drawable; + TQCString *name; + + /* check and see if this is the drawable the floating selection + * is attached to. if it is then we'll do the attachment in our caller. + */ + is_fs_drawable = (info->cp == info->floating_sel_offset); + + /* read in the layer width, height, type and name */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & type, 1); + info->cp += xcf_read_string (info->fp, &name, 1); + + /* create a new layer */ + layer = gimp_layer_new (gimage, width, height, + type, name, 255, GIMP_NORMAL_MODE); + g_free (name); + if (!layer) + return NULL; + + /* read in the layer properties */ + if (!xcf_load_layer_props (info, gimage, layer, + &apply_tqmask, &edit_tqmask, &show_tqmask, + &text_layer_flags)) + goto error; + + /* call the evil text layer hack that might change our layer pointer */ + active = (info->active_layer == layer); + floating = (info->floating_sel == layer); + + if (gimp_text_layer_xcf_load_hack (&layer)) + { + gimp_text_layer_set_xcf_flags (GIMP_TEXT_LAYER (layer), + text_layer_flags); + + if (active) + info->active_layer = layer; + if (floating) + info->floating_sel = layer; + } + + /* read the hierarchy and layer tqmask offsets */ + info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1); + info->cp += xcf_read_int32 (info->fp, &layer_tqmask_offset, 1); + + /* read in the hierarchy */ + if (!xcf_seek_pos (info, hierarchy_offset, NULL)) + goto error; + + if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer)->tiles)) + goto error; + + /* read in the layer tqmask */ + if (layer_tqmask_offset != 0) + { + if (!xcf_seek_pos (info, layer_tqmask_offset, NULL)) + goto error; + + layer_tqmask = xcf_load_layer_tqmask (info, gimage); + if (!layer_tqmask) + goto error; + + layer_tqmask->apply_tqmask = apply_tqmask; + layer_tqmask->edit_tqmask = edit_tqmask; + layer_tqmask->show_tqmask = show_tqmask; + + gimp_layer_add_tqmask (layer, layer_tqmask, FALSE); + } + + /* attach the floating selection... */ + if (is_fs_drawable) + info->floating_sel_drawable = GIMP_DRAWABLE (layer); + + return layer; + +error: + g_object_unref (layer); + return NULL; +} + +static GimpChannel * +xcf_load_channel (XcfInfo * info, KisImage * gimage) +{ + GimpChannel *channel; + TQ_INT32 hierarchy_offset; + TQ_INT32 width; + TQ_INT32 height; + bool is_fs_drawable; + TQCString *name; + GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE }; + + /* check and see if this is the drawable the floating selection + * is attached to. if it is then we'll do the attachment in our caller. + */ + is_fs_drawable = (info->cp == info->floating_sel_offset); + + /* read in the layer width, height and name */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + info->cp += xcf_read_string (info->fp, &name, 1); + + /* create a new channel */ + channel = gimp_channel_new (gimage, width, height, name, &color); + g_free (name); + if (!channel) + return NULL; + + /* read in the channel properties */ + if (!xcf_load_channel_props (info, gimage, &channel)) + goto error; + + /* read the hierarchy and layer tqmask offsets */ + info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1); + + /* read in the hierarchy */ + if (!xcf_seek_pos (info, hierarchy_offset, NULL)) + goto error; + + if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (channel)->tiles)) + goto error; + + if (is_fs_drawable) + info->floating_sel_drawable = GIMP_DRAWABLE (channel); + + return channel; + +error: + g_object_unref (channel); + return NULL; +} + +static GimpLayerMask * +xcf_load_layer_tqmask (XcfInfo * info, KisImage * gimage) +{ + GimpLayerMask *layer_tqmask; + GimpChannel *channel; + TQ_INT32 hierarchy_offset; + TQ_INT32 width; + TQ_INT32 height; + bool is_fs_drawable; + TQCString *name; + GimpRGB color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE }; + + /* check and see if this is the drawable the floating selection + * is attached to. if it is then we'll do the attachment in our caller. + */ + is_fs_drawable = (info->cp == info->floating_sel_offset); + + /* read in the layer width, height and name */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + info->cp += xcf_read_string (info->fp, &name, 1); + + /* create a new layer tqmask */ + layer_tqmask = gimp_layer_tqmask_new (gimage, width, height, name, &color); + g_free (name); + if (!layer_tqmask) + return NULL; + + /* read in the layer_tqmask properties */ + channel = GIMP_CHANNEL (layer_tqmask); + if (!xcf_load_channel_props (info, gimage, &channel)) + goto error; + + /* read the hierarchy and layer tqmask offsets */ + info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1); + + /* read in the hierarchy */ + if (!xcf_seek_pos (info, hierarchy_offset, NULL)) + goto error; + + if (!xcf_load_hierarchy (info, GIMP_DRAWABLE (layer_tqmask)->tiles)) + goto error; + + /* attach the floating selection... */ + if (is_fs_drawable) + info->floating_sel_drawable = GIMP_DRAWABLE (layer_tqmask); + + return layer_tqmask; + +error: + g_object_unref (layer_tqmask); + return NULL; +} + +static bool +xcf_load_hierarchy (XcfInfo * info, TileManager * tiles) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset; + TQ_INT32 junk; + TQ_INT32 width; + TQ_INT32 height; + TQ_INT32 bpp; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & bpp, 1); + + /* make sure the values in the file correspond to the values + * calculated when the TileManager was created. + */ + if (width != tile_manager_width (tiles) || + height != tile_manager_height (tiles) || + bpp != tile_manager_bpp (tiles)) + return FALSE; + + /* load in the levels...we make sure that the number of levels + * calculated when the TileManager was created is the same + * as the number of levels found in the file. + */ + + info->cp += xcf_read_int32 (info->fp, &offset, 1); /* top level */ + + /* discard offsets for layers below first, if any. + */ + do + { + info->cp += xcf_read_int32 (info->fp, &junk, 1); + } + while (junk != 0); + + /* save the current position as it is where the + * next level offset is stored. + */ + saved_pos = info->cp; + + /* seek to the level offset */ + if (!xcf_seek_pos (info, offset, NULL)) + return FALSE; + + /* read in the level */ + if (!xcf_load_level (info, tiles)) + return FALSE; + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + if (!xcf_seek_pos (info, saved_pos, NULL)) + return FALSE; + + return TRUE; +} + + +static bool +xcf_load_level (XcfInfo * info, TileManager * tiles) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset, offset2; + TQ_UINT32 ntiles; + TQ_INT32 width; + TQ_INT32 height; + TQ_INT32 i; + TQ_INT32 fail; + Tile *previous; + Tile *tile; + + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & width, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & height, 1); + + if (width != tile_manager_width (tiles) || + height != tile_manager_height (tiles)) + return FALSE; + + /* read in the first tile offset. + * if it is '0', then this tile level is empty + * and we can simply return. + */ + info->cp += xcf_read_int32 (info->fp, &offset, 1); + if (offset == 0) + return TRUE; + + /* Initialise the reference for the in-memory tile-compression + */ + previous = NULL; + + ntiles = tiles->ntile_rows * tiles->ntile_cols; + for (i = 0; i < ntiles; i++) + { + fail = FALSE; + + if (offset == 0) + { + g_message ("not enough tiles found in level"); + return FALSE; + } + + /* save the current position as it is where the + * next tile offset is stored. + */ + saved_pos = info->cp; + + /* read in the offset of the next tile so we can calculate the amount + of data needed for this tile */ + info->cp += xcf_read_int32 (info->fp, &offset2, 1); + + /* if the offset is 0 then we need to read in the maximum possible + allowing for negative compression */ + if (offset2 == 0) + offset2 = offset + TILE_WIDTH * TILE_WIDTH * 4 * 1.5; + /* 1.5 is probably more + than we need to allow */ + + /* seek to the tile offset */ + if (!xcf_seek_pos (info, offset, NULL)) + return FALSE; + + /* get the tile from the tile manager */ + tile = tile_manager_get (tiles, i, TRUE, TRUE); + + /* read in the tile */ + switch (info->compression) + { + case COMPRESS_NONE: + if (!xcf_load_tile (info, tile)) + fail = TRUE; + break; + case COMPRESS_RLE: + if (!xcf_load_tile_rle (info, tile, offset2 - offset)) + fail = TRUE; + break; + case COMPRESS_ZLIB: + g_error ("xcf: zlib compression unimplemented"); + fail = TRUE; + break; + case COMPRESS_FRACTAL: + g_error ("xcf: fractal compression unimplemented"); + fail = TRUE; + break; + } + + if (fail) + { + tile_release (tile, TRUE); + return FALSE; + } + + /* To potentially save memory, we compare the + * newly-fetched tile against the last one, and + * if they're the same we copy-on-write mirror one against + * the other. + */ + if (previous != NULL) + { + tile_lock (previous); + if (tile_ewidth (tile) == tile_ewidth (previous) && + tile_eheight (tile) == tile_eheight (previous) && + tile_bpp (tile) == tile_bpp (previous) && + memcmp (tile_data_pointer (tile, 0, 0), + tile_data_pointer (previous, 0, 0), + tile_size (tile)) == 0) + tile_manager_map (tiles, i, previous); + tile_release (previous, FALSE); + } + tile_release (tile, TRUE); + previous = tile_manager_get (tiles, i, FALSE, FALSE); + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + if (!xcf_seek_pos (info, saved_pos, NULL)) + return FALSE; + + /* read in the offset of the next tile */ + info->cp += xcf_read_int32 (info->fp, &offset, 1); + } + + if (offset != 0) + { + g_message ("encountered garbage after reading level: %d", offset); + return FALSE; + } + + return TRUE; +} + +static bool +xcf_load_tile (XcfInfo * info, Tile * tile) +{ +#ifdef SWAP_FROM_FILE + + if (!info->swap_num) + { + info->ref_count = g_new (int, 1); + info->swap_num = tile_swap_add (info->filename, + xcf_swap_func, info->ref_count); + } + + tile->swap_num = info->swap_num; + tile->swap_offset = info->cp; + *info->ref_count += 1; + +#else + + info->cp += xcf_read_int8 (info->fp, tile_data_pointer (tile, 0, 0), + tile_size (tile)); + +#endif + + return TRUE; +} + +static bool +xcf_load_tile_rle (XcfInfo * info, Tile * tile, int data_length) +{ + guchar *data; + guchar val; + TQ_INT32 size; + TQ_INT32 count; + TQ_INT32 length; + TQ_INT32 bpp; + TQ_INT32 i, j; + TQ_INT32 nmemb_read_successfully; + guchar *xcfdata, *xcfodata, *xcfdatalimit; + + data = tile_data_pointer (tile, 0, 0); + bpp = tile_bpp (tile); + + xcfdata = xcfodata = g_malloc (data_length); + + /* we have to use fread instead of xcf_read_* because we may be + reading past the end of the file here */ + nmemb_read_successfully = fread ((TQCString *) xcfdata, sizeof (TQCString), + data_length, info->fp); + info->cp += nmemb_read_successfully; + + xcfdatalimit = &xcfodata[nmemb_read_successfully - 1]; + + for (i = 0; i < bpp; i++) + { + data = (guchar *) tile_data_pointer (tile, 0, 0) + i; + size = tile_ewidth (tile) * tile_eheight (tile); + count = 0; + + while (size > 0) + { + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } + + val = *xcfdata++; + + length = val; + if (length >= 128) + { + length = 255 - (length - 1); + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } + + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } + + count += length; + size -= length; + + if (size < 0) + { + goto bogus_rle; + } + + if (&xcfdata[length - 1] > xcfdatalimit) + { + goto bogus_rle; + } + + while (length-- > 0) + { + *data = *xcfdata++; + data += bpp; + } + } + else + { + length += 1; + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } + + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } + + count += length; + size -= length; + + if (size < 0) + { + goto bogus_rle; + } + + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } + + val = *xcfdata++; + + for (j = 0; j < length; j++) + { + *data = val; + data += bpp; + } + } + } + } + g_free (xcfodata); + return TRUE; + +bogus_rle: + if (xcfodata) + g_free (xcfodata); + return FALSE; +} + +static KisAnnotation * +xcf_load_parasite (XcfInfo * info) +{ + KisAnnotation *p; + + p = g_new (KisAnnotation, 1); + info->cp += xcf_read_string (info->fp, &p->name, 1); + info->cp += xcf_read_int32 (info->fp, &p->flags, 1); + info->cp += xcf_read_int32 (info->fp, &p->size, 1); + p->data = g_new (TQCString, p->size); + info->cp += xcf_read_int8 (info->fp, p->data, p->size); + + return p; +} + +static bool +xcf_load_old_paths (XcfInfo * info, KisImage * gimage) +{ + TQ_INT32 num_paths; + TQ_INT32 last_selected_row; + GimpVectors *active_vectors; + + info->cp += xcf_read_int32 (info->fp, &last_selected_row, 1); + info->cp += xcf_read_int32 (info->fp, &num_paths, 1); + + while (num_paths-- > 0) + xcf_load_old_path (info, gimage); + + active_vectors = (GimpVectors *) + gimp_container_get_child_by_index (gimage->vectors, last_selected_row); + + if (active_vectors) + gimp_image_set_active_vectors (gimage, active_vectors); + + return TRUE; +} + +static bool +xcf_load_old_path (XcfInfo * info, KisImage * gimage) +{ + TQCString *name; + TQ_INT32 locked; + TQ_UINT8 state; + TQ_INT32 closed; + TQ_INT32 num_points; + TQ_INT32 version; /* changed from num_paths */ + GimpTattoo tattoo = 0; + GimpVectors *vectors; + GimpVectorsCompatPoint *points; + TQ_INT32 i; + + info->cp += xcf_read_string (info->fp, &name, 1); + info->cp += xcf_read_int32 (info->fp, &locked, 1); + info->cp += xcf_read_int8 (info->fp, &state, 1); + info->cp += xcf_read_int32 (info->fp, &closed, 1); + info->cp += xcf_read_int32 (info->fp, &num_points, 1); + info->cp += xcf_read_int32 (info->fp, &version, 1); + + if (version == 2) + { + TQ_INT32 dummy; + + /* Had extra type field and points are stored as doubles */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1); + } + else if (version == 3) + { + TQ_INT32 dummy; + + /* Has extra tatto field */ + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & dummy, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & tattoo, 1); + } + else if (version != 1) + { + g_warning ("Unknown path type. Possibly corrupt XCF file"); + + return FALSE; + } + + /* skip empty compatibility paths */ + if (num_points == 0) + return FALSE; + + points = g_new0 (GimpVectorsCompatPoint, num_points); + + for (i = 0; i < num_points; i++) + { + if (version == 1) + { + TQ_INT3232 x; + TQ_INT3232 y; + + info->cp += xcf_read_int32 (info->fp, &points[i].type, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & x, 1); + info->cp += xcf_read_int32 (info->fp, (TQ_INT32 *) & y, 1); + + points[i].x = x; + points[i].y = y; + } + else + { + float x; + float y; + + info->cp += xcf_read_int32 (info->fp, &points[i].type, 1); + info->cp += xcf_read_float (info->fp, &x, 1); + info->cp += xcf_read_float (info->fp, &y, 1); + + points[i].x = x; + points[i].y = y; + } + } + + vectors = + gimp_vectors_compat_new (gimage, name, points, num_points, closed); + + g_free (name); + g_free (points); + + GIMP_ITEM (vectors)->linked = locked; + + if (tattoo) + GIMP_ITEM (vectors)->tattoo = tattoo; + + gimp_image_add_vectors (gimage, vectors, + gimp_container_num_tqchildren (gimage->vectors)); + + return TRUE; +} + +static bool +xcf_load_vectors (XcfInfo * info, KisImage * gimage) +{ + TQ_INT32 version; + TQ_INT32 active_index; + TQ_INT32 num_paths; + GimpVectors *active_vectors; + TQ_INT32 base; + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("xcf_load_vectors\n"); +#endif + + base = info->cp; + + info->cp += xcf_read_int32 (info->fp, &version, 1); + + if (version != 1) + { + g_message ("Unknown vectors version: %d (skipping)", version); + return FALSE; + } + + info->cp += xcf_read_int32 (info->fp, &active_index, 1); + info->cp += xcf_read_int32 (info->fp, &num_paths, 1); + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("%d paths (active: %d)\n", num_paths, active_index); +#endif + + while (num_paths-- > 0) + if (!xcf_load_vector (info, gimage)) + return FALSE; + + active_vectors = (GimpVectors *) + gimp_container_get_child_by_index (gimage->vectors, active_index); + + if (active_vectors) + gimp_image_set_active_vectors (gimage, active_vectors); + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("xcf_load_vectors: loaded %d bytes\n", info->cp - base); +#endif + return TRUE; +} + +static bool +xcf_load_vector (XcfInfo * info, KisImage * gimage) +{ + TQCString *name; + GimpTattoo tattoo = 0; + TQ_INT32 visible; + TQ_INT32 linked; + TQ_INT32 num_parasites; + TQ_INT32 num_strokes; + GimpVectors *vectors; + TQ_INT32 i; + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("xcf_load_vector\n"); +#endif + + info->cp += xcf_read_string (info->fp, &name, 1); + info->cp += xcf_read_int32 (info->fp, &tattoo, 1); + info->cp += xcf_read_int32 (info->fp, &visible, 1); + info->cp += xcf_read_int32 (info->fp, &linked, 1); + info->cp += xcf_read_int32 (info->fp, &num_parasites, 1); + info->cp += xcf_read_int32 (info->fp, &num_strokes, 1); + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr + ("name: %s, tattoo: %d, visible: %d, linked: %d, num_parasites %d, " + "num_strokes %d\n", name, tattoo, visible, linked, num_parasites, + num_strokes); +#endif + + vectors = gimp_vectors_new (gimage, name); + + GIMP_ITEM (vectors)->visible = visible ? TRUE : FALSE; + GIMP_ITEM (vectors)->linked = linked ? TRUE : FALSE; + + if (tattoo) + GIMP_ITEM (vectors)->tattoo = tattoo; + + for (i = 0; i < num_parasites; i++) + { + KisAnnotation *parasite; + + parasite = xcf_load_parasite (info); + + if (!parasite) + return FALSE; + + gimp_item_parasite_attach (GIMP_ITEM (vectors), parasite); + gimp_parasite_free (parasite); + } + + for (i = 0; i < num_strokes; i++) + { + TQ_INT32 stroke_type_id; + TQ_INT32 closed; + TQ_INT32 num_axes; + TQ_INT32 num_control_points; + TQ_INT32 type; + float coords[6] = { 0.0, 0.0, 1.0, 0.5, 0.5, 0.5 }; + GimpStroke *stroke; + TQ_INT32 j; + + GValueArray *control_points; + GValue value = { 0, }; + GimpAnchor anchor; + GType stroke_type; + + g_value_init (&value, GIMP_TYPE_ANCHOR); + + info->cp += xcf_read_int32 (info->fp, &stroke_type_id, 1); + info->cp += xcf_read_int32 (info->fp, &closed, 1); + info->cp += xcf_read_int32 (info->fp, &num_axes, 1); + info->cp += xcf_read_int32 (info->fp, &num_control_points, 1); + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("stroke_type: %d, closed: %d, num_axes %d, len %d\n", + stroke_type_id, closed, num_axes, num_control_points); +#endif + + switch (stroke_type_id) + { + case XCF_STROKETYPE_BEZIER_STROKE: + stroke_type = GIMP_TYPE_BEZIER_STROKE; + break; + + default: + g_printerr ("skipping unknown stroke type\n"); + xcf_seek_pos (info, + info->cp + 4 * num_axes * num_control_points, NULL); + continue; + } + + control_points = g_value_array_new (num_control_points); + + anchor.selected = FALSE; + + for (j = 0; j < num_control_points; j++) + { + info->cp += xcf_read_int32 (info->fp, &type, 1); + info->cp += xcf_read_float (info->fp, coords, num_axes); + + anchor.type = type; + anchor.position.x = coords[0]; + anchor.position.y = coords[1]; + anchor.position.pressure = coords[2]; + anchor.position.xtilt = coords[3]; + anchor.position.ytilt = coords[4]; + anchor.position.wheel = coords[5]; + + g_value_set_boxed (&value, &anchor); + g_value_array_append (control_points, &value); + +#ifdef GIMP_XCF_PATH_DEBUG + g_printerr ("Anchor: %d, (%f, %f, %f, %f, %f, %f)\n", type, + coords[0], coords[1], coords[2], coords[3], + coords[4], coords[5]); +#endif + } + + g_value_unset (&value); + + stroke = g_object_new (stroke_type, + "closed", closed, + "control-points", control_points, NULL); + + gimp_vectors_stroke_add (vectors, stroke); + } + + gimp_image_add_vectors (gimage, vectors, + gimp_container_num_tqchildren (gimage->vectors)); + + return TRUE; +} + +#ifdef SWAP_FROM_FILE + +static bool +xcf_swap_func (TQ_INT32 fd, Tile * tile, TQ_INT32 cmd, gpointer user_data) +{ + TQ_INT32 bytes; + TQ_INT32 err; + TQ_INT32 nleft; + TQ_INT32 *ref_count; + + switch (cmd) + { + case SWAP_IN: + lseek (fd, tile->swap_offset, SEEK_SET); + + bytes = tile_size (tile); + tile_alloc (tile); + + nleft = bytes; + while (nleft > 0) + { + do + { + err = read (fd, tile->data + bytes - nleft, nleft); + } + while ((err == -1) && ((errno == EAGAIN) || (errno == EINTR))); + + if (err <= 0) + { + g_message ("unable to read tile data from xcf file: " + "%d ( %d ) bytes read", err, nleft); + return FALSE; + } + + nleft -= err; + } + break; + + case SWAP_OUT: + case SWAP_DELETE: + case SWAP_COMPRESS: + ref_count = user_data; + *ref_count -= 1; + if (*ref_count == 0) + { + tile_swap_remove (tile->swap_num); + g_free (ref_count); + } + + tile->swap_num = 1; + tile->swap_offset = -1; + + return TRUE; + } + + return FALSE; +} + +#endif diff --git a/filters/chalk/xcf/xcf/xcf-load.h b/filters/chalk/xcf/xcf/xcf-load.h new file mode 100644 index 00000000..75bc0e9c --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-load.h @@ -0,0 +1,27 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_LOAD_H__ +#define __XCF_LOAD_H__ + +class KisImage; +class XcfInfo; + +KisImage * xcf_load_image (XcfInfo *info); + +#endif /* __XCF_LOAD_H__ */ diff --git a/filters/chalk/xcf/xcf/xcf-private.h b/filters/chalk/xcf/xcf/xcf-private.h new file mode 100644 index 00000000..3a832fbd --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-private.h @@ -0,0 +1,95 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_PRIVATE_H__ +#define __XCF_PRIVATE_H__ + +#include + +typedef enum +{ + PROP_END = 0, + PROP_COLORMAP = 1, + PROP_ACTIVE_LAYER = 2, + PROP_ACTIVE_CHANNEL = 3, + PROP_SELECTION = 4, + PROP_FLOATING_SELECTION = 5, + PROP_OPACITY = 6, + PROP_MODE = 7, + PROP_VISIBLE = 8, + PROP_LINKED = 9, + PROP_LOCK_ALPHA = 10, + PROP_APPLY_MASK = 11, + PROP_EDIT_MASK = 12, + PROP_SHOW_MASK = 13, + PROP_SHOW_MASKED = 14, + PROP_OFFSETS = 15, + PROP_COLOR = 16, + PROP_COMPRESSION = 17, + PROP_GUIDES = 18, + PROP_RESOLUTION = 19, + PROP_TATTOO = 20, + PROP_PARASITES = 21, + PROP_UNIT = 22, + PROP_PATHS = 23, + PROP_USER_UNIT = 24, + PROP_VECTORS = 25, + PROP_TEXT_LAYER_FLAGS = 26 +} PropType; + +typedef enum +{ + COMPRESS_NONE = 0, + COMPRESS_RLE = 1, + COMPRESS_ZLIB = 2, /* unused */ + COMPRESS_FRACTAL = 3 /* unused */ +} XcfCompressionType; + +typedef enum +{ + XCF_ORIENTATION_HORIZONTAL = 1, + XCF_ORIENTATION_VERTICAL = 2 +} XcfQt::OrientationType; + +typedef enum +{ + XCF_STROKETYPE_STROKE = 0, + XCF_STROKETYPE_BEZIER_STROKE = 1 +} XcfStrokeType; + +typedef struct _XcfInfo XcfInfo; + +struct _XcfInfo +{ + FILE *fp; + TQ_UINT32 cp; + const TQCString filename; + //GimpTattoo tattoo_state; + KisLayer *active_layer; + //GimpChannel *active_channel; + //GimpDrawable *floating_sel_drawable; + KisLayer *floating_sel; + TQ_UINT32 floating_sel_offset; + TQ_INT32 swap_num; + TQ_INT32 *ref_count; + XcfCompressionType compression; + TQ_INT32 file_version; +}; + + +#endif /* __XCF_PRIVATE_H__ */ diff --git a/filters/chalk/xcf/xcf/xcf-read.cc b/filters/chalk/xcf/xcf/xcf-read.cc new file mode 100644 index 00000000..314daa90 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-read.cc @@ -0,0 +1,118 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "xcf-read.h" + +#include "gimp-intl.h" + + +TQ_UINT32 +xcf_read_int32 (FILE *fp, + TQ_INT32 *data, + TQ_INT32 count) +{ + TQ_UINT32 total; + + total = count; + if (count > 0) + { + xcf_read_int8 (fp, (TQ_UINT8 *) data, count * 4); + + while (count--) + { + *data = g_ntohl (*data); + data++; + } + } + + return total * 4; +} + +TQ_UINT32 +xcf_read_float (FILE *fp, + float *data, + TQ_INT32 count) +{ + return xcf_read_int32 (fp, (TQ_INT32 *) ((void *) data), count); +} + +TQ_UINT32 +xcf_read_int8 (FILE *fp, + TQ_UINT8 *data, + TQ_INT32 count) +{ + TQ_UINT32 total; + TQ_INT32 bytes; + + total = count; + while (count > 0) + { + bytes = fread ((char *) data, sizeof (char), count, fp); + if (bytes <= 0) /* something bad happened */ + break; + count -= bytes; + data += bytes; + } + + return total; +} + +TQ_UINT32 +xcf_read_string (FILE *fp, + TQCString **data, + TQ_INT32 count) +{ + TQ_INT32 tmp; + TQ_UINT32 total; + TQ_INT32 i; + + total = 0; + for (i = 0; i < count; i++) + { + total += xcf_read_int32 (fp, &tmp, 1); + if (tmp > 0) + { + TQCString *str; + + str = g_new (TQCString, tmp); + total += xcf_read_int8 (fp, (TQ_UINT8*) str, tmp); + + if (str[tmp - 1] != '\0') + str[tmp - 1] = '\0'; + + data[i] = gimp_any_to_utf8 (str, -1, + _("Invalid UTF-8 string in XCF file")); + + g_free (str); + } + else + { + data[i] = NULL; + } + } + + return total; +} diff --git a/filters/chalk/xcf/xcf/xcf-read.h b/filters/chalk/xcf/xcf/xcf-read.h new file mode 100644 index 00000000..b90b8a41 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-read.h @@ -0,0 +1,37 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_READ_H__ +#define __XCF_READ_H__ + + +TQ_UINT32 xcf_read_int32 (FILE *fp, + TQ_INT32 *data, + TQ_INT32 count); +TQ_UINT32 xcf_read_float (FILE *fp, + float *data, + TQ_INT32 count); +TQ_UINT32 xcf_read_int8 (FILE *fp, + TQ_UINT8 *data, + TQ_INT32 count); +TQ_UINT32 xcf_read_string (FILE *fp, + TQCString **data, + TQ_INT32 count); + + +#endif /* __XCF_READ_H__ */ diff --git a/filters/chalk/xcf/xcf/xcf-save.cc b/filters/chalk/xcf/xcf/xcf-save.cc new file mode 100644 index 00000000..50e5fb17 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-save.cc @@ -0,0 +1,1826 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include /* strcpy, strlen */ + +#include + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" + +#include "core/core-types.h" + +#include "base/tile.h" +#include "base/tile-manager.h" +#include "base/tile-manager-private.h" + +#include "core/gimpchannel.h" +#include "core/gimpdrawable.h" +#include "core/gimpgrid.h" +#include "core/gimpimage.h" +#include "core/gimpimage-grid.h" +#include "core/gimpimage-guides.h" +#include "core/gimplayer.h" +#include "core/gimplayer-floating-sel.h" +#include "core/gimplayertqmask.h" +#include "core/gimplist.h" +#include "core/gimpparasitelist.h" +#include "core/gimpunit.h" + +#include "text/gimptextlayer.h" +#include "text/gimptextlayer-xcf.h" + +#include "vectors/gimpanchor.h" +#include "vectors/gimpstroke.h" +#include "vectors/gimpbezierstroke.h" +#include "vectors/gimpvectors.h" +#include "vectors/gimpvectors-compat.h" + +#include "xcf-private.h" +#include "xcf-read.h" +#include "xcf-seek.h" +#include "xcf-write.h" + +#include "gimp-intl.h" + + +static bool xcf_save_image_props (XcfInfo *info, + KisImage *gimage, + GError **error); +static bool xcf_save_layer_props (XcfInfo *info, + KisImage *gimage, + KisLayer *layer, + GError **error); +static bool xcf_save_channel_props (XcfInfo *info, + KisImage *gimage, + GimpChannel *channel, + GError **error); +static bool xcf_save_prop (XcfInfo *info, + KisImage *gimage, + PropType prop_type, + GError **error, + ...); +static bool xcf_save_layer (XcfInfo *info, + KisImage *gimage, + KisLayer *layer, + GError **error); +static bool xcf_save_channel (XcfInfo *info, + KisImage *gimage, + GimpChannel *channel, + GError **error); +static bool xcf_save_hierarchy (XcfInfo *info, + TileManager *tiles, + GError **error); +static bool xcf_save_level (XcfInfo *info, + TileManager *tiles, + GError **error); +static bool xcf_save_tile (XcfInfo *info, + Tile *tile, + GError **error); +static bool xcf_save_tile_rle (XcfInfo *info, + Tile *tile, + guchar *rlebuf, + GError **error); +static bool xcf_save_parasite (XcfInfo *info, + KisAnnotation *parasite, + GError **error); +static bool xcf_save_parasite_list (XcfInfo *info, + KisAnnotationList *parasite, + GError **error); +static bool xcf_save_old_paths (XcfInfo *info, + KisImage *gimage, + GError **error); +static bool xcf_save_vectors (XcfInfo *info, + KisImage *gimage, + GError **error); + + +/* private convenience macros */ +#define xcf_write_int32_check_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_int32 (info->fp, data, count, &tmp_error); \ + if (tmp_error) \ + { \ + g_propagate_error (error, tmp_error); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_int8_check_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_int8 (info->fp, data, count, &tmp_error); \ + if (tmp_error) \ + { \ + g_propagate_error (error, tmp_error); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_float_check_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_float (info->fp, data, count, &tmp_error); \ + if (tmp_error) \ + { \ + g_propagate_error (error, tmp_error); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_string_check_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_string (info->fp, data, count, &tmp_error); \ + if (tmp_error) \ + { \ + g_propagate_error (error, tmp_error); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_int32_print_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_int32 (info->fp, data, count, &error); \ + if (error) \ + { \ + g_message (_("Error saving XCF file: %s"), \ + error->message); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_int8_print_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_int8 (info->fp, data, count, &error); \ + if (error) \ + { \ + g_message (_("Error saving XCF file: %s"), \ + error->message); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_float_print_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_float (info->fp, data, count, &error); \ + if (error) \ + { \ + g_message (_("Error saving XCF file: %s"), \ + error->message); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_string_print_error(info, data, count) G_STMT_START { \ + info->cp += xcf_write_string (info->fp, data, count, &error); \ + if (error) \ + { \ + g_message (_("Error saving XCF file: %s"), \ + error->message); \ + return FALSE; \ + } \ + } G_STMT_END + +#define xcf_write_prop_type_check_error(info, prop_type) G_STMT_START { \ + TQ_INT32 _prop_int32 = prop_type; \ + xcf_write_int32_check_error (info, &_prop_int32, 1); \ + } G_STMT_END + +#define xcf_write_prop_type_print_error(info, prop_type) G_STMT_START { \ + TQ_INT32 _prop_int32 = prop_type; \ + xcf_write_int32_print_error (info, &_prop_int32, 1); \ + } G_STMT_END + +#define xcf_check_error(x) G_STMT_START { \ + if (! (x)) \ + return FALSE; \ + } G_STMT_END + +#define xcf_print_error(x) G_STMT_START { \ + if (! (x)) \ + { \ + g_message (_("Error saving XCF file: %s"), \ + error->message); \ + return FALSE; \ + } \ + } G_STMT_END + + +void +xcf_save_choose_format (XcfInfo *info, + KisImage *gimage) +{ + KisLayer *layer; + GList *list; + + TQ_INT32 save_version = 0; /* default to oldest */ + + if (gimage->cmap) + save_version = 1; /* need version 1 for colormaps */ + + for (list = GIMP_LIST (gimage->layers)->list; + list && save_version < 2; + list = g_list_next (list)) + { + layer = GIMP_LAYER (list->data); + + switch (layer->mode) + { + /* new layer modes not supported by gimp-1.2 */ + case GIMP_SOFTLIGHT_MODE: + case GIMP_GRAIN_EXTRACT_MODE: + case GIMP_GRAIN_MERGE_MODE: + case GIMP_COLOR_ERASE_MODE: + save_version = 2; + break; + + default: + break; + } + } + + info->file_version = save_version; +} + +TQ_INT32 +xcf_save_image (XcfInfo *info, + KisImage *gimage) +{ + KisLayer *layer; + KisLayer *floating_layer; + GimpChannel *channel; + TQ_INT32 saved_pos; + TQ_INT32 offset; + TQ_UINT32 nlayers; + TQ_UINT32 nchannels; + GList *list; + bool have_selection; + TQ_INT32 t1, t2, t3, t4; + TQCString version_tag[14]; + GError *error = NULL; + + floating_layer = gimp_image_floating_sel (gimage); + if (floating_layer) + floating_sel_relax (floating_layer, FALSE); + + /* write out the tag information for the image */ + if (info->file_version > 0) + { + sprintf (version_tag, "gimp xcf v%03d", info->file_version); + } + else + { + strcpy (version_tag, "gimp xcf file"); + } + xcf_write_int8_print_error (info, (TQ_UINT8 *) version_tag, 14); + + /* write out the width, height and image type information for the image */ + xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->width, 1); + xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->height, 1); + xcf_write_int32_print_error (info, (TQ_INT32 *) &gimage->base_type, 1); + + /* determine the number of layers and channels in the image */ + nlayers = (TQ_UINT32) gimp_container_num_tqchildren (gimage->layers); + nchannels = (TQ_UINT32) gimp_container_num_tqchildren (gimage->channels); + + /* check and see if we have to save out the selection */ + have_selection = gimp_channel_bounds (gimp_image_get_tqmask (gimage), + &t1, &t2, &t3, &t4); + if (have_selection) + nchannels += 1; + + /* write the property information for the image. + */ + + xcf_print_error (xcf_save_image_props (info, gimage, &error)); + + /* save the current file position as it is the start of where + * we place the layer offset information. + */ + saved_pos = info->cp; + + /* seek to after the offset lists */ + xcf_print_error (xcf_seek_pos (info, + info->cp + (nlayers + nchannels + 2) * 4, + &error)); + + for (list = GIMP_LIST (gimage->layers)->list; + list; + list = g_list_next (list)) + { + layer = (KisLayer *) list->data; + + /* save the start offset of where we are writing + * out the next layer. + */ + offset = info->cp; + + /* write out the layer. */ + xcf_print_error (xcf_save_layer (info, gimage, layer, &error)); + + /* seek back to where we are to write out the next + * layer offset and write it out. + */ + xcf_print_error (xcf_seek_pos (info, saved_pos, &error)); + xcf_write_int32_print_error (info, &offset, 1); + + /* increment the location we are to write out the + * next offset. + */ + saved_pos = info->cp; + + /* seek to the end of the file which is where + * we will write out the next layer. + */ + xcf_print_error (xcf_seek_end (info, &error)); + } + + /* write out a '0' offset position to indicate the end + * of the layer offsets. + */ + offset = 0; + xcf_print_error (xcf_seek_pos (info, saved_pos, &error)); + xcf_write_int32_print_error (info, &offset, 1); + saved_pos = info->cp; + xcf_print_error (xcf_seek_end (info, &error)); + + list = GIMP_LIST (gimage->channels)->list; + + while (list || have_selection) + { + if (list) + { + channel = (GimpChannel *) list->data; + + list = g_list_next (list); + } + else + { + channel = gimage->selection_tqmask; + have_selection = FALSE; + } + + /* save the start offset of where we are writing + * out the next channel. + */ + offset = info->cp; + + /* write out the layer. */ + xcf_print_error (xcf_save_channel (info, gimage, channel, &error)); + + /* seek back to where we are to write out the next + * channel offset and write it out. + */ + xcf_print_error (xcf_seek_pos (info, saved_pos, &error)); + xcf_write_int32_print_error (info, &offset, 1); + + /* increment the location we are to write out the + * next offset. + */ + saved_pos = info->cp; + + /* seek to the end of the file which is where + * we will write out the next channel. + */ + xcf_print_error (xcf_seek_end (info, &error)); + } + + /* write out a '0' offset position to indicate the end + * of the channel offsets. + */ + offset = 0; + xcf_print_error (xcf_seek_pos (info, saved_pos, &error)); + xcf_write_int32_print_error (info, &offset, 1); + saved_pos = info->cp; + + if (floating_layer) + floating_sel_rigor (floating_layer, FALSE); + + return !ferror(info->fp); +} + +static bool +xcf_save_image_props (XcfInfo *info, + KisImage *gimage, + GError **error) +{ + KisAnnotation *parasite = NULL; + GimpUnit unit = gimp_image_get_unit (gimage); + + /* check and see if we should save the colormap property */ + if (gimage->cmap) + xcf_check_error (xcf_save_prop (info, gimage, PROP_COLORMAP, error, + gimage->num_cols, gimage->cmap)); + + if (info->compression != COMPRESS_NONE) + xcf_check_error (xcf_save_prop (info, gimage, PROP_COMPRESSION, + error, info->compression)); + + if (gimage->guides) + xcf_check_error (xcf_save_prop (info, gimage, PROP_GUIDES, + error, gimage->guides)); + + xcf_check_error (xcf_save_prop (info, gimage, PROP_RESOLUTION, error, + gimage->xresolution, gimage->yresolution)); + + xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error, + gimage->tattoo_state)); + + if (gimp_parasite_list_length (gimage->parasites) > 0) + xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, + error, gimage->parasites)); + + if (unit < _gimp_unit_get_number_of_built_in_units (gimage->gimp)) + xcf_check_error (xcf_save_prop (info, gimage, PROP_UNIT, error, unit)); + + if (gimp_container_num_tqchildren (gimage->vectors) > 0) + { + if (gimp_vectors_compat_is_compatible (gimage)) + xcf_check_error (xcf_save_prop (info, gimage, PROP_PATHS, error)); + else + xcf_check_error (xcf_save_prop (info, gimage, PROP_VECTORS, error)); + } + + if (unit >= _gimp_unit_get_number_of_built_in_units (gimage->gimp)) + xcf_check_error (xcf_save_prop (info, gimage, PROP_USER_UNIT, error, unit)); + + if (GIMP_IS_GRID (gimage->grid)) + { + GimpGrid *grid = gimp_image_get_grid (gimage); + + parasite = gimp_grid_to_parasite (grid); + gimp_parasite_list_add (GIMP_IMAGE (gimage)->parasites, parasite); + } + + if (gimp_parasite_list_length (GIMP_IMAGE (gimage)->parasites) > 0) + { + xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error, + GIMP_IMAGE (gimage)->parasites)); + } + + if (parasite) + { + gimp_parasite_list_remove (GIMP_IMAGE (gimage)->parasites, + gimp_parasite_name (parasite)); + gimp_parasite_free (parasite); + } + + xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error)); + + return TRUE; +} + +static bool +xcf_save_layer_props (XcfInfo *info, + KisImage *gimage, + KisLayer *layer, + GError **error) +{ + KisAnnotation *parasite = NULL; + + if (layer == gimp_image_get_active_layer (gimage)) + xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_LAYER, error)); + + if (layer == gimp_image_floating_sel (gimage)) + { + info->floating_sel_drawable = layer->fs.drawable; + xcf_check_error (xcf_save_prop (info, gimage, PROP_FLOATING_SELECTION, + error)); + } + + xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error, + layer->opacity)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error, + gimp_item_get_visible (GIMP_ITEM (layer)))); + xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error, + gimp_item_get_linked (GIMP_ITEM (layer)))); + xcf_check_error (xcf_save_prop (info, gimage, PROP_LOCK_ALPHA, + error, layer->lock_alpha)); + + if (layer->tqmask) + { + xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK, + error, layer->tqmask->apply_tqmask)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK, + error, layer->tqmask->edit_tqmask)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK, + error, layer->tqmask->show_tqmask)); + } + else + { + xcf_check_error (xcf_save_prop (info, gimage, PROP_APPLY_MASK, + error, FALSE)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_EDIT_MASK, + error, FALSE)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASK, + error, FALSE)); + } + + xcf_check_error (xcf_save_prop (info, gimage, PROP_OFFSETS, error, + GIMP_ITEM (layer)->offset_x, + GIMP_ITEM (layer)->offset_y)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_MODE, error, + layer->mode)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error, + GIMP_ITEM (layer)->tattoo)); + + if (GIMP_IS_TEXT_LAYER (layer) && GIMP_TEXT_LAYER (layer)->text) + { + GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer); + TQ_INT32 flags = gimp_text_layer_get_xcf_flags (text_layer); + + gimp_text_layer_xcf_save_prepare (text_layer); + + if (flags) + xcf_check_error (xcf_save_prop (info, + gimage, PROP_TEXT_LAYER_FLAGS, error, + flags)); + } + + if (gimp_parasite_list_length (GIMP_ITEM (layer)->parasites) > 0) + { + xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error, + GIMP_ITEM (layer)->parasites)); + } + + if (parasite) + { + gimp_parasite_list_remove (GIMP_ITEM (layer)->parasites, + gimp_parasite_name (parasite)); + gimp_parasite_free (parasite); + } + + xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error)); + + return TRUE; +} + +static bool +xcf_save_channel_props (XcfInfo *info, + KisImage *gimage, + GimpChannel *channel, + GError **error) +{ + guchar col[3]; + + if (channel == gimp_image_get_active_channel (gimage)) + xcf_check_error (xcf_save_prop (info, gimage, PROP_ACTIVE_CHANNEL, error)); + + if (channel == gimage->selection_tqmask) + xcf_check_error (xcf_save_prop (info, gimage, PROP_SELECTION, error)); + + xcf_check_error (xcf_save_prop (info, gimage, PROP_OPACITY, error, + channel->color.a)); + xcf_check_error (xcf_save_prop (info, gimage, PROP_VISIBLE, error, + gimp_item_get_visible (GIMP_ITEM (channel)))); + xcf_check_error (xcf_save_prop (info, gimage, PROP_LINKED, error, + gimp_item_get_linked (GIMP_ITEM (channel)))); + xcf_check_error (xcf_save_prop (info, gimage, PROP_SHOW_MASKED, error, + channel->show_tqmasked)); + + gimp_rgb_get_uchar (&channel->color, &col[0], &col[1], &col[2]); + xcf_check_error (xcf_save_prop (info, gimage, PROP_COLOR, error, col)); + + xcf_check_error (xcf_save_prop (info, gimage, PROP_TATTOO, error, + GIMP_ITEM (channel)->tattoo)); + + if (gimp_parasite_list_length (GIMP_ITEM (channel)->parasites) > 0) + xcf_check_error (xcf_save_prop (info, gimage, PROP_PARASITES, error, + GIMP_ITEM (channel)->parasites)); + + xcf_check_error (xcf_save_prop (info, gimage, PROP_END, error)); + + return TRUE; +} + +static bool +xcf_save_prop (XcfInfo *info, + KisImage *gimage, + PropType prop_type, + GError **error, + ...) +{ + TQ_INT32 size; + va_list args; + + GError *tmp_error = NULL; + + va_start (args, error); + + switch (prop_type) + { + case PROP_END: + size = 0; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + break; + + case PROP_COLORMAP: + { + TQ_INT32 ncolors; + guchar *colors; + + ncolors = va_arg (args, TQ_INT32); + colors = va_arg (args, guchar*); + size = 4 + ncolors * 3; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &ncolors, 1); + xcf_write_int8_check_error (info, colors, ncolors * 3); + } + break; + + case PROP_ACTIVE_LAYER: + case PROP_ACTIVE_CHANNEL: + case PROP_SELECTION: + size = 0; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + break; + + case PROP_FLOATING_SELECTION: + { + TQ_INT32 dummy; + + dummy = 0; + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + info->floating_sel_offset = info->cp; + xcf_write_int32_check_error (info, &dummy, 1); + } + break; + + case PROP_OPACITY: + { + gdouble opacity; + TQ_INT32 uint_opacity; + + opacity = va_arg (args, gdouble); + + uint_opacity = opacity * 255.999; + + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &uint_opacity, 1); + } + break; + + case PROP_MODE: + { + TQ_INT3232 mode; + + mode = va_arg (args, TQ_INT3232); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &mode, 1); + } + break; + + case PROP_VISIBLE: + { + TQ_INT32 visible; + + visible = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &visible, 1); + } + break; + + case PROP_LINKED: + { + TQ_INT32 linked; + + linked = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &linked, 1); + } + break; + + case PROP_LOCK_ALPHA: + { + TQ_INT32 lock_alpha; + + lock_alpha = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &lock_alpha, 1); + } + break; + + case PROP_APPLY_MASK: + { + TQ_INT32 apply_tqmask; + + apply_tqmask = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &apply_tqmask, 1); + } + break; + + case PROP_EDIT_MASK: + { + TQ_INT32 edit_tqmask; + + edit_tqmask = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &edit_tqmask, 1); + } + break; + + case PROP_SHOW_MASK: + { + TQ_INT32 show_tqmask; + + show_tqmask = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &show_tqmask, 1); + } + break; + + case PROP_SHOW_MASKED: + { + TQ_INT32 show_tqmasked; + + show_tqmasked = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &show_tqmasked, 1); + } + break; + + case PROP_OFFSETS: + { + TQ_INT3232 offsets[2]; + + offsets[0] = va_arg (args, TQ_INT3232); + offsets[1] = va_arg (args, TQ_INT3232); + size = 8; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) offsets, 2); + } + break; + + case PROP_COLOR: + { + guchar *color; + + color = va_arg (args, guchar*); + size = 3; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int8_check_error (info, color, 3); + } + break; + + case PROP_COMPRESSION: + { + TQ_UINT8 compression; + + compression = (TQ_UINT8) va_arg (args, TQ_INT32); + size = 1; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int8_check_error (info, &compression, 1); + } + break; + + case PROP_GUIDES: + { + GList *guides; + GimpGuide *guide; + TQ_INT3232 position; + TQ_INT328 orientation; + TQ_INT32 nguides; + + guides = va_arg (args, GList *); + nguides = g_list_length (guides); + + size = nguides * (4 + 1); + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + + for (; guides; guides = g_list_next (guides)) + { + guide = (GimpGuide *) guides->data; + + position = guide->position; + + switch (guide->orientation) + { + case GIMP_ORIENTATION_HORIZONTAL: + orientation = XCF_ORIENTATION_HORIZONTAL; + break; + + case GIMP_ORIENTATION_VERTICAL: + orientation = XCF_ORIENTATION_VERTICAL; + break; + + default: + g_warning ("%s: skipping guide with bad orientation", + G_STRFUNC); + continue; + } + + xcf_write_int32_check_error (info, (TQ_INT32 *) &position, 1); + xcf_write_int8_check_error (info, (TQ_UINT8 *) &orientation, 1); + } + } + break; + + case PROP_RESOLUTION: + { + float xresolution, yresolution; + + /* we pass in floats, + but they are promoted to double by the compiler */ + xresolution = va_arg (args, double); + yresolution = va_arg (args, double); + + size = 4*2; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + + xcf_write_float_check_error (info, &xresolution, 1); + xcf_write_float_check_error (info, &yresolution, 1); + } + break; + + case PROP_TATTOO: + { + TQ_INT32 tattoo; + + tattoo = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &tattoo, 1); + } + break; + + case PROP_PARASITES: + { + KisAnnotationList *list; + TQ_INT32 base, length; + long pos; + + list = va_arg (args, KisAnnotationList *); + + if (gimp_parasite_list_persistent_length (list) > 0) + { + xcf_write_prop_type_check_error (info, prop_type); + + /* because we don't know how much room the parasite list will take + * we save the file position and write the length later + */ + pos = info->cp; + xcf_write_int32_check_error (info, &length, 1); + base = info->cp; + + xcf_check_error (xcf_save_parasite_list (info, list, error)); + + length = info->cp - base; + /* go back to the saved position and write the length */ + xcf_check_error (xcf_seek_pos (info, pos, error)); + xcf_write_int32 (info->fp, &length, 1, &tmp_error); + if (tmp_error) + { + g_propagate_error (error, tmp_error); + return FALSE; + } + + xcf_check_error (xcf_seek_end (info, error)); + } + } + break; + + case PROP_UNIT: + { + TQ_INT32 unit; + + unit = va_arg (args, TQ_INT32); + + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &unit, 1); + } + break; + + case PROP_PATHS: + { + TQ_INT32 base, length; + glong pos; + + xcf_write_prop_type_check_error (info, prop_type); + + /* because we don't know how much room the paths list will take + * we save the file position and write the length later + */ + pos = info->cp; + xcf_write_int32_check_error (info, &length, 1); + + base = info->cp; + + xcf_check_error (xcf_save_old_paths (info, gimage, error)); + + length = info->cp - base; + + /* go back to the saved position and write the length */ + xcf_check_error (xcf_seek_pos (info, pos, error)); + xcf_write_int32 (info->fp, &length, 1, &tmp_error); + if (tmp_error) + { + g_propagate_error (error, tmp_error); + return FALSE; + } + + xcf_check_error (xcf_seek_end (info, error)); + } + break; + + case PROP_USER_UNIT: + { + GimpUnit unit; + const TQCString *unit_strings[5]; + float factor; + TQ_INT32 digits; + + unit = va_arg (args, TQ_INT32); + + /* write the entire unit definition */ + unit_strings[0] = _gimp_unit_get_identifier (gimage->gimp, unit); + factor = _gimp_unit_get_factor (gimage->gimp, unit); + digits = _gimp_unit_get_digits (gimage->gimp, unit); + unit_strings[1] = _gimp_unit_get_symbol (gimage->gimp, unit); + unit_strings[2] = _gimp_unit_get_abbreviation (gimage->gimp, unit); + unit_strings[3] = _gimp_unit_get_singular (gimage->gimp, unit); + unit_strings[4] = _gimp_unit_get_plural (gimage->gimp, unit); + + size = + 2 * 4 + + strlen (unit_strings[0]) ? strlen (unit_strings[0]) + 5 : 4 + + strlen (unit_strings[1]) ? strlen (unit_strings[1]) + 5 : 4 + + strlen (unit_strings[2]) ? strlen (unit_strings[2]) + 5 : 4 + + strlen (unit_strings[3]) ? strlen (unit_strings[3]) + 5 : 4 + + strlen (unit_strings[4]) ? strlen (unit_strings[4]) + 5 : 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_float_check_error (info, &factor, 1); + xcf_write_int32_check_error (info, &digits, 1); + xcf_write_string_check_error (info, (TQCString **) unit_strings, 5); + } + break; + + case PROP_VECTORS: + { + TQ_INT32 base, length; + glong pos; + + xcf_write_prop_type_check_error (info, prop_type); + + /* because we don't know how much room the paths list will take + * we save the file position and write the length later + */ + pos = info->cp; + xcf_write_int32_check_error (info, &length, 1); + + base = info->cp; + + xcf_check_error (xcf_save_vectors (info, gimage, error)); + + length = info->cp - base; + + /* go back to the saved position and write the length */ + xcf_check_error (xcf_seek_pos (info, pos, error)); + xcf_write_int32 (info->fp, &length, 1, &tmp_error); + if (tmp_error) + { + g_propagate_error (error, tmp_error); + return FALSE; + } + + xcf_check_error (xcf_seek_end (info, error)); + } + break; + + case PROP_TEXT_LAYER_FLAGS: + { + TQ_INT32 flags; + + flags = va_arg (args, TQ_INT32); + size = 4; + + xcf_write_prop_type_check_error (info, prop_type); + xcf_write_int32_check_error (info, &size, 1); + xcf_write_int32_check_error (info, &flags, 1); + } + break; + } + + va_end (args); + + return TRUE; +} + +static bool +xcf_save_layer (XcfInfo *info, + KisImage *gimage, + KisLayer *layer, + GError **error) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset; + + GError *tmp_error = NULL; + + /* check and see if this is the drawable that the floating + * selection is attached to. + */ + if (GIMP_DRAWABLE (layer) == info->floating_sel_drawable) + { + saved_pos = info->cp; + xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error)); + xcf_write_int32_check_error (info, &saved_pos, 1); + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + } + + /* write out the width, height and image type information for the layer */ + xcf_write_int32_check_error (info, + (TQ_INT32 *) &GIMP_ITEM (layer)->width, 1); + xcf_write_int32_check_error (info, + (TQ_INT32 *) &GIMP_ITEM (layer)->height, 1); + xcf_write_int32_check_error (info, + (TQ_INT32 *) &GIMP_DRAWABLE (layer)->type, 1); + + /* write out the layers name */ + xcf_write_string_check_error (info, &GIMP_OBJECT (layer)->name, 1); + + /* write out the layer properties */ + xcf_save_layer_props (info, gimage, layer, error); + + /* save the current position which is where the hierarchy offset + * will be stored. + */ + saved_pos = info->cp; + + /* write out the layer tile hierarchy */ + xcf_check_error (xcf_seek_pos (info, info->cp + 8, error)); + offset = info->cp; + + xcf_check_error (xcf_save_hierarchy (info, + GIMP_DRAWABLE(layer)->tiles, error)); + + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + saved_pos = info->cp; + + /* write out the layer tqmask */ + if (layer->tqmask) + { + xcf_check_error (xcf_seek_end (info, error)); + offset = info->cp; + + xcf_check_error (xcf_save_channel (info, + gimage, GIMP_CHANNEL(layer->tqmask), + error)); + } + else + offset = 0; + + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + + return TRUE; +} + +static bool +xcf_save_channel (XcfInfo *info, + KisImage *gimage, + GimpChannel *channel, + GError **error) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset; + + GError *tmp_error = NULL; + + /* check and see if this is the drawable that the floating + * selection is attached to. + */ + if (GIMP_DRAWABLE (channel) == info->floating_sel_drawable) + { + saved_pos = info->cp; + xcf_check_error (xcf_seek_pos (info, info->floating_sel_offset, error)); + xcf_write_int32_check_error (info, &saved_pos, 1); + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + } + + /* write out the width and height information for the channel */ + xcf_write_int32_check_error (info, + (TQ_INT32 *) &GIMP_ITEM (channel)->width, 1); + xcf_write_int32_check_error (info, + (TQ_INT32 *) &GIMP_ITEM (channel)->height, 1); + + /* write out the channels name */ + xcf_write_string_check_error (info, &GIMP_OBJECT (channel)->name, 1); + + /* write out the channel properties */ + xcf_save_channel_props (info, gimage, channel, error); + + /* save the current position which is where the hierarchy offset + * will be stored. + */ + saved_pos = info->cp; + + /* write out the channel tile hierarchy */ + xcf_check_error (xcf_seek_pos (info, info->cp + 4, error)); + offset = info->cp; + + xcf_check_error (xcf_save_hierarchy (info, + GIMP_DRAWABLE (channel)->tiles, error)); + + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + saved_pos = info->cp; + + return TRUE; +} + +static TQ_INT32 +xcf_calc_levels (TQ_INT32 size, + TQ_INT32 tile_size) +{ + int levels; + + levels = 1; + while (size > tile_size) + { + size /= 2; + levels += 1; + } + + return levels; +} + + +static bool +xcf_save_hierarchy (XcfInfo *info, + TileManager *tiles, + GError **error) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset; + TQ_INT32 width; + TQ_INT32 height; + TQ_INT32 bpp; + TQ_INT32 i; + TQ_INT32 nlevels; + TQ_INT32 tmp1, tmp2; + + GError *tmp_error = NULL; + + width = tile_manager_width (tiles); + height = tile_manager_height (tiles); + bpp = tile_manager_bpp (tiles); + + xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &bpp, 1); + + saved_pos = info->cp; + + tmp1 = xcf_calc_levels (width, TILE_WIDTH); + tmp2 = xcf_calc_levels (height, TILE_HEIGHT); + nlevels = MAX (tmp1, tmp2); + + xcf_check_error (xcf_seek_pos (info, info->cp + (1 + nlevels) * 4, error)); + + for (i = 0; i < nlevels; i++) + { + offset = info->cp; + + if (i == 0) + { + /* write out the level. */ + xcf_check_error (xcf_save_level (info, tiles, error)); + } + else + { + /* fake an empty level */ + tmp1 = 0; + width /= 2; + height /= 2; + xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &tmp1, 1); + } + + /* seek back to where we are to write out the next + * level offset and write it out. + */ + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + + /* increment the location we are to write out the + * next offset. + */ + saved_pos = info->cp; + + /* seek to the end of the file which is where + * we will write out the next level. + */ + xcf_check_error (xcf_seek_end (info, error)); + } + + /* write out a '0' offset position to indicate the end + * of the level offsets. + */ + offset = 0; + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + + return TRUE; +} + +static bool +xcf_save_level (XcfInfo *info, + TileManager *level, + GError **error) +{ + TQ_INT32 saved_pos; + TQ_INT32 offset; + TQ_INT32 width; + TQ_INT32 height; + TQ_UINT32 ntiles; + TQ_INT32 i; + guchar *rlebuf; + + GError *tmp_error = NULL; + + width = tile_manager_width (level); + height = tile_manager_height (level); + + xcf_write_int32_check_error (info, (TQ_INT32 *) &width, 1); + xcf_write_int32_check_error (info, (TQ_INT32 *) &height, 1); + + saved_pos = info->cp; + + /* allocate a temporary buffer to store the rle data before it is + written to disk */ + rlebuf = + g_malloc (TILE_WIDTH * TILE_HEIGHT * tile_manager_bpp (level) * 1.5); + + if (level->tiles) + { + ntiles = level->ntile_rows * level->ntile_cols; + xcf_check_error (xcf_seek_pos (info, info->cp + (ntiles + 1) * 4, error)); + + for (i = 0; i < ntiles; i++) + { + /* save the start offset of where we are writing + * out the next tile. + */ + offset = info->cp; + + /* write out the tile. */ + switch (info->compression) + { + case COMPRESS_NONE: + xcf_check_error(xcf_save_tile (info, level->tiles[i], error)); + break; + case COMPRESS_RLE: + xcf_check_error (xcf_save_tile_rle (info, level->tiles[i], + rlebuf, error)); + break; + case COMPRESS_ZLIB: + g_error ("xcf: zlib compression unimplemented"); + break; + case COMPRESS_FRACTAL: + g_error ("xcf: fractal compression unimplemented"); + break; + } + + /* seek back to where we are to write out the next + * tile offset and write it out. + */ + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + + /* increment the location we are to write out the + * next offset. + */ + saved_pos = info->cp; + + /* seek to the end of the file which is where + * we will write out the next tile. + */ + xcf_check_error (xcf_seek_end (info, error)); + } + } + + g_free (rlebuf); + + /* write out a '0' offset position to indicate the end + * of the level offsets. + */ + offset = 0; + xcf_check_error (xcf_seek_pos (info, saved_pos, error)); + xcf_write_int32_check_error (info, &offset, 1); + + return TRUE; + +} + +static bool +xcf_save_tile (XcfInfo *info, + Tile *tile, + GError **error) +{ + GError *tmp_error = NULL; + + tile_lock (tile); + xcf_write_int8_check_error (info, tile_data_pointer (tile, 0, 0), + tile_size (tile)); + tile_release (tile, FALSE); + + return TRUE; +} + +static bool +xcf_save_tile_rle (XcfInfo *info, + Tile *tile, + guchar *rlebuf, + GError **error) +{ + guchar *data, *t; + unsigned int last; + TQ_INT32 state; + TQ_INT32 length; + TQ_INT32 count; + TQ_INT32 size; + TQ_INT32 bpp; + TQ_INT32 i, j; + TQ_INT32 len = 0; + + GError *tmp_error = NULL; + + tile_lock (tile); + + bpp = tile_bpp (tile); + + for (i = 0; i < bpp; i++) + { + data = (guchar*) tile_data_pointer (tile, 0, 0) + i; + + state = 0; + length = 0; + count = 0; + size = tile_ewidth(tile) * tile_eheight(tile); + last = -1; + + while (size > 0) + { + switch (state) + { + case 0: + /* in state 0 we try to find a long sequence of + * matching values. + */ + if ((length == 32768) || + ((size - length) <= 0) || + ((length > 1) && (last != *data))) + { + count += length; + if (length >= 128) + { + rlebuf[len++] = 127; + rlebuf[len++] = (length >> 8); + rlebuf[len++] = length & 0x00FF; + rlebuf[len++] = last; + } + else + { + rlebuf[len++] = length - 1; + rlebuf[len++] = last; + } + size -= length; + length = 0; + } + else if ((length == 1) && (last != *data)) + state = 1; + break; + + case 1: + /* in state 1 we try and find a long sequence of + * non-matching values. + */ + if ((length == 32768) || + ((size - length) == 0) || + ((length > 0) && (last == *data) && + ((size - length) == 1 || last == data[bpp]))) + { + count += length; + state = 0; + + if (length >= 128) + { + rlebuf[len++] = 255 - 127; + rlebuf[len++] = (length >> 8); + rlebuf[len++] = length & 0x00FF; + } + else + { + rlebuf[len++] = 255 - (length - 1); + } + + t = data - length * bpp; + for (j = 0; j < length; j++) + { + rlebuf[len++] = *t; + t += bpp; + } + + size -= length; + length = 0; + } + break; + } + + if (size > 0) { + length += 1; + last = *data; + data += bpp; + } + } + + if (count != (tile_ewidth (tile) * tile_eheight (tile))) + g_message ("xcf: uh oh! xcf rle tile saving error: %d", count); + } + xcf_write_int8_check_error (info, rlebuf, len); + tile_release (tile, FALSE); + + return TRUE; +} + +static bool +xcf_save_parasite (XcfInfo *info, + KisAnnotation *parasite, + GError **error) +{ + if (gimp_parasite_is_persistent (parasite)) + { + GError *tmp_error = NULL; + + xcf_write_string_check_error (info, ¶site->name, 1); + xcf_write_int32_check_error (info, ¶site->flags, 1); + xcf_write_int32_check_error (info, ¶site->size, 1); + xcf_write_int8_check_error (info, parasite->data, parasite->size); + } + + return TRUE; +} + +typedef struct +{ + XcfInfo *info; + GError *error; +} XcfParasiteData; + +static void +xcf_save_parasite_func (TQCString *key, + KisAnnotation *parasite, + XcfParasiteData *data) +{ + if (! data->error) + xcf_save_parasite (data->info, parasite, &data->error); +} + +static bool +xcf_save_parasite_list (XcfInfo *info, + KisAnnotationList *list, + GError **error) +{ + XcfParasiteData data; + + data.info = info; + data.error = NULL; + + gimp_parasite_list_foreach (list, (GHFunc) xcf_save_parasite_func, &data); + + if (data.error) + { + g_propagate_error (error, data.error); + return FALSE; + } + + return TRUE; +} + +static bool +xcf_save_old_paths (XcfInfo *info, + KisImage *gimage, + GError **error) +{ + GimpVectors *active_vectors; + TQ_INT32 num_paths; + TQ_INT32 active_index = 0; + GList *list; + GError *tmp_error = NULL; + + /* Write out the following:- + * + * last_selected_row (TQ_INT32) + * number_of_paths (TQ_INT32) + * + * then each path:- + */ + + num_paths = gimp_container_num_tqchildren (gimage->vectors); + + active_vectors = gimp_image_get_active_vectors (gimage); + + if (active_vectors) + active_index = gimp_container_get_child_index (gimage->vectors, + GIMP_OBJECT (active_vectors)); + + xcf_write_int32_check_error (info, &active_index, 1); + xcf_write_int32_check_error (info, &num_paths, 1); + + for (list = GIMP_LIST (gimage->vectors)->list; + list; + list = g_list_next (list)) + { + GimpVectors *vectors = list->data; + TQCString *name; + TQ_INT32 locked; + TQ_UINT8 state; + TQ_INT32 version; + TQ_INT32 pathtype; + TQ_INT32 tattoo; + GimpVectorsCompatPoint *points; + TQ_INT3232 num_points; + TQ_INT3232 closed; + TQ_INT32 i; + + /* + * name (string) + * locked (TQ_INT32) + * state (TQCString) + * closed (TQ_INT32) + * number points (TQ_INT32) + * version (TQ_INT32) + * pathtype (TQ_INT32) + * tattoo (TQ_INT32) + * then each point. + */ + + points = gimp_vectors_compat_get_points (vectors, &num_points, &closed); + + /* if no points are generated because of a faulty path we should + * skip saving the path - this is unfortunately impossible, because + * we already saved the number of paths and I wont start seeking + * around to fix that cruft */ + + name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors)); + locked = gimp_item_get_linked (GIMP_ITEM (vectors)); + state = closed ? 4 : 2; /* EDIT : ADD (editing state, 1.2 compat) */ + version = 3; + pathtype = 1; /* BEZIER (1.2 compat) */ + tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors)); + + xcf_write_string_check_error (info, &name, 1); + xcf_write_int32_check_error (info, &locked, 1); + xcf_write_int8_check_error (info, &state, 1); + xcf_write_int32_check_error (info, &closed, 1); + xcf_write_int32_check_error (info, &num_points, 1); + xcf_write_int32_check_error (info, &version, 1); + xcf_write_int32_check_error (info, &pathtype, 1); + xcf_write_int32_check_error (info, &tattoo, 1); + + for (i = 0; i < num_points; i++) + { + float x; + float y; + + x = points[i].x; + y = points[i].y; + + /* + * type (TQ_INT32) + * x (float) + * y (float) + */ + + xcf_write_int32_check_error (info, &points[i].type, 1); + xcf_write_float_check_error (info, &x, 1); + xcf_write_float_check_error (info, &y, 1); + } + + g_free (points); + } + + return TRUE; +} + +static bool +xcf_save_vectors (XcfInfo *info, + KisImage *gimage, + GError **error) +{ + GimpVectors *active_vectors; + TQ_INT32 version = 1; + TQ_INT32 active_index = 0; + TQ_INT32 num_paths; + GList *list; + GList *stroke_list; + GError *tmp_error = NULL; + + /* Write out the following:- + * + * version (TQ_INT32) + * active_index (TQ_INT32) + * num_paths (TQ_INT32) + * + * then each path:- + */ + + active_vectors = gimp_image_get_active_vectors (gimage); + + if (active_vectors) + active_index = gimp_container_get_child_index (gimage->vectors, + GIMP_OBJECT (active_vectors)); + + num_paths = gimp_container_num_tqchildren (gimage->vectors); + + xcf_write_int32_check_error (info, &version, 1); + xcf_write_int32_check_error (info, &active_index, 1); + xcf_write_int32_check_error (info, &num_paths, 1); + + for (list = GIMP_LIST (gimage->vectors)->list; + list; + list = g_list_next (list)) + { + GimpVectors *vectors = list->data; + KisAnnotationList *parasites; + TQCString *name; + TQ_INT32 tattoo; + TQ_INT32 visible; + TQ_INT32 linked; + TQ_INT32 num_parasites; + TQ_INT32 num_strokes; + + /* + * name (string) + * tattoo (TQ_INT32) + * visible (TQ_INT32) + * linked (TQ_INT32) + * num_parasites (TQ_INT32) + * num_strokes (TQ_INT32) + * + * then each parasite + * then each stroke + */ + + parasites = GIMP_ITEM (vectors)->parasites; + + name = (TQCString *) gimp_object_get_name (GIMP_OBJECT (vectors)); + visible = gimp_item_get_visible (GIMP_ITEM (vectors)); + linked = gimp_item_get_linked (GIMP_ITEM (vectors)); + tattoo = gimp_item_get_tattoo (GIMP_ITEM (vectors)); + num_parasites = gimp_parasite_list_persistent_length (parasites); + num_strokes = g_list_length (vectors->strokes); + + xcf_write_string_check_error (info, &name, 1); + xcf_write_int32_check_error (info, &tattoo, 1); + xcf_write_int32_check_error (info, &visible, 1); + xcf_write_int32_check_error (info, &linked, 1); + xcf_write_int32_check_error (info, &num_parasites, 1); + xcf_write_int32_check_error (info, &num_strokes, 1); + + xcf_check_error (xcf_save_parasite_list (info, parasites, error)); + + for (stroke_list = g_list_first (vectors->strokes); + stroke_list; + stroke_list = g_list_next (stroke_list)) + { + GimpStroke *stroke; + TQ_INT32 stroke_type; + TQ_INT32 closed; + TQ_INT32 num_axes; + GArray *control_points; + TQ_INT32 i; + + TQ_INT32 type; + float coords[6]; + + /* + * stroke_type (TQ_INT32) + * closed (TQ_INT32) + * num_axes (TQ_INT32) + * num_control_points (TQ_INT32) + * + * then each control point. + */ + + stroke = GIMP_STROKE (stroke_list->data); + + if (GIMP_IS_BEZIER_STROKE (stroke)) + { + stroke_type = XCF_STROKETYPE_BEZIER_STROKE; + num_axes = 2; /* hardcoded, might be increased later */ + } + else + { + g_printerr ("Skipping unknown stroke type!\n"); + continue; + } + + control_points = gimp_stroke_control_points_get (stroke, &closed); + + xcf_write_int32_check_error (info, &stroke_type, 1); + xcf_write_int32_check_error (info, &closed, 1); + xcf_write_int32_check_error (info, &num_axes, 1); + xcf_write_int32_check_error (info, &control_points->len, 1); + + for (i = 0; i < control_points->len; i++) + { + GimpAnchor *anchor; + + anchor = & (g_array_index (control_points, GimpAnchor, i)); + + type = anchor->type; + coords[0] = anchor->position.x; + coords[1] = anchor->position.y; + coords[2] = anchor->position.pressure; + coords[3] = anchor->position.xtilt; + coords[4] = anchor->position.ytilt; + coords[5] = anchor->position.wheel; + + /* + * type (TQ_INT32) + * + * the first num_axis elements of: + * [0] x (float) + * [1] y (float) + * [2] pressure (float) + * [3] xtilt (float) + * [4] ytilt (float) + * [5] wheel (float) + */ + + xcf_write_int32_check_error (info, &type, 1); + xcf_write_float_check_error (info, coords, num_axes); + } + + g_array_free (control_points, TRUE); + } + } + + return TRUE; +} diff --git a/filters/chalk/xcf/xcf/xcf-save.h b/filters/chalk/xcf/xcf/xcf-save.h new file mode 100644 index 00000000..cc49d2d3 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-save.h @@ -0,0 +1,29 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_SAVE_H__ +#define __XCF_SAVE_H__ + + +void xcf_save_choose_format (XcfInfo *info, + KisImage *gimage); +TQ_INT32 xcf_save_image (XcfInfo *info, + KisImage *gimage); + + +#endif /* __XCF_SAVE_H__ */ diff --git a/filters/chalk/xcf/xcf/xcf-seek.cc b/filters/chalk/xcf/xcf/xcf-seek.cc new file mode 100644 index 00000000..a24271f5 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-seek.cc @@ -0,0 +1,79 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include + +#include + +#include "core/core-types.h" + +#include "xcf-private.h" +#include "xcf-seek.h" + +#include "gimp-intl.h" + +bool +xcf_seek_pos (XcfInfo *info, + TQ_UINT32 pos, + GError **error) +{ + if (info->cp != pos) + { + info->cp = pos; + if (fseek (info->fp, info->cp, SEEK_SET) == -1) + { + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), + _("Could not seek in XCF file: %s"), + g_strerror (errno)); + + return FALSE; + } + } + + return TRUE; +} + +bool +xcf_seek_end (XcfInfo *info, + GError **error) +{ + if (fseek (info->fp, 0, SEEK_END) == -1) + { + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), + _("Could not seek in XCF file: %s"), + g_strerror (errno)); + + return FALSE; + } + + info->cp = ftell (info->fp); + + if (fseek (info->fp, 0, SEEK_END) == -1) + { + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), + _("Could not seek in XCF file: %s"), + g_strerror (errno)); + + return FALSE; + } + + return TRUE; +} diff --git a/filters/chalk/xcf/xcf/xcf-seek.h b/filters/chalk/xcf/xcf/xcf-seek.h new file mode 100644 index 00000000..1bb7b7a9 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-seek.h @@ -0,0 +1,30 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_SEEK_H__ +#define __XCF_SEEK_H__ + + +bool xcf_seek_pos (XcfInfo *info, + TQ_UINT32 pos, + GError **error); +bool xcf_seek_end (XcfInfo *info, + GError **error); + + +#endif /* __XCF_SEEK_H__ */ diff --git a/filters/chalk/xcf/xcf/xcf-write.cc b/filters/chalk/xcf/xcf/xcf-write.cc new file mode 100644 index 00000000..4010ab18 --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-write.cc @@ -0,0 +1,104 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include /* strlen */ +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#include "xcf-write.h" + +TQ_UINT32 xcf_write_int32 (FILE *fp, TQ_INT32 *data, TQ_INT32 count); +{ + TQ_INT32 tmp; + TQ_INT32 i; + + if (count > 0) + { + for (i = 0; i < count; i++) + { + tmp = htonl (data[i]); + xcf_write_int8 (fp, (TQ_UINT8*) &tmp, 4); + + if (fp->status() != IO_Ok) + { + return i * 4; + } + } + } + + return count * 4; +} + +TQ_UINT32 xcf_write_float (FILE *fp, float *data, TQ_INT32 count); +{ + return xcf_write_int32 (fp, (TQ_INT32 *)((void *)data), count, error); +} + +TQ_UINT32 xcf_write_int8 (FILE *fp, TQ_UINT8 *data, TQ_INT32 count); +{ + TQ_INT32 bytes; + bytes = fp->writeBlock( data, count ); + return bytes; +} + +TQ_UINT32 xcf_write_string (FILE *fp, TQCString *data, TQ_INT32 count); +{ + GError *tmp_error = NULL; + TQ_INT32 tmp; + TQ_UINT32 total; + TQ_INT32 i; + + total = 0; + for (i = 0; i < count; i++) + { + if (data[i]) + tmp = strlen (data[i]) + 1; + else + tmp = 0; + + xcf_write_int32 (fp, &tmp, 1, &tmp_error); + if (tmp_error) + { + g_propagate_error (error, tmp_error); + return total; + } + + if (tmp > 0) + xcf_write_int8 (fp, (TQ_UINT8*) data[i], tmp, &tmp_error); + if (tmp_error) + { + g_propagate_error (error, tmp_error); + return total; + } + + total += 4 + tmp; + } + + return total; +} diff --git a/filters/chalk/xcf/xcf/xcf-write.h b/filters/chalk/xcf/xcf/xcf-write.h new file mode 100644 index 00000000..8e21a08e --- /dev/null +++ b/filters/chalk/xcf/xcf/xcf-write.h @@ -0,0 +1,39 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __XCF_WRITE_H__ +#define __XCF_WRITE_H__ + +#include +#include +#include + +// Write count integers to the file +TQ_UINT32 xcf_write_int32 (TQFile *fp, TQ_INT32 *data, TQ_INT32 count); + +// Write count of floats to the file +TQ_UINT32 xcf_write_float (TQFile *fp, float *data, TQ_INT32 count); + +// Write count chars to the file +TQ_UINT32 xcf_write_int8 (TQFile *fp, TQ_UINT8 *data, TQ_INT32 count); + +// Write count zero-terminated strings to the file, each string preceded by its length as an integer +TQ_UINT32 xcf_write_string (TQFile *fp, TQCString *data, TQ_INT32 count); + + +#endif /* __XCF_WRITE_H__ */ diff --git a/filters/chalk/xcf/xcfexport.cpp b/filters/chalk/xcf/xcfexport.cpp new file mode 100644 index 00000000..b26fdba8 --- /dev/null +++ b/filters/chalk/xcf/xcfexport.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +typedef KGenericFactory XCFExportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkxcfexport, XCFExportFactory("kofficefilters")) + +XCFExport::XCFExport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +XCFExport::~XCFExport() +{ +} + +KoFilter::ConversiontqStatus XCFExport::convert(const TQCString& from, const TQCString& to) +{ + kdDebug(41008) << "xcf export! From: " << from << ", To: " << to << "\n"; + + if (from != "application/x-chalk") + return KoFilter::NotImplemented; + + KisDoc *output = dynamic_cast(m_chain->inputDocument()); + TQString filename = m_chain->outputFile(); + + if (!output) + return KoFilter::CreationError; + + + if (filename.isEmpty()) return KoFilter::FileNotFound; + + KURL url(filename); + + KisImageSP img = output->currentImage(); + if (!img) return KoFilter::ParsingError; + + KisXCFConverter ib(output, output->undoAdapter()); + + vKisAnnotationSP_it beginIt = img->beginAnnotations(); + vKisAnnotationSP_it endIt = img->endAnnotations(); + + if (ib.buildFile(url, img, beginIt, endIt) == KisImageBuilder_RESULT_OK) { + return KoFilter::OK; + } + + return KoFilter::InternalError; +} + +#include + diff --git a/filters/chalk/xcf/xcfexport.h b/filters/chalk/xcf/xcfexport.h new file mode 100644 index 00000000..b6acf737 --- /dev/null +++ b/filters/chalk/xcf/xcfexport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef XCFEXPORT_H_ +#define XCFEXPORT_H_ + +#include + +class XCFExport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + XCFExport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~XCFExport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // XCFEXPORT_H_ + diff --git a/filters/chalk/xcf/xcfimport.cpp b/filters/chalk/xcf/xcfimport.cpp new file mode 100644 index 00000000..6f07ebcf --- /dev/null +++ b/filters/chalk/xcf/xcfimport.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef KGenericFactory XCFImportFactory; +K_EXPORT_COMPONENT_FACTORY(libchalkxcfimport, XCFImportFactory("kofficefilters")) + +XCFImport::XCFImport(KoFilter *, const char *, const TQStringList&) : KoFilter() +{ +} + +XCFImport::~XCFImport() +{ +} + +KoFilter::ConversiontqStatus XCFImport::convert(const TQCString&, const TQCString& to) +{ + kdDebug(41008) << "Importing using XCFImport!\n"; + + if (to != "application/x-chalk") + return KoFilter::BadMimeType; + + KisDoc * doc = dynamic_cast(m_chain -> outputDocument()); + KisView * view = static_cast(doc -> views().getFirst()); + + TQString filename = m_chain -> inputFile(); + + if (!doc) + return KoFilter::CreationError; + + doc -> prepareForImport(); + + + if (!filename.isEmpty()) { + + KURL url(filename); + + if (url.isEmpty()) + return KoFilter::FileNotFound; + + KisXCFConverter ib(doc, doc -> undoAdapter()); + + switch (ib.buildImage(url)) { + case KisImageBuilder_RESULT_UNSUPPORTED: + return KoFilter::NotImplemented; + break; + case KisImageBuilder_RESULT_INVALID_ARG: + return KoFilter::BadMimeType; + break; + case KisImageBuilder_RESULT_NO_URI: + case KisImageBuilder_RESULT_NOT_LOCAL: + return KoFilter::FileNotFound; + break; + case KisImageBuilder_RESULT_BAD_FETCH: + case KisImageBuilder_RESULT_EMPTY: + return KoFilter::ParsingError; + break; + case KisImageBuilder_RESULT_FAILURE: + return KoFilter::InternalError; + break; + case KisImageBuilder_RESULT_OK: + doc -> setCurrentImage( ib.image()); + return KoFilter::OK; + default: + break; + } + + } + return KoFilter::StorageCreationError; +} + +#include + diff --git a/filters/chalk/xcf/xcfimport.h b/filters/chalk/xcf/xcfimport.h new file mode 100644 index 00000000..038e7604 --- /dev/null +++ b/filters/chalk/xcf/xcfimport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef XCFIMPORT_H_ +#define XCFIMPORT_H_ + +#include + +class XCFImport : public KoFilter { + Q_OBJECT + TQ_OBJECT + +public: + XCFImport(KoFilter *tqparent, const char *name, const TQStringList&); + virtual ~XCFImport(); + +public: + virtual KoFilter::ConversiontqStatus convert(const TQCString& from, const TQCString& to); +}; + +#endif // XCFIMPORT_H_ + diff --git a/filters/configure.in.mid b/filters/configure.in.mid index a996cfb7..ba359970 100644 --- a/filters/configure.in.mid +++ b/filters/configure.in.mid @@ -21,7 +21,7 @@ for args in $SUBDIRLIST ; do kpresenter) COMPILE_FILTER_KPRESENTER="$args " ;; kformula) COMPILE_FILTER_KFORMULA="$args " ;; kugar) COMPILE_FILTER_KUGAR="$args " ;; - krita) COMPILE_FILTER_KRITA="$args " ;; + chalk) COMPILE_FILTER_KRITA="$args " ;; kivio) COMPILE_FILTER_KIVIO="$args " ;; kexi) COMPILE_FILTER_KEXI="$args " ;; esac @@ -37,7 +37,7 @@ for args in $DO_NOT_COMPILE ; do kpresenter) COMPILE_FILTER_KPRESENTER= ;; kformula) COMPILE_FILTER_KFORMULA= ;; kugar) COMPILE_FILTER_KUGAR= ;; - krita) COMPILE_FILTER_KRITA= ;; + chalk) COMPILE_FILTER_KRITA= ;; kivio) COMPILE_FILTER_KIVIO= ;; kexi) COMPILE_FILTER_KEXI= ;; esac diff --git a/filters/filterstatus.xml b/filters/filterstatus.xml index 6dc47680..6af39854 100644 --- a/filters/filterstatus.xml +++ b/filters/filterstatus.xml @@ -347,12 +347,12 @@ - - Krita Krita can use <a + + Chalk Chalk can use <a href="http://imagemagick.org/">ImageMagick</a> for importing and exporting images. This means that, in - addition to the file formats listed below, Krita can work + addition to the file formats listed below, Chalk can work with all images that your installation of ImageMagick supports. This includes all common image file formats, including the native formats of Photoshop and the Gimp. @@ -361,29 +361,29 @@ information on file formats supported by ImageMagick.</a> - - + + PNG Portable Network Graphics - - + + JPEG - - + + TIFF - - + + RAW - - + + OpenEXR <a href="http://www.openexr.com/">OpenEXR</a> is a high dynamic-range (HDR) format <br /> @@ -391,14 +391,14 @@ - - + + PDF Portable Document Format - - + + Gimp (XCF) Native file format of the <a href="http://www.gimp.org/">Gimp</a> diff --git a/filters/kspread/gnumeric/gnumericimport.cc b/filters/kspread/gnumeric/gnumericimport.cc index 4374d14a..ad97a548 100644 --- a/filters/kspread/gnumeric/gnumericimport.cc +++ b/filters/kspread/gnumeric/gnumericimport.cc @@ -961,19 +961,19 @@ void GNUMERICFilter::ParseFormat(TQString const & formatString, Cell * kspread_c kspread_cell->format()->setCurrency( 1, "$" ); lastPos = 1; } - else if (formatString[0] == '�') + else if ((int)(formatString[0]) == '�') { kspread_cell->format()->setFormatType(Money_format); kspread_cell->format()->setCurrency( 1, "�" ); lastPos = 1; } - else if (formatString[0] == '�') + else if ((int)(formatString[0]) == '�') { kspread_cell->format()->setFormatType(Money_format); kspread_cell->format()->setCurrency( 1, "�" ); lastPos = 1; } - else if (formatString[0] == '�') + else if ((int)(formatString[0]) == '�') { kspread_cell->format()->setFormatType(Money_format); kspread_cell->format()->setCurrency( 1, "�" ); diff --git a/filters/tests/global-filter-test.sh b/filters/tests/global-filter-test.sh index b4885023..ee622bb0 100755 --- a/filters/tests/global-filter-test.sh +++ b/filters/tests/global-filter-test.sh @@ -73,8 +73,8 @@ case "$1" in exit 1; esac ;; - krita) - appname=krita + chalk) + appname=chalk oldextension=kra case "$3" in magick-png) @@ -94,7 +94,7 @@ case "$1" in newmimetype=image/tiff ;; *) - printf "Usage: %s {kspread|kword|kpresenter|krita} {magick-png}\n" "$0" + printf "Usage: %s {kspread|kword|kpresenter|chalk} {magick-png}\n" "$0" exit1; esac ;; @@ -112,7 +112,7 @@ case "$1" in esac ;; *) - printf "Usage: %s {kspread|kword|kpresenter|krita} \n" "$0" + printf "Usage: %s {kspread|kword|kpresenter|chalk} \n" "$0" exit 1; esac diff --git a/karbon/CHANGES b/karbon/CHANGES index 3241a4a5..a8bee6dc 100644 --- a/karbon/CHANGES +++ b/karbon/CHANGES @@ -8,7 +8,7 @@ These are changes that can not be backported, and will be available from KOffice - How to bring back the overview window if you close it? (#111717) - Rename plugins menu to "Effect" (#111618) - Change Align Center (Vertical) to Align Middle and add some extra separators (#109520) -- Keybindings like krita, and other tweak (#108789) +- Keybindings like chalk, and other tweak (#108789) - Always use this document at startup, Karbon has not way to stop doing this (#108755) Add a basic karbon template - Dockers now use the KoPalette library. This means a huge improvement when it comes to docker management. diff --git a/karbon/GRAPHICS_MEETING b/karbon/GRAPHICS_MEETING index c5eaddd8..d945ca80 100644 --- a/karbon/GRAPHICS_MEETING +++ b/karbon/GRAPHICS_MEETING @@ -1,7 +1,7 @@ Ideas from graphics meeting (but also in my head before it): - use QPainterPath, get rid of libart -- use color profiles/matching (krita?) +- use color profiles/matching (chalk?) - get rid of the old freetype code to convert text to path, use QPainterPath::addText instead. - use koText for text boxes? diff --git a/karbon/TODO b/karbon/TODO index 9c268232..1c98b1da 100644 --- a/karbon/TODO +++ b/karbon/TODO @@ -74,7 +74,7 @@ TODO: - write odf enhanced-path parser (use some code from svgpathparser in lib) WISHLIST: -- krita export filter (with layers) +- chalk export filter (with layers) - add a nice grid-like shape like in Illu and webdraw - pdf import filter (based on poppler) diff --git a/karbon/karbon_factory.cc b/karbon/karbon_factory.cc index e230dea7..d8356184 100644 --- a/karbon/karbon_factory.cc +++ b/karbon/karbon_factory.cc @@ -112,10 +112,10 @@ KarbonFactory::instance() // Add any application-specific resource directories here s_instance->dirs()->addResourceType( "kis_brushes", - KStandardDirs::kde_default( "data" ) + "krita/brushes/" ); + KStandardDirs::kde_default( "data" ) + "chalk/brushes/" ); s_instance->dirs()->addResourceType( "kis_pattern", - KStandardDirs::kde_default( "data" ) + "krita/patterns/" ); + KStandardDirs::kde_default( "data" ) + "chalk/patterns/" ); s_instance->dirs()->addResourceType( "karbon_gradient", KStandardDirs::kde_default( "data" ) + "karbon/gradients/" ); diff --git a/karbon/tools/vcurvefit.cc b/karbon/tools/vcurvefit.cc index 42b90a13..fee361c2 100644 --- a/karbon/tools/vcurvefit.cc +++ b/karbon/tools/vcurvefit.cc @@ -26,7 +26,7 @@ #include #include #include -#include +#include /* An Algorithm for Automatically Fitting Digitized Curves diff --git a/karbon/tools/vdefaulttools.cc b/karbon/tools/vdefaulttools.cc index f26bcf52..ecc5e048 100644 --- a/karbon/tools/vdefaulttools.cc +++ b/karbon/tools/vdefaulttools.cc @@ -37,7 +37,7 @@ #include "vroundrecttool.h" #include "vselectnodestool.h" #include "vselecttool.h" -#include "vtqshapetool.h" +#include "vshapetool.h" #include "vsheartool.h" #include "vsinustool.h" #include "vspiraltool.h" diff --git a/karbon/tools/vellipsetool.cc b/karbon/tools/vellipsetool.cc index ff68c350..49e80ec8 100644 --- a/karbon/tools/vellipsetool.cc +++ b/karbon/tools/vellipsetool.cc @@ -29,7 +29,7 @@ #include #include -#include +#include #include "vellipsetool.h" #include "vglobal.h" diff --git a/karbon/tools/vellipsetool.h b/karbon/tools/vellipsetool.h index f0276779..c07d2e77 100644 --- a/karbon/tools/vellipsetool.h +++ b/karbon/tools/vellipsetool.h @@ -22,7 +22,7 @@ #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KoUnitDoubleSpinBox; class KComboBox; diff --git a/karbon/tools/vpenciltool.cc b/karbon/tools/vpenciltool.cc index 7347e0f9..587182de 100644 --- a/karbon/tools/vpenciltool.cc +++ b/karbon/tools/vpenciltool.cc @@ -45,7 +45,7 @@ #include #include #include "vpenciltool.h" -#include +#include #include "vcurvefit.h" diff --git a/karbon/tools/vpolygontool.cc b/karbon/tools/vpolygontool.cc index a9584be6..8fd8d740 100644 --- a/karbon/tools/vpolygontool.cc +++ b/karbon/tools/vpolygontool.cc @@ -27,7 +27,7 @@ #include #include -#include +#include #include "vpolygontool.h" VPolygonTool::VPolygonOptionsWidget::VPolygonOptionsWidget( KarbonView *view, TQWidget* tqparent, const char* name ) diff --git a/karbon/tools/vpolygontool.h b/karbon/tools/vpolygontool.h index c74ad182..227e9d37 100644 --- a/karbon/tools/vpolygontool.h +++ b/karbon/tools/vpolygontool.h @@ -22,7 +22,7 @@ #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KoUnitDoubleSpinBox; class KIntSpinBox; diff --git a/karbon/tools/vpolylinetool.cc b/karbon/tools/vpolylinetool.cc index 673503f9..083ee1ea 100644 --- a/karbon/tools/vpolylinetool.cc +++ b/karbon/tools/vpolylinetool.cc @@ -35,7 +35,7 @@ #include #include #include "vpolylinetool.h" -#include +#include #include #include diff --git a/karbon/tools/vrectangletool.cc b/karbon/tools/vrectangletool.cc index 9d19edd2..d3668fc4 100644 --- a/karbon/tools/vrectangletool.cc +++ b/karbon/tools/vrectangletool.cc @@ -25,7 +25,7 @@ #include #include -#include +#include #include "vrectangletool.h" #include diff --git a/karbon/tools/vrectangletool.h b/karbon/tools/vrectangletool.h index d38ead75..2b71e27e 100644 --- a/karbon/tools/vrectangletool.h +++ b/karbon/tools/vrectangletool.h @@ -24,7 +24,7 @@ #include #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KarbonView; class TQLabel; diff --git a/karbon/tools/vroundrecttool.cc b/karbon/tools/vroundrecttool.cc index a211114f..0e97530f 100644 --- a/karbon/tools/vroundrecttool.cc +++ b/karbon/tools/vroundrecttool.cc @@ -25,7 +25,7 @@ #include #include -#include +#include #include "vroundrecttool.h" #include "KoUnitWidgets.h" diff --git a/karbon/tools/vroundrecttool.h b/karbon/tools/vroundrecttool.h index 9ab0c3fb..9b70bf27 100644 --- a/karbon/tools/vroundrecttool.h +++ b/karbon/tools/vroundrecttool.h @@ -25,7 +25,7 @@ #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KarbonView; class KarbonPart; diff --git a/karbon/tools/vshapetool.cc b/karbon/tools/vshapetool.cc index 4f46c317..49197773 100644 --- a/karbon/tools/vshapetool.cc +++ b/karbon/tools/vshapetool.cc @@ -28,8 +28,8 @@ #include "vglobal.h" #include "vpainter.h" #include "vpainterfactory.h" -#include "vtqshapecmd.h" -#include "vtqshapetool.h" +#include "vshapecmd.h" +#include "vshapetool.h" #include "vselection.h" #include "vcursor.h" diff --git a/karbon/tools/vsinustool.cc b/karbon/tools/vsinustool.cc index a520afba..4982141b 100644 --- a/karbon/tools/vsinustool.cc +++ b/karbon/tools/vsinustool.cc @@ -27,7 +27,7 @@ #include #include -#include +#include #include "vsinustool.h" #include "KoUnitWidgets.h" diff --git a/karbon/tools/vsinustool.h b/karbon/tools/vsinustool.h index 1ad343a2..8e2adfc3 100644 --- a/karbon/tools/vsinustool.h +++ b/karbon/tools/vsinustool.h @@ -21,7 +21,7 @@ #define __VSINUSTOOL_H__ #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KoUnitDoubleSpinBox; class KIntSpinBox; diff --git a/karbon/tools/vspiraltool.cc b/karbon/tools/vspiraltool.cc index a9a361f5..58401309 100644 --- a/karbon/tools/vspiraltool.cc +++ b/karbon/tools/vspiraltool.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include "vspiraltool.h" #include "KoUnitWidgets.h" diff --git a/karbon/tools/vspiraltool.h b/karbon/tools/vspiraltool.h index c9c4d388..9a09bd83 100644 --- a/karbon/tools/vspiraltool.h +++ b/karbon/tools/vspiraltool.h @@ -23,7 +23,7 @@ #include #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KComboBox; class KoUnitDoubleSpinBox; diff --git a/karbon/tools/vstartool.cc b/karbon/tools/vstartool.cc index fbad70ce..6110969a 100644 --- a/karbon/tools/vstartool.cc +++ b/karbon/tools/vstartool.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include "vstartool.h" #include "KoUnitWidgets.h" diff --git a/karbon/tools/vstartool.h b/karbon/tools/vstartool.h index 89af45db..3ab94916 100644 --- a/karbon/tools/vstartool.h +++ b/karbon/tools/vstartool.h @@ -23,7 +23,7 @@ #include #include -#include "vtqshapetool.h" +#include "vshapetool.h" class KoUnitDoubleSpinBox; diff --git a/karbon/widgets/vruler.h b/karbon/widgets/vruler.h index a97b4cf0..47458039 100644 --- a/karbon/widgets/vruler.h +++ b/karbon/widgets/vruler.h @@ -25,7 +25,7 @@ #include // XXX: Make this look more like the KOffice ruler -- the KOffice -// ruler is not quite suited to Krita. Also: start units with 0, +// ruler is not quite suited to Chalk. Also: start units with 0, // print every 100 units. class TQPainter; diff --git a/kchart/kdchart/KDChartAxisParams.h b/kchart/kdchart/KDChartAxisParams.h index 18f4a6bf..b5819709 100644 --- a/kchart/kdchart/KDChartAxisParams.h +++ b/kchart/kdchart/KDChartAxisParams.h @@ -132,7 +132,7 @@ class KDChartParams; class KDCHART_EXPORT KDChartAxisParams : public TQObject { Q_OBJECT - TQ_OBJECT + TQ_OBJECT Q_ENUMS(AxisType) Q_ENUMS(AxisPos) Q_ENUMS(AxisAreaMode) @@ -141,7 +141,7 @@ class KDCHART_EXPORT KDChartAxisParams : public TQObject Q_ENUMS(ValueScale) // Neede by TQSA - Q_ENUMS( Qt::PenStyle ) + Q_ENUMS( PenStyle ) public: diff --git a/kchart/kdchart/KDChartParams.h b/kchart/kdchart/KDChartParams.h index d090a96f..7196ef2c 100644 --- a/kchart/kdchart/KDChartParams.h +++ b/kchart/kdchart/KDChartParams.h @@ -158,9 +158,9 @@ class KDCHART_EXPORT KDChartParams : public TQObject Q_ENUMS(HdFtPos) // Needed for TQSA - Q_ENUMS( Qt::BrushStyle ) - Q_ENUMS( Qt::PenStyle ) - Q_ENUMS( Qt::Orientation ) + Q_ENUMS( BrushStyle ) + Q_ENUMS( PenStyle ) + Q_ENUMS( Orientation ) public slots: // PENDING(blackie) merge public slots into one section. diff --git a/kchart/kdchart/KDChartPropertySet.h b/kchart/kdchart/KDChartPropertySet.h index 54ece25d..a3e94953 100644 --- a/kchart/kdchart/KDChartPropertySet.h +++ b/kchart/kdchart/KDChartPropertySet.h @@ -66,11 +66,11 @@ instead of the value that is stored locally. class KDCHART_EXPORT KDChartPropertySet :public TQObject { Q_OBJECT - TQ_OBJECT + TQ_OBJECT Q_ENUMS( SpecialDataPropertyID ) // Required by TQSA - Q_ENUMS( Qt::PenStyle ) + Q_ENUMS( PenStyle ) friend class KDChartParams; diff --git a/kchart/kdchart/KDChartTableBase.cpp b/kchart/kdchart/KDChartTableBase.cpp index da0d1d92..1ebfa9fd 100644 --- a/kchart/kdchart/KDChartTableBase.cpp +++ b/kchart/kdchart/KDChartTableBase.cpp @@ -56,7 +56,7 @@ You may adjust or modify your table like this: \li Entering the data can be done either manually using \c setCell() - or by passing a TQTable to the \c importFromTQTable() function. + or by passing a TQTable to the \c importFromQTable() function. \li Performance of KD Chart can be increased by specifying the number of rows and or the number of columns actually used: \c setUsedRows() @@ -740,7 +740,7 @@ uint KDChartTableDataBase::lastPositiveCellInColumn( uint col, int coordinate ) } -void KDChartTableDataBase::importFromTQTable( TQTable* table ) +void KDChartTableDataBase::importFromQTable( TQTable* table ) { if( table->numRows() > (int)rows() || table->numCols() > (int)cols() ) diff --git a/kchart/kdchart/KDChartTableBase.h b/kchart/kdchart/KDChartTableBase.h index 620597f7..b79e6e75 100644 --- a/kchart/kdchart/KDChartTableBase.h +++ b/kchart/kdchart/KDChartTableBase.h @@ -435,7 +435,7 @@ const double xVal = data.cellVal( r, c, 2 ).toDouble(); \endverbatim return isNormalDouble( dVal ); } - virtual void importFromTQTable( TQTable* table ); + virtual void importFromQTable( TQTable* table ); virtual double maxValue( int coordinate=1 ) const; virtual double minValue( int coordinate=1, bool bOnlyGTZero=false ) const; diff --git a/kexi/3rdparty/kolibs/koGlobal.cc b/kexi/3rdparty/kolibs/koGlobal.cc index 58c90445..b8f6e23d 100644 --- a/kexi/3rdparty/kolibs/koGlobal.cc +++ b/kexi/3rdparty/kolibs/koGlobal.cc @@ -61,7 +61,7 @@ KoGlobal::KoGlobal() // Another way to get the DPI of the display would be TQPaintDeviceMetrics, // but we have no widget here (and moving this to KoView wouldn't allow // using this from the document easily). -#ifdef TQ_WS_X11 +#ifdef Q_WS_X11 m_dpiX = TQPaintDevice::x11AppDpiX(); m_dpiY = TQPaintDevice::x11AppDpiY(); #else diff --git a/kexi/main/keximainwindowimpl.cpp b/kexi/main/keximainwindowimpl.cpp index 15491d5c..a2cf0e0c 100644 --- a/kexi/main/keximainwindowimpl.cpp +++ b/kexi/main/keximainwindowimpl.cpp @@ -1422,7 +1422,7 @@ void KexiMainWindowImpl::updateReadOnlyState() // update "insert ....." actions for every part KActionCollection *ac = actionCollection(); for (KexiPart::PartInfoListIterator it(*Kexi::partManager().partInfoList()); it.current(); ++it) { - KAction *a = ac->action( TQString(KexiPart::nameForCreateAction( *it.current() )) ); + KAction *a = ac->action( TQString(KexiPart::nameForCreateAction( *it.current() )).ascii() ); if (a) a->setEnabled(!readOnly); } diff --git a/kexi/migration/mysql/mysqlmigrate.cpp b/kexi/migration/mysql/mysqlmigrate.cpp index 013613ea..9b69350b 100644 --- a/kexi/migration/mysql/mysqlmigrate.cpp +++ b/kexi/migration/mysql/mysqlmigrate.cpp @@ -509,7 +509,7 @@ void MySQLMigrate::getConstraints(int flags, KexiDB::Field* fld) { fld->setPrimaryKey(flags & PRI_KEY_FLAG); fld->setAutoIncrement(flags & AUTO_INCREMENT_FLAG); fld->setNotNull(flags & NOT_NULL_FLAG); - fld->setUniqueKey(flags & UNITQUE_KEY_FLAG); + fld->setUniqueKey(flags & UNIQUE_KEY_FLAG); //! @todo: Keys and uniqueness } diff --git a/kexi/widget/kexibrowser.cpp b/kexi/widget/kexibrowser.cpp index a4ec402f..cbaf0e0c 100644 --- a/kexi/widget/kexibrowser.cpp +++ b/kexi/widget/kexibrowser.cpp @@ -763,7 +763,7 @@ void KexiBrowser::slotNewObjectPopupAboutToShow() for (KexiPart::PartInfoListIterator it(*list); it.current(); ++it) { //add an item to "New object" toolbar popup KAction *action = m_mainWin->actionCollection()->action( - TQString(KexiPart::nameForCreateAction(*it.current())) ); + TQString(KexiPart::nameForCreateAction(*it.current())).ascii() ); if (action) { action->plug(m_newObjectPopup); } diff --git a/kivio/kiviopart/stencilbardockmanager.cpp b/kivio/kiviopart/stencilbardockmanager.cpp index 606c6a93..a0dca0ee 100644 --- a/kivio/kiviopart/stencilbardockmanager.cpp +++ b/kivio/kiviopart/stencilbardockmanager.cpp @@ -308,14 +308,14 @@ void StencilBarDockManager::setAllStackBarsShown(bool shown) KoToolDockMoveManager::KoToolDockMoveManager() : TQObject() { -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XGCValues gv; #endif working=false; noLast=true; -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY scr = qt_xscreen(); root = qt_xrootwin(); @@ -386,7 +386,7 @@ void KoToolDockMoveManager::doMoveInternal() if (check(xp, yp, w, h)) { paintProcess(false,xp, yp, w, h); -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XFlush(qt_xdisplay()); XSync(qt_xdisplay(),false); #endif @@ -402,7 +402,7 @@ void KoToolDockMoveManager::stop() TQApplication::restoreOverrideCursor(); paintProcess(); -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XFlush(qt_xdisplay()); #endif @@ -424,7 +424,7 @@ void KoToolDockMoveManager::setGeometry(int _x, int _y, int _w, int _h) check(_x, _y, _w, _h, true); paintProcess(false,_x, _y, _w, _h); -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XFlush(qt_xdisplay()); XSync(qt_xdisplay(),false); #endif @@ -440,7 +440,7 @@ void KoToolDockMoveManager::drawRectangle( int _x, int _y, int _w, int _h) ow = _w; oh = _h; -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XDrawRectangle(qt_xdisplay(), root, rootgc, _x, _y, _w, _h); #endif noLast = false; @@ -454,7 +454,7 @@ void KoToolDockMoveManager::paintProcess( bool onlyDelete, int _x, int _y, int _ if ( ox == _x && oy == _y && ow ==_w && oh == _h ) return; -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XDrawRectangle(qt_xdisplay(), root, rootgc, ox, oy, ow, oh); #endif noLast = true; @@ -546,7 +546,7 @@ void KoToolDockMoveManager::doResizeInternal() if (check(xp, yp, w, h)) { paintProcess(false,xp, yp, w, h); -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY XFlush(qt_xdisplay()); XSync(qt_xdisplay(),false); #endif diff --git a/kivio/kiviopart/stencilbardockmanager.h b/kivio/kiviopart/stencilbardockmanager.h index 12eb18c9..8894def1 100644 --- a/kivio/kiviopart/stencilbardockmanager.h +++ b/kivio/kiviopart/stencilbardockmanager.h @@ -19,9 +19,13 @@ #ifndef STENCILBARDOCKMANAGER_H #define STENCILBARDOCKMANAGER_H +#ifdef Q_MOC_RUN +#define Q_WS_X11 +#endif // Q_MOC_RUN + #include #include -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY #include #include #include @@ -167,7 +171,7 @@ class KoToolDockMoveManager: public TQObject int offX, offY; /* X-stuff */ -#if defined TQ_WS_X11 && !defined K_WS_TQTONLY +#if defined Q_WS_X11 && !defined K_WS_TQTONLY Window root; GC rootgc; int scr; diff --git a/kplato/Makefile.am b/kplato/Makefile.am index fbe328a6..214a23f1 100644 --- a/kplato/Makefile.am +++ b/kplato/Makefile.am @@ -103,7 +103,7 @@ noinst_HEADERS = \ lib_LTLIBRARIES = kde_module_LTLIBRARIES = libkplatopart.la libkplatopart_la_LDFLAGS = $(KDE_LDFLAGS) $(KDE_PLUGIN) -lkdecore -lkdeui $(LIB_QT) -lkjs -lkdefx -lkio -lkparts -L../lib/kofficecore/.libs/ -lkofficecore -L../lib/kofficeui/.libs/ -lkofficeui -L../lib/store/.libs/ -lkstore -lkdeprint -libkplatopart_la_LIBADD = $(LIB_KABC) $(LIB_KOFFICEUI) \ +libkplatopart_la_LIBADD = $(LIB_KABC) $(LIB_KOFFICEUI) -lDCOP \ $(top_builddir)/kdgantt/libkdgantt.la ## $(top_builddir)/kugar/lib/libkugarlib.la diff --git a/kspread/kspread_editors.cc b/kspread/kspread_editors.cc index 24df68ed..85690b13 100644 --- a/kspread/kspread_editors.cc +++ b/kspread/kspread_editors.cc @@ -37,7 +37,7 @@ #include #include #include -#include +#include //#include #include diff --git a/kspread/plugins/scripting/kspreadcore/kspreadcoremodule.h b/kspread/plugins/scripting/kspreadcore/kspreadcoremodule.h index 03bde5fc..1816096c 100644 --- a/kspread/plugins/scripting/kspreadcore/kspreadcoremodule.h +++ b/kspread/plugins/scripting/kspreadcore/kspreadcoremodule.h @@ -65,8 +65,8 @@ namespace Kross { namespace KSpreadCore { * * For example (in ruby) : * @code - * Krosskritacore::newRGBColor(255,0,0) # create a red color - * Krosskritacore::newRGBColor(255,255,255) # create a white color + * Krosschalkcore::newRGBColor(255,0,0) # create a red color + * Krosschalkcore::newRGBColor(255,255,255) # create a white color * @endcode */ Kross::Api::Object::Ptr newRGBColor(Kross::Api::List::Ptr); diff --git a/kword/mailmerge/sql/KWMySqlCursor.h b/kword/mailmerge/sql/KWMySqlCursor.h index a7843f6a..4a25323b 100644 --- a/kword/mailmerge/sql/KWMySqlCursor.h +++ b/kword/mailmerge/sql/KWMySqlCursor.h @@ -17,8 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _SERIALLETTER_TQtSql_STQLCURSOR_H_ -#define _SERIALLETTER_TQtSql_STQLCURSOR_H_ +#ifndef _SERIALLETTER_QtSql_SQLCURSOR_H_ +#define _SERIALLETTER_QtSql_SQLCURSOR_H_ /* FOR THE DIRTY HACK */ #include diff --git a/kword/mailmerge/sql/KWQtSqlEasyFilter.cpp b/kword/mailmerge/sql/KWQtSqlEasyFilter.cpp index c2c14249..8444b65c 100644 --- a/kword/mailmerge/sql/KWQtSqlEasyFilter.cpp +++ b/kword/mailmerge/sql/KWQtSqlEasyFilter.cpp @@ -1,12 +1,12 @@ -#include "KWTQtSqlEasyFilter.h" -#include "KWTQtSqlEasyFilter.moc" +#include "KWQtSqlEasyFilter.h" +#include "KWQtSqlEasyFilter.moc" #include #include #include #include #include -KWTQtSqlEasyFilter::KWTQtSqlEasyFilter( TQWidget *tqparent) +KWQtSqlEasyFilter::KWQtSqlEasyFilter( TQWidget *tqparent) :KDialogBase( Swallow, i18n( "Mail Merge - Editor" ), Ok | Cancel, Ok, tqparent, "", true) { m_fieldList << "" <<"one" << "two" << "three" << "four"; @@ -43,7 +43,7 @@ KWTQtSqlEasyFilter::KWTQtSqlEasyFilter( TQWidget *tqparent) connect(m_table,TQT_SIGNAL(valueChanged ( int, int)),this,TQT_SLOT(slotValueChanged ( int, int))); } -void KWTQtSqlEasyFilter::createColumn(int i) +void KWQtSqlEasyFilter::createColumn(int i) { TQTableItem *it; m_table->setItem(0,i,it=new TQComboTableItem(m_table,m_fieldList,false)); @@ -61,7 +61,7 @@ void KWTQtSqlEasyFilter::createColumn(int i) } -void KWTQtSqlEasyFilter::slotValueChanged ( int row, int col ) +void KWQtSqlEasyFilter::slotValueChanged ( int row, int col ) { switch (row) { @@ -94,5 +94,5 @@ void KWTQtSqlEasyFilter::slotValueChanged ( int row, int col ) } } -KWTQtSqlEasyFilter::~KWTQtSqlEasyFilter(){;} +KWQtSqlEasyFilter::~KWQtSqlEasyFilter(){;} diff --git a/kword/mailmerge/sql/KWQtSqlEasyFilter.h b/kword/mailmerge/sql/KWQtSqlEasyFilter.h index f5602793..1384dec7 100644 --- a/kword/mailmerge/sql/KWQtSqlEasyFilter.h +++ b/kword/mailmerge/sql/KWQtSqlEasyFilter.h @@ -1,5 +1,5 @@ -#ifndef MAILMERGE_TQtSqlPLUGIN_EASYFILTER -#define MAILMERGE_TQtSqlPLUGIN_EASYFILTER +#ifndef MAILMERGE_QtSqlPLUGIN_EASYFILTER +#define MAILMERGE_QtSqlPLUGIN_EASYFILTER #include @@ -7,13 +7,13 @@ class TQTable; class TQScrollView; class TQStringList; -class KWTQtSqlEasyFilter: public KDialogBase +class KWQtSqlEasyFilter: public KDialogBase { Q_OBJECT TQ_OBJECT public: - KWTQtSqlEasyFilter( TQWidget *tqparent); - virtual ~KWTQtSqlEasyFilter(); + KWQtSqlEasyFilter( TQWidget *tqparent); + virtual ~KWQtSqlEasyFilter(); protected: void createColumn(int i); diff --git a/kword/mailmerge/sql/KWQtSqlMailMergeOpen.cpp b/kword/mailmerge/sql/KWQtSqlMailMergeOpen.cpp index 02ff145f..2518399b 100644 --- a/kword/mailmerge/sql/KWQtSqlMailMergeOpen.cpp +++ b/kword/mailmerge/sql/KWQtSqlMailMergeOpen.cpp @@ -17,8 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#include "KWTQtSqlMailMergeOpen.h" -#include "KWTQtSqlMailMergeOpen.moc" +#include "KWQtSqlMailMergeOpen.h" +#include "KWQtSqlMailMergeOpen.moc" #include #include #include @@ -33,14 +33,14 @@ /****************************************************************** * - * Class: KWTQtSqlMailMergeOpen + * Class: KWQtSqlMailMergeOpen * ******************************************************************/ -KWTQtSqlMailMergeOpen::KWTQtSqlMailMergeOpen( TQWidget *tqparent, KWTQtSqlSerialDataSourceBase *db_ ) +KWQtSqlMailMergeOpen::KWQtSqlMailMergeOpen( TQWidget *tqparent, KWQtSqlSerialDataSourceBase *db_ ) :KDialogBase( Plain, i18n( "Mail Merge - Setup Database Connection" ), Ok | Cancel, Ok, tqparent, "", true ), db( db_ ){ (new TQVBoxLayout(plainPage()))->setAutoAdd(true); - setMainWidget(widget=new KWTQtSqlOpenWidget(plainPage())); + setMainWidget(widget=new KWQtSqlOpenWidget(plainPage())); widget->drivers->insertStringList(TQSqlDatabase::drivers()); widget->hostname->setText(db->hostname); widget->username->setText(db->username); @@ -54,9 +54,9 @@ KWTQtSqlMailMergeOpen::KWTQtSqlMailMergeOpen( TQWidget *tqparent, KWTQtSqlSerial this, TQT_SLOT(slotSave())); } -KWTQtSqlMailMergeOpen::~KWTQtSqlMailMergeOpen(){;} +KWQtSqlMailMergeOpen::~KWQtSqlMailMergeOpen(){;} -void KWTQtSqlMailMergeOpen::savedPropertiesChanged(const TQString& name) +void KWQtSqlMailMergeOpen::savedPropertiesChanged(const TQString& name) { if (name!=i18n("")) { @@ -77,7 +77,7 @@ void KWTQtSqlMailMergeOpen::savedPropertiesChanged(const TQString& name) } -void KWTQtSqlMailMergeOpen::fillSavedProperties() +void KWQtSqlMailMergeOpen::fillSavedProperties() { widget->savedProperties->clear(); widget->savedProperties->insertItem(i18n("")); @@ -91,7 +91,7 @@ void KWTQtSqlMailMergeOpen::fillSavedProperties() } } -void KWTQtSqlMailMergeOpen::slotSave() +void KWQtSqlMailMergeOpen::slotSave() { TQString value; bool ok; @@ -113,7 +113,7 @@ void KWTQtSqlMailMergeOpen::slotSave() } } -void KWTQtSqlMailMergeOpen::handleOk() +void KWQtSqlMailMergeOpen::handleOk() { db->hostname=widget->hostname->text(); db->username=widget->username->text(); diff --git a/kword/mailmerge/sql/KWQtSqlMailMergeOpen.h b/kword/mailmerge/sql/KWQtSqlMailMergeOpen.h index 9a427cc1..949dc2c6 100644 --- a/kword/mailmerge/sql/KWQtSqlMailMergeOpen.h +++ b/kword/mailmerge/sql/KWQtSqlMailMergeOpen.h @@ -17,33 +17,33 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _SERIALLETTER_TQtSql_OPEN_EDITOR_H_ -#define _SERIALLETTER_TQtSql_OPEN_EDITOR_H_ +#ifndef _SERIALLETTER_QtSql_OPEN_EDITOR_H_ +#define _SERIALLETTER_QtSql_OPEN_EDITOR_H_ #include #include #include #include "KWMailMergeDataSource.h" -#include "KWTQtSqlSerialDataSourceBase.h" -#include "tqtsqlopenwidget.h" +#include "KWQtSqlSerialDataSourceBase.h" +#include "qtsqlopenwidget.h" /****************************************************************** * - * Class: KWTQtSqlMailMergeOpen + * Class: KWQtSqlMailMergeOpen * ******************************************************************/ -class KWTQtSqlMailMergeOpen : public KDialogBase +class KWQtSqlMailMergeOpen : public KDialogBase { Q_OBJECT TQ_OBJECT public: - KWTQtSqlMailMergeOpen( TQWidget *tqparent, KWTQtSqlSerialDataSourceBase *db_ ); - ~KWTQtSqlMailMergeOpen(); + KWQtSqlMailMergeOpen( TQWidget *tqparent, KWQtSqlSerialDataSourceBase *db_ ); + ~KWQtSqlMailMergeOpen(); private: - KWTQtSqlSerialDataSourceBase *db; - KWTQtSqlOpenWidget *widget; + KWQtSqlSerialDataSourceBase *db; + KWQtSqlOpenWidget *widget; void fillSavedProperties(); diff --git a/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.cpp b/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.cpp index dd88750a..8020b0aa 100644 --- a/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.cpp +++ b/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.cpp @@ -17,9 +17,9 @@ * Boston, MA 02110-1301, USA. */ -#include "KWTQtSqlPowerSerialDataSource.h" -#include "KWTQtSqlPowerSerialDataSource.moc" -#include "KWTQtSqlMailMergeOpen.h" +#include "KWQtSqlPowerSerialDataSource.h" +#include "KWQtSqlPowerSerialDataSource.moc" +#include "KWQtSqlMailMergeOpen.h" #include #include #include @@ -33,27 +33,27 @@ #include #include -#define KWTQtSqlBarIcon( x ) BarIcon( x, db->KWInstance() ) +#define KWQtSqlBarIcon( x ) BarIcon( x, db->KWInstance() ) /****************************************************************** * - * Class: KWTQtSqlSerialDataSource + * Class: KWQtSqlSerialDataSource * ******************************************************************/ -KWTQtSqlPowerSerialDataSource::KWTQtSqlPowerSerialDataSource(KInstance *inst,TQObject *tqparent) - : KWTQtSqlSerialDataSourceBase(inst,tqparent),myquery(0) +KWQtSqlPowerSerialDataSource::KWQtSqlPowerSerialDataSource(KInstance *inst,TQObject *tqparent) + : KWQtSqlSerialDataSourceBase(inst,tqparent),myquery(0) { port=i18n("default"); } -KWTQtSqlPowerSerialDataSource::~KWTQtSqlPowerSerialDataSource() +KWQtSqlPowerSerialDataSource::~KWQtSqlPowerSerialDataSource() { if (myquery) delete myquery; - TQSqlDatabase::removeDatabase("KWTQTSTQLPOWER"); + TQSqlDatabase::removeDatabase("KWTQTSQLPOWER"); } -void KWTQtSqlPowerSerialDataSource::refresh(bool force) +void KWQtSqlPowerSerialDataSource::refresh(bool force) { if ((force) || (myquery==0)) { @@ -71,7 +71,7 @@ void KWTQtSqlPowerSerialDataSource::refresh(bool force) kdDebug()<size())<value(name)).toString(); } -void KWTQtSqlPowerSerialDataSource::save( TQDomDocument &doc, TQDomElement &tqparent) +void KWQtSqlPowerSerialDataSource::save( TQDomDocument &doc, TQDomElement &tqparent) { TQDomElement def=doc.createElement(TQString::tqfromLatin1("DEFINITION")); tqparent.appendChild(def); @@ -111,7 +111,7 @@ void KWTQtSqlPowerSerialDataSource::save( TQDomDocument &doc, TQDomElement &tqpa } } -void KWTQtSqlPowerSerialDataSource::load( TQDomElement& tqparentElem ) +void KWQtSqlPowerSerialDataSource::load( TQDomElement& tqparentElem ) { clearSampleRecord(); TQDomNode defNd=tqparentElem.namedItem("DEFINITION"); @@ -149,37 +149,37 @@ void KWTQtSqlPowerSerialDataSource::load( TQDomElement& tqparentElem ) } } -bool KWTQtSqlPowerSerialDataSource::showConfigDialog(TQWidget *par,int action) +bool KWQtSqlPowerSerialDataSource::showConfigDialog(TQWidget *par,int action) { bool ret=false; if (action==KWSLEdit) { if ((!database) || (!database->isOpen()))openDatabase(); - KWTQtSqlPowerMailMergeEditor *dia=new KWTQtSqlPowerMailMergeEditor(par,this); + KWQtSqlPowerMailMergeEditor *dia=new KWQtSqlPowerMailMergeEditor(par,this); ret=dia->exec(); delete dia; } - else ret=KWTQtSqlSerialDataSourceBase::showConfigDialog(par,action); + else ret=KWQtSqlSerialDataSourceBase::showConfigDialog(par,action); return ret; } -void KWTQtSqlPowerSerialDataSource::clearSampleRecord() {sampleRecord.clear();} +void KWQtSqlPowerSerialDataSource::clearSampleRecord() {sampleRecord.clear();} -void KWTQtSqlPowerSerialDataSource::addSampleRecordEntry(TQString name) +void KWQtSqlPowerSerialDataSource::addSampleRecordEntry(TQString name) {sampleRecord[name]=name; }//i18n("No Value");} /****************************************************************** * - * Class: KWTQtSqlMailMergeEditor + * Class: KWQtSqlMailMergeEditor * ******************************************************************/ -KWTQtSqlPowerMailMergeEditor::KWTQtSqlPowerMailMergeEditor( TQWidget *tqparent, KWTQtSqlPowerSerialDataSource *db_ ) +KWQtSqlPowerMailMergeEditor::KWQtSqlPowerMailMergeEditor( TQWidget *tqparent, KWQtSqlPowerSerialDataSource *db_ ) :KDialogBase( Plain, i18n( "Mail Merge - Editor" ), Ok | Cancel, Ok, tqparent, "", true ), db( db_ ) { (new TQVBoxLayout(plainPage()))->setAutoAdd(true); - setMainWidget(widget=new KWTQtSqlPowerWidget(plainPage())); + setMainWidget(widget=new KWQtSqlPowerWidget(plainPage())); connect(widget->setup,TQT_SIGNAL(clicked()),this,TQT_SLOT(openSetup())); connect(widget->tables,TQT_SIGNAL(currentChanged(TQListBoxItem*)),this,TQT_SLOT(slotTableChanged(TQListBoxItem*))); connect(widget->execute,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotExecute())); @@ -188,13 +188,13 @@ KWTQtSqlPowerMailMergeEditor::KWTQtSqlPowerMailMergeEditor( TQWidget *tqparent, updateDBViews(); } -void KWTQtSqlPowerMailMergeEditor::slotSetQuery() +void KWQtSqlPowerMailMergeEditor::slotSetQuery() { db->query=widget->query->text(); db->refresh(true); } -void KWTQtSqlPowerMailMergeEditor::slotExecute() +void KWQtSqlPowerMailMergeEditor::slotExecute() { if (!db->database) if (!db->openDatabase()) return; TQString tmp=widget->query->text().upper(); @@ -211,7 +211,7 @@ void KWTQtSqlPowerMailMergeEditor::slotExecute() widget->queryresult->refresh(TQDataTable::RefreshAll); } -void KWTQtSqlPowerMailMergeEditor::slotTableChanged ( TQListBoxItem * item ) +void KWQtSqlPowerMailMergeEditor::slotTableChanged ( TQListBoxItem * item ) { widget->fields->clear(); if (item) @@ -225,9 +225,9 @@ void KWTQtSqlPowerMailMergeEditor::slotTableChanged ( TQListBoxItem * item ) } } -void KWTQtSqlPowerMailMergeEditor::openSetup() +void KWQtSqlPowerMailMergeEditor::openSetup() { - KWTQtSqlMailMergeOpen *dia=new KWTQtSqlMailMergeOpen(this,db); + KWQtSqlMailMergeOpen *dia=new KWQtSqlMailMergeOpen(this,db); if (dia->exec()) { db->openDatabase(); @@ -237,7 +237,7 @@ void KWTQtSqlPowerMailMergeEditor::openSetup() } -void KWTQtSqlPowerMailMergeEditor::updateDBViews() +void KWQtSqlPowerMailMergeEditor::updateDBViews() { widget->fields->clear(); widget->tables->clear(); @@ -245,12 +245,12 @@ void KWTQtSqlPowerMailMergeEditor::updateDBViews() widget->tables->insertStringList(db->database->tables()); } -KWTQtSqlPowerMailMergeEditor::~KWTQtSqlPowerMailMergeEditor(){;} +KWQtSqlPowerMailMergeEditor::~KWQtSqlPowerMailMergeEditor(){;} extern "C" { KWORD_MAILMERGE_EXPORT KWMailMergeDataSource *create_kwmailmerge_qtsqldb_power(KInstance *inst,TQObject *tqparent) { - return new KWTQtSqlPowerSerialDataSource(inst,tqparent); + return new KWQtSqlPowerSerialDataSource(inst,tqparent); } } diff --git a/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.h b/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.h index 1c36b196..6870afe1 100644 --- a/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.h +++ b/kword/mailmerge/sql/KWQtSqlPowerSerialDataSource.h @@ -17,8 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _SERIALLETTER_TQtSql_POWER_PLUGIN_H_ -#define _SERIALLETTER_TQtSql_POWER_PLUGIN_H_ +#ifndef _SERIALLETTER_QtSql_POWER_PLUGIN_H_ +#define _SERIALLETTER_QtSql_POWER_PLUGIN_H_ #include #include @@ -33,22 +33,22 @@ #include "defs.h" #include "KWMailMergeDataSource.h" -#include "KWTQtSqlSerialDataSourceBase.h" +#include "KWQtSqlSerialDataSourceBase.h" #include "kwqtsqlpower.h" #include "KWMySqlCursor.h" /****************************************************************** * - * Class: KWTQtSqlSerialDataSource + * Class: KWQtSqlSerialDataSource * ******************************************************************/ -class KWTQtSqlPowerSerialDataSource: public KWTQtSqlSerialDataSourceBase +class KWQtSqlPowerSerialDataSource: public KWQtSqlSerialDataSourceBase { Q_OBJECT - TQ_OBJECT +// TQ_OBJECT public: - KWTQtSqlPowerSerialDataSource(KInstance *inst,TQObject *tqparent); - ~KWTQtSqlPowerSerialDataSource(); + KWQtSqlPowerSerialDataSource(KInstance *inst,TQObject *tqparent); + ~KWQtSqlPowerSerialDataSource(); virtual void save( TQDomDocument &doc,TQDomElement&); virtual void load( TQDomElement& elem ); @@ -60,7 +60,7 @@ class KWTQtSqlPowerSerialDataSource: public KWTQtSqlSerialDataSourceBase virtual void refresh(bool force); protected: - friend class KWTQtSqlPowerMailMergeEditor; + friend class KWQtSqlPowerMailMergeEditor; TQString query; KWMySqlCursor *myquery; @@ -71,21 +71,21 @@ class KWTQtSqlPowerSerialDataSource: public KWTQtSqlSerialDataSourceBase /****************************************************************** * - * Class: KWTQtSqlPowerMailMergeEditor + * Class: KWQtSqlPowerMailMergeEditor * ******************************************************************/ -class KWTQtSqlPowerMailMergeEditor : public KDialogBase +class KWQtSqlPowerMailMergeEditor : public KDialogBase { Q_OBJECT - TQ_OBJECT +// TQ_OBJECT public: - KWTQtSqlPowerMailMergeEditor( TQWidget *tqparent, KWTQtSqlPowerSerialDataSource *db_ ); - ~KWTQtSqlPowerMailMergeEditor(); + KWQtSqlPowerMailMergeEditor( TQWidget *tqparent, KWQtSqlPowerSerialDataSource *db_ ); + ~KWQtSqlPowerMailMergeEditor(); private: - KWTQtSqlPowerSerialDataSource *db; - KWTQtSqlPowerWidget *widget; + KWQtSqlPowerSerialDataSource *db; + KWQtSqlPowerWidget *widget; private slots: void openSetup(); void updateDBViews(); diff --git a/kword/mailmerge/sql/KWQtSqlSerialDataSource.cpp b/kword/mailmerge/sql/KWQtSqlSerialDataSource.cpp index fa5bc8f6..4476b4d3 100644 --- a/kword/mailmerge/sql/KWQtSqlSerialDataSource.cpp +++ b/kword/mailmerge/sql/KWQtSqlSerialDataSource.cpp @@ -17,9 +17,9 @@ * Boston, MA 02110-1301, USA. */ -#include "KWTQtSqlSerialDataSource.h" -#include "KWTQtSqlSerialDataSource.moc" -#include "KWTQtSqlEasyFilter.h" +#include "KWQtSqlSerialDataSource.h" +#include "KWQtSqlSerialDataSource.moc" +#include "KWQtSqlEasyFilter.h" #include #include @@ -30,28 +30,28 @@ #include #include -#define KWTQtSqlBarIcon( x ) BarIcon( x, db->KWInstance() ) +#define KWQtSqlBarIcon( x ) BarIcon( x, db->KWInstance() ) /****************************************************************** * - * Class: KWTQtSqlSerialDataSource + * Class: KWQtSqlSerialDataSource * ******************************************************************/ -KWTQtSqlSerialDataSource::KWTQtSqlSerialDataSource(KInstance *inst,TQObject *tqparent) - : KWTQtSqlSerialDataSourceBase(inst,tqparent) +KWQtSqlSerialDataSource::KWQtSqlSerialDataSource(KInstance *inst,TQObject *tqparent) + : KWQtSqlSerialDataSourceBase(inst,tqparent) { myquery=0; } -KWTQtSqlSerialDataSource::~KWTQtSqlSerialDataSource() +KWQtSqlSerialDataSource::~KWQtSqlSerialDataSource() { delete myquery; - TQSqlDatabase::removeDatabase("KWTQTSTQLPOWER"); + TQSqlDatabase::removeDatabase("KWTQTSQLPOWER"); } -TQString KWTQtSqlSerialDataSource::getValue( const TQString &name, int record ) const +TQString KWQtSqlSerialDataSource::getValue( const TQString &name, int record ) const { int num=record; @@ -63,7 +63,7 @@ TQString KWTQtSqlSerialDataSource::getValue( const TQString &name, int record ) return (myquery->value(name)).toString(); } -void KWTQtSqlSerialDataSource::save( TQDomDocument & /*doc*/, TQDomElement & /*tqparent*/) +void KWQtSqlSerialDataSource::save( TQDomDocument & /*doc*/, TQDomElement & /*tqparent*/) { /* TQDomElement def=doc.createElement(TQString::tqfromLatin1("DEFINITION")); @@ -91,7 +91,7 @@ void KWTQtSqlSerialDataSource::save( TQDomDocument & /*doc*/, TQDomElement & /*t */ } -void KWTQtSqlSerialDataSource::load( TQDomElement& /*tqparentElem*/ ) +void KWQtSqlSerialDataSource::load( TQDomElement& /*tqparentElem*/ ) { /* db.clear(); @@ -117,21 +117,21 @@ void KWTQtSqlSerialDataSource::load( TQDomElement& /*tqparentElem*/ ) */ } -bool KWTQtSqlSerialDataSource::showConfigDialog(TQWidget *par,int action) +bool KWQtSqlSerialDataSource::showConfigDialog(TQWidget *par,int action) { bool ret=false; if (action==KWSLEdit) { - KWTQtSqlDataSourceEditor *dia=new KWTQtSqlDataSourceEditor(par,this); + KWQtSqlDataSourceEditor *dia=new KWQtSqlDataSourceEditor(par,this); ret=dia->exec(); delete dia; } - else ret=KWTQtSqlSerialDataSourceBase::showConfigDialog(par,action); + else ret=KWQtSqlSerialDataSourceBase::showConfigDialog(par,action); return ret; } -void KWTQtSqlSerialDataSource::refresh(bool force) +void KWQtSqlSerialDataSource::refresh(bool force) { if ((force) || (myquery==0)) { @@ -156,19 +156,19 @@ void KWTQtSqlSerialDataSource::refresh(bool force) /****************************************************************** * - * Class: KWTQtSqlDataSourceEditor + * Class: KWQtSqlDataSourceEditor * ******************************************************************/ -KWTQtSqlDataSourceEditor::KWTQtSqlDataSourceEditor( TQWidget *tqparent, KWTQtSqlSerialDataSource *db_ ) +KWQtSqlDataSourceEditor::KWQtSqlDataSourceEditor( TQWidget *tqparent, KWQtSqlSerialDataSource *db_ ) :KDialogBase( Plain, i18n( "Mail Merge - Editor" ), Ok | Cancel, Ok, tqparent, "", true ), db( db_ ) { tableName=db->tableName; filter=db->filter; (new TQVBoxLayout(plainPage()))->setAutoAdd(true); - setMainWidget(widget=new TQtSqlDataSourceEditor(plainPage())); + setMainWidget(widget=new QtSqlDataSourceEditor(plainPage())); connect(widget->tableCombo,TQT_SIGNAL(activated(int)),this,TQT_SLOT(tableChanged(int))); connect(widget->editFilter,TQT_SIGNAL(clicked()),this,TQT_SLOT(editFilter())); updateTableCombo(); @@ -176,7 +176,7 @@ KWTQtSqlDataSourceEditor::KWTQtSqlDataSourceEditor( TQWidget *tqparent, KWTQtSql // connect(this,TQT_SIGNAL(okClicked()),this,TQT_SLOT(slotSetQuery())); } -void KWTQtSqlDataSourceEditor::tableChanged(int item) +void KWQtSqlDataSourceEditor::tableChanged(int item) { tableName=widget->tableCombo->text(item); TQSqlCursor *tmpCursor=new TQSqlCursor(tableName,true,db->database); @@ -188,7 +188,7 @@ void KWTQtSqlDataSourceEditor::tableChanged(int item) widget->DataTable->refresh(TQDataTable::RefreshAll); } -void KWTQtSqlDataSourceEditor::updateTableCombo() +void KWQtSqlDataSourceEditor::updateTableCombo() { widget->tableCombo->clear(); if (!db->database) return; @@ -196,7 +196,7 @@ void KWTQtSqlDataSourceEditor::updateTableCombo() widget->tableCombo->insertStringList(db->database->tables()); } -void KWTQtSqlDataSourceEditor::slotSetQuery() +void KWQtSqlDataSourceEditor::slotSetQuery() { db->tableName=tableName; db->filter=filter; @@ -204,15 +204,15 @@ void KWTQtSqlDataSourceEditor::slotSetQuery() } -void KWTQtSqlDataSourceEditor::editFilter() +void KWQtSqlDataSourceEditor::editFilter() { - KWTQtSqlEasyFilter *f=new KWTQtSqlEasyFilter(static_cast(tqparent())); + KWQtSqlEasyFilter *f=new KWQtSqlEasyFilter(static_cast(tqparent())); f->exec(); } extern "C" { KWORD_MAILMERGE_EXPORT KWMailMergeDataSource *create_kwmailmerge_qtsqldb(KInstance *inst,TQObject *tqparent) { - return new KWTQtSqlSerialDataSource(inst,tqparent); + return new KWQtSqlSerialDataSource(inst,tqparent); } } diff --git a/kword/mailmerge/sql/KWQtSqlSerialDataSource.h b/kword/mailmerge/sql/KWQtSqlSerialDataSource.h index c415c19c..cc6061a9 100644 --- a/kword/mailmerge/sql/KWQtSqlSerialDataSource.h +++ b/kword/mailmerge/sql/KWQtSqlSerialDataSource.h @@ -17,27 +17,27 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _SERIALLETTER_TQtSql_PLUGIN_H_ -#define _SERIALLETTER_TQtSql_PLUGIN_H_ +#ifndef _SERIALLETTER_QtSql_PLUGIN_H_ +#define _SERIALLETTER_QtSql_PLUGIN_H_ #include #include #include "KWMailMergeDataSource.h" -#include "KWTQtSqlSerialDataSourceBase.h" -#include "tqtsqldatasourceeditor.h" +#include "KWQtSqlSerialDataSourceBase.h" +#include "qtsqldatasourceeditor.h" /****************************************************************** * - * Class: KWTQtSqlSerialDataSource + * Class: KWQtSqlSerialDataSource * ******************************************************************/ -class KWTQtSqlSerialDataSource: public KWTQtSqlSerialDataSourceBase +class KWQtSqlSerialDataSource: public KWQtSqlSerialDataSourceBase { public: - KWTQtSqlSerialDataSource(KInstance *inst,TQObject *tqparent); - ~KWTQtSqlSerialDataSource(); + KWQtSqlSerialDataSource(KInstance *inst,TQObject *tqparent); + ~KWQtSqlSerialDataSource(); virtual void save( TQDomDocument &doc,TQDomElement&); virtual void load( TQDomElement& elem ); @@ -49,7 +49,7 @@ class KWTQtSqlSerialDataSource: public KWTQtSqlSerialDataSourceBase virtual bool showConfigDialog(TQWidget *,int); protected: - friend class KWTQtSqlDataSourceEditor; + friend class KWQtSqlDataSourceEditor; TQString tableName; TQString filter; TQSqlCursor *myquery; @@ -57,21 +57,21 @@ class KWTQtSqlSerialDataSource: public KWTQtSqlSerialDataSourceBase /****************************************************************** * - * Class: KWTQtSqlDataSourceEditor + * Class: KWQtSqlDataSourceEditor * ******************************************************************/ -class KWTQtSqlDataSourceEditor : public KDialogBase +class KWQtSqlDataSourceEditor : public KDialogBase { Q_OBJECT TQ_OBJECT public: - KWTQtSqlDataSourceEditor( TQWidget *tqparent, KWTQtSqlSerialDataSource *db_ ); - ~KWTQtSqlDataSourceEditor(){;} + KWQtSqlDataSourceEditor( TQWidget *tqparent, KWQtSqlSerialDataSource *db_ ); + ~KWQtSqlDataSourceEditor(){;} private: - KWTQtSqlSerialDataSource *db; - TQtSqlDataSourceEditor *widget; + KWQtSqlSerialDataSource *db; + QtSqlDataSourceEditor *widget; void updateTableCombo(); TQString filter; TQString tableName; diff --git a/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.cpp b/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.cpp index ddb32794..040c657e 100644 --- a/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.cpp +++ b/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.cpp @@ -17,9 +17,9 @@ * Boston, MA 02110-1301, USA. */ -#include "KWTQtSqlSerialDataSourceBase.h" -#include "KWTQtSqlSerialDataSourceBase.moc" -#include "KWTQtSqlMailMergeOpen.h" +#include "KWQtSqlSerialDataSourceBase.h" +#include "KWQtSqlSerialDataSourceBase.moc" +#include "KWQtSqlMailMergeOpen.h" #include #include #include @@ -40,31 +40,31 @@ /****************************************************************** * - * Class: KWTQtSqlSerialDataSourceBase + * Class: KWQtSqlSerialDataSourceBase * ******************************************************************/ -int KWTQtSqlSerialDataSourceBase::connectionId=0; +int KWQtSqlSerialDataSourceBase::connectionId=0; -KWTQtSqlSerialDataSourceBase::KWTQtSqlSerialDataSourceBase(KInstance *inst,TQObject *tqparent) +KWQtSqlSerialDataSourceBase::KWQtSqlSerialDataSourceBase(KInstance *inst,TQObject *tqparent) : KWMailMergeDataSource(inst,tqparent) { - DataBaseConnection=TQString("KWTQTSTQLPOWER")+tqparent->name()+TQString("--%1").tqarg(connectionId++); + DataBaseConnection=TQString("KWTQTSQLPOWER")+tqparent->name()+TQString("--%1").tqarg(connectionId++); port=i18n("default"); } -KWTQtSqlSerialDataSourceBase::~KWTQtSqlSerialDataSourceBase() +KWQtSqlSerialDataSourceBase::~KWQtSqlSerialDataSourceBase() { TQSqlDatabase::removeDatabase(DataBaseConnection); } -bool KWTQtSqlSerialDataSourceBase::showConfigDialog(TQWidget *par,int action) +bool KWQtSqlSerialDataSourceBase::showConfigDialog(TQWidget *par,int action) { bool ret=false; if (action==KWSLOpen) { - KWTQtSqlMailMergeOpen *dia=new KWTQtSqlMailMergeOpen(par,this); + KWQtSqlMailMergeOpen *dia=new KWQtSqlMailMergeOpen(par,this); ret=dia->exec(); if (ret) openDatabase(); @@ -73,7 +73,7 @@ bool KWTQtSqlSerialDataSourceBase::showConfigDialog(TQWidget *par,int action) return ret; } -bool KWTQtSqlSerialDataSourceBase::openDatabase() +bool KWQtSqlSerialDataSourceBase::openDatabase() { TQCString pwd; TQSqlDatabase::removeDatabase(DataBaseConnection); diff --git a/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.h b/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.h index a0705bdf..ee4e02a8 100644 --- a/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.h +++ b/kword/mailmerge/sql/KWQtSqlSerialDataSourceBase.h @@ -17,8 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _SERIALLETTER_TQtSql_BASE_H_ -#define _SERIALLETTER_TQtSql_BASE_H_ +#ifndef _SERIALLETTER_QtSql_BASE_H_ +#define _SERIALLETTER_QtSql_BASE_H_ #include #include @@ -26,28 +26,28 @@ #include #include "KWMailMergeDataSource.h" -#include "tqtsqlopenwidget.h" +#include "qtsqlopenwidget.h" /****************************************************************** * - * Class: KWTQtSqlSerialDataSourceBase + * Class: KWQtSqlSerialDataSourceBase * ******************************************************************/ -class KWTQtSqlSerialDataSourceBase: public KWMailMergeDataSource +class KWQtSqlSerialDataSourceBase: public KWMailMergeDataSource { Q_OBJECT - TQ_OBJECT +// TQ_OBJECT K_DCOP public: - KWTQtSqlSerialDataSourceBase(KInstance *inst,TQObject *tqparent); - ~KWTQtSqlSerialDataSourceBase(); + KWQtSqlSerialDataSourceBase(KInstance *inst,TQObject *tqparent); + ~KWQtSqlSerialDataSourceBase(); virtual bool showConfigDialog(TQWidget *par,int action); protected: - friend class KWTQtSqlMailMergeOpen; + friend class KWQtSqlMailMergeOpen; TQString hostname; TQString username; TQString driver; diff --git a/kword/mailmerge/sql/qtsqldatasourceeditor.ui.h b/kword/mailmerge/sql/qtsqldatasourceeditor.ui.h index 160596f6..3f9fe366 100644 --- a/kword/mailmerge/sql/qtsqldatasourceeditor.ui.h +++ b/kword/mailmerge/sql/qtsqldatasourceeditor.ui.h @@ -7,7 +7,7 @@ *****************************************************************************/ -void TQtSqlDataSourceEditor::filterCheckBox_toggled( bool fcb_state ) +void QtSqlDataSourceEditor::filterCheckBox_toggled( bool fcb_state ) { editFilter->setEnabled(fcb_state); } diff --git a/lib/configure.in.mid b/lib/configure.in.mid index 7fc54555..718d6d35 100644 --- a/lib/configure.in.mid +++ b/lib/configure.in.mid @@ -29,7 +29,7 @@ AC_MSG_CHECKING([whether kopainter should be compiled]) # first check which main application we could compile for args in $SUBDIRLIST ; do case $args in - krita) COMPILE_LIB_FOR_KRITA="$args " ;; + chalk) COMPILE_LIB_FOR_KRITA="$args " ;; karbon) COMPILE_LIB_FOR_KARBON="$args " ;; kivio) COMPILE_LIB_FOR_KIVIO="$args " ;; esac @@ -39,7 +39,7 @@ done COMPILE_LIB_FOR_KPRESENTER="#" for args in $DO_NOT_COMPILE ; do case $args in - krita) COMPILE_LIB_FOR_KRITA= ;; + chalk) COMPILE_LIB_FOR_KRITA= ;; karbon) COMPILE_LIB_FOR_KARBON= ;; kivio) COMPILE_LIB_FOR_KIVIO= ;; kpresenter) COMPILE_LIB_FOR_KPRESENTER= ;; diff --git a/lib/kofficecore/KoGlobal.cpp b/lib/kofficecore/KoGlobal.cpp index 53c9e4fe..57868746 100644 --- a/lib/kofficecore/KoGlobal.cpp +++ b/lib/kofficecore/KoGlobal.cpp @@ -64,7 +64,7 @@ KoGlobal::KoGlobal() // Another way to get the DPI of the display would be TQPaintDeviceMetrics, // but we have no widget here (and moving this to KoView wouldn't allow // using this from the document easily). -#ifdef TQ_WS_X11 +#ifdef Q_WS_X11 m_dpiX = TQPaintDevice::x11AppDpiX(); m_dpiY = TQPaintDevice::x11AppDpiY(); #else diff --git a/lib/kofficecore/tests/filterchain_test.cpp b/lib/kofficecore/tests/filterchain_test.cpp index 773bd02f..05592b92 100644 --- a/lib/kofficecore/tests/filterchain_test.cpp +++ b/lib/kofficecore/tests/filterchain_test.cpp @@ -41,12 +41,12 @@ int main( int /*argc*/, char ** /*argv*/ ) chain->dump(); } - mimeType = "application/x-krita"; + mimeType = "application/x-chalk"; chain = g.chain( manager, mimeType ); if ( !chain ) - kdDebug() << "Chain for 'application/x-krita' is not available, OK" << endl; + kdDebug() << "Chain for 'application/x-chalk' is not available, OK" << endl; else { - kdError() << "Chain 'application/x-krita' is available!" << endl; + kdError() << "Chain 'application/x-chalk' is available!" << endl; chain->dump(); } diff --git a/lib/kofficecore/tests/koxmlreadertest.cpp b/lib/kofficecore/tests/koxmlreadertest.cpp index f8e6ed89..aec06fae 100644 --- a/lib/kofficecore/tests/koxmlreadertest.cpp +++ b/lib/kofficecore/tests/koxmlreadertest.cpp @@ -606,7 +606,7 @@ void testDocument() xmlstream << ""; xmlstream << " \n"; xmlstream << " \n"; - xmlstream << " \n"; + xmlstream << " \n"; xmlstream << ""; KoXmlDocument doc; diff --git a/lib/kopainter/koIconChooser.h b/lib/kopainter/koIconChooser.h index df69fd72..59057f2e 100644 --- a/lib/kopainter/koIconChooser.h +++ b/lib/kopainter/koIconChooser.h @@ -119,7 +119,7 @@ private: }; // This is a first attempt at a pattern chooser widget abstraction which is at least -// useful for two applications(karbon and krita). It is really a light version of +// useful for two applications(karbon and chalk). It is really a light version of // kis_patternchooser. (Rob) class KOPAINTER_EXPORT KoPatternChooser : public TQWidget { diff --git a/lib/kopainter/ko_rgb_widget.cc b/lib/kopainter/ko_rgb_widget.cc index 64b15366..22df059b 100644 --- a/lib/kopainter/ko_rgb_widget.cc +++ b/lib/kopainter/ko_rgb_widget.cc @@ -1,5 +1,5 @@ /* - * This file is part of Krita + * This file is part of Chalk * * Copyright (c) 1999 Matthias Elter (me@kde.org) * Copyright (c) 2001-2002 Igor Jansen (rm@kde.org) diff --git a/lib/kopainter/kogradientmanager.cc b/lib/kopainter/kogradientmanager.cc index 7c936c4b..242b5470 100644 --- a/lib/kopainter/kogradientmanager.cc +++ b/lib/kopainter/kogradientmanager.cc @@ -50,7 +50,7 @@ KoGradient* KoGradientManager::loadGradient(const TQString& filename) { if(strExt == ".ggr") { - return loadKritaGradient(&f); + return loadChalkGradient(&f); } else if(strExt==".kgr") { @@ -89,7 +89,7 @@ KoGradient* KoGradientManager::loadKarbonGradient(TQFile* file) return 0; } -KoGradient* KoGradientManager::loadKritaGradient(TQFile* file) +KoGradient* KoGradientManager::loadChalkGradient(TQFile* file) { KoGradient* grad = new KoGradient(); diff --git a/lib/kopainter/kogradientmanager.h b/lib/kopainter/kogradientmanager.h index 86130480..b898ce89 100644 --- a/lib/kopainter/kogradientmanager.h +++ b/lib/kopainter/kogradientmanager.h @@ -103,7 +103,7 @@ public: private: KoGradient* loadKarbonGradient(TQFile* file); - KoGradient* loadKritaGradient(TQFile* file); + KoGradient* loadChalkGradient(TQFile* file); KoGradient* loadSvgGradient(TQFile* file); KoGradient* parseKarbonGradient(const TQDomElement& element); KoGradient* parseSvgGradient(const TQDomElement& element); diff --git a/lib/kotext/KoTextZoomHandler.cpp b/lib/kotext/KoTextZoomHandler.cpp index e7e6d1b4..acd2285d 100644 --- a/lib/kotext/KoTextZoomHandler.cpp +++ b/lib/kotext/KoTextZoomHandler.cpp @@ -40,7 +40,7 @@ double KoTextZoomHandler::tqlayoutUnitToFontSize( int luSize, bool /*forPrint*/ { // TQt will use TQPaintDevice::x11AppDpiY() to go from pt to pixel for fonts return tqlayoutUnitPtToPt( luSize ) * m_zoomedResolutionY -#ifdef TQ_WS_X11 +#ifdef Q_WS_X11 / POINT_TO_INCH(TQPaintDevice::x11AppDpiY()) #endif ; diff --git a/lib/kross/test/testcase.rb b/lib/kross/test/testcase.rb index 71354ea2..34f73c13 100644 --- a/lib/kross/test/testcase.rb +++ b/lib/kross/test/testcase.rb @@ -4,7 +4,7 @@ class TestKross < Test::Unit::TestCase def setup: require "krosstestpluginmodule" testpluginobject1 = Krosstestpluginmodule::get("testpluginobject1") - #Krosskritacore::get("KritaDocument") + #Krosschalkcore::get("ChalkDocument") #testpluginobject1.func1() #def test_primitive # print "---------------- 1\n" diff --git a/mimetypes/kde33/vnd.oasis.opendocument.image.desktop b/mimetypes/kde33/vnd.oasis.opendocument.image.desktop index dd37fc02..09e2601d 100644 --- a/mimetypes/kde33/vnd.oasis.opendocument.image.desktop +++ b/mimetypes/kde33/vnd.oasis.opendocument.image.desktop @@ -2,7 +2,7 @@ Type=MimeType MimeType=application/vnd.oasis.opendocument.image Patterns=*.odi;*.ODI -Icon=krita_kra +Icon=chalk_kra Comment=OASIS OpenDocument Image Comment[bg]=Изображение на OASIS OpenDocument Comment[br]=Skeudenn OpenDocument OASIS diff --git a/plugins/scan/Makefile.am b/plugins/scan/Makefile.am index f3e46938..cf50d517 100644 --- a/plugins/scan/Makefile.am +++ b/plugins/scan/Makefile.am @@ -1,13 +1,13 @@ kwordrcdir = $(kde_datadir)/kword/kpartplugins kwordrc_DATA = scan-kword.rc -kritarcdir = $(kde_datadir)/krita/kpartplugins -kritarc_DATA = scan-krita.rc +chalkrcdir = $(kde_datadir)/chalk/kpartplugins +chalkrc_DATA = scan-chalk.rc kpresenterrcdir = $(kde_datadir)/kpresenter/kpartplugins kpresenterrc_DATA = scan-kpresenter.rc -EXTRA_DIST = $(kwordrc_DATA) $(kritarc_DATA) $(kpresenterrc_DATA) +EXTRA_DIST = $(kwordrc_DATA) $(chalkrc_DATA) $(kpresenterrc_DATA) INCLUDES = $(KOFFICE_INCLUDES) $(all_includes) kde_module_LTLIBRARIES = kofficescan.la diff --git a/plugins/scan/scan-chalk.rc b/plugins/scan/scan-chalk.rc new file mode 100644 index 00000000..c7298729 --- /dev/null +++ b/plugins/scan/scan-chalk.rc @@ -0,0 +1,9 @@ + + + + &Tools + + + + + diff --git a/subdirs b/subdirs index aca359ca..5e82c6f0 100644 --- a/subdirs +++ b/subdirs @@ -11,7 +11,7 @@ kivio koshell kounavail kpresenter -krita +chalk kspread kugar mimetypes diff --git a/tools/kfile-plugins/koffice/kfile_koffice.cpp b/tools/kfile-plugins/koffice/kfile_koffice.cpp index 2ca0b31e..88d7fe8b 100644 --- a/tools/kfile-plugins/koffice/kfile_koffice.cpp +++ b/tools/kfile-plugins/koffice/kfile_koffice.cpp @@ -45,7 +45,7 @@ KOfficePlugin::KOfficePlugin(TQObject *tqparent, const char *name, makeMimeTypeInfo( "application/x-kontour" ); makeMimeTypeInfo( "application/x-kchart" ); makeMimeTypeInfo( "application/x-kivio" ); - makeMimeTypeInfo( "application/x-krita" ); + makeMimeTypeInfo( "application/x-chalk" ); makeMimeTypeInfo( "application/x-kformula" ); /*makeMimeTypeInfo( "application/vnd.kde.kword" ); diff --git a/tools/quickprint/Makefile.am b/tools/quickprint/Makefile.am index 5615d445..96f13f3b 100644 --- a/tools/quickprint/Makefile.am +++ b/tools/quickprint/Makefile.am @@ -1,2 +1,2 @@ -konqservice_DATA = kchart_konqi.desktop karbon_konqi.desktop kspread_konqi.desktop kformula_konqi.desktop kpresenter_konqi.desktop kword_konqi.desktop kexi_konqi.desktop krita_konqi.desktop kivio_konqi.desktop +konqservice_DATA = kchart_konqi.desktop karbon_konqi.desktop kspread_konqi.desktop kformula_konqi.desktop kpresenter_konqi.desktop kword_konqi.desktop kexi_konqi.desktop chalk_konqi.desktop kivio_konqi.desktop konqservicedir = $(kde_datadir)/konqueror/servicemenus diff --git a/tools/quickprint/chalk_konqi.desktop b/tools/quickprint/chalk_konqi.desktop new file mode 100644 index 00000000..720103bd --- /dev/null +++ b/tools/quickprint/chalk_konqi.desktop @@ -0,0 +1,63 @@ +[Desktop Entry] +ServiceTypes=application/x-chalk +Actions=Print; + +[Desktop Action Print] +Name=Print... +Name[ar]=طباعة... +Name[bg]=Печат... +Name[br]=Moulañ ... +Name[ca]=Imprimir... +Name[cs]=Tisk... +Name[cy]=Argraffu... +Name[da]=Udskriv... +Name[de]=Drucken ... +Name[el]=Εκτύπωση... +Name[eo]=Presi... +Name[es]=Imprimir... +Name[et]=Trükkimine... +Name[eu]=Inprimatu... +Name[fa]=چاپ... +Name[fi]=Tulosta... +Name[fr]=Impression... +Name[fy]=Printsje... +Name[ga]=Priontáil... +Name[gl]=Imprimir... +Name[he]=הדפסה... +Name[hi]=छापें... +Name[hr]=Ispiši... +Name[hu]=Nyomtatás... +Name[is]=Prenta... +Name[it]=Stampa... +Name[ja]=印刷... +Name[km]=បោះពុម្ព​... +Name[lo]=ເຄື່ອງພິມ - K +Name[lv]=Drukāt... +Name[ms]=Cetak... +Name[nb]=Skriv ut … +Name[nds]=Drucken... +Name[ne]=मुद्रण गर्नुहोस्... +Name[nl]=Afdrukken... +Name[nn]=Skriv ut … +Name[pa]=ਛਾਪੋ... +Name[pl]=Drukuj... +Name[pt]=Imprimir... +Name[pt_BR]=Imprimir... +Name[ru]=Печать... +Name[se]=Čálit … +Name[sk]=Tlačiť... +Name[sl]=Natisni ... +Name[sr]=Штампај... +Name[sr@Latn]=Štampaj... +Name[sv]=Skriv ut... +Name[ta]=அச்சு... +Name[tg]=Чоп... +Name[tr]=Yazdır... +Name[uk]=Друк... +Name[uz]=Bosib chiqarish +Name[uz@cyrillic]=Босиб чиқариш +Name[wa]=Imprimer... +Name[zh_CN]=打印... +Name[zh_TW]=列印... +Exec=chalk --print %U +Icon=filequickprint diff --git a/tools/thumbnail/kofficethumbnail.desktop b/tools/thumbnail/kofficethumbnail.desktop index d15b5986..c2f3a7cf 100644 --- a/tools/thumbnail/kofficethumbnail.desktop +++ b/tools/thumbnail/kofficethumbnail.desktop @@ -65,6 +65,6 @@ Name[xh]=Iifayile ze KOffice Name[zh_CN]=KOffice 文件 Name[zh_TW]=KOffice 檔案 ServiceTypes=ThumbCreator -MimeTypes=application/x-kword,application/x-kspread,application/x-kpresenter,application/x-karbon,application/x-krita,application/x-kchart,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.text-template,application/vnd.oasis.opendocument.graphics,application/vnd.oasis.opendocument.graphics-template,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.presentation-template,application/vnd.oasis.opendocument.spreadsheet,application/vnd.oasis.opendocument.spreadsheet-template,application/vnd.oasis.opendocument.chart,application/vnd.oasis.opendocument.chart-template,application/vnd.oasis.opendocument.formula,application/vnd.oasis.opendocument.formula-template +MimeTypes=application/x-kword,application/x-kspread,application/x-kpresenter,application/x-karbon,application/x-chalk,application/x-kchart,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.text-template,application/vnd.oasis.opendocument.graphics,application/vnd.oasis.opendocument.graphics-template,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.presentation-template,application/vnd.oasis.opendocument.spreadsheet,application/vnd.oasis.opendocument.spreadsheet-template,application/vnd.oasis.opendocument.chart,application/vnd.oasis.opendocument.chart-template,application/vnd.oasis.opendocument.formula,application/vnd.oasis.opendocument.formula-template X-KDE-Library=kofficethumbnail CacheThumbnail=true -- cgit v1.2.1